Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e383c704 authored by Stanislaw Gruszka's avatar Stanislaw Gruszka Committed by Kalle Valo
Browse files

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: default avatarRandy Oostdyk <linux-kernel@oostdyk.com>
Signed-off-by: default avatarStanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent bb3b18c9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+19 −3
Original line number Diff line number Diff line
@@ -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);