xhci->cmd_ring_reserved_trbs = 0;
        xhci->num_usb2_ports = 0;
        xhci->num_usb3_ports = 0;
+       xhci->usb2_rhub.num_ports = 0;
+       xhci->usb3_rhub.num_ports = 0;
        xhci->num_active_eps = 0;
        kfree(xhci->usb2_ports);
        kfree(xhci->usb3_ports);
        kfree(xhci->port_array);
+       kfree(xhci->usb2_rhub.ports);
+       kfree(xhci->usb3_rhub.ports);
+       kfree(xhci->hw_ports);
        kfree(xhci->rh_bw);
        kfree(xhci->ext_caps);
 
        xhci->usb2_ports = NULL;
        xhci->usb3_ports = NULL;
        xhci->port_array = NULL;
+       xhci->usb2_rhub.ports = NULL;
+       xhci->usb3_rhub.ports = NULL;
+       xhci->hw_ports = NULL;
        xhci->rh_bw = NULL;
        xhci->ext_caps = NULL;
 
 
        port_offset--;
        for (i = port_offset; i < (port_offset + port_count); i++) {
+               struct xhci_port *hw_port = &xhci->hw_ports[i];
                /* Duplicate entry.  Ignore the port if the revisions differ. */
-               if (xhci->port_array[i] != 0) {
+               if (xhci->port_array[i] != 0 ||
+                   hw_port->rhub) {
                        xhci_warn(xhci, "Duplicate port entry, Ext Cap %p,"
                                        " port %u\n", addr, i);
                        xhci_warn(xhci, "Port was marked as USB %u, "
                                xhci->port_array[i] = DUPLICATE_ENTRY;
                        }
                        /* FIXME: Should we disable the port? */
+                       if (hw_port->rhub != rhub &&
+                                hw_port->hcd_portnum != DUPLICATE_ENTRY) {
+                               hw_port->rhub->num_ports--;
+                               hw_port->hcd_portnum = DUPLICATE_ENTRY;
+                       }
                        continue;
                }
                xhci->port_array[i] = major_revision;
+               hw_port->rhub = rhub;
+               rhub->num_ports++;
                if (major_revision == 0x03)
                        xhci->num_usb3_ports++;
                else
        /* FIXME: Should we disable ports not in the Extended Capabilities? */
 }
 
+static void xhci_create_rhub_port_array(struct xhci_hcd *xhci,
+                                       struct xhci_hub *rhub, gfp_t flags)
+{
+       int port_index = 0;
+       int i;
+
+       if (!rhub->num_ports)
+               return;
+       rhub->ports = kcalloc(rhub->num_ports, sizeof(rhub->ports), flags);
+       for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
+               if (xhci->hw_ports[i].rhub != rhub ||
+                   xhci->hw_ports[i].hcd_portnum == DUPLICATE_ENTRY)
+                       continue;
+               xhci->hw_ports[i].hcd_portnum = port_index;
+               rhub->ports[port_index] = &xhci->hw_ports[i];
+               port_index++;
+               if (port_index == rhub->num_ports)
+                       break;
+       }
+}
+
 /*
  * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that
  * specify what speeds each port is supposed to be.  We can't count on the port
 
        num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
        xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags);
+       xhci->hw_ports = kcalloc(num_ports, sizeof(*xhci->hw_ports), flags);
        if (!xhci->port_array)
                return -ENOMEM;
 
+       for (i = 0; i < num_ports; i++) {
+               xhci->hw_ports[i].addr = &xhci->op_regs->port_status_base +
+                       NUM_PORT_REGS * i;
+               xhci->hw_ports[i].hw_portnum = i;
+       }
+
        xhci->rh_bw = kzalloc(sizeof(*xhci->rh_bw)*num_ports, flags);
        if (!xhci->rh_bw)
                return -ENOMEM;
                xhci_add_in_port(xhci, num_ports, base + offset, cap_count);
                if (xhci->num_usb2_ports + xhci->num_usb3_ports == num_ports)
                        break;
+               if (xhci->usb2_rhub.num_ports + xhci->usb3_rhub.num_ports ==
+                   num_ports)
+                       break;
                offset = xhci_find_next_ext_cap(base, offset,
                                                XHCI_EXT_CAPS_PROTOCOL);
        }
                xhci_warn(xhci, "No ports on the roothubs?\n");
                return -ENODEV;
        }
+       if (xhci->usb2_rhub.num_ports == 0 && xhci->usb3_rhub.num_ports == 0) {
+               xhci_warn(xhci, "No ports on the roothubs?\n");
+               return -ENODEV;
+       }
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "Found %u USB 2.0 ports and %u USB 3.0 ports.",
                        xhci->num_usb2_ports, xhci->num_usb3_ports);
         * Note we could have all USB 3.0 ports, or all USB 2.0 ports.
         * Not sure how the USB core will handle a hub with no ports...
         */
+
+       xhci_create_rhub_port_array(xhci, &xhci->usb2_rhub, flags);
+       xhci_create_rhub_port_array(xhci, &xhci->usb3_rhub, flags);
+
        if (xhci->num_usb2_ports) {
                xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)*
                                xhci->num_usb2_ports, flags);