Re: [PATCH] usb: hcd: allow wakeups while suspended for Moorestown

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Apr 07, 2011 at 03:34:59PM -0700, Greg KH wrote:
> On Thu, Apr 07, 2011 at 02:54:39PM -0700, Kristen Carlson Accardi wrote:
> > On Thu, 7 Apr 2011 13:35:02 -0700
> > Greg KH <greg@xxxxxxxxx> wrote:
> > 
> > > On Thu, Apr 07, 2011 at 09:56:54AM -0700, Kristen Carlson Accardi wrote:
> > > > > Have you made timing/performance studies, comparing (for example) USB 
> > > > > disk throughput with and without threaded interrupts?
> > > > >
> > > > 
> > > > I could never do this with all the different types of hw.  I suggest
> > > > that if you decide to move to a threaded irq you have a long period of
> > > > testing time where people can determine whether or not it impacts
> > > > performance on their own hw.  Just from googling I can see that tglx
> > > > did some performance analysis, but you'd have to ask him what the
> > > > findings were.
> > > 
> > > I asked him about this an hour ago, and he found that he got a
> > > performance increase in USB throughput switching to threaded irqs,
> > > especially for usb-storage devices.
> > > 
> > > So I'm all for it now, send me the patch and let's see what breaks :)
> > > 
> > > thanks,
> > > 
> > > greg k-h
> > 
> > I sent him an email to see if he'll submit the patches he's been
> > testing with -- I figured it'd be better to use those since he's
> > got time on them already.
> 
> Yes, it turns out that your patch will not work properly on some
> hardware in the first place, so his changes are needed.  I see him
> working on them right now in front of me in the conference meeting we
> are currently sitting in...

Here's Thomas's first cut at doing this, totally untested and written
during a legal track at the LF Collab summit.

Kristen, can you take this and test and see if it works for you?

thanks,

greg k-h


Subject: usb.patch
From: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Date: Thu, 07 Apr 2011 23:35:16 +0200

Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
---
 drivers/usb/core/hcd.c      |   42 ++++++++++++++++++++----------------------
 drivers/usb/host/ehci-hcd.c |   33 +++++++++++++++++++++++++++------
 drivers/usb/host/ehci-pci.c |    1 +
 include/linux/usb/hcd.h     |    1 +
 4 files changed, 49 insertions(+), 28 deletions(-)

Index: linux-2.6/drivers/usb/core/hcd.c
===================================================================
--- linux-2.6.orig/drivers/usb/core/hcd.c
+++ linux-2.6/drivers/usb/core/hcd.c
@@ -2111,34 +2111,36 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
 irqreturn_t usb_hcd_irq (int irq, void *__hcd)
 {
 	struct usb_hcd		*hcd = __hcd;
-	unsigned long		flags;
 	irqreturn_t		rc;
 
-	/* IRQF_DISABLED doesn't work correctly with shared IRQs
-	 * when the first handler doesn't use it.  So let's just
-	 * assume it's never used.
-	 */
-	local_irq_save(flags);
-
 	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) {
 		rc = IRQ_NONE;
-	} else if (hcd->driver->irq(hcd) == IRQ_NONE) {
-		rc = IRQ_NONE;
 	} else {
+		rc = hcd->driver->irq(hcd);
+		if (rc == IRQ_NONE)
+			return rc;
+
 		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
 		if (hcd->shared_hcd)
 			set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
 
 		if (unlikely(hcd->state == HC_STATE_HALT))
 			usb_hc_died(hcd);
-		rc = IRQ_HANDLED;
 	}
-
-	local_irq_restore(flags);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(usb_hcd_irq);
 
+irqreturn_t usb_hcd_thread_irq (int irq, void *__hcd)
+{
+	struct usb_hcd		*hcd = __hcd;
+
+	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
+		return IRQ_NONE;
+
+	return hcd->driver->threaded_irq(hcd);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /**
@@ -2189,7 +2191,7 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
 /**
  * usb_create_shared_hcd - create and initialize an HCD structure
  * @driver: HC driver that will use this hcd
- * @dev: device for this HC, stored in hcd->self.controller
+s * @dev: device for this HC, stored in hcd->self.controller
  * @bus_name: value to store in hcd->self.bus_name
  * @primary_hcd: a pointer to the usb_hcd structure that is sharing the
  *              PCI device.  Only allocate certain resources for the primary HCD
@@ -2323,17 +2325,13 @@ static int usb_hcd_request_irqs(struct u
 
 	if (hcd->driver->irq) {
 
-		/* IRQF_DISABLED doesn't work as advertised when used together
-		 * with IRQF_SHARED. As usb_hcd_irq() will always disable
-		 * interrupts we can remove it here.
-		 */
-		if (irqflags & IRQF_SHARED)
-			irqflags &= ~IRQF_DISABLED;
-
 		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,
-				hcd->irq_descr, hcd);
+
+		retval = request_threaded_irq(irqnum,
+				hcd->driver->irq ? &usb_hcd_irq : NULL,
+				hcd->driver->threaded_irq ? &usb_hcd_thread_irq : NULL,
+				irqflags, hcd->irq_descr, hcd);
 		if (retval != 0) {
 			dev_err(hcd->self.controller,
 					"request interrupt %d failed\n",
Index: linux-2.6/drivers/usb/host/ehci-hcd.c
===================================================================
--- linux-2.6.orig/drivers/usb/host/ehci-hcd.c
+++ linux-2.6/drivers/usb/host/ehci-hcd.c
@@ -764,10 +764,35 @@ static int ehci_run (struct usb_hcd *hcd
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			status;
+
+	spin_lock(&ehci->lock);
+
+	status = ehci_readl(ehci, &ehci->regs->status);
+	if (status & INTR_MASK)
+		ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+
+	spin_unlock(&ehci->lock);
+
+	return status & INTR_MASK ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
+static irqreturn_t ehci_thread_irq (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			status, masked_status, pcd_status = 0, cmd;
 	int			bh;
 
-	spin_lock (&ehci->lock);
+	/*
+	 * The scope of this lock wants to be reduced to protect the
+	 * status register access. Serializiation at the thread level
+	 * should simply use a mutex, which is not simple either as
+	 * you have to deal with the watchdog timer stuff. Needs some
+	 * thought. Making it spin_lock_bh() now should be fine. We
+	 * just need to disable interrupts right before we write the
+	 * interrupt mask register.
+	 */
+	spin_lock_irq(&ehci->lock);
 
 	status = ehci_readl(ehci, &ehci->regs->status);
 
@@ -778,10 +803,6 @@ static irqreturn_t ehci_irq (struct usb_
 	}
 
 	masked_status = status & INTR_MASK;
-	if (!masked_status) {		/* irq sharing? */
-		spin_unlock(&ehci->lock);
-		return IRQ_NONE;
-	}
 
 	/* clear (just) interrupts */
 	ehci_writel(ehci, masked_status, &ehci->regs->status);
@@ -881,7 +902,7 @@ dead:
 
 	if (bh)
 		ehci_work (ehci);
-	spin_unlock (&ehci->lock);
+	spin_unlock_irq (&ehci->lock);
 	if (pcd_status)
 		usb_hcd_poll_rh_status(hcd);
 	return IRQ_HANDLED;
Index: linux-2.6/drivers/usb/host/ehci-pci.c
===================================================================
--- linux-2.6.orig/drivers/usb/host/ehci-pci.c
+++ linux-2.6/drivers/usb/host/ehci-pci.c
@@ -430,6 +430,7 @@ static const struct hc_driver ehci_pci_h
 	 * generic hardware linkage
 	 */
 	.irq =			ehci_irq,
+	.threaded_irq =		ehci_thread_irq,
 	.flags =		HCD_MEMORY | HCD_USB2,
 
 	/*
Index: linux-2.6/include/linux/usb/hcd.h
===================================================================
--- linux-2.6.orig/include/linux/usb/hcd.h
+++ linux-2.6/include/linux/usb/hcd.h
@@ -207,6 +207,7 @@ struct hc_driver {
 
 	/* irq handler */
 	irqreturn_t	(*irq) (struct usb_hcd *hcd);
+	irqreturn_t	(*threaded_irq) (struct usb_hcd *hcd);
 
 	int	flags;
 #define	HCD_MEMORY	0x0001		/* HC regs use memory (else I/O) */
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux