aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/r8169.c50
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
384enum features { 385enum features {
385 RTL_FEATURE_WOL = (1 << 0), 386 RTL_FEATURE_WOL = (1 << 0),
387 RTL_FEATURE_MSI = (1 << 1),
386}; 388};
387 389
388struct rtl8169_private { 390struct 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. */
1502static 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
1521static 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
1495static int __devinit 1529static int __devinit
1496rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 1530rtl8169_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)
1717out: 1752out:
1718 return rc; 1753 return rc;
1719 1754
1720err_out_unmap_5: 1755err_out_msi_5:
1756 rtl_disable_msi(pdev, tp);
1721 iounmap(ioaddr); 1757 iounmap(ioaddr);
1722err_out_free_res_4: 1758err_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;