11
11
#include <linux/phy.h>
12
12
#include <linux/rtnetlink.h>
13
13
#include <linux/iopoll.h>
14
+ #include <linux/crc16.h>
14
15
#include "lan743x_main.h"
15
16
#include "lan743x_ethtool.h"
16
17
@@ -2749,10 +2750,182 @@ static void lan743x_pcidev_shutdown(struct pci_dev *pdev)
2749
2750
lan743x_netdev_close (netdev );
2750
2751
rtnl_unlock ();
2751
2752
2753
+ #ifdef CONFIG_PM
2754
+ pci_save_state (pdev );
2755
+ #endif
2756
+
2752
2757
/* clean up lan743x portion */
2753
2758
lan743x_hardware_cleanup (adapter );
2754
2759
}
2755
2760
2761
+ #ifdef CONFIG_PM
2762
+ static u16 lan743x_pm_wakeframe_crc16 (const u8 * buf , int len )
2763
+ {
2764
+ return bitrev16 (crc16 (0xFFFF , buf , len ));
2765
+ }
2766
+
2767
+ static void lan743x_pm_set_wol (struct lan743x_adapter * adapter )
2768
+ {
2769
+ const u8 ipv4_multicast [3 ] = { 0x01 , 0x00 , 0x5E };
2770
+ const u8 ipv6_multicast [3 ] = { 0x33 , 0x33 };
2771
+ const u8 arp_type [2 ] = { 0x08 , 0x06 };
2772
+ int mask_index ;
2773
+ u32 pmtctl ;
2774
+ u32 wucsr ;
2775
+ u32 macrx ;
2776
+ u16 crc ;
2777
+
2778
+ for (mask_index = 0 ; mask_index < MAC_NUM_OF_WUF_CFG ; mask_index ++ )
2779
+ lan743x_csr_write (adapter , MAC_WUF_CFG (mask_index ), 0 );
2780
+
2781
+ /* clear wake settings */
2782
+ pmtctl = lan743x_csr_read (adapter , PMT_CTL );
2783
+ pmtctl |= PMT_CTL_WUPS_MASK_ ;
2784
+ pmtctl &= ~(PMT_CTL_GPIO_WAKEUP_EN_ | PMT_CTL_EEE_WAKEUP_EN_ |
2785
+ PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ |
2786
+ PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ | PMT_CTL_ETH_PHY_WAKE_EN_ );
2787
+
2788
+ macrx = lan743x_csr_read (adapter , MAC_RX );
2789
+
2790
+ wucsr = 0 ;
2791
+ mask_index = 0 ;
2792
+
2793
+ pmtctl |= PMT_CTL_ETH_PHY_D3_COLD_OVR_ | PMT_CTL_ETH_PHY_D3_OVR_ ;
2794
+
2795
+ if (adapter -> wolopts & WAKE_PHY ) {
2796
+ pmtctl |= PMT_CTL_ETH_PHY_EDPD_PLL_CTL_ ;
2797
+ pmtctl |= PMT_CTL_ETH_PHY_WAKE_EN_ ;
2798
+ }
2799
+ if (adapter -> wolopts & WAKE_MAGIC ) {
2800
+ wucsr |= MAC_WUCSR_MPEN_ ;
2801
+ macrx |= MAC_RX_RXEN_ ;
2802
+ pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ ;
2803
+ }
2804
+ if (adapter -> wolopts & WAKE_UCAST ) {
2805
+ wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_PFDA_EN_ ;
2806
+ macrx |= MAC_RX_RXEN_ ;
2807
+ pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ ;
2808
+ pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ ;
2809
+ }
2810
+ if (adapter -> wolopts & WAKE_BCAST ) {
2811
+ wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_BCST_EN_ ;
2812
+ macrx |= MAC_RX_RXEN_ ;
2813
+ pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ ;
2814
+ pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ ;
2815
+ }
2816
+ if (adapter -> wolopts & WAKE_MCAST ) {
2817
+ /* IPv4 multicast */
2818
+ crc = lan743x_pm_wakeframe_crc16 (ipv4_multicast , 3 );
2819
+ lan743x_csr_write (adapter , MAC_WUF_CFG (mask_index ),
2820
+ MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ |
2821
+ (0 << MAC_WUF_CFG_OFFSET_SHIFT_ ) |
2822
+ (crc & MAC_WUF_CFG_CRC16_MASK_ ));
2823
+ lan743x_csr_write (adapter , MAC_WUF_MASK0 (mask_index ), 7 );
2824
+ lan743x_csr_write (adapter , MAC_WUF_MASK1 (mask_index ), 0 );
2825
+ lan743x_csr_write (adapter , MAC_WUF_MASK2 (mask_index ), 0 );
2826
+ lan743x_csr_write (adapter , MAC_WUF_MASK3 (mask_index ), 0 );
2827
+ mask_index ++ ;
2828
+
2829
+ /* IPv6 multicast */
2830
+ crc = lan743x_pm_wakeframe_crc16 (ipv6_multicast , 2 );
2831
+ lan743x_csr_write (adapter , MAC_WUF_CFG (mask_index ),
2832
+ MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ |
2833
+ (0 << MAC_WUF_CFG_OFFSET_SHIFT_ ) |
2834
+ (crc & MAC_WUF_CFG_CRC16_MASK_ ));
2835
+ lan743x_csr_write (adapter , MAC_WUF_MASK0 (mask_index ), 3 );
2836
+ lan743x_csr_write (adapter , MAC_WUF_MASK1 (mask_index ), 0 );
2837
+ lan743x_csr_write (adapter , MAC_WUF_MASK2 (mask_index ), 0 );
2838
+ lan743x_csr_write (adapter , MAC_WUF_MASK3 (mask_index ), 0 );
2839
+ mask_index ++ ;
2840
+
2841
+ wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_ ;
2842
+ macrx |= MAC_RX_RXEN_ ;
2843
+ pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ ;
2844
+ pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ ;
2845
+ }
2846
+ if (adapter -> wolopts & WAKE_ARP ) {
2847
+ /* set MAC_WUF_CFG & WUF_MASK
2848
+ * for packettype (offset 12,13) = ARP (0x0806)
2849
+ */
2850
+ crc = lan743x_pm_wakeframe_crc16 (arp_type , 2 );
2851
+ lan743x_csr_write (adapter , MAC_WUF_CFG (mask_index ),
2852
+ MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_ALL_ |
2853
+ (0 << MAC_WUF_CFG_OFFSET_SHIFT_ ) |
2854
+ (crc & MAC_WUF_CFG_CRC16_MASK_ ));
2855
+ lan743x_csr_write (adapter , MAC_WUF_MASK0 (mask_index ), 0x3000 );
2856
+ lan743x_csr_write (adapter , MAC_WUF_MASK1 (mask_index ), 0 );
2857
+ lan743x_csr_write (adapter , MAC_WUF_MASK2 (mask_index ), 0 );
2858
+ lan743x_csr_write (adapter , MAC_WUF_MASK3 (mask_index ), 0 );
2859
+ mask_index ++ ;
2860
+
2861
+ wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_ ;
2862
+ macrx |= MAC_RX_RXEN_ ;
2863
+ pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ ;
2864
+ pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ ;
2865
+ }
2866
+
2867
+ lan743x_csr_write (adapter , MAC_WUCSR , wucsr );
2868
+ lan743x_csr_write (adapter , PMT_CTL , pmtctl );
2869
+ lan743x_csr_write (adapter , MAC_RX , macrx );
2870
+ }
2871
+
2872
+ static int lan743x_pm_suspend (struct device * dev )
2873
+ {
2874
+ struct pci_dev * pdev = to_pci_dev (dev );
2875
+ struct net_device * netdev = pci_get_drvdata (pdev );
2876
+ struct lan743x_adapter * adapter = netdev_priv (netdev );
2877
+ int ret ;
2878
+
2879
+ lan743x_pcidev_shutdown (pdev );
2880
+
2881
+ /* clear all wakes */
2882
+ lan743x_csr_write (adapter , MAC_WUCSR , 0 );
2883
+ lan743x_csr_write (adapter , MAC_WUCSR2 , 0 );
2884
+ lan743x_csr_write (adapter , MAC_WK_SRC , 0xFFFFFFFF );
2885
+
2886
+ if (adapter -> wolopts )
2887
+ lan743x_pm_set_wol (adapter );
2888
+
2889
+ /* Host sets PME_En, put D3hot */
2890
+ ret = pci_prepare_to_sleep (pdev );
2891
+
2892
+ return 0 ;
2893
+ }
2894
+
2895
+ static int lan743x_pm_resume (struct device * dev )
2896
+ {
2897
+ struct pci_dev * pdev = to_pci_dev (dev );
2898
+ struct net_device * netdev = pci_get_drvdata (pdev );
2899
+ struct lan743x_adapter * adapter = netdev_priv (netdev );
2900
+ int ret ;
2901
+
2902
+ pci_set_power_state (pdev , PCI_D0 );
2903
+ pci_restore_state (pdev );
2904
+ pci_save_state (pdev );
2905
+
2906
+ ret = lan743x_hardware_init (adapter , pdev );
2907
+ if (ret ) {
2908
+ netif_err (adapter , probe , adapter -> netdev ,
2909
+ "lan743x_hardware_init returned %d\n" , ret );
2910
+ }
2911
+
2912
+ /* open netdev when netdev is at running state while resume.
2913
+ * For instance, it is true when system wakesup after pm-suspend
2914
+ * However, it is false when system wakes up after suspend GUI menu
2915
+ */
2916
+ if (netif_running (netdev ))
2917
+ lan743x_netdev_open (netdev );
2918
+
2919
+ netif_device_attach (netdev );
2920
+
2921
+ return 0 ;
2922
+ }
2923
+
2924
+ const struct dev_pm_ops lan743x_pm_ops = {
2925
+ SET_SYSTEM_SLEEP_PM_OPS (lan743x_pm_suspend , lan743x_pm_resume )
2926
+ };
2927
+ #endif /*CONFIG_PM */
2928
+
2756
2929
static const struct pci_device_id lan743x_pcidev_tbl [] = {
2757
2930
{ PCI_DEVICE (PCI_VENDOR_ID_SMSC , PCI_DEVICE_ID_SMSC_LAN7430 ) },
2758
2931
{ 0 , }
@@ -2763,6 +2936,9 @@ static struct pci_driver lan743x_pcidev_driver = {
2763
2936
.id_table = lan743x_pcidev_tbl ,
2764
2937
.probe = lan743x_pcidev_probe ,
2765
2938
.remove = lan743x_pcidev_remove ,
2939
+ #ifdef CONFIG_PM
2940
+ .driver .pm = & lan743x_pm_ops ,
2941
+ #endif
2766
2942
.shutdown = lan743x_pcidev_shutdown ,
2767
2943
};
2768
2944
0 commit comments