diff options
author | Francois Romieu <romieu@fr.zoreil.com> | 2007-10-04 16:51:38 -0400 |
---|---|---|
committer | Francois Romieu <romieu@fr.zoreil.com> | 2007-10-18 15:24:43 -0400 |
commit | fbac58fcde6bbbd33c45870eb16f17795660093a (patch) | |
tree | e58bf89990adb56300ffc708f61ac4ed3a4fb5f8 | |
parent | f23e7fdad166a4968f1f7f56964b75acfdcf57a4 (diff) |
r8169: MSI support
It is currently limited to the tested 0x8136 and 0x8168. 8169sb/8110sb ought
to handle it as well where they support MSI.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Cc: Edward Hsu <edward_hsu@realtek.com.tw>
Tester-Cc: Rolf Eike Beer <eike-kernel@sf-tec.de>
-rw-r--r-- | drivers/net/r8169.c | 50 |
1 files changed, 44 insertions, 6 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 16ecba15830d..ee1c2743eab4 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -278,6 +278,7 @@ enum rtl_register_content { | |||
278 | TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ | 278 | TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ |
279 | 279 | ||
280 | /* Config1 register p.24 */ | 280 | /* Config1 register p.24 */ |
281 | MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ | ||
281 | PMEnable = (1 << 0), /* Power Management Enable */ | 282 | PMEnable = (1 << 0), /* Power Management Enable */ |
282 | 283 | ||
283 | /* Config2 register p. 25 */ | 284 | /* Config2 register p. 25 */ |
@@ -383,6 +384,7 @@ struct ring_info { | |||
383 | 384 | ||
384 | enum features { | 385 | enum features { |
385 | RTL_FEATURE_WOL = (1 << 0), | 386 | RTL_FEATURE_WOL = (1 << 0), |
387 | RTL_FEATURE_MSI = (1 << 1), | ||
386 | }; | 388 | }; |
387 | 389 | ||
388 | struct rtl8169_private { | 390 | struct rtl8169_private { |
@@ -1465,6 +1467,7 @@ static const struct rtl_cfg_info { | |||
1465 | unsigned int align; | 1467 | unsigned int align; |
1466 | u16 intr_event; | 1468 | u16 intr_event; |
1467 | u16 napi_event; | 1469 | u16 napi_event; |
1470 | unsigned msi; | ||
1468 | } rtl_cfg_infos [] = { | 1471 | } rtl_cfg_infos [] = { |
1469 | [RTL_CFG_0] = { | 1472 | [RTL_CFG_0] = { |
1470 | .hw_start = rtl_hw_start_8169, | 1473 | .hw_start = rtl_hw_start_8169, |
@@ -1472,7 +1475,8 @@ static const struct rtl_cfg_info { | |||
1472 | .align = 0, | 1475 | .align = 0, |
1473 | .intr_event = SYSErr | LinkChg | RxOverflow | | 1476 | .intr_event = SYSErr | LinkChg | RxOverflow | |
1474 | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, | 1477 | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, |
1475 | .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow | 1478 | .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, |
1479 | .msi = 0 | ||
1476 | }, | 1480 | }, |
1477 | [RTL_CFG_1] = { | 1481 | [RTL_CFG_1] = { |
1478 | .hw_start = rtl_hw_start_8168, | 1482 | .hw_start = rtl_hw_start_8168, |
@@ -1480,7 +1484,8 @@ static const struct rtl_cfg_info { | |||
1480 | .align = 8, | 1484 | .align = 8, |
1481 | .intr_event = SYSErr | LinkChg | RxOverflow | | 1485 | .intr_event = SYSErr | LinkChg | RxOverflow | |
1482 | TxErr | TxOK | RxOK | RxErr, | 1486 | TxErr | TxOK | RxOK | RxErr, |
1483 | .napi_event = TxErr | TxOK | RxOK | RxOverflow | 1487 | .napi_event = TxErr | TxOK | RxOK | RxOverflow, |
1488 | .msi = RTL_FEATURE_MSI | ||
1484 | }, | 1489 | }, |
1485 | [RTL_CFG_2] = { | 1490 | [RTL_CFG_2] = { |
1486 | .hw_start = rtl_hw_start_8101, | 1491 | .hw_start = rtl_hw_start_8101, |
@@ -1488,10 +1493,39 @@ static const struct rtl_cfg_info { | |||
1488 | .align = 8, | 1493 | .align = 8, |
1489 | .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | | 1494 | .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | |
1490 | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, | 1495 | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, |
1491 | .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow | 1496 | .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, |
1497 | .msi = RTL_FEATURE_MSI | ||
1492 | } | 1498 | } |
1493 | }; | 1499 | }; |
1494 | 1500 | ||
1501 | /* Cfg9346_Unlock assumed. */ | ||
1502 | static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr, | ||
1503 | const struct rtl_cfg_info *cfg) | ||
1504 | { | ||
1505 | unsigned msi = 0; | ||
1506 | u8 cfg2; | ||
1507 | |||
1508 | cfg2 = RTL_R8(Config2) & ~MSIEnable; | ||
1509 | if (cfg->msi) { | ||
1510 | if (pci_enable_msi(pdev)) { | ||
1511 | dev_info(&pdev->dev, "no MSI. Back to INTx.\n"); | ||
1512 | } else { | ||
1513 | cfg2 |= MSIEnable; | ||
1514 | msi = RTL_FEATURE_MSI; | ||
1515 | } | ||
1516 | } | ||
1517 | RTL_W8(Config2, cfg2); | ||
1518 | return msi; | ||
1519 | } | ||
1520 | |||
1521 | static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp) | ||
1522 | { | ||
1523 | if (tp->features & RTL_FEATURE_MSI) { | ||
1524 | pci_disable_msi(pdev); | ||
1525 | tp->features &= ~RTL_FEATURE_MSI; | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1495 | static int __devinit | 1529 | static int __devinit |
1496 | rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 1530 | rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
1497 | { | 1531 | { |
@@ -1627,6 +1661,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1627 | RTL_W8(Cfg9346, Cfg9346_Unlock); | 1661 | RTL_W8(Cfg9346, Cfg9346_Unlock); |
1628 | RTL_W8(Config1, RTL_R8(Config1) | PMEnable); | 1662 | RTL_W8(Config1, RTL_R8(Config1) | PMEnable); |
1629 | RTL_W8(Config5, RTL_R8(Config5) & PMEStatus); | 1663 | RTL_W8(Config5, RTL_R8(Config5) & PMEStatus); |
1664 | tp->features |= rtl_try_msi(pdev, ioaddr, cfg); | ||
1630 | RTL_W8(Cfg9346, Cfg9346_Lock); | 1665 | RTL_W8(Cfg9346, Cfg9346_Lock); |
1631 | 1666 | ||
1632 | if (RTL_R8(PHYstatus) & TBI_Enable) { | 1667 | if (RTL_R8(PHYstatus) & TBI_Enable) { |
@@ -1694,7 +1729,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1694 | 1729 | ||
1695 | rc = register_netdev(dev); | 1730 | rc = register_netdev(dev); |
1696 | if (rc < 0) | 1731 | if (rc < 0) |
1697 | goto err_out_unmap_5; | 1732 | goto err_out_msi_5; |
1698 | 1733 | ||
1699 | pci_set_drvdata(pdev, dev); | 1734 | pci_set_drvdata(pdev, dev); |
1700 | 1735 | ||
@@ -1717,7 +1752,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1717 | out: | 1752 | out: |
1718 | return rc; | 1753 | return rc; |
1719 | 1754 | ||
1720 | err_out_unmap_5: | 1755 | err_out_msi_5: |
1756 | rtl_disable_msi(pdev, tp); | ||
1721 | iounmap(ioaddr); | 1757 | iounmap(ioaddr); |
1722 | err_out_free_res_4: | 1758 | err_out_free_res_4: |
1723 | pci_release_regions(pdev); | 1759 | pci_release_regions(pdev); |
@@ -1738,6 +1774,7 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) | |||
1738 | flush_scheduled_work(); | 1774 | flush_scheduled_work(); |
1739 | 1775 | ||
1740 | unregister_netdev(dev); | 1776 | unregister_netdev(dev); |
1777 | rtl_disable_msi(pdev, tp); | ||
1741 | rtl8169_release_board(pdev, dev, tp->mmio_addr); | 1778 | rtl8169_release_board(pdev, dev, tp->mmio_addr); |
1742 | pci_set_drvdata(pdev, NULL); | 1779 | pci_set_drvdata(pdev, NULL); |
1743 | } | 1780 | } |
@@ -1781,7 +1818,8 @@ static int rtl8169_open(struct net_device *dev) | |||
1781 | 1818 | ||
1782 | smp_mb(); | 1819 | smp_mb(); |
1783 | 1820 | ||
1784 | retval = request_irq(dev->irq, rtl8169_interrupt, IRQF_SHARED, | 1821 | retval = request_irq(dev->irq, rtl8169_interrupt, |
1822 | (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED, | ||
1785 | dev->name, dev); | 1823 | dev->name, dev); |
1786 | if (retval < 0) | 1824 | if (retval < 0) |
1787 | goto err_release_ring_2; | 1825 | goto err_release_ring_2; |