aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-10-09 02:02:23 -0400
committerJeff Garzik <jeff@garzik.org>2007-10-12 14:55:47 -0400
commit5f226c6bf78edab023ed1ea679531731d9df92a6 (patch)
tree01e0dff1224476aa52c240ee958ec7948bb85cc6
parent1c954a4d9a9e351fa3509533fd8dd5f3821206cd (diff)
ahci: fix notification handling
Asynchronous notification on ICH9 didn't work because it didn't write AN FIS into the RX area - it only updates SNotification. Also, snooping SDB_FIS RX area is racy against further SDB FIS receptions. Let sata_async_notification() determine using SNTF if it's available and snoop RX area iff SNTF isn't available Signed-off-by: Tejun Heo <htejun@gmail.com> Cc: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/ata/ahci.c30
1 files changed, 21 insertions, 9 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 6633c7422fc4..abfb72aae3de 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1420,6 +1420,7 @@ static void ahci_port_intr(struct ata_port *ap)
1420 void __iomem *port_mmio = ap->ioaddr.cmd_addr; 1420 void __iomem *port_mmio = ap->ioaddr.cmd_addr;
1421 struct ata_eh_info *ehi = &ap->link.eh_info; 1421 struct ata_eh_info *ehi = &ap->link.eh_info;
1422 struct ahci_port_priv *pp = ap->private_data; 1422 struct ahci_port_priv *pp = ap->private_data;
1423 struct ahci_host_priv *hpriv = ap->host->private_data;
1423 u32 status, qc_active; 1424 u32 status, qc_active;
1424 int rc, known_irq = 0; 1425 int rc, known_irq = 0;
1425 1426
@@ -1432,17 +1433,28 @@ static void ahci_port_intr(struct ata_port *ap)
1432 } 1433 }
1433 1434
1434 if (status & PORT_IRQ_SDB_FIS) { 1435 if (status & PORT_IRQ_SDB_FIS) {
1435 /* If the 'N' bit in word 0 of the FIS is set, we just 1436 /* If SNotification is available, leave notification
1436 * received asynchronous notification. Tell libata 1437 * handling to sata_async_notification(). If not,
1437 * about it. Note that as the SDB FIS itself is 1438 * emulate it by snooping SDB FIS RX area.
1438 * accessible, SNotification can be emulated by the 1439 *
1439 * driver but don't bother for the time being. 1440 * Snooping FIS RX area is probably cheaper than
1441 * poking SNotification but some constrollers which
1442 * implement SNotification, ICH9 for example, don't
1443 * store AN SDB FIS into receive area.
1440 */ 1444 */
1441 const __le32 *f = pp->rx_fis + RX_FIS_SDB; 1445 if (hpriv->cap & HOST_CAP_SNTF)
1442 u32 f0 = le32_to_cpu(f[0]);
1443
1444 if (f0 & (1 << 15))
1445 sata_async_notification(ap); 1446 sata_async_notification(ap);
1447 else {
1448 /* If the 'N' bit in word 0 of the FIS is set,
1449 * we just received asynchronous notification.
1450 * Tell libata about it.
1451 */
1452 const __le32 *f = pp->rx_fis + RX_FIS_SDB;
1453 u32 f0 = le32_to_cpu(f[0]);
1454
1455 if (f0 & (1 << 15))
1456 sata_async_notification(ap);
1457 }
1446 } 1458 }
1447 1459
1448 /* pp->active_link is valid iff any command is in flight */ 1460 /* pp->active_link is valid iff any command is in flight */