diff options
Diffstat (limited to 'drivers/net/atlx/atl1.c')
-rw-r--r-- | drivers/net/atlx/atl1.c | 157 |
1 files changed, 98 insertions, 59 deletions
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 0afe522b8f7b..9c2394d49428 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. | 2 | * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. |
3 | * Copyright(c) 2006 - 2007 Chris Snook <csnook@redhat.com> | 3 | * Copyright(c) 2006 - 2007 Chris Snook <csnook@redhat.com> |
4 | * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com> | 4 | * Copyright(c) 2006 - 2008 Jay Cliburn <jcliburn@gmail.com> |
5 | * | 5 | * |
6 | * Derived from Intel e1000 driver | 6 | * Derived from Intel e1000 driver |
7 | * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. | 7 | * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. |
@@ -36,7 +36,6 @@ | |||
36 | * A very incomplete list of things that need to be dealt with: | 36 | * A very incomplete list of things that need to be dealt with: |
37 | * | 37 | * |
38 | * TODO: | 38 | * TODO: |
39 | * Wake on LAN. | ||
40 | * Add more ethtool functions. | 39 | * Add more ethtool functions. |
41 | * Fix abstruse irq enable/disable condition described here: | 40 | * Fix abstruse irq enable/disable condition described here: |
42 | * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2 | 41 | * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2 |
@@ -638,21 +637,18 @@ static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw) | |||
638 | } | 637 | } |
639 | 638 | ||
640 | /* | 639 | /* |
641 | *TODO: do something or get rid of this | 640 | * Force the PHY into power saving mode using vendor magic. |
642 | */ | 641 | */ |
643 | #ifdef CONFIG_PM | 642 | #ifdef CONFIG_PM |
644 | static s32 atl1_phy_enter_power_saving(struct atl1_hw *hw) | 643 | static void atl1_phy_enter_power_saving(struct atl1_hw *hw) |
645 | { | 644 | { |
646 | /* s32 ret_val; | 645 | atl1_write_phy_reg(hw, MII_DBG_ADDR, 0); |
647 | * u16 phy_data; | 646 | atl1_write_phy_reg(hw, MII_DBG_DATA, 0x124E); |
648 | */ | 647 | atl1_write_phy_reg(hw, MII_DBG_ADDR, 2); |
648 | atl1_write_phy_reg(hw, MII_DBG_DATA, 0x3000); | ||
649 | atl1_write_phy_reg(hw, MII_DBG_ADDR, 3); | ||
650 | atl1_write_phy_reg(hw, MII_DBG_DATA, 0); | ||
649 | 651 | ||
650 | /* | ||
651 | ret_val = atl1_write_phy_reg(hw, ...); | ||
652 | ret_val = atl1_write_phy_reg(hw, ...); | ||
653 | .... | ||
654 | */ | ||
655 | return 0; | ||
656 | } | 652 | } |
657 | #endif | 653 | #endif |
658 | 654 | ||
@@ -2784,64 +2780,93 @@ static int atl1_suspend(struct pci_dev *pdev, pm_message_t state) | |||
2784 | struct atl1_hw *hw = &adapter->hw; | 2780 | struct atl1_hw *hw = &adapter->hw; |
2785 | u32 ctrl = 0; | 2781 | u32 ctrl = 0; |
2786 | u32 wufc = adapter->wol; | 2782 | u32 wufc = adapter->wol; |
2783 | u32 val; | ||
2784 | int retval; | ||
2785 | u16 speed; | ||
2786 | u16 duplex; | ||
2787 | 2787 | ||
2788 | netif_device_detach(netdev); | 2788 | netif_device_detach(netdev); |
2789 | if (netif_running(netdev)) | 2789 | if (netif_running(netdev)) |
2790 | atl1_down(adapter); | 2790 | atl1_down(adapter); |
2791 | 2791 | ||
2792 | retval = pci_save_state(pdev); | ||
2793 | if (retval) | ||
2794 | return retval; | ||
2795 | |||
2792 | atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); | 2796 | atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); |
2793 | atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); | 2797 | atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); |
2794 | if (ctrl & BMSR_LSTATUS) | 2798 | val = ctrl & BMSR_LSTATUS; |
2799 | if (val) | ||
2795 | wufc &= ~ATLX_WUFC_LNKC; | 2800 | wufc &= ~ATLX_WUFC_LNKC; |
2796 | 2801 | ||
2797 | /* reduce speed to 10/100M */ | 2802 | if (val && wufc) { |
2798 | if (wufc) { | 2803 | val = atl1_get_speed_and_duplex(hw, &speed, &duplex); |
2799 | atl1_phy_enter_power_saving(hw); | 2804 | if (val) { |
2800 | /* if resume, let driver to re- setup link */ | 2805 | if (netif_msg_ifdown(adapter)) |
2801 | hw->phy_configured = false; | 2806 | dev_printk(KERN_DEBUG, &pdev->dev, |
2802 | atl1_set_mac_addr(hw); | 2807 | "error getting speed/duplex\n"); |
2803 | atlx_set_multi(netdev); | 2808 | goto disable_wol; |
2809 | } | ||
2804 | 2810 | ||
2805 | ctrl = 0; | 2811 | ctrl = 0; |
2806 | /* turn on magic packet wol */ | ||
2807 | if (wufc & ATLX_WUFC_MAG) | ||
2808 | ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN; | ||
2809 | 2812 | ||
2810 | /* turn on Link change WOL */ | 2813 | /* enable magic packet WOL */ |
2811 | if (wufc & ATLX_WUFC_LNKC) | 2814 | if (wufc & ATLX_WUFC_MAG) |
2812 | ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); | 2815 | ctrl |= (WOL_MAGIC_EN | WOL_MAGIC_PME_EN); |
2813 | iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); | 2816 | iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); |
2814 | 2817 | ioread32(hw->hw_addr + REG_WOL_CTRL); | |
2815 | /* turn on all-multi mode if wake on multicast is enabled */ | 2818 | |
2816 | ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL); | 2819 | /* configure the mac */ |
2817 | ctrl &= ~MAC_CTRL_DBG; | 2820 | ctrl = MAC_CTRL_RX_EN; |
2818 | ctrl &= ~MAC_CTRL_PROMIS_EN; | 2821 | ctrl |= ((u32)((speed == SPEED_1000) ? MAC_CTRL_SPEED_1000 : |
2819 | if (wufc & ATLX_WUFC_MC) | 2822 | MAC_CTRL_SPEED_10_100) << MAC_CTRL_SPEED_SHIFT); |
2820 | ctrl |= MAC_CTRL_MC_ALL_EN; | 2823 | if (duplex == FULL_DUPLEX) |
2821 | else | 2824 | ctrl |= MAC_CTRL_DUPLX; |
2822 | ctrl &= ~MAC_CTRL_MC_ALL_EN; | 2825 | ctrl |= (((u32)adapter->hw.preamble_len & |
2823 | 2826 | MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); | |
2824 | /* turn on broadcast mode if wake on-BC is enabled */ | 2827 | if (adapter->vlgrp) |
2825 | if (wufc & ATLX_WUFC_BC) | 2828 | ctrl |= MAC_CTRL_RMV_VLAN; |
2829 | if (wufc & ATLX_WUFC_MAG) | ||
2826 | ctrl |= MAC_CTRL_BC_EN; | 2830 | ctrl |= MAC_CTRL_BC_EN; |
2827 | else | ||
2828 | ctrl &= ~MAC_CTRL_BC_EN; | ||
2829 | |||
2830 | /* enable RX */ | ||
2831 | ctrl |= MAC_CTRL_RX_EN; | ||
2832 | iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL); | 2831 | iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL); |
2833 | pci_enable_wake(pdev, PCI_D3hot, 1); | 2832 | ioread32(hw->hw_addr + REG_MAC_CTRL); |
2834 | pci_enable_wake(pdev, PCI_D3cold, 1); | 2833 | |
2835 | } else { | 2834 | /* poke the PHY */ |
2836 | iowrite32(0, hw->hw_addr + REG_WOL_CTRL); | 2835 | ctrl = ioread32(hw->hw_addr + REG_PCIE_PHYMISC); |
2837 | pci_enable_wake(pdev, PCI_D3hot, 0); | 2836 | ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; |
2838 | pci_enable_wake(pdev, PCI_D3cold, 0); | 2837 | iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC); |
2838 | ioread32(hw->hw_addr + REG_PCIE_PHYMISC); | ||
2839 | |||
2840 | pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); | ||
2841 | goto exit; | ||
2839 | } | 2842 | } |
2840 | 2843 | ||
2841 | pci_save_state(pdev); | 2844 | if (!val && wufc) { |
2845 | ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); | ||
2846 | iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); | ||
2847 | ioread32(hw->hw_addr + REG_WOL_CTRL); | ||
2848 | iowrite32(0, hw->hw_addr + REG_MAC_CTRL); | ||
2849 | ioread32(hw->hw_addr + REG_MAC_CTRL); | ||
2850 | hw->phy_configured = false; | ||
2851 | pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); | ||
2852 | goto exit; | ||
2853 | } | ||
2854 | |||
2855 | disable_wol: | ||
2856 | iowrite32(0, hw->hw_addr + REG_WOL_CTRL); | ||
2857 | ioread32(hw->hw_addr + REG_WOL_CTRL); | ||
2858 | ctrl = ioread32(hw->hw_addr + REG_PCIE_PHYMISC); | ||
2859 | ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; | ||
2860 | iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC); | ||
2861 | ioread32(hw->hw_addr + REG_PCIE_PHYMISC); | ||
2862 | atl1_phy_enter_power_saving(hw); | ||
2863 | hw->phy_configured = false; | ||
2864 | pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); | ||
2865 | exit: | ||
2866 | if (netif_running(netdev)) | ||
2867 | pci_disable_msi(adapter->pdev); | ||
2842 | pci_disable_device(pdev); | 2868 | pci_disable_device(pdev); |
2843 | 2869 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | |
2844 | pci_set_power_state(pdev, PCI_D3hot); | ||
2845 | 2870 | ||
2846 | return 0; | 2871 | return 0; |
2847 | } | 2872 | } |
@@ -2855,20 +2880,26 @@ static int atl1_resume(struct pci_dev *pdev) | |||
2855 | pci_set_power_state(pdev, PCI_D0); | 2880 | pci_set_power_state(pdev, PCI_D0); |
2856 | pci_restore_state(pdev); | 2881 | pci_restore_state(pdev); |
2857 | 2882 | ||
2858 | /* FIXME: check and handle */ | ||
2859 | err = pci_enable_device(pdev); | 2883 | err = pci_enable_device(pdev); |
2884 | if (err) { | ||
2885 | if (netif_msg_ifup(adapter)) | ||
2886 | dev_printk(KERN_DEBUG, &pdev->dev, | ||
2887 | "error enabling pci device\n"); | ||
2888 | return err; | ||
2889 | } | ||
2890 | |||
2891 | pci_set_master(pdev); | ||
2892 | iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL); | ||
2860 | pci_enable_wake(pdev, PCI_D3hot, 0); | 2893 | pci_enable_wake(pdev, PCI_D3hot, 0); |
2861 | pci_enable_wake(pdev, PCI_D3cold, 0); | 2894 | pci_enable_wake(pdev, PCI_D3cold, 0); |
2862 | 2895 | ||
2863 | iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL); | 2896 | atl1_reset_hw(&adapter->hw); |
2864 | atl1_reset(adapter); | 2897 | adapter->cmb.cmb->int_stats = 0; |
2865 | 2898 | ||
2866 | if (netif_running(netdev)) | 2899 | if (netif_running(netdev)) |
2867 | atl1_up(adapter); | 2900 | atl1_up(adapter); |
2868 | netif_device_attach(netdev); | 2901 | netif_device_attach(netdev); |
2869 | 2902 | ||
2870 | atl1_via_workaround(adapter); | ||
2871 | |||
2872 | return 0; | 2903 | return 0; |
2873 | } | 2904 | } |
2874 | #else | 2905 | #else |
@@ -2876,6 +2907,13 @@ static int atl1_resume(struct pci_dev *pdev) | |||
2876 | #define atl1_resume NULL | 2907 | #define atl1_resume NULL |
2877 | #endif | 2908 | #endif |
2878 | 2909 | ||
2910 | static void atl1_shutdown(struct pci_dev *pdev) | ||
2911 | { | ||
2912 | #ifdef CONFIG_PM | ||
2913 | atl1_suspend(pdev, PMSG_SUSPEND); | ||
2914 | #endif | ||
2915 | } | ||
2916 | |||
2879 | #ifdef CONFIG_NET_POLL_CONTROLLER | 2917 | #ifdef CONFIG_NET_POLL_CONTROLLER |
2880 | static void atl1_poll_controller(struct net_device *netdev) | 2918 | static void atl1_poll_controller(struct net_device *netdev) |
2881 | { | 2919 | { |
@@ -3122,7 +3160,8 @@ static struct pci_driver atl1_driver = { | |||
3122 | .probe = atl1_probe, | 3160 | .probe = atl1_probe, |
3123 | .remove = __devexit_p(atl1_remove), | 3161 | .remove = __devexit_p(atl1_remove), |
3124 | .suspend = atl1_suspend, | 3162 | .suspend = atl1_suspend, |
3125 | .resume = atl1_resume | 3163 | .resume = atl1_resume, |
3164 | .shutdown = atl1_shutdown | ||
3126 | }; | 3165 | }; |
3127 | 3166 | ||
3128 | /* | 3167 | /* |