Received: by 10.223.185.116 with SMTP id b49csp5221970wrg; Tue, 27 Feb 2018 09:41:06 -0800 (PST) X-Google-Smtp-Source: AH8x225Dz4ZKUMwEx9RicFeAC8VKon/Db0fUJ9Ol3fMmF9EWSfNHrgf07OLkIugOUpc7r8XuwPnl X-Received: by 2002:a17:902:f81:: with SMTP id 1-v6mr14533586plz.265.1519753265904; Tue, 27 Feb 2018 09:41:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519753265; cv=none; d=google.com; s=arc-20160816; b=zttVmNcuNY1hM8H6xJ3BWGbt6jwUM/sPZqBYxmoIcaLp+p/fvBRU8ZHnpiUZho0Nux sVA93+WT8tkUTO0Mlb85EVdJa9XU8C6tWV+rhp9hhkPGhzhUqBZsW9AhUqzfylr7ngVI Y+Ndyfg7yX0epalw1E3MkUmDN5cexldyPPeEWvgt01gY9WLZ7mXfalQuWJzg3V/7uESc eDrkbT3zHo7XLDv3OcOIpBbpPm9LIdYHnkT4F2ujHt6yx2F1frfBjUTxgxZOHBALwv5j sqjSaubioJreTrq1f8AQdf1aV6+rGJKmT/fypwgWrzyv/WJQdeUiJRZpQ4lh7aAizlNo WESw== 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 :organization:references:in-reply-to:message-id:subject:cc:to:from :date:arc-authentication-results; bh=gPut4gagnduSUYKEuliuHZUtFk9OLTBAupkIY/IZGK8=; b=oyT/vyJPXl5gFJm+GixamDZDiqGp1KDLT/0gkWcL2L56rAdA3xsV7ggEBxwINzxLsR TYR5EpzB1FlSdr3mZ4Sh2QHL1KAZh5lrCrd/1uMBl2dHz5Hz8dmRSZv5P8dHz9Z2VINw nxWqZJxiqqGUudi5ndZHGFg2Of0jZ8POECqfD4GO5kAzy7eQo7DMbdWbpMP7idM8oZ37 SCPN3KictQplf241/bmqxnycsV+JhVRHd/gTYKlggZTlEWxDiup+Rwv8dg21fZBVQG70 mhoa9s4U4No6LqOjaRQGfeGiOlfypdU+GDqWetuYOs0v7CTDkE+ZKKlNrbyPyUJypv8y qC4w== 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 y12si7222022pgv.251.2018.02.27.09.40.50; Tue, 27 Feb 2018 09:41:05 -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 S1751960AbeB0Rjn (ORCPT + 99 others); Tue, 27 Feb 2018 12:39:43 -0500 Received: from osg.samsung.com ([64.30.133.232]:63077 "EHLO osg.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751518AbeB0Rjl (ORCPT ); Tue, 27 Feb 2018 12:39:41 -0500 Received: from localhost (localhost [127.0.0.1]) by osg.samsung.com (Postfix) with ESMTP id 526E429B22; Tue, 27 Feb 2018 09:39:41 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at dev.s-opensource.com Received: from osg.samsung.com ([127.0.0.1]) by localhost (localhost [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Hmfrj0ZWQVit; Tue, 27 Feb 2018 09:39:39 -0800 (PST) Received: from vento.lan (177.41.102.20.dynamic.adsl.gvt.net.br [177.41.102.20]) by osg.samsung.com (Postfix) with ESMTPSA id 64AD629B16; Tue, 27 Feb 2018 09:39:37 -0800 (PST) Date: Tue, 27 Feb 2018 14:39:34 -0300 From: Mauro Carvalho Chehab To: Sebastian Andrzej Siewior Cc: Frederic Weisbecker , LKML , Peter Zijlstra , Thomas Gleixner , Alan Stern , linux-usb@vger.kernel.org Subject: Re: [RFC PATCH] usb: hcd: complete URBs in threaded-IRQ context instead of tasklet Message-ID: <20180227143934.2aa847ac@vento.lan> In-Reply-To: <20180216170450.yl5owfphuvltstnt@breakpoint.cc> References: <20180216170450.yl5owfphuvltstnt@breakpoint.cc> Organization: Samsung X-Mailer: Claws Mail 3.15.1-dirty (GTK+ 2.24.32; x86_64-redhat-linux-gnu) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Sebastian, Em Fri, 16 Feb 2018 18:04:50 +0100 Sebastian Andrzej Siewior escreveu: > I've been going over Frederic's softirq patches and it seems that there > were two problems. One was network related, the other was Mauro's USB > dvb-[stc] device which was not able to stream properly over time. > > Here is an attempt to let the URB complete in the threaded handler > instead of going to the tasklet. In case the system is SMP then the > patch [0] would be required in order to have the IRQ and its thread on > the same CPU. > > Mauro, would you mind giving it a shot? Sorry for taking some time to test it, has been busy those days... Anyway, I tested it today. Didn't work. It keep losing data. Regards, > > [0] genirq: Let irq thread follow the effective hard irq affinity > https://git.kernel.org/tip/cbf8699996a6e7f2f674b3a2a4cef9f666ff613e > > --- > > The urb->complete callback was initially invoked in IRQ context after > the HCD dropped its lock because the callback could re-queue the URB > again. Later this completion was deferred to the tasklet allowing the > HCD hold the lock. Also the BH handler can be interrupted by the IRQ > handler adding more "completed" requests to its queue. > While this batching is good in general, the softirq defers its doing for > short period of time if it is running constantly without a break. This > breaks some use cases where constant USB throughput is required. > As an alternative approach to tasklet handling, I defer the URB > completion to the HCD's threaded handler. There are two lists for > "high-prio" proccessing and lower priority (to mimic current behaviour). > The URBs in the high-priority list are always preffered over the URBs > in the low-priority list. > The URBs from the root-hub never create an interrupt so I currently > process them in a workqueue (I'm not sure if an URB-enqueue in the > completion handler would break something). > > Signed-off-by: Sebastian Andrzej Siewior > --- > drivers/usb/core/hcd.c | 131 ++++++++++++++++++++++++++++++++---------------- > include/linux/usb/hcd.h | 14 +++--- > 2 files changed, 95 insertions(+), 50 deletions(-) > > diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c > index fc32391a34d5..8d6dd4d3cbe7 100644 > --- a/drivers/usb/core/hcd.c > +++ b/drivers/usb/core/hcd.c > @@ -1775,33 +1775,75 @@ static void __usb_hcd_giveback_urb(struct urb *urb) > usb_put_urb(urb); > } > > -static void usb_giveback_urb_bh(unsigned long param) > +static void usb_hcd_rh_gb_urb(struct work_struct *work) > { > - struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param; > - struct list_head local_list; > + struct giveback_urb *bh = container_of(work, struct giveback_urb, > + rh_compl); > + struct list_head urb_list; > > spin_lock_irq(&bh->lock); > - bh->running = true; > - restart: > - list_replace_init(&bh->head, &local_list); > + list_replace_init(&bh->rh_head, &urb_list); > spin_unlock_irq(&bh->lock); > > - while (!list_empty(&local_list)) { > + while (!list_empty(&urb_list)) { > struct urb *urb; > > - urb = list_entry(local_list.next, struct urb, urb_list); > + urb = list_first_entry(&urb_list, struct urb, urb_list); > list_del_init(&urb->urb_list); > - bh->completing_ep = urb->ep; > __usb_hcd_giveback_urb(urb); > - bh->completing_ep = NULL; > + } > +} > + > + > +#define URB_PRIO_HIGH 0 > +#define URB_PRIO_LOW 1 > + > +static irqreturn_t usb_hcd_gb_urb(int irq, void *__hcd) > +{ > + struct usb_hcd *hcd = __hcd; > + struct giveback_urb *bh = &hcd->gb_urb; > + struct list_head urb_list[2]; > + int i; > + > + INIT_LIST_HEAD(&urb_list[URB_PRIO_HIGH]); > + INIT_LIST_HEAD(&urb_list[URB_PRIO_LOW]); > + > + spin_lock_irq(&bh->lock); > + restart: > + list_splice_tail_init(&bh->prio_hi_head, &urb_list[URB_PRIO_HIGH]); > + list_splice_tail_init(&bh->prio_lo_head, &urb_list[URB_PRIO_LOW]); > + spin_unlock_irq(&bh->lock); > + > + for (i = 0; i < ARRAY_SIZE(urb_list); i++) { > + while (!list_empty(&urb_list[i])) { > + struct urb *urb; > + > + urb = list_first_entry(&urb_list[i], > + struct urb, urb_list); > + list_del_init(&urb->urb_list); > + if (i == URB_PRIO_HIGH) > + bh->completing_ep = urb->ep; > + > + __usb_hcd_giveback_urb(urb); > + > + if (i == URB_PRIO_HIGH) > + bh->completing_ep = NULL; > + > + if (i == URB_PRIO_LOW && > + !list_empty_careful(&urb_list[URB_PRIO_HIGH])) { > + spin_lock_irq(&bh->lock); > + goto restart; > + } > + } > } > > /* check if there are new URBs to giveback */ > spin_lock_irq(&bh->lock); > - if (!list_empty(&bh->head)) > + if (!list_empty(&bh->prio_hi_head) || > + !list_empty(&bh->prio_lo_head)) > goto restart; > - bh->running = false; > spin_unlock_irq(&bh->lock); > + return IRQ_HANDLED; > } > > /** > @@ -1823,37 +1865,32 @@ static void usb_giveback_urb_bh(unsigned long param) > */ > void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) > { > - struct giveback_urb_bh *bh; > - bool running, high_prio_bh; > + struct giveback_urb *bh = &hcd->gb_urb; > + struct list_head *lh; > > /* pass status to tasklet via unlinked */ > if (likely(!urb->unlinked)) > urb->unlinked = status; > > - if (!hcd_giveback_urb_in_bh(hcd) && !is_root_hub(urb->dev)) { > + if (is_root_hub(urb->dev)) { > + spin_lock(&bh->lock); > + list_add_tail(&urb->urb_list, &bh->rh_head); > + spin_unlock(&bh->lock); > + queue_work(system_highpri_wq, &bh->rh_compl); > + return; > + } > + if (!hcd_giveback_urb_in_bh(hcd)) { > __usb_hcd_giveback_urb(urb); > return; > } > > - if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) { > - bh = &hcd->high_prio_bh; > - high_prio_bh = true; > - } else { > - bh = &hcd->low_prio_bh; > - high_prio_bh = false; > - } > - > - spin_lock(&bh->lock); > - list_add_tail(&urb->urb_list, &bh->head); > - running = bh->running; > - spin_unlock(&bh->lock); > - > - if (running) > - ; > - else if (high_prio_bh) > - tasklet_hi_schedule(&bh->bh); > + if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) > + lh = &bh->prio_hi_head; > else > - tasklet_schedule(&bh->bh); > + lh = &bh->prio_lo_head; > + spin_lock(&bh->lock); > + list_add_tail(&urb->urb_list, lh); > + spin_unlock(&bh->lock); > } > EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb); > > @@ -2436,9 +2473,17 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) > rc = IRQ_NONE; > else if (hcd->driver->irq(hcd) == IRQ_NONE) > rc = IRQ_NONE; > - else > - rc = IRQ_HANDLED; > + else { > + struct giveback_urb *bh = &hcd->gb_urb; > > + spin_lock(&bh->lock); > + if (!list_empty(&bh->prio_hi_head) || > + !list_empty(&bh->prio_lo_head)) > + rc = IRQ_WAKE_THREAD; > + else > + rc = IRQ_HANDLED; > + spin_unlock(&bh->lock); > + } > return rc; > } > EXPORT_SYMBOL_GPL(usb_hcd_irq); > @@ -2492,12 +2537,13 @@ EXPORT_SYMBOL_GPL (usb_hc_died); > > /*-------------------------------------------------------------------------*/ > > -static void init_giveback_urb_bh(struct giveback_urb_bh *bh) > +static void init_giveback_urb(struct giveback_urb *bh) > { > - > spin_lock_init(&bh->lock); > - INIT_LIST_HEAD(&bh->head); > - tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh); > + INIT_LIST_HEAD(&bh->prio_lo_head); > + INIT_LIST_HEAD(&bh->prio_hi_head); > + INIT_LIST_HEAD(&bh->rh_head); > + INIT_WORK(&bh->rh_compl, usb_hcd_rh_gb_urb); > } > > struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver, > @@ -2672,7 +2718,8 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd, > > snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", > hcd->driver->description, hcd->self.busnum); > - retval = request_irq(irqnum, &usb_hcd_irq, irqflags, > + retval = request_threaded_irq(irqnum, usb_hcd_irq, > + usb_hcd_gb_urb, irqflags, > hcd->irq_descr, hcd); > if (retval != 0) { > dev_err(hcd->self.controller, > @@ -2863,9 +2910,7 @@ int usb_add_hcd(struct usb_hcd *hcd, > && device_can_wakeup(&hcd->self.root_hub->dev)) > dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); > > - /* initialize tasklets */ > - init_giveback_urb_bh(&hcd->high_prio_bh); > - init_giveback_urb_bh(&hcd->low_prio_bh); > + init_giveback_urb(&hcd->gb_urb); > > /* enable irqs just before we start the controller, > * if the BIOS provides legacy PCI irqs. > diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h > index 176900528822..12573515acb6 100644 > --- a/include/linux/usb/hcd.h > +++ b/include/linux/usb/hcd.h > @@ -64,11 +64,12 @@ > > /*-------------------------------------------------------------------------*/ > > -struct giveback_urb_bh { > - bool running; > +struct giveback_urb { > spinlock_t lock; > - struct list_head head; > - struct tasklet_struct bh; > + struct list_head prio_lo_head; > + struct list_head prio_hi_head; > + struct list_head rh_head; > + struct work_struct rh_compl; > struct usb_host_endpoint *completing_ep; > }; > > @@ -169,8 +170,7 @@ struct usb_hcd { > resource_size_t rsrc_len; /* memory/io resource length */ > unsigned power_budget; /* in mA, 0 = no limit */ > > - struct giveback_urb_bh high_prio_bh; > - struct giveback_urb_bh low_prio_bh; > + struct giveback_urb gb_urb; > > /* bandwidth_mutex should be taken before adding or removing > * any new bus bandwidth constraints: > @@ -410,7 +410,7 @@ static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd) > static inline bool hcd_periodic_completion_in_progress(struct usb_hcd *hcd, > struct usb_host_endpoint *ep) > { > - return hcd->high_prio_bh.completing_ep == ep; > + return hcd->gb_urb.completing_ep == ep; > } > > extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); Thanks, Mauro