aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ralink/rt2x00
diff options
context:
space:
mode:
authorStanislaw Gruszka <sgruszka@redhat.com>2019-03-12 10:51:42 +0100
committerKalle Valo <kvalo@codeaurora.org>2019-04-25 19:40:53 +0300
commite383c70474db32b9d4a3de6dfbd08784d19e6751 (patch)
treed8af3360d26de89f63b8484331ef9609d8d757b6 /drivers/net/wireless/ralink/rt2x00
parentrt2x00: use ratelimited variants dev_warn/dev_err (diff)
downloadlinux-dev-e383c70474db32b9d4a3de6dfbd08784d19e6751.tar.xz
linux-dev-e383c70474db32b9d4a3de6dfbd08784d19e6751.zip
rt2x00: check number of EPROTO errors
Some USB host devices/drivers on some conditions can always return EPROTO error on submitted URBs. That can cause infinity loop in the rt2x00 driver. Since we can have single EPROTO errors we can not mark as device as removed to avoid infinity loop. However we can count consecutive EPROTO errors and mark device as removed if get lot of it. I choose number 10 as threshold. Reported-and-tested-by: Randy Oostdyk <linux-kernel@oostdyk.com> Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/ralink/rt2x00')
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00.h1
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00usb.c22
2 files changed, 20 insertions, 3 deletions
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index ebe4c7f90542..48c0957b18d1 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -1016,6 +1016,7 @@ struct rt2x00_dev {
unsigned int extra_tx_headroom;
struct usb_anchor *anchor;
+ unsigned int num_proto_errs;
/* Clock for System On Chip devices. */
struct clk *clk;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
index 086aad22743d..9cdd7f2c92b5 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -31,6 +31,22 @@
#include "rt2x00.h"
#include "rt2x00usb.h"
+static bool rt2x00usb_check_usb_error(struct rt2x00_dev *rt2x00dev, int status)
+{
+ if (status == -ENODEV || status == -ENOENT)
+ return true;
+
+ if (status == -EPROTO || status == -ETIMEDOUT)
+ rt2x00dev->num_proto_errs++;
+ else
+ rt2x00dev->num_proto_errs = 0;
+
+ if (rt2x00dev->num_proto_errs > 3)
+ return true;
+
+ return false;
+}
+
/*
* Interfacing with the HW.
*/
@@ -57,7 +73,7 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
if (status >= 0)
return 0;
- if (status == -ENODEV || status == -ENOENT) {
+ if (rt2x00usb_check_usb_error(rt2x00dev, status)) {
/* Device has disappeared. */
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
break;
@@ -321,7 +337,7 @@ static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void *data)
status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
if (status) {
- if (status == -ENODEV || status == -ENOENT)
+ if (rt2x00usb_check_usb_error(rt2x00dev, status))
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
@@ -410,7 +426,7 @@ static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void *data)
status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
if (status) {
- if (status == -ENODEV || status == -ENOENT)
+ if (rt2x00usb_check_usb_error(rt2x00dev, status))
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);