aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2016-09-05 11:21:45 -0400
committerTejun Heo <tj@kernel.org>2016-09-06 12:38:17 -0400
commit0b9e2988ab2261fd6d4a0039edf81ed1e3662be8 (patch)
tree75dbefd4076fca402d2c62b4e62bd0e4469439e0 /drivers/ata
parent2536524a91fe5c5a9fddd282fd4e79ee0976aefe (diff)
ahci: use pci_alloc_irq_vectors
Use the new pci_alloc_irq_vectors API to allocate MSI-X and MSI vectors. The big advantage over the old code is that we can use the same API for MSI and MSI-X, and that we don't need to store the MSI-X vector mapping in driver-private data structures. This first conversion keeps the probe order as-is: MSI-X multi vector, MSI multi vector, MSI single vector, MSI-X single vector and last a single least legacy interrupt line. There is one small change of behavior: we now check the "MSI Revert to Single Message" flag for MSI-X in addition to MSI. Because the API to find the Linux IRQ number for a MSI/MSI-X vector is PCI specific, but libahaci is bus-agnostic I had to a get_irq_vector function pointer to struct ahci_host_priv. The alternative would be to move the multi-vector case of ahci_host_activate to ahci.c and just call ata_host_activate directly from the others users of ahci_host_activate. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ahci.c149
-rw-r--r--drivers/ata/ahci.h24
-rw-r--r--drivers/ata/libahci.c11
3 files changed, 45 insertions, 139 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 90eabaf81215..ba5f11cebee2 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1400,142 +1400,56 @@ static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
1400} 1400}
1401#endif 1401#endif
1402 1402
1403/* 1403static int ahci_get_irq_vector(struct ata_host *host, int port)
1404 * ahci_init_msix() - optionally enable per-port MSI-X otherwise defer
1405 * to single msi.
1406 */
1407static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports,
1408 struct ahci_host_priv *hpriv, unsigned long flags)
1409{ 1404{
1410 int nvec, i, rc; 1405 return pci_irq_vector(to_pci_dev(host->dev), port);
1411
1412 /* Do not init MSI-X if MSI is disabled for the device */
1413 if (hpriv->flags & AHCI_HFLAG_NO_MSI)
1414 return -ENODEV;
1415
1416 nvec = pci_msix_vec_count(pdev);
1417 if (nvec < 0)
1418 return nvec;
1419
1420 /*
1421 * Proper MSI-X implementations will have a vector per-port.
1422 * Barring that, we prefer single-MSI over single-MSIX. If this
1423 * check fails (not enough MSI-X vectors for all ports) we will
1424 * be called again with the flag clear iff ahci_init_msi()
1425 * fails.
1426 */
1427 if (flags & AHCI_HFLAG_MULTI_MSIX) {
1428 if (nvec < n_ports)
1429 return -ENODEV;
1430 nvec = n_ports;
1431 } else if (nvec) {
1432 nvec = 1;
1433 } else {
1434 /*
1435 * Emit dev_err() since this was the non-legacy irq
1436 * method of last resort.
1437 */
1438 rc = -ENODEV;
1439 goto fail;
1440 }
1441
1442 for (i = 0; i < nvec; i++)
1443 hpriv->msix[i].entry = i;
1444 rc = pci_enable_msix_exact(pdev, hpriv->msix, nvec);
1445 if (rc < 0)
1446 goto fail;
1447
1448 if (nvec > 1)
1449 hpriv->flags |= AHCI_HFLAG_MULTI_MSIX;
1450 hpriv->irq = hpriv->msix[0].vector; /* for single msi-x */
1451
1452 return nvec;
1453fail:
1454 dev_err(&pdev->dev,
1455 "failed to enable MSI-X with error %d, # of vectors: %d\n",
1456 rc, nvec);
1457
1458 return rc;
1459} 1406}
1460 1407
1461static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, 1408static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
1462 struct ahci_host_priv *hpriv) 1409 struct ahci_host_priv *hpriv)
1463{ 1410{
1464 int rc, nvec; 1411 int nvec;
1465 1412
1466 if (hpriv->flags & AHCI_HFLAG_NO_MSI) 1413 if (hpriv->flags & AHCI_HFLAG_NO_MSI)
1467 return -ENODEV; 1414 return -ENODEV;
1468 1415
1469 nvec = pci_msi_vec_count(pdev);
1470 if (nvec < 0)
1471 return nvec;
1472
1473 /* 1416 /*
1474 * If number of MSIs is less than number of ports then Sharing Last 1417 * If number of MSIs is less than number of ports then Sharing Last
1475 * Message mode could be enforced. In this case assume that advantage 1418 * Message mode could be enforced. In this case assume that advantage
1476 * of multipe MSIs is negated and use single MSI mode instead. 1419 * of multipe MSIs is negated and use single MSI mode instead.
1477 */ 1420 */
1478 if (nvec < n_ports) 1421 nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX,
1479 goto single_msi; 1422 PCI_IRQ_MSIX | PCI_IRQ_MSI);
1480 1423 if (nvec > 0) {
1481 rc = pci_enable_msi_exact(pdev, nvec); 1424 if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) {
1482 if (rc == -ENOSPC) 1425 hpriv->get_irq_vector = ahci_get_irq_vector;
1483 goto single_msi; 1426 hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
1484 if (rc < 0) 1427 return nvec;
1485 return rc; 1428 }
1486 1429
1487 /* fallback to single MSI mode if the controller enforced MRSM mode */ 1430 /*
1488 if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) { 1431 * Fallback to single MSI mode if the controller enforced MRSM
1489 pci_disable_msi(pdev); 1432 * mode.
1433 */
1490 printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n"); 1434 printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n");
1491 goto single_msi; 1435 pci_free_irq_vectors(pdev);
1492 } 1436 }
1493 1437
1494 if (nvec > 1)
1495 hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
1496
1497 goto out;
1498
1499single_msi:
1500 nvec = 1;
1501
1502 rc = pci_enable_msi(pdev);
1503 if (rc < 0)
1504 return rc;
1505out:
1506 hpriv->irq = pdev->irq;
1507
1508 return nvec;
1509}
1510
1511static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
1512 struct ahci_host_priv *hpriv)
1513{
1514 int nvec;
1515
1516 /* 1438 /*
1517 * Try to enable per-port MSI-X. If the host is not capable 1439 * -ENOSPC indicated we don't have enough vectors. Don't bother trying
1518 * fall back to single MSI before finally attempting single 1440 * a single vectors for any other error:
1519 * MSI-X.
1520 */ 1441 */
1521 nvec = ahci_init_msix(pdev, n_ports, hpriv, AHCI_HFLAG_MULTI_MSIX); 1442 if (nvec < 0 && nvec != -ENOSPC)
1522 if (nvec >= 0)
1523 return nvec; 1443 return nvec;
1524 1444
1525 nvec = ahci_init_msi(pdev, n_ports, hpriv); 1445 /*
1526 if (nvec >= 0) 1446 * If the host is not capable of supporting per-port vectors, fall
1527 return nvec; 1447 * back to single MSI before finally attempting single MSI-X.
1528 1448 */
1529 /* try single-msix */ 1449 nvec = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
1530 nvec = ahci_init_msix(pdev, n_ports, hpriv, 0); 1450 if (nvec == 1)
1531 if (nvec >= 0)
1532 return nvec; 1451 return nvec;
1533 1452 return pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
1534 /* legacy intx interrupts */
1535 pci_intx(pdev, 1);
1536 hpriv->irq = pdev->irq;
1537
1538 return 0;
1539} 1453}
1540 1454
1541static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 1455static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -1698,11 +1612,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1698 if (!host) 1612 if (!host)
1699 return -ENOMEM; 1613 return -ENOMEM;
1700 host->private_data = hpriv; 1614 host->private_data = hpriv;
1701 hpriv->msix = devm_kzalloc(&pdev->dev, 1615
1702 sizeof(struct msix_entry) * n_ports, GFP_KERNEL); 1616 if (ahci_init_msi(pdev, n_ports, hpriv) < 0) {
1703 if (!hpriv->msix) 1617 /* legacy intx interrupts */
1704 return -ENOMEM; 1618 pci_intx(pdev, 1);
1705 ahci_init_interrupts(pdev, n_ports, hpriv); 1619 }
1620 hpriv->irq = pdev->irq;
1706 1621
1707 if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) 1622 if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
1708 host->flags |= ATA_HOST_PARALLEL_SCAN; 1623 host->flags |= ATA_HOST_PARALLEL_SCAN;
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 70b06bcfb7e3..0cc08f892fea 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -242,12 +242,10 @@ enum {
242 AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */ 242 AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
243 243
244#ifdef CONFIG_PCI_MSI 244#ifdef CONFIG_PCI_MSI
245 AHCI_HFLAG_MULTI_MSI = (1 << 20), /* multiple PCI MSIs */ 245 AHCI_HFLAG_MULTI_MSI = (1 << 20), /* per-port MSI(-X) */
246 AHCI_HFLAG_MULTI_MSIX = (1 << 21), /* per-port MSI-X */
247#else 246#else
248 /* compile out MSI infrastructure */ 247 /* compile out MSI infrastructure */
249 AHCI_HFLAG_MULTI_MSI = 0, 248 AHCI_HFLAG_MULTI_MSI = 0,
250 AHCI_HFLAG_MULTI_MSIX = 0,
251#endif 249#endif
252 AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */ 250 AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */
253 251
@@ -351,7 +349,6 @@ struct ahci_host_priv {
351 * the PHY position in this array. 349 * the PHY position in this array.
352 */ 350 */
353 struct phy **phys; 351 struct phy **phys;
354 struct msix_entry *msix; /* Optional MSI-X support */
355 unsigned nports; /* Number of ports */ 352 unsigned nports; /* Number of ports */
356 void *plat_data; /* Other platform data */ 353 void *plat_data; /* Other platform data */
357 unsigned int irq; /* interrupt line */ 354 unsigned int irq; /* interrupt line */
@@ -362,22 +359,11 @@ struct ahci_host_priv {
362 */ 359 */
363 void (*start_engine)(struct ata_port *ap); 360 void (*start_engine)(struct ata_port *ap);
364 irqreturn_t (*irq_handler)(int irq, void *dev_instance); 361 irqreturn_t (*irq_handler)(int irq, void *dev_instance);
365};
366 362
367#ifdef CONFIG_PCI_MSI 363 /* only required for per-port MSI(-X) support */
368static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port) 364 int (*get_irq_vector)(struct ata_host *host,
369{ 365 int port);
370 if (hpriv->flags & AHCI_HFLAG_MULTI_MSIX) 366};
371 return hpriv->msix[port].vector;
372 else
373 return hpriv->irq + port;
374}
375#else
376static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port)
377{
378 return hpriv->irq;
379}
380#endif
381 367
382extern int ahci_ignore_sss; 368extern int ahci_ignore_sss;
383 369
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 5a1329e31609..0d028ead99e8 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -2378,7 +2378,7 @@ static int ahci_port_start(struct ata_port *ap)
2378 /* 2378 /*
2379 * Switch to per-port locking in case each port has its own MSI vector. 2379 * Switch to per-port locking in case each port has its own MSI vector.
2380 */ 2380 */
2381 if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) { 2381 if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) {
2382 spin_lock_init(&pp->lock); 2382 spin_lock_init(&pp->lock);
2383 ap->lock = &pp->lock; 2383 ap->lock = &pp->lock;
2384 } 2384 }
@@ -2520,7 +2520,7 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host,
2520 */ 2520 */
2521 for (i = 0; i < host->n_ports; i++) { 2521 for (i = 0; i < host->n_ports; i++) {
2522 struct ahci_port_priv *pp = host->ports[i]->private_data; 2522 struct ahci_port_priv *pp = host->ports[i]->private_data;
2523 int irq = ahci_irq_vector(hpriv, i); 2523 int irq = hpriv->get_irq_vector(host, i);
2524 2524
2525 /* Do not receive interrupts sent by dummy ports */ 2525 /* Do not receive interrupts sent by dummy ports */
2526 if (!pp) { 2526 if (!pp) {
@@ -2556,10 +2556,15 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
2556 int irq = hpriv->irq; 2556 int irq = hpriv->irq;
2557 int rc; 2557 int rc;
2558 2558
2559 if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) { 2559 if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) {
2560 if (hpriv->irq_handler) 2560 if (hpriv->irq_handler)
2561 dev_warn(host->dev, 2561 dev_warn(host->dev,
2562 "both AHCI_HFLAG_MULTI_MSI flag set and custom irq handler implemented\n"); 2562 "both AHCI_HFLAG_MULTI_MSI flag set and custom irq handler implemented\n");
2563 if (!hpriv->get_irq_vector) {
2564 dev_err(host->dev,
2565 "AHCI_HFLAG_MULTI_MSI requires ->get_irq_vector!\n");
2566 return -EIO;
2567 }
2563 2568
2564 rc = ahci_host_activate_multi_irqs(host, sht); 2569 rc = ahci_host_activate_multi_irqs(host, sht);
2565 } else { 2570 } else {