From patchwork Mon May 21 13:39:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathias Nyman X-Patchwork-Id: 10415349 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 6C5B66032C for ; Mon, 21 May 2018 13:38:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5D25826E46 for ; Mon, 21 May 2018 13:38:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5232227968; Mon, 21 May 2018 13:38:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B3AB326E46 for ; Mon, 21 May 2018 13:38:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751574AbeEUNhw (ORCPT ); Mon, 21 May 2018 09:37:52 -0400 Received: from mga05.intel.com ([192.55.52.43]:64081 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751286AbeEUNhu (ORCPT ); Mon, 21 May 2018 09:37:50 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 21 May 2018 06:37:50 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,426,1520924400"; d="scan'208";a="40976818" Received: from mattu-haswell.fi.intel.com ([10.237.72.164]) by fmsmga007.fm.intel.com with ESMTP; 21 May 2018 06:37:49 -0700 From: Mathias Nyman To: Cc: , Mathias Nyman Subject: [PATCH 04/18] xhci: Create new structures to store xhci port information Date: Mon, 21 May 2018 16:39:52 +0300 Message-Id: <1526910006-26104-5-git-send-email-mathias.nyman@linux.intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1526910006-26104-1-git-send-email-mathias.nyman@linux.intel.com> References: <1526910006-26104-1-git-send-email-mathias.nyman@linux.intel.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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 e5ace89..8819286 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 6dfc486..38aa8a6 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1683,13 +1683,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 */ @@ -1838,6 +1848,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;