Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ahci: Workaround for ThunderX Errata#22536

Due to Errata in ThunderX, HOST_IRQ_STAT should be
cleared before leaving the interrupt handler.
The patch attempts to satisfy the need.

Changes from V2:
- removed newfile
- code is now under CONFIG_ARM64

Changes from V1:
- Rebased on top of libata/for-4.6
- Moved ThunderX intr handler to new file

tj: Minor adjustments to comments.

Signed-off-by: Tirumalesh Chalamarla <tchalamarla@caviumnetworks.com>
Signed-off-by: Tejun Heo <tj@kernel.org>

authored by

Tirumalesh Chalamarla and committed by
Tejun Heo
d243bed3 4ee34ea3

+43
+43
drivers/ata/ahci.c
··· 1331 1331 {} 1332 1332 #endif 1333 1333 1334 + #ifdef CONFIG_ARM64 1335 + /* 1336 + * Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently. 1337 + * Workaround is to make sure all pending IRQs are served before leaving 1338 + * handler. 1339 + */ 1340 + static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance) 1341 + { 1342 + struct ata_host *host = dev_instance; 1343 + struct ahci_host_priv *hpriv; 1344 + unsigned int rc = 0; 1345 + void __iomem *mmio; 1346 + u32 irq_stat, irq_masked; 1347 + unsigned int handled = 1; 1348 + 1349 + VPRINTK("ENTER\n"); 1350 + hpriv = host->private_data; 1351 + mmio = hpriv->mmio; 1352 + irq_stat = readl(mmio + HOST_IRQ_STAT); 1353 + if (!irq_stat) 1354 + return IRQ_NONE; 1355 + 1356 + do { 1357 + irq_masked = irq_stat & hpriv->port_map; 1358 + spin_lock(&host->lock); 1359 + rc = ahci_handle_port_intr(host, irq_masked); 1360 + if (!rc) 1361 + handled = 0; 1362 + writel(irq_stat, mmio + HOST_IRQ_STAT); 1363 + irq_stat = readl(mmio + HOST_IRQ_STAT); 1364 + spin_unlock(&host->lock); 1365 + } while (irq_stat); 1366 + VPRINTK("EXIT\n"); 1367 + 1368 + return IRQ_RETVAL(handled); 1369 + } 1370 + #endif 1371 + 1334 1372 /* 1335 1373 * ahci_init_msix() - optionally enable per-port MSI-X otherwise defer 1336 1374 * to single msi. ··· 1603 1565 /* must set flag prior to save config in order to take effect */ 1604 1566 if (ahci_broken_devslp(pdev)) 1605 1567 hpriv->flags |= AHCI_HFLAG_NO_DEVSLP; 1568 + 1569 + #ifdef CONFIG_ARM64 1570 + if (pdev->vendor == 0x177d && pdev->device == 0xa01c) 1571 + hpriv->irq_handler = ahci_thunderx_irq_handler; 1572 + #endif 1606 1573 1607 1574 /* save initial config */ 1608 1575 ahci_pci_save_initial_config(pdev, hpriv);