aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/ahci.c57
1 files changed, 49 insertions, 8 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index e3c7b312287a..2fe5a58195de 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -75,6 +75,7 @@ enum {
75 AHCI_CMD_CLR_BUSY = (1 << 10), 75 AHCI_CMD_CLR_BUSY = (1 << 10),
76 76
77 RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ 77 RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
78 RX_FIS_SDB = 0x58, /* offset of SDB FIS data */
78 RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ 79 RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
79 80
80 board_ahci = 0, 81 board_ahci = 0,
@@ -202,6 +203,10 @@ struct ahci_port_priv {
202 dma_addr_t cmd_tbl_dma; 203 dma_addr_t cmd_tbl_dma;
203 void *rx_fis; 204 void *rx_fis;
204 dma_addr_t rx_fis_dma; 205 dma_addr_t rx_fis_dma;
206 /* for NCQ spurious interrupt analysis */
207 int ncq_saw_spurious_sdb_cnt;
208 unsigned int ncq_saw_d2h:1;
209 unsigned int ncq_saw_dmas:1;
205}; 210};
206 211
207static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); 212static 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)
1109 void __iomem *mmio = ap->host->mmio_base; 1114 void __iomem *mmio = ap->host->mmio_base;
1110 void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1115 void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1111 struct ata_eh_info *ehi = &ap->eh_info; 1116 struct ata_eh_info *ehi = &ap->eh_info;
1117 struct ahci_port_priv *pp = ap->private_data;
1112 u32 status, qc_active; 1118 u32 status, qc_active;
1113 int rc; 1119 int rc, known_irq = 0;
1114 1120
1115 status = readl(port_mmio + PORT_IRQ_STAT); 1121 status = readl(port_mmio + PORT_IRQ_STAT);
1116 writel(status, port_mmio + PORT_IRQ_STAT); 1122 writel(status, port_mmio + PORT_IRQ_STAT);
@@ -1137,17 +1143,52 @@ static void ahci_host_intr(struct ata_port *ap)
1137 1143
1138 /* hmmm... a spurious interupt */ 1144 /* hmmm... a spurious interupt */
1139 1145
1140 /* some devices send D2H reg with I bit set during NCQ command phase */ 1146 /* if !NCQ, ignore. No modern ATA device has broken HSM
1141 if (ap->sactive && (status & PORT_IRQ_D2H_REG_FIS)) 1147 * implementation for non-NCQ commands.
1148 */
1149 if (!ap->sactive)
1142 return; 1150 return;
1143 1151
1144 /* ignore interim PIO setup fis interrupts */ 1152 if (status & PORT_IRQ_D2H_REG_FIS) {
1145 if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS)) 1153 if (!pp->ncq_saw_d2h)
1146 return; 1154 ata_port_printk(ap, KERN_INFO,
1155 "D2H reg with I during NCQ, "
1156 "this message won't be printed again\n");
1157 pp->ncq_saw_d2h = 1;
1158 known_irq = 1;
1159 }
1160
1161 if (status & PORT_IRQ_DMAS_FIS) {
1162 if (!pp->ncq_saw_dmas)
1163 ata_port_printk(ap, KERN_INFO,
1164 "DMAS FIS during NCQ, "
1165 "this message won't be printed again\n");
1166 pp->ncq_saw_dmas = 1;
1167 known_irq = 1;
1168 }
1169
1170 if (status & PORT_IRQ_SDB_FIS &&
1171 pp->ncq_saw_spurious_sdb_cnt < 10) {
1172 /* SDB FIS containing spurious completions might be
1173 * dangerous, we need to know more about them. Print
1174 * more of it.
1175 */
1176 const u32 *f = pp->rx_fis + RX_FIS_SDB;
1177
1178 ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ "
1179 "issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n",
1180 readl(port_mmio + PORT_CMD_ISSUE),
1181 readl(port_mmio + PORT_SCR_ACT), f[0], f[1],
1182 pp->ncq_saw_spurious_sdb_cnt < 10 ?
1183 "" : ", shutting up");
1184
1185 pp->ncq_saw_spurious_sdb_cnt++;
1186 known_irq = 1;
1187 }
1147 1188
1148 if (ata_ratelimit()) 1189 if (!known_irq)
1149 ata_port_printk(ap, KERN_INFO, "spurious interrupt " 1190 ata_port_printk(ap, KERN_INFO, "spurious interrupt "
1150 "(irq_stat 0x%x active_tag %d sactive 0x%x)\n", 1191 "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
1151 status, ap->active_tag, ap->sactive); 1192 status, ap->active_tag, ap->sactive);
1152} 1193}
1153 1194