usb: add find_raw_port_number callback to struct hc_driver()
authorLan Tianyu <tianyu.lan@intel.com>
Tue, 19 Mar 2013 08:48:12 +0000 (16:48 +0800)
committerSarah Sharp <sarah.a.sharp@linux.intel.com>
Mon, 25 Mar 2013 17:39:17 +0000 (10:39 -0700)
xhci driver divides the root hub into two logical hubs which work
respectively for usb 2.0 and usb 3.0 devices. They are independent
devices in the usb core. But in the ACPI table, it's one device node
and all usb2.0 and usb3.0 ports are under it. Binding usb port with
its acpi node needs the raw port number which is reflected in the xhci
extended capabilities table. This patch is to add find_raw_port_number
callback to struct hc_driver(), fill it with xhci_find_raw_port_number()
which will return raw port number and add a wrap usb_hcd_find_raw_port_number().

Otherwise, refactor xhci_find_real_port_number(). Using
xhci_find_raw_port_number() to get real index in the HW port status
registers instead of scanning through the xHCI roothub port array.
This can help to speed up.

All addresses in xhci->usb2_ports and xhci->usb3_ports array are
kown good ports and don't include following bad ports in the extended
capabilities talbe.
     (1) root port that doesn't have an entry
     (2) root port with unknown speed
     (3) root port that is listed twice and with different speeds.

So xhci_find_raw_port_number() will only return port num of good ones
and never touch bad ports above.

Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
drivers/usb/core/hcd.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
include/linux/usb/hcd.h

index 99b34a3..f9ec44c 100644 (file)
@@ -2412,6 +2412,14 @@ int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
 }
 EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd);
 
+int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1)
+{
+       if (!hcd->driver->find_raw_port_number)
+               return port1;
+
+       return hcd->driver->find_raw_port_number(hcd, port1);
+}
+
 static int usb_hcd_request_irqs(struct usb_hcd *hcd,
                unsigned int irqnum, unsigned long irqflags)
 {
index 35616ff..6dc238c 100644 (file)
@@ -1022,44 +1022,24 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
  * is attached to (or the roothub port its ancestor hub is attached to).  All we
  * know is the index of that port under either the USB 2.0 or the USB 3.0
  * roothub, but that doesn't give us the real index into the HW port status
- * registers.  Scan through the xHCI roothub port array, looking for the Nth
- * entry of the correct port speed.  Return the port number of that entry.
+ * registers. Call xhci_find_raw_port_number() to get real index.
  */
 static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
                struct usb_device *udev)
 {
        struct usb_device *top_dev;
-       unsigned int num_similar_speed_ports;
-       unsigned int faked_port_num;
-       int i;
+       struct usb_hcd *hcd;
+
+       if (udev->speed == USB_SPEED_SUPER)
+               hcd = xhci->shared_hcd;
+       else
+               hcd = xhci->main_hcd;
 
        for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
                        top_dev = top_dev->parent)
                /* Found device below root hub */;
-       faked_port_num = top_dev->portnum;
-       for (i = 0, num_similar_speed_ports = 0;
-                       i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
-               u8 port_speed = xhci->port_array[i];
-
-               /*
-                * Skip ports that don't have known speeds, or have duplicate
-                * Extended Capabilities port speed entries.
-                */
-               if (port_speed == 0 || port_speed == DUPLICATE_ENTRY)
-                       continue;
 
-               /*
-                * USB 3.0 ports are always under a USB 3.0 hub.  USB 2.0 and
-                * 1.1 ports are under the USB 2.0 hub.  If the port speed
-                * matches the device speed, it's a similar speed port.
-                */
-               if ((port_speed == 0x03) == (udev->speed == USB_SPEED_SUPER))
-                       num_similar_speed_ports++;
-               if (num_similar_speed_ports == faked_port_num)
-                       /* Roothub ports are numbered from 1 to N */
-                       return i+1;
-       }
-       return 0;
+       return  xhci_find_raw_port_number(hcd, top_dev->portnum);
 }
 
 /* Setup an xHCI virtual device for a Set Address command */
index af259e0..1a30c38 100644 (file)
@@ -313,6 +313,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
        .set_usb2_hw_lpm =      xhci_set_usb2_hardware_lpm,
        .enable_usb3_lpm_timeout =      xhci_enable_usb3_lpm_timeout,
        .disable_usb3_lpm_timeout =     xhci_disable_usb3_lpm_timeout,
+       .find_raw_port_number = xhci_find_raw_port_number,
 };
 
 /*-------------------------------------------------------------------------*/
index 849470b..53b8f89 100644 (file)
@@ -3779,6 +3779,28 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
        return 0;
 }
 
+/*
+ * Transfer the port index into real index in the HW port status
+ * registers. Caculate offset between the port's PORTSC register
+ * and port status base. Divide the number of per port register
+ * to get the real index. The raw port number bases 1.
+ */
+int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       __le32 __iomem *base_addr = &xhci->op_regs->port_status_base;
+       __le32 __iomem *addr;
+       int raw_port;
+
+       if (hcd->speed != HCD_USB3)
+               addr = xhci->usb2_ports[port1 - 1];
+       else
+               addr = xhci->usb3_ports[port1 - 1];
+
+       raw_port = (addr - base_addr)/NUM_PORT_REGS + 1;
+       return raw_port;
+}
+
 #ifdef CONFIG_USB_SUSPEND
 
 /* BESL to HIRD Encoding array for USB2 LPM */
index 2c510e4..d798b69 100644 (file)
@@ -1829,6 +1829,7 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
                char *buf, u16 wLength);
 int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
+int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
 
 #ifdef CONFIG_PM
 int xhci_bus_suspend(struct usb_hcd *hcd);
index 0a78df5..59694b5 100644 (file)
@@ -357,6 +357,7 @@ struct hc_driver {
                 */
        int     (*disable_usb3_lpm_timeout)(struct usb_hcd *,
                        struct usb_device *, enum usb3_link_state state);
+       int     (*find_raw_port_number)(struct usb_hcd *, int);
 };
 
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@@ -396,6 +397,7 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd);
 extern int usb_add_hcd(struct usb_hcd *hcd,
                unsigned int irqnum, unsigned long irqflags);
 extern void usb_remove_hcd(struct usb_hcd *hcd);
+extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
 
 struct platform_device;
 extern void usb_hcd_platform_shutdown(struct platform_device *dev);