|
@@ -75,6 +75,7 @@ enum {
|
|
AHCI_CMD_CLR_BUSY = (1 << 10),
|
|
AHCI_CMD_CLR_BUSY = (1 << 10),
|
|
|
|
|
|
RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
|
|
RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
|
|
|
|
+ RX_FIS_SDB = 0x58, /* offset of SDB FIS data */
|
|
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
|
|
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
|
|
|
|
|
|
board_ahci = 0,
|
|
board_ahci = 0,
|
|
@@ -202,6 +203,10 @@ struct ahci_port_priv {
|
|
dma_addr_t cmd_tbl_dma;
|
|
dma_addr_t cmd_tbl_dma;
|
|
void *rx_fis;
|
|
void *rx_fis;
|
|
dma_addr_t rx_fis_dma;
|
|
dma_addr_t rx_fis_dma;
|
|
|
|
+ /* for NCQ spurious interrupt analysis */
|
|
|
|
+ int ncq_saw_spurious_sdb_cnt;
|
|
|
|
+ unsigned int ncq_saw_d2h:1;
|
|
|
|
+ unsigned int ncq_saw_dmas:1;
|
|
};
|
|
};
|
|
|
|
|
|
static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
|
|
static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
|
|
@@ -1109,8 +1114,9 @@ static void ahci_host_intr(struct ata_port *ap)
|
|
void __iomem *mmio = ap->host->mmio_base;
|
|
void __iomem *mmio = ap->host->mmio_base;
|
|
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
|
|
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
|
|
struct ata_eh_info *ehi = &ap->eh_info;
|
|
struct ata_eh_info *ehi = &ap->eh_info;
|
|
|
|
+ struct ahci_port_priv *pp = ap->private_data;
|
|
u32 status, qc_active;
|
|
u32 status, qc_active;
|
|
- int rc;
|
|
|
|
|
|
+ int rc, known_irq = 0;
|
|
|
|
|
|
status = readl(port_mmio + PORT_IRQ_STAT);
|
|
status = readl(port_mmio + PORT_IRQ_STAT);
|
|
writel(status, port_mmio + PORT_IRQ_STAT);
|
|
writel(status, port_mmio + PORT_IRQ_STAT);
|
|
@@ -1137,17 +1143,52 @@ static void ahci_host_intr(struct ata_port *ap)
|
|
|
|
|
|
/* hmmm... a spurious interupt */
|
|
/* hmmm... a spurious interupt */
|
|
|
|
|
|
- /* some devices send D2H reg with I bit set during NCQ command phase */
|
|
|
|
- if (ap->sactive && (status & PORT_IRQ_D2H_REG_FIS))
|
|
|
|
|
|
+ /* if !NCQ, ignore. No modern ATA device has broken HSM
|
|
|
|
+ * implementation for non-NCQ commands.
|
|
|
|
+ */
|
|
|
|
+ if (!ap->sactive)
|
|
return;
|
|
return;
|
|
|
|
|
|
- /* ignore interim PIO setup fis interrupts */
|
|
|
|
- if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS))
|
|
|
|
- return;
|
|
|
|
|
|
+ if (status & PORT_IRQ_D2H_REG_FIS) {
|
|
|
|
+ if (!pp->ncq_saw_d2h)
|
|
|
|
+ ata_port_printk(ap, KERN_INFO,
|
|
|
|
+ "D2H reg with I during NCQ, "
|
|
|
|
+ "this message won't be printed again\n");
|
|
|
|
+ pp->ncq_saw_d2h = 1;
|
|
|
|
+ known_irq = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (status & PORT_IRQ_DMAS_FIS) {
|
|
|
|
+ if (!pp->ncq_saw_dmas)
|
|
|
|
+ ata_port_printk(ap, KERN_INFO,
|
|
|
|
+ "DMAS FIS during NCQ, "
|
|
|
|
+ "this message won't be printed again\n");
|
|
|
|
+ pp->ncq_saw_dmas = 1;
|
|
|
|
+ known_irq = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (status & PORT_IRQ_SDB_FIS &&
|
|
|
|
+ pp->ncq_saw_spurious_sdb_cnt < 10) {
|
|
|
|
+ /* SDB FIS containing spurious completions might be
|
|
|
|
+ * dangerous, we need to know more about them. Print
|
|
|
|
+ * more of it.
|
|
|
|
+ */
|
|
|
|
+ const u32 *f = pp->rx_fis + RX_FIS_SDB;
|
|
|
|
+
|
|
|
|
+ ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ "
|
|
|
|
+ "issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n",
|
|
|
|
+ readl(port_mmio + PORT_CMD_ISSUE),
|
|
|
|
+ readl(port_mmio + PORT_SCR_ACT), f[0], f[1],
|
|
|
|
+ pp->ncq_saw_spurious_sdb_cnt < 10 ?
|
|
|
|
+ "" : ", shutting up");
|
|
|
|
+
|
|
|
|
+ pp->ncq_saw_spurious_sdb_cnt++;
|
|
|
|
+ known_irq = 1;
|
|
|
|
+ }
|
|
|
|
|
|
- if (ata_ratelimit())
|
|
|
|
|
|
+ if (!known_irq)
|
|
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
|
|
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
|
|
- "(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
|
|
|
|
|
|
+ "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
|
|
status, ap->active_tag, ap->sactive);
|
|
status, ap->active_tag, ap->sactive);
|
|
}
|
|
}
|
|
|
|
|