Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp8289016imu; Thu, 15 Nov 2018 09:15:39 -0800 (PST) X-Google-Smtp-Source: AJdET5fcCTfNvnOsO5RK2rA8xEpQYsflmxvkfJEy8PyV6IqkcNxWn5pFyRnyFIFoHpnMQ75brLvp X-Received: by 2002:a17:902:a70b:: with SMTP id w11mr3179245plq.84.1542302139495; Thu, 15 Nov 2018 09:15:39 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1542302139; cv=none; d=google.com; s=arc-20160816; b=i4ZycLH5Z0jyXOvp6D2F0i+WtYKAgKDQAzSbXvjXkfwxI7F3ARjrM4wNXx6nbH58KP HNkiTGEnRBofiyyX69OkFm5D2iqib5G0bVuXNe8aAZ8JA/LbXfHOciPomCUAVtNrkCVV KFzRlNhzFXFaCzaJJ7bDCamWODT4pOFLaFYfiH7Rbr2y5qn2401HXd2vGG8haQNBCmXF Ki1owk5ZQ7MBMpQ0c+9BCE+Sf36Gqmxo03Et4TWZJBY99QgSyC4qKnWJZvrZM5S91Ye6 /bnImiHR1acJqkzSZnyHbvgvKqMOlReWEl7NO1T1OtWU6HOp2MEAD6GV4Qoxmj5DKsMn 49Tg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=XvpUyikq8mlmDnqo4/XMZOdrZ4PHAajBuPDOCBmNuz0=; b=bsmdCS70dsjhGVd5jqPvpnvLKyn71vPDOJwkry+jTPW9K7GpEnTDexov6bNmD4Jwp5 NuVg5Mlsh0nPWgCp3zvwzAX1dnZNU5J4g+/3Q1Fi4V/dK4CidY+ICRGfNxCUyr1Nd/s6 wDVJYfWT8Cu2v1sROlNu/4qbm0/t1MSaH9qrYoYgxQ9je8UcDkMtDQgLZa2/I06jviMz p5z1tCG1uzHjpfgPYQ6SNwLmfqKHPP9rXLS1svmlWEGycFDo64T8c47b1fGCmnXZkJzG 15uriKNvLbnudpiRVscv33WjJfjRoJgrlEAiJoklu/6adwCxHsRVKN5U0txYW880rfyl fxSQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 129-v6si30932391pfy.164.2018.11.15.09.15.14; Thu, 15 Nov 2018 09:15:39 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388485AbeKPDXE (ORCPT + 99 others); Thu, 15 Nov 2018 22:23:04 -0500 Received: from mx2.suse.de ([195.135.220.15]:40256 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2387839AbeKPDXE (ORCPT ); Thu, 15 Nov 2018 22:23:04 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id E8A07AD98; Thu, 15 Nov 2018 17:14:22 +0000 (UTC) From: Nicolas Saenz Julienne To: nsaaenzjulienne@suse.de, linux-kernel@vger.kernel.org Cc: Nicolas Saenz Julienne , Greg Kroah-Hartman , linux-usb@vger.kernel.org Subject: [PATCH] usb: hub: add I/O error retry & reset routine Date: Thu, 15 Nov 2018 18:14:18 +0100 Message-Id: <20181115171418.23522-1-nsaenzjulienne@suse.de> X-Mailer: git-send-email 2.19.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org An URB submission error in the HUB's endpoint completion function renders the whole HUB device unresponsive. This patch introduces a routine that retries the submission for 1s to then, as a last resort, reset the whole device. The implementation is based on usbhid/hid_core.c's, which implements the same functionality. It was tested with the help of BCC's error injection tool (inject.py). Signed-off-by: Nicolas Saenz Julienne --- drivers/usb/core/hub.c | 43 +++++++++++++++++++++++++++++++++++++++++- drivers/usb/core/hub.h | 3 +++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d9bd7576786a..1447bdba59ec 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -607,6 +607,44 @@ static int hub_port_status(struct usb_hub *hub, int port1, status, change, NULL); } +static void hub_io_error(struct usb_hub *hub) +{ + /* + * If it has been a while since the last error, we'll assume + * this a brand new error and reset the retry timeout. + */ + if (time_after(jiffies, hub->stop_retry + HZ/2)) + hub->retry_delay = 0; + + /* When an error occurs, retry at increasing intervals */ + if (hub->retry_delay == 0) { + hub->retry_delay = 13; /* Then 26, 52, 104, 104, ... */ + hub->stop_retry = jiffies + msecs_to_jiffies(1000); + } else if (hub->retry_delay < 100) + hub->retry_delay *= 2; + + if (time_after(jiffies, hub->stop_retry)) { + /* Retries failed, so do a port reset */ + usb_queue_reset_device(to_usb_interface(hub->intfdev)); + return; + } + + mod_timer(&hub->io_retry, + jiffies + msecs_to_jiffies(hub->retry_delay)); +} + +static void hub_retry_timeout(struct timer_list *t) +{ + struct usb_hub *hub = from_timer(hub, t, io_retry); + + if (hub->disconnected || hub->quiescing) + return; + + dev_err(hub->intfdev, "retrying int urb\n"); + if (usb_submit_urb(hub->urb, GFP_ATOMIC)) + hub_io_error(hub); +} + static void kick_hub_wq(struct usb_hub *hub) { struct usb_interface *intf; @@ -713,8 +751,10 @@ static void hub_irq(struct urb *urb) return; status = usb_submit_urb(hub->urb, GFP_ATOMIC); - if (status != 0 && status != -ENODEV && status != -EPERM) + if (status != 0 && status != -ENODEV && status != -EPERM) { dev_err(hub->intfdev, "resubmit --> %d\n", status); + hub_io_error(hub); + } } /* USB 2.0 spec Section 11.24.2.3 */ @@ -1800,6 +1840,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); INIT_WORK(&hub->events, hub_event); + timer_setup(&hub->io_retry, hub_retry_timeout, 0); usb_get_intf(intf); usb_get_dev(hdev); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 4accfb63f7dc..7dbd19c2c8d9 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -69,6 +69,9 @@ struct usb_hub { struct delayed_work leds; struct delayed_work init_work; struct work_struct events; + struct timer_list io_retry; + unsigned long stop_retry; + unsigned int retry_delay; struct usb_port **ports; }; -- 2.19.1