diff options
author | Tejun Heo <htejun@gmail.com> | 2007-10-09 02:02:23 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-12 14:55:47 -0400 |
commit | 5f226c6bf78edab023ed1ea679531731d9df92a6 (patch) | |
tree | 01e0dff1224476aa52c240ee958ec7948bb85cc6 /drivers/ata/ahci.c | |
parent | 1c954a4d9a9e351fa3509533fd8dd5f3821206cd (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>
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r-- | drivers/ata/ahci.c | 30 |
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 */ |