| From 7ac4a0bd38eaceca547d7cb24ca59d82eca7a225 Mon Sep 17 00:00:00 2001 |
| From: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Date: Mon, 21 May 2018 16:39:52 +0300 |
| Subject: [PATCH 1440/1795] xhci: Create new structures to store xhci port |
| information |
| |
| Current way of having one array telling only the port speed, |
| and then two separate arrays with mmio addresses for usb2 and usb3 ports |
| requeres helper functions to transate hw to hcd, and hcd to hw port |
| numbers, and is hard to expand. |
| |
| Instead create a structure describing a port, including the mmio address, |
| the port hardware index, hcd port index, and a pointer to the roothub |
| it belongs to. |
| |
| Create one array containing all port structures in the same order the |
| hardware controller sees them. Then add an array of port pointers to |
| each xhci hub structure pointing to the ports that belonging to the |
| roothub. |
| |
| This way we can easily convert hw indexed port events to usb core |
| hcd port numbers, and vice versa usb core hub hcd port numbers |
| to hw index and mmio address. |
| |
| Other benefit is that we can easily find the parent hcd and xhci |
| structure of a port structure. This is useful in debugfs where |
| we can give one port structure pointer as parameter and get both |
| the correct mmio address and xhci lock needed to set some port |
| parameter. |
| |
| Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| (cherry picked from commit bcaa9d5c59005eceed5f2112c13240401f0fb93b) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| --- |
| drivers/usb/host/xhci-mem.c | 58 ++++++++++++++++++++++++++++++++++++- |
| drivers/usb/host/xhci.h | 21 ++++++++++---- |
| 2 files changed, 73 insertions(+), 6 deletions(-) |
| |
| diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c |
| index 0b424a4b58ec..76ec1cfb746b 100644 |
| --- a/drivers/usb/host/xhci-mem.c |
| +++ b/drivers/usb/host/xhci-mem.c |
| @@ -1892,16 +1892,24 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) |
| 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; |
| |
| @@ -2186,8 +2194,10 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, |
| |
| 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, " |
| @@ -2205,9 +2215,16 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, |
| 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 |
| @@ -2216,6 +2233,27 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, |
| /* 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 |
| @@ -2234,9 +2272,16 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) |
| |
| 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; |
| @@ -2274,6 +2319,9 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) |
| 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); |
| } |
| @@ -2282,6 +2330,10 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) |
| 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); |
| @@ -2306,6 +2358,10 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) |
| * 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); |
| diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h |
| index 9751c1373fbb..2ec0ca2cd87f 100644 |
| --- a/drivers/usb/host/xhci.h |
| +++ b/drivers/usb/host/xhci.h |
| @@ -1687,13 +1687,23 @@ static inline unsigned int hcd_index(struct usb_hcd *hcd) |
| else |
| return 1; |
| } |
| +struct xhci_port { |
| + __le32 __iomem *addr; |
| + int hw_portnum; |
| + int hcd_portnum; |
| + struct xhci_hub *rhub; |
| +}; |
| |
| struct xhci_hub { |
| - u8 maj_rev; |
| - u8 min_rev; |
| - u32 *psi; /* array of protocol speed ID entries */ |
| - u8 psi_count; |
| - u8 psi_uid_count; |
| + struct xhci_port **ports; |
| + unsigned int num_ports; |
| + struct usb_hcd *hcd; |
| + /* supported prococol extended capabiliy values */ |
| + u8 maj_rev; |
| + u8 min_rev; |
| + u32 *psi; /* array of protocol speed ID entries */ |
| + u8 psi_count; |
| + u8 psi_uid_count; |
| }; |
| |
| /* There is one xhci_hcd structure per controller */ |
| @@ -1842,6 +1852,7 @@ struct xhci_hcd { |
| struct xhci_bus_state bus_state[2]; |
| /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */ |
| u8 *port_array; |
| + struct xhci_port *hw_ports; |
| /* Array of pointers to USB 3.0 PORTSC registers */ |
| __le32 __iomem **usb3_ports; |
| unsigned int num_usb3_ports; |
| -- |
| 2.19.0 |
| |