]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
USB: EHCI: EHCI 1.1 addendum: Enable Per-port change detect bits
authorAlek Du <alek.du@intel.com>
Fri, 4 Jun 2010 07:47:56 +0000 (15:47 +0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 10 Aug 2010 21:35:35 +0000 (14:35 -0700)
This patch will enable Per-port event feature defined in EHCI 1.1
addendum. This feature addresses an issue where HCD is currently
required to read and parse PORTSC for all enabled root hub ports. With
this patch, the overhead will be reduced.

Signed-off-by: Alek Du <alek.du@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci.h

index baf9b648bb1f4c464d2f89d65d9297d9979a1bd3..8697ad19f313c1d9002e2339e2871b18db6bb366 100644 (file)
@@ -584,6 +584,11 @@ static int ehci_init(struct usb_hcd *hcd)
        if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
                log2_irq_thresh = 0;
        temp = 1 << (16 + log2_irq_thresh);
+       if (HCC_PER_PORT_CHANGE_EVENT(hcc_params)) {
+               ehci->has_ppcd = 1;
+               ehci_dbg(ehci, "enable per-port change event\n");
+               temp |= CMD_PPCEE;
+       }
        if (HCC_CANPARK(hcc_params)) {
                /* HW default park == 3, on hardware that supports it (like
                 * NVidia and ALI silicon), maximizes throughput on the async
@@ -782,6 +787,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        /* remote wakeup [4.3.1] */
        if (status & STS_PCD) {
                unsigned        i = HCS_N_PORTS (ehci->hcs_params);
+               u32             ppcd = 0;
 
                /* kick root hub later */
                pcd_status = status;
@@ -790,9 +796,18 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
                if (!(cmd & CMD_RUN))
                        usb_hcd_resume_root_hub(hcd);
 
+               /* get per-port change detect bits */
+               if (ehci->has_ppcd)
+                       ppcd = status >> 16;
+
                while (i--) {
-                       int pstatus = ehci_readl(ehci,
-                                                &ehci->regs->port_status [i]);
+                       int pstatus;
+
+                       /* leverage per-port change bits feature */
+                       if (ehci->has_ppcd && !(ppcd & (1 << i)))
+                               continue;
+                       pstatus = ehci_readl(ehci,
+                                        &ehci->regs->port_status[i]);
 
                        if (pstatus & PORT_OWNER)
                                continue;
index 8a28dae8a375b318b772bf1561620520eae739a7..84e792d71c224c7f7918d8a58446f83a658a084b 100644 (file)
@@ -603,6 +603,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
        u32             mask;
        int             ports, i, retval = 1;
        unsigned long   flags;
+       u32             ppcd = 0;
 
        /* if !USB_SUSPEND, root hub timers won't get shut down ... */
        if (!HC_IS_RUNNING(hcd->state))
@@ -632,7 +633,15 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
 
        /* port N changes (bit N)? */
        spin_lock_irqsave (&ehci->lock, flags);
+
+       /* get per-port change detect bits */
+       if (ehci->has_ppcd)
+               ppcd = ehci_readl(ehci, &ehci->regs->status) >> 16;
+
        for (i = 0; i < ports; i++) {
+               /* leverage per-port change bits feature */
+               if (ehci->has_ppcd && !(ppcd & (1 << i)))
+                       continue;
                temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
 
                /*
index 21f30a0c3d2fef752eacb367b2ee7c49a3ab83c9..e6c57cc416f689c136f23f4b5fb11e7445d65b71 100644 (file)
@@ -141,6 +141,7 @@ struct ehci_hcd {                   /* one per controller */
        __hc32                  *ohci_hcctrl_reg;
        unsigned                has_hostpc:1;
        unsigned                has_lpm:1;  /* support link power management */
+       unsigned                has_ppcd:1; /* support per-port change bits */
        u8                      sbrn;           /* packed release number */
 
        /* irq statistics */