aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhayeswang <hayeswang@realtek.com>2015-09-06 23:57:44 -0400
committerDavid S. Miller <davem@davemloft.net>2015-09-09 23:27:54 -0400
commit2dd49e0f16fb0e07c6fcc1322ebba310f5827072 (patch)
tree900c4c812c1432bb2c847350420faa021cd0d2ac
parentd0942473e3ca4629a40bbf0c9fd74fc0c7ff2a79 (diff)
r8152: fix the runtime suspend issues
Fix the runtime suspend issues result from the linking change. Case 1: a) link down occurs. b) driver disable tx/rx. c) autosuspend occurs. d) hw linking up. e) device suspends without enabling tx/rx. f) couldn't wake up when receiving packets. Case 2: a) Nway results in linking down. b) autosuspend occurs. c) device suspends. d) device may not wake up when linking up. Signed-off-by: Hayes Wang <hayeswang@realtek.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/usb/r8152.c59
1 files changed, 57 insertions, 2 deletions
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 6bb48bc51484..d9427ca3dba7 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -30,7 +30,7 @@
30#define NETNEXT_VERSION "08" 30#define NETNEXT_VERSION "08"
31 31
32/* Information for net */ 32/* Information for net */
33#define NET_VERSION "1" 33#define NET_VERSION "2"
34 34
35#define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION 35#define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION
36#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" 36#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
@@ -148,6 +148,7 @@
148#define OCP_EEE_ABLE 0xa5c4 148#define OCP_EEE_ABLE 0xa5c4
149#define OCP_EEE_ADV 0xa5d0 149#define OCP_EEE_ADV 0xa5d0
150#define OCP_EEE_LPABLE 0xa5d2 150#define OCP_EEE_LPABLE 0xa5d2
151#define OCP_PHY_STATE 0xa708 /* nway state for 8153 */
151#define OCP_ADC_CFG 0xbc06 152#define OCP_ADC_CFG 0xbc06
152 153
153/* SRAM Register */ 154/* SRAM Register */
@@ -432,6 +433,10 @@
432/* OCP_DOWN_SPEED */ 433/* OCP_DOWN_SPEED */
433#define EN_10M_BGOFF 0x0080 434#define EN_10M_BGOFF 0x0080
434 435
436/* OCP_PHY_STATE */
437#define TXDIS_STATE 0x01
438#define ABD_STATE 0x02
439
435/* OCP_ADC_CFG */ 440/* OCP_ADC_CFG */
436#define CKADSEL_L 0x0100 441#define CKADSEL_L 0x0100
437#define ADC_EN 0x0080 442#define ADC_EN 0x0080
@@ -609,6 +614,7 @@ struct r8152 {
609 void (*unload)(struct r8152 *); 614 void (*unload)(struct r8152 *);
610 int (*eee_get)(struct r8152 *, struct ethtool_eee *); 615 int (*eee_get)(struct r8152 *, struct ethtool_eee *);
611 int (*eee_set)(struct r8152 *, struct ethtool_eee *); 616 int (*eee_set)(struct r8152 *, struct ethtool_eee *);
617 bool (*in_nway)(struct r8152 *);
612 } rtl_ops; 618 } rtl_ops;
613 619
614 int intr_interval; 620 int intr_interval;
@@ -2946,6 +2952,32 @@ static void rtl8153_down(struct r8152 *tp)
2946 r8153_enable_aldps(tp); 2952 r8153_enable_aldps(tp);
2947} 2953}
2948 2954
2955static 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
2971static 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
2949static void set_carrier(struct r8152 *tp) 2981static void set_carrier(struct r8152 *tp)
2950{ 2982{
2951 struct net_device *netdev = tp->netdev; 2983 struct net_device *netdev = tp->netdev;
@@ -3410,6 +3442,27 @@ static int rtl8152_post_reset(struct usb_interface *intf)
3410 return 0; 3442 return 0;
3411} 3443}
3412 3444
3445static 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
3413static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) 3466static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
3414{ 3467{
3415 struct r8152 *tp = usb_get_intfdata(intf); 3468 struct r8152 *tp = usb_get_intfdata(intf);
@@ -3419,7 +3472,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
3419 mutex_lock(&tp->control); 3472 mutex_lock(&tp->control);
3420 3473
3421 if (PMSG_IS_AUTO(message)) { 3474 if (PMSG_IS_AUTO(message)) {
3422 if (netif_running(netdev) && work_busy(&tp->schedule.work)) { 3475 if (netif_running(netdev) && delay_autosuspend(tp)) {
3423 ret = -EBUSY; 3476 ret = -EBUSY;
3424 goto out1; 3477 goto out1;
3425 } 3478 }
@@ -4049,6 +4102,7 @@ static int rtl_ops_init(struct r8152 *tp)
4049 ops->unload = rtl8152_unload; 4102 ops->unload = rtl8152_unload;
4050 ops->eee_get = r8152_get_eee; 4103 ops->eee_get = r8152_get_eee;
4051 ops->eee_set = r8152_set_eee; 4104 ops->eee_set = r8152_set_eee;
4105 ops->in_nway = rtl8152_in_nway;
4052 break; 4106 break;
4053 4107
4054 case RTL_VER_03: 4108 case RTL_VER_03:
@@ -4063,6 +4117,7 @@ static int rtl_ops_init(struct r8152 *tp)
4063 ops->unload = rtl8153_unload; 4117 ops->unload = rtl8153_unload;
4064 ops->eee_get = r8153_get_eee; 4118 ops->eee_get = r8153_get_eee;
4065 ops->eee_set = r8153_set_eee; 4119 ops->eee_set = r8153_set_eee;
4120 ops->in_nway = rtl8153_in_nway;
4066 break; 4121 break;
4067 4122
4068 default: 4123 default: