| From foo@baz Thu Jan 12 21:36:14 CET 2017 |
| From: hayeswang <hayeswang@realtek.com> |
| Date: Tue, 10 Jan 2017 17:04:07 +0800 |
| Subject: r8152: fix rx issue for runtime suspend |
| |
| From: hayeswang <hayeswang@realtek.com> |
| |
| |
| [ Upstream commit 75dc692eda114cb234a46cb11893a9c3ea520934 ] |
| |
| Pause the rx and make sure the rx fifo is empty when the autosuspend |
| occurs. |
| |
| If the rx data comes when the driver is canceling the rx urb, the host |
| controller would stop getting the data from the device and continue |
| it after next rx urb is submitted. That is, one continuing data is |
| split into two different urb buffers. That let the driver take the |
| data as a rx descriptor, and unexpected behavior happens. |
| |
| Signed-off-by: Hayes Wang <hayeswang@realtek.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/usb/r8152.c | 31 ++++++++++++++++++++++++++++--- |
| 1 file changed, 28 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/net/usb/r8152.c |
| +++ b/drivers/net/usb/r8152.c |
| @@ -3452,17 +3452,42 @@ static int rtl8152_rumtime_suspend(struc |
| int ret = 0; |
| |
| if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { |
| + u32 rcr = 0; |
| + |
| if (delay_autosuspend(tp)) { |
| ret = -EBUSY; |
| goto out1; |
| } |
| |
| + if (netif_carrier_ok(netdev)) { |
| + u32 ocp_data; |
| + |
| + rcr = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); |
| + ocp_data = rcr & ~RCR_ACPT_ALL; |
| + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); |
| + rxdy_gated_en(tp, true); |
| + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, |
| + PLA_OOB_CTRL); |
| + if (!(ocp_data & RXFIFO_EMPTY)) { |
| + rxdy_gated_en(tp, false); |
| + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr); |
| + ret = -EBUSY; |
| + goto out1; |
| + } |
| + } |
| + |
| clear_bit(WORK_ENABLE, &tp->flags); |
| usb_kill_urb(tp->intr_urb); |
| - napi_disable(&tp->napi); |
| - rtl_stop_rx(tp); |
| + |
| rtl_runtime_suspend_enable(tp, true); |
| - napi_enable(&tp->napi); |
| + |
| + if (netif_carrier_ok(netdev)) { |
| + napi_disable(&tp->napi); |
| + rtl_stop_rx(tp); |
| + rxdy_gated_en(tp, false); |
| + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr); |
| + napi_enable(&tp->napi); |
| + } |
| } |
| |
| set_bit(SELECTIVE_SUSPEND, &tp->flags); |