diff options
author | Dave Kleikamp <shaggy@austin.ibm.com> | 2006-03-14 18:05:45 -0500 |
---|---|---|
committer | Dave Kleikamp <shaggy@austin.ibm.com> | 2006-03-14 18:05:45 -0500 |
commit | c5111f504d2a9b0d258d7c4752b4093523315989 (patch) | |
tree | 6a52864aff79691689aea21cb0cb928327d5de5b /drivers/net/r8169.c | |
parent | 69eb66d7da7dba2696281981347698e1693c2340 (diff) | |
parent | a488edc914aa1d766a4e2c982b5ae03d5657ec1b (diff) |
Merge with /home/shaggy/git/linus-clean/
Diffstat (limited to 'drivers/net/r8169.c')
-rw-r--r-- | drivers/net/r8169.c | 202 |
1 files changed, 153 insertions, 49 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 2e1bed153c39..8cc0d0bbdf50 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -287,6 +287,20 @@ enum RTL8169_register_content { | |||
287 | TxInterFrameGapShift = 24, | 287 | TxInterFrameGapShift = 24, |
288 | TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ | 288 | TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ |
289 | 289 | ||
290 | /* Config1 register p.24 */ | ||
291 | PMEnable = (1 << 0), /* Power Management Enable */ | ||
292 | |||
293 | /* Config3 register p.25 */ | ||
294 | MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */ | ||
295 | LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */ | ||
296 | |||
297 | /* Config5 register p.27 */ | ||
298 | BWF = (1 << 6), /* Accept Broadcast wakeup frame */ | ||
299 | MWF = (1 << 5), /* Accept Multicast wakeup frame */ | ||
300 | UWF = (1 << 4), /* Accept Unicast wakeup frame */ | ||
301 | LanWake = (1 << 1), /* LanWake enable/disable */ | ||
302 | PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ | ||
303 | |||
290 | /* TBICSR p.28 */ | 304 | /* TBICSR p.28 */ |
291 | TBIReset = 0x80000000, | 305 | TBIReset = 0x80000000, |
292 | TBILoopback = 0x40000000, | 306 | TBILoopback = 0x40000000, |
@@ -433,6 +447,7 @@ struct rtl8169_private { | |||
433 | unsigned int (*phy_reset_pending)(void __iomem *); | 447 | unsigned int (*phy_reset_pending)(void __iomem *); |
434 | unsigned int (*link_ok)(void __iomem *); | 448 | unsigned int (*link_ok)(void __iomem *); |
435 | struct work_struct task; | 449 | struct work_struct task; |
450 | unsigned wol_enabled : 1; | ||
436 | }; | 451 | }; |
437 | 452 | ||
438 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); | 453 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); |
@@ -484,13 +499,12 @@ static void mdio_write(void __iomem *ioaddr, int RegAddr, int value) | |||
484 | int i; | 499 | int i; |
485 | 500 | ||
486 | RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value); | 501 | RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value); |
487 | udelay(1000); | ||
488 | 502 | ||
489 | for (i = 2000; i > 0; i--) { | 503 | for (i = 20; i > 0; i--) { |
490 | /* Check if the RTL8169 has completed writing to the specified MII register */ | 504 | /* Check if the RTL8169 has completed writing to the specified MII register */ |
491 | if (!(RTL_R32(PHYAR) & 0x80000000)) | 505 | if (!(RTL_R32(PHYAR) & 0x80000000)) |
492 | break; | 506 | break; |
493 | udelay(100); | 507 | udelay(25); |
494 | } | 508 | } |
495 | } | 509 | } |
496 | 510 | ||
@@ -499,15 +513,14 @@ static int mdio_read(void __iomem *ioaddr, int RegAddr) | |||
499 | int i, value = -1; | 513 | int i, value = -1; |
500 | 514 | ||
501 | RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16); | 515 | RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16); |
502 | udelay(1000); | ||
503 | 516 | ||
504 | for (i = 2000; i > 0; i--) { | 517 | for (i = 20; i > 0; i--) { |
505 | /* Check if the RTL8169 has completed retrieving data from the specified MII register */ | 518 | /* Check if the RTL8169 has completed retrieving data from the specified MII register */ |
506 | if (RTL_R32(PHYAR) & 0x80000000) { | 519 | if (RTL_R32(PHYAR) & 0x80000000) { |
507 | value = (int) (RTL_R32(PHYAR) & 0xFFFF); | 520 | value = (int) (RTL_R32(PHYAR) & 0xFFFF); |
508 | break; | 521 | break; |
509 | } | 522 | } |
510 | udelay(100); | 523 | udelay(25); |
511 | } | 524 | } |
512 | return value; | 525 | return value; |
513 | } | 526 | } |
@@ -609,6 +622,80 @@ static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex) | |||
609 | *duplex = p->duplex; | 622 | *duplex = p->duplex; |
610 | } | 623 | } |
611 | 624 | ||
625 | static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
626 | { | ||
627 | struct rtl8169_private *tp = netdev_priv(dev); | ||
628 | void __iomem *ioaddr = tp->mmio_addr; | ||
629 | u8 options; | ||
630 | |||
631 | wol->wolopts = 0; | ||
632 | |||
633 | #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) | ||
634 | wol->supported = WAKE_ANY; | ||
635 | |||
636 | spin_lock_irq(&tp->lock); | ||
637 | |||
638 | options = RTL_R8(Config1); | ||
639 | if (!(options & PMEnable)) | ||
640 | goto out_unlock; | ||
641 | |||
642 | options = RTL_R8(Config3); | ||
643 | if (options & LinkUp) | ||
644 | wol->wolopts |= WAKE_PHY; | ||
645 | if (options & MagicPacket) | ||
646 | wol->wolopts |= WAKE_MAGIC; | ||
647 | |||
648 | options = RTL_R8(Config5); | ||
649 | if (options & UWF) | ||
650 | wol->wolopts |= WAKE_UCAST; | ||
651 | if (options & BWF) | ||
652 | wol->wolopts |= WAKE_BCAST; | ||
653 | if (options & MWF) | ||
654 | wol->wolopts |= WAKE_MCAST; | ||
655 | |||
656 | out_unlock: | ||
657 | spin_unlock_irq(&tp->lock); | ||
658 | } | ||
659 | |||
660 | static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
661 | { | ||
662 | struct rtl8169_private *tp = netdev_priv(dev); | ||
663 | void __iomem *ioaddr = tp->mmio_addr; | ||
664 | int i; | ||
665 | static struct { | ||
666 | u32 opt; | ||
667 | u16 reg; | ||
668 | u8 mask; | ||
669 | } cfg[] = { | ||
670 | { WAKE_ANY, Config1, PMEnable }, | ||
671 | { WAKE_PHY, Config3, LinkUp }, | ||
672 | { WAKE_MAGIC, Config3, MagicPacket }, | ||
673 | { WAKE_UCAST, Config5, UWF }, | ||
674 | { WAKE_BCAST, Config5, BWF }, | ||
675 | { WAKE_MCAST, Config5, MWF }, | ||
676 | { WAKE_ANY, Config5, LanWake } | ||
677 | }; | ||
678 | |||
679 | spin_lock_irq(&tp->lock); | ||
680 | |||
681 | RTL_W8(Cfg9346, Cfg9346_Unlock); | ||
682 | |||
683 | for (i = 0; i < ARRAY_SIZE(cfg); i++) { | ||
684 | u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask; | ||
685 | if (wol->wolopts & cfg[i].opt) | ||
686 | options |= cfg[i].mask; | ||
687 | RTL_W8(cfg[i].reg, options); | ||
688 | } | ||
689 | |||
690 | RTL_W8(Cfg9346, Cfg9346_Lock); | ||
691 | |||
692 | tp->wol_enabled = (wol->wolopts) ? 1 : 0; | ||
693 | |||
694 | spin_unlock_irq(&tp->lock); | ||
695 | |||
696 | return 0; | ||
697 | } | ||
698 | |||
612 | static void rtl8169_get_drvinfo(struct net_device *dev, | 699 | static void rtl8169_get_drvinfo(struct net_device *dev, |
613 | struct ethtool_drvinfo *info) | 700 | struct ethtool_drvinfo *info) |
614 | { | 701 | { |
@@ -677,6 +764,9 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, | |||
677 | 764 | ||
678 | if (duplex == DUPLEX_HALF) | 765 | if (duplex == DUPLEX_HALF) |
679 | auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full); | 766 | auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full); |
767 | |||
768 | if (duplex == DUPLEX_FULL) | ||
769 | auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_100_Half); | ||
680 | } | 770 | } |
681 | 771 | ||
682 | tp->phy_auto_nego_reg = auto_nego; | 772 | tp->phy_auto_nego_reg = auto_nego; |
@@ -1024,6 +1114,8 @@ static struct ethtool_ops rtl8169_ethtool_ops = { | |||
1024 | .get_tso = ethtool_op_get_tso, | 1114 | .get_tso = ethtool_op_get_tso, |
1025 | .set_tso = ethtool_op_set_tso, | 1115 | .set_tso = ethtool_op_set_tso, |
1026 | .get_regs = rtl8169_get_regs, | 1116 | .get_regs = rtl8169_get_regs, |
1117 | .get_wol = rtl8169_get_wol, | ||
1118 | .set_wol = rtl8169_set_wol, | ||
1027 | .get_strings = rtl8169_get_strings, | 1119 | .get_strings = rtl8169_get_strings, |
1028 | .get_stats_count = rtl8169_get_stats_count, | 1120 | .get_stats_count = rtl8169_get_stats_count, |
1029 | .get_ethtool_stats = rtl8169_get_ethtool_stats, | 1121 | .get_ethtool_stats = rtl8169_get_ethtool_stats, |
@@ -1441,6 +1533,11 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, | |||
1441 | } | 1533 | } |
1442 | tp->chipset = i; | 1534 | tp->chipset = i; |
1443 | 1535 | ||
1536 | RTL_W8(Cfg9346, Cfg9346_Unlock); | ||
1537 | RTL_W8(Config1, RTL_R8(Config1) | PMEnable); | ||
1538 | RTL_W8(Config5, RTL_R8(Config5) & PMEStatus); | ||
1539 | RTL_W8(Cfg9346, Cfg9346_Lock); | ||
1540 | |||
1444 | *ioaddr_out = ioaddr; | 1541 | *ioaddr_out = ioaddr; |
1445 | *dev_out = dev; | 1542 | *dev_out = dev; |
1446 | out: | 1543 | out: |
@@ -1611,49 +1708,6 @@ rtl8169_remove_one(struct pci_dev *pdev) | |||
1611 | pci_set_drvdata(pdev, NULL); | 1708 | pci_set_drvdata(pdev, NULL); |
1612 | } | 1709 | } |
1613 | 1710 | ||
1614 | #ifdef CONFIG_PM | ||
1615 | |||
1616 | static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state) | ||
1617 | { | ||
1618 | struct net_device *dev = pci_get_drvdata(pdev); | ||
1619 | struct rtl8169_private *tp = netdev_priv(dev); | ||
1620 | void __iomem *ioaddr = tp->mmio_addr; | ||
1621 | unsigned long flags; | ||
1622 | |||
1623 | if (!netif_running(dev)) | ||
1624 | return 0; | ||
1625 | |||
1626 | netif_device_detach(dev); | ||
1627 | netif_stop_queue(dev); | ||
1628 | spin_lock_irqsave(&tp->lock, flags); | ||
1629 | |||
1630 | /* Disable interrupts, stop Rx and Tx */ | ||
1631 | RTL_W16(IntrMask, 0); | ||
1632 | RTL_W8(ChipCmd, 0); | ||
1633 | |||
1634 | /* Update the error counts. */ | ||
1635 | tp->stats.rx_missed_errors += RTL_R32(RxMissed); | ||
1636 | RTL_W32(RxMissed, 0); | ||
1637 | spin_unlock_irqrestore(&tp->lock, flags); | ||
1638 | |||
1639 | return 0; | ||
1640 | } | ||
1641 | |||
1642 | static int rtl8169_resume(struct pci_dev *pdev) | ||
1643 | { | ||
1644 | struct net_device *dev = pci_get_drvdata(pdev); | ||
1645 | |||
1646 | if (!netif_running(dev)) | ||
1647 | return 0; | ||
1648 | |||
1649 | netif_device_attach(dev); | ||
1650 | rtl8169_hw_start(dev); | ||
1651 | |||
1652 | return 0; | ||
1653 | } | ||
1654 | |||
1655 | #endif /* CONFIG_PM */ | ||
1656 | |||
1657 | static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, | 1711 | static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, |
1658 | struct net_device *dev) | 1712 | struct net_device *dev) |
1659 | { | 1713 | { |
@@ -2699,6 +2753,56 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev) | |||
2699 | return &tp->stats; | 2753 | return &tp->stats; |
2700 | } | 2754 | } |
2701 | 2755 | ||
2756 | #ifdef CONFIG_PM | ||
2757 | |||
2758 | static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state) | ||
2759 | { | ||
2760 | struct net_device *dev = pci_get_drvdata(pdev); | ||
2761 | struct rtl8169_private *tp = netdev_priv(dev); | ||
2762 | void __iomem *ioaddr = tp->mmio_addr; | ||
2763 | |||
2764 | if (!netif_running(dev)) | ||
2765 | goto out; | ||
2766 | |||
2767 | netif_device_detach(dev); | ||
2768 | netif_stop_queue(dev); | ||
2769 | |||
2770 | spin_lock_irq(&tp->lock); | ||
2771 | |||
2772 | rtl8169_asic_down(ioaddr); | ||
2773 | |||
2774 | tp->stats.rx_missed_errors += RTL_R32(RxMissed); | ||
2775 | RTL_W32(RxMissed, 0); | ||
2776 | |||
2777 | spin_unlock_irq(&tp->lock); | ||
2778 | |||
2779 | pci_save_state(pdev); | ||
2780 | pci_enable_wake(pdev, pci_choose_state(pdev, state), tp->wol_enabled); | ||
2781 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
2782 | out: | ||
2783 | return 0; | ||
2784 | } | ||
2785 | |||
2786 | static int rtl8169_resume(struct pci_dev *pdev) | ||
2787 | { | ||
2788 | struct net_device *dev = pci_get_drvdata(pdev); | ||
2789 | |||
2790 | if (!netif_running(dev)) | ||
2791 | goto out; | ||
2792 | |||
2793 | netif_device_attach(dev); | ||
2794 | |||
2795 | pci_set_power_state(pdev, PCI_D0); | ||
2796 | pci_restore_state(pdev); | ||
2797 | pci_enable_wake(pdev, PCI_D0, 0); | ||
2798 | |||
2799 | rtl8169_schedule_work(dev, rtl8169_reset_task); | ||
2800 | out: | ||
2801 | return 0; | ||
2802 | } | ||
2803 | |||
2804 | #endif /* CONFIG_PM */ | ||
2805 | |||
2702 | static struct pci_driver rtl8169_pci_driver = { | 2806 | static struct pci_driver rtl8169_pci_driver = { |
2703 | .name = MODULENAME, | 2807 | .name = MODULENAME, |
2704 | .id_table = rtl8169_pci_tbl, | 2808 | .id_table = rtl8169_pci_tbl, |