|
|
@@ -2064,17 +2064,19 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
|
|
|
}
|
|
|
|
|
|
static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
|
|
|
- __le32 __iomem *addr, u8 major_revision, int max_caps)
|
|
|
+ __le32 __iomem *addr, int max_caps)
|
|
|
{
|
|
|
u32 temp, port_offset, port_count;
|
|
|
int i;
|
|
|
+ u8 major_revision;
|
|
|
struct xhci_hub *rhub;
|
|
|
|
|
|
temp = readl(addr);
|
|
|
+ major_revision = XHCI_EXT_PORT_MAJOR(temp);
|
|
|
|
|
|
- if (XHCI_EXT_PORT_MAJOR(temp) == 0x03) {
|
|
|
+ if (major_revision == 0x03) {
|
|
|
rhub = &xhci->usb3_rhub;
|
|
|
- } else if (XHCI_EXT_PORT_MAJOR(temp) <= 0x02) {
|
|
|
+ } else if (major_revision <= 0x02) {
|
|
|
rhub = &xhci->usb2_rhub;
|
|
|
} else {
|
|
|
xhci_warn(xhci, "Ignoring unknown port speed, "
|
|
|
@@ -2190,19 +2192,12 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
|
|
|
*/
|
|
|
static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
|
|
|
{
|
|
|
- __le32 __iomem *addr, *tmp_addr;
|
|
|
- u32 offset, tmp_offset;
|
|
|
+ void __iomem *base;
|
|
|
+ u32 offset;
|
|
|
unsigned int num_ports;
|
|
|
int i, j, port_index;
|
|
|
int cap_count = 0;
|
|
|
-
|
|
|
- addr = &xhci->cap_regs->hcc_params;
|
|
|
- offset = XHCI_HCC_EXT_CAPS(readl(addr));
|
|
|
- if (offset == 0) {
|
|
|
- xhci_err(xhci, "No Extended Capability registers, "
|
|
|
- "unable to set up roothub.\n");
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
+ u32 cap_start;
|
|
|
|
|
|
num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
|
|
xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags);
|
|
|
@@ -2220,48 +2215,34 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
|
|
|
for (j = 0; j < XHCI_MAX_INTERVAL; j++)
|
|
|
INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints);
|
|
|
}
|
|
|
+ base = &xhci->cap_regs->hc_capbase;
|
|
|
|
|
|
- /*
|
|
|
- * For whatever reason, the first capability offset is from the
|
|
|
- * capability register base, not from the HCCPARAMS register.
|
|
|
- * See section 5.3.6 for offset calculation.
|
|
|
- */
|
|
|
- addr = &xhci->cap_regs->hc_capbase + offset;
|
|
|
-
|
|
|
- tmp_addr = addr;
|
|
|
- tmp_offset = offset;
|
|
|
+ cap_start = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_PROTOCOL);
|
|
|
+ if (!cap_start) {
|
|
|
+ xhci_err(xhci, "No Extended Capability registers, unable to set up roothub\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
|
|
|
+ offset = cap_start;
|
|
|
/* count extended protocol capability entries for later caching */
|
|
|
- do {
|
|
|
- u32 cap_id;
|
|
|
- cap_id = readl(tmp_addr);
|
|
|
- if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)
|
|
|
- cap_count++;
|
|
|
- tmp_offset = XHCI_EXT_CAPS_NEXT(cap_id);
|
|
|
- tmp_addr += tmp_offset;
|
|
|
- } while (tmp_offset);
|
|
|
+ while (offset) {
|
|
|
+ cap_count++;
|
|
|
+ offset = xhci_find_next_ext_cap(base, offset,
|
|
|
+ XHCI_EXT_CAPS_PROTOCOL);
|
|
|
+ }
|
|
|
|
|
|
xhci->ext_caps = kzalloc(sizeof(*xhci->ext_caps) * cap_count, flags);
|
|
|
if (!xhci->ext_caps)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- while (1) {
|
|
|
- u32 cap_id;
|
|
|
-
|
|
|
- cap_id = readl(addr);
|
|
|
- if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)
|
|
|
- xhci_add_in_port(xhci, num_ports, addr,
|
|
|
- (u8) XHCI_EXT_PORT_MAJOR(cap_id),
|
|
|
- cap_count);
|
|
|
- offset = XHCI_EXT_CAPS_NEXT(cap_id);
|
|
|
- if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports)
|
|
|
- == num_ports)
|
|
|
+ offset = cap_start;
|
|
|
+
|
|
|
+ while (offset) {
|
|
|
+ xhci_add_in_port(xhci, num_ports, base + offset, cap_count);
|
|
|
+ if (xhci->num_usb2_ports + xhci->num_usb3_ports == num_ports)
|
|
|
break;
|
|
|
- /*
|
|
|
- * Once you're into the Extended Capabilities, the offset is
|
|
|
- * always relative to the register holding the offset.
|
|
|
- */
|
|
|
- addr += offset;
|
|
|
+ offset = xhci_find_next_ext_cap(base, offset,
|
|
|
+ XHCI_EXT_CAPS_PROTOCOL);
|
|
|
}
|
|
|
|
|
|
if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) {
|