diff options
author | David S. Miller <davem@davemloft.net> | 2015-09-09 23:27:54 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-09-09 23:27:54 -0400 |
commit | 1d68c286384d147838d252e2969f2f787e7fbffb (patch) | |
tree | 900c4c812c1432bb2c847350420faa021cd0d2ac | |
parent | 52fe51f8523751da0e79c85350c47eb3bb94da5b (diff) | |
parent | 2dd49e0f16fb0e07c6fcc1322ebba310f5827072 (diff) |
Merge branch 'r8152-autoresume'
Hayes Wang says:
====================
r8152: fix the autoresume may fail
Fix the autosuspend issues which occur about linking change.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/usb/r8152.c | 66 |
1 files changed, 63 insertions, 3 deletions
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index fe4ec324aebc..d9427ca3dba7 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c | |||
@@ -26,8 +26,13 @@ | |||
26 | #include <linux/mdio.h> | 26 | #include <linux/mdio.h> |
27 | #include <linux/usb/cdc.h> | 27 | #include <linux/usb/cdc.h> |
28 | 28 | ||
29 | /* Version Information */ | 29 | /* Information for net-next */ |
30 | #define DRIVER_VERSION "v1.08.1 (2015/07/28)" | 30 | #define NETNEXT_VERSION "08" |
31 | |||
32 | /* Information for net */ | ||
33 | #define NET_VERSION "2" | ||
34 | |||
35 | #define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION | ||
31 | #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" | 36 | #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" |
32 | #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" | 37 | #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" |
33 | #define MODULENAME "r8152" | 38 | #define MODULENAME "r8152" |
@@ -143,6 +148,7 @@ | |||
143 | #define OCP_EEE_ABLE 0xa5c4 | 148 | #define OCP_EEE_ABLE 0xa5c4 |
144 | #define OCP_EEE_ADV 0xa5d0 | 149 | #define OCP_EEE_ADV 0xa5d0 |
145 | #define OCP_EEE_LPABLE 0xa5d2 | 150 | #define OCP_EEE_LPABLE 0xa5d2 |
151 | #define OCP_PHY_STATE 0xa708 /* nway state for 8153 */ | ||
146 | #define OCP_ADC_CFG 0xbc06 | 152 | #define OCP_ADC_CFG 0xbc06 |
147 | 153 | ||
148 | /* SRAM Register */ | 154 | /* SRAM Register */ |
@@ -427,6 +433,10 @@ | |||
427 | /* OCP_DOWN_SPEED */ | 433 | /* OCP_DOWN_SPEED */ |
428 | #define EN_10M_BGOFF 0x0080 | 434 | #define EN_10M_BGOFF 0x0080 |
429 | 435 | ||
436 | /* OCP_PHY_STATE */ | ||
437 | #define TXDIS_STATE 0x01 | ||
438 | #define ABD_STATE 0x02 | ||
439 | |||
430 | /* OCP_ADC_CFG */ | 440 | /* OCP_ADC_CFG */ |
431 | #define CKADSEL_L 0x0100 | 441 | #define CKADSEL_L 0x0100 |
432 | #define ADC_EN 0x0080 | 442 | #define ADC_EN 0x0080 |
@@ -604,6 +614,7 @@ struct r8152 { | |||
604 | void (*unload)(struct r8152 *); | 614 | void (*unload)(struct r8152 *); |
605 | int (*eee_get)(struct r8152 *, struct ethtool_eee *); | 615 | int (*eee_get)(struct r8152 *, struct ethtool_eee *); |
606 | int (*eee_set)(struct r8152 *, struct ethtool_eee *); | 616 | int (*eee_set)(struct r8152 *, struct ethtool_eee *); |
617 | bool (*in_nway)(struct r8152 *); | ||
607 | } rtl_ops; | 618 | } rtl_ops; |
608 | 619 | ||
609 | int intr_interval; | 620 | int intr_interval; |
@@ -2941,6 +2952,32 @@ static void rtl8153_down(struct r8152 *tp) | |||
2941 | r8153_enable_aldps(tp); | 2952 | r8153_enable_aldps(tp); |
2942 | } | 2953 | } |
2943 | 2954 | ||
2955 | static bool rtl8152_in_nway(struct r8152 *tp) | ||
2956 | { | ||
2957 | u16 nway_state; | ||
2958 | |||
2959 | ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, 0x2000); | ||
2960 | tp->ocp_base = 0x2000; | ||
2961 | ocp_write_byte(tp, MCU_TYPE_PLA, 0xb014, 0x4c); /* phy state */ | ||
2962 | nway_state = ocp_read_word(tp, MCU_TYPE_PLA, 0xb01a); | ||
2963 | |||
2964 | /* bit 15: TXDIS_STATE, bit 14: ABD_STATE */ | ||
2965 | if (nway_state & 0xc000) | ||
2966 | return false; | ||
2967 | else | ||
2968 | return true; | ||
2969 | } | ||
2970 | |||
2971 | static bool rtl8153_in_nway(struct r8152 *tp) | ||
2972 | { | ||
2973 | u16 phy_state = ocp_reg_read(tp, OCP_PHY_STATE) & 0xff; | ||
2974 | |||
2975 | if (phy_state == TXDIS_STATE || phy_state == ABD_STATE) | ||
2976 | return false; | ||
2977 | else | ||
2978 | return true; | ||
2979 | } | ||
2980 | |||
2944 | static void set_carrier(struct r8152 *tp) | 2981 | static void set_carrier(struct r8152 *tp) |
2945 | { | 2982 | { |
2946 | struct net_device *netdev = tp->netdev; | 2983 | struct net_device *netdev = tp->netdev; |
@@ -3405,6 +3442,27 @@ static int rtl8152_post_reset(struct usb_interface *intf) | |||
3405 | return 0; | 3442 | return 0; |
3406 | } | 3443 | } |
3407 | 3444 | ||
3445 | static bool delay_autosuspend(struct r8152 *tp) | ||
3446 | { | ||
3447 | bool sw_linking = !!netif_carrier_ok(tp->netdev); | ||
3448 | bool hw_linking = !!(rtl8152_get_speed(tp) & LINK_STATUS); | ||
3449 | |||
3450 | /* This means a linking change occurs and the driver doesn't detect it, | ||
3451 | * yet. If the driver has disabled tx/rx and hw is linking on, the | ||
3452 | * device wouldn't wake up by receiving any packet. | ||
3453 | */ | ||
3454 | if (work_busy(&tp->schedule.work) || sw_linking != hw_linking) | ||
3455 | return true; | ||
3456 | |||
3457 | /* If the linking down is occurred by nway, the device may miss the | ||
3458 | * linking change event. And it wouldn't wake when linking on. | ||
3459 | */ | ||
3460 | if (!sw_linking && tp->rtl_ops.in_nway(tp)) | ||
3461 | return true; | ||
3462 | else | ||
3463 | return false; | ||
3464 | } | ||
3465 | |||
3408 | static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) | 3466 | static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) |
3409 | { | 3467 | { |
3410 | struct r8152 *tp = usb_get_intfdata(intf); | 3468 | struct r8152 *tp = usb_get_intfdata(intf); |
@@ -3414,7 +3472,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) | |||
3414 | mutex_lock(&tp->control); | 3472 | mutex_lock(&tp->control); |
3415 | 3473 | ||
3416 | if (PMSG_IS_AUTO(message)) { | 3474 | if (PMSG_IS_AUTO(message)) { |
3417 | if (netif_running(netdev) && work_busy(&tp->schedule.work)) { | 3475 | if (netif_running(netdev) && delay_autosuspend(tp)) { |
3418 | ret = -EBUSY; | 3476 | ret = -EBUSY; |
3419 | goto out1; | 3477 | goto out1; |
3420 | } | 3478 | } |
@@ -4044,6 +4102,7 @@ static int rtl_ops_init(struct r8152 *tp) | |||
4044 | ops->unload = rtl8152_unload; | 4102 | ops->unload = rtl8152_unload; |
4045 | ops->eee_get = r8152_get_eee; | 4103 | ops->eee_get = r8152_get_eee; |
4046 | ops->eee_set = r8152_set_eee; | 4104 | ops->eee_set = r8152_set_eee; |
4105 | ops->in_nway = rtl8152_in_nway; | ||
4047 | break; | 4106 | break; |
4048 | 4107 | ||
4049 | case RTL_VER_03: | 4108 | case RTL_VER_03: |
@@ -4058,6 +4117,7 @@ static int rtl_ops_init(struct r8152 *tp) | |||
4058 | ops->unload = rtl8153_unload; | 4117 | ops->unload = rtl8153_unload; |
4059 | ops->eee_get = r8153_get_eee; | 4118 | ops->eee_get = r8153_get_eee; |
4060 | ops->eee_set = r8153_set_eee; | 4119 | ops->eee_set = r8153_set_eee; |
4120 | ops->in_nway = rtl8153_in_nway; | ||
4061 | break; | 4121 | break; |
4062 | 4122 | ||
4063 | default: | 4123 | default: |