[SRU] [Bionic] [OEM-B] [PATCH 00/16] Fix "xHCI host controller not responding, assume dead"

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
22 messages Options
12
Reply | Threaded
Open this post in threaded view
|

[SRU] [Bionic] [OEM-B] [PATCH 00/16] Fix "xHCI host controller not responding, assume dead"

Kai-Heng Feng
BugLink: https://bugs.launchpad.net/bugs/1763594

[Impact]
xHC stops to work after some time. This happens when the xHC gets
runtime resumed/suspended constantly.

[Test]
User reports this backport fixes the issue.

[Fix]
In addition to check EINT, also check ports' status.

[Regression Potential]
Low. It fixes a known bug and it's in -stable.

Mathias Nyman (16):
  xhci: Create new structures to store xhci port information
  xhci: set hcd pointers for xhci usb2 and usb3 roothub structures
  xhci: Add helper to get xhci roothub from hcd
  xhci: xhci-hub: use new port structures to get port address instead of
    port array
  xhci: xhci-hub: use new port structures for cas and wake mask
    functions.
  xhci: xhci-ring: use port structures for port event handler
  xhci: rename faked_port_index to hcd_portnum
  xhci: change xhci_set_link_state() to work with port structures
  xhci: change xhci_test_and_clear_bit() to use new port structure
  xhci: use port structures instead of port arrays in xhci.c functions
  xhci: xhci-hub: use port structure members instead of xhci_get_ports()
  xhci-mtk: use xhci hub structures to get number of ports in roothubs
  xhci: xhci-mem: remove port_arrays and the code initializing them
  xhci: debugfs: add usb ports to xhci debugfs
  xhci: debugfs: add debugfs interface to enable compliance mode for a
    port
  xhci: Fix perceived dead host due to runtime suspend race with event
    handler

 drivers/usb/host/xhci-debugfs.c |  85 +++++++++++
 drivers/usb/host/xhci-hub.c     | 244 ++++++++++++++++----------------
 drivers/usb/host/xhci-mem.c     | 140 ++++++++----------
 drivers/usb/host/xhci-mtk-sch.c |   4 +-
 drivers/usb/host/xhci-ring.c    | 126 ++++-------------
 drivers/usb/host/xhci.c         |  93 ++++++++----
 drivers/usb/host/xhci.h         |  43 +++---
 7 files changed, 381 insertions(+), 354 deletions(-)

--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 01/16] xhci: Create new structures to store xhci port information

Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

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 <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit bcaa9d5c59005eceed5f2112c13240401f0fb93b)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 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 ee980c3dec54..dbe36cbbf3af 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1886,16 +1886,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;
 
@@ -2180,8 +2188,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, "
@@ -2199,9 +2209,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
@@ -2210,6 +2227,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
@@ -2228,9 +2266,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;
@@ -2268,6 +2313,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);
  }
@@ -2276,6 +2324,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);
@@ -2300,6 +2352,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 5fe51e59bdb2..faacd9bbc1ed 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1681,13 +1681,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 */
@@ -1832,6 +1842,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.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 02/16] xhci: set hcd pointers for xhci usb2 and usb3 roothub structures

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

Allows us to know the correct hcd a xhci roothub and its ports
belong to.

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(backported from commit 9ea95ecc7ffd338a62972ddd6b0ac46bdc5e7d49)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index d5dee03c2ce9..61f2eb9f0217 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4800,6 +4800,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 
  if (usb_hcd_is_primary_hcd(hcd)) {
  xhci->main_hcd = hcd;
+ xhci->usb2_rhub.hcd = hcd;
  /* Mark the first roothub as being USB 2.0.
  * The xHCI driver will register the USB 3.0 roothub.
  */
@@ -4818,6 +4819,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
  hcd->speed = HCD_USB31;
  hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
  }
+
+ xhci->usb3_rhub.hcd = hcd;
  /* xHCI private pointer was set in xhci_pci_probe for the second
  * registered roothub.
  */
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 03/16] xhci: Add helper to get xhci roothub from hcd

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

quick way to get the xhci roothub and thus all the ports
belonging to a certain hcd

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit ffd4b4fc0b9a1526b64240676d309506b2d5eceb)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-hub.c | 9 +++++++++
 drivers/usb/host/xhci.h     | 2 ++
 2 files changed, 11 insertions(+)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 2a90229be7a6..119f594d1d27 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -555,6 +555,15 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
  return max_ports;
 }
 
+struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ if (hcd->speed >= HCD_USB3)
+ return &xhci->usb3_rhub;
+ return &xhci->usb2_rhub;
+}
+
 static __le32 __iomem *xhci_get_port_io_addr(struct usb_hcd *hcd, int index)
 {
  __le32 __iomem **port_array;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index faacd9bbc1ed..59c7ff346d9b 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -2108,6 +2108,8 @@ 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);
+struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
+
 void xhci_hc_died(struct xhci_hcd *xhci);
 
 #ifdef CONFIG_PM
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 04/16] xhci: xhci-hub: use new port structures to get port address instead of port array

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

Use the new port structures for functions in xhci-hub.c to get
port mmio address of portsc register instead of the port array

xhci_get_port_io_addr() is no longer needeed and is removed.
Plan is to get rid of the mmio port array completely.

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit e740b019d7c6b4de38f57a26d4cf1b15125bdcbf)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-hub.c | 140 ++++++++++++++++++++----------------
 1 file changed, 78 insertions(+), 62 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 119f594d1d27..557c16b81b58 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -189,9 +189,10 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
  __u8 port_removable[(USB_MAXCHILDREN + 1 + 7) / 8];
  u32 portsc;
  unsigned int i;
+ struct xhci_hub *rhub;
 
- ports = xhci->num_usb2_ports;
-
+ rhub = &xhci->usb2_rhub;
+ ports = rhub->num_ports;
  xhci_common_hub_descriptor(xhci, desc, ports);
  desc->bDescriptorType = USB_DT_HUB;
  temp = 1 + (ports / 8);
@@ -202,7 +203,7 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
  */
  memset(port_removable, 0, sizeof(port_removable));
  for (i = 0; i < ports; i++) {
- portsc = readl(xhci->usb2_ports[i]);
+ portsc = readl(rhub->ports[i]->addr);
  /* If a device is removable, PORTSC reports a 0, same as in the
  * hub descriptor DeviceRemovable bits.
  */
@@ -241,8 +242,10 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
  u16 port_removable;
  u32 portsc;
  unsigned int i;
+ struct xhci_hub *rhub;
 
- ports = xhci->num_usb3_ports;
+ rhub = &xhci->usb3_rhub;
+ ports = rhub->num_ports;
  xhci_common_hub_descriptor(xhci, desc, ports);
  desc->bDescriptorType = USB_DT_SS_HUB;
  desc->bDescLength = USB_DT_SS_HUB_SIZE;
@@ -256,7 +259,7 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
  port_removable = 0;
  /* bit 0 is reserved, bit 1 is for port 1, etc. */
  for (i = 0; i < ports; i++) {
- portsc = readl(xhci->usb3_ports[i]);
+ portsc = readl(rhub->ports[i]->addr);
  if (portsc & PORT_DEV_REMOVE)
  port_removable |= 1 << (i + 1);
  }
@@ -564,14 +567,6 @@ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd)
  return &xhci->usb2_rhub;
 }
 
-static __le32 __iomem *xhci_get_port_io_addr(struct usb_hcd *hcd, int index)
-{
- __le32 __iomem **port_array;
-
- xhci_get_ports(hcd, &port_array);
- return port_array[index];
-}
-
 /*
  * xhci_set_port_power() must be called with xhci->lock held.
  * It will release and re-aquire the lock while calling ACPI
@@ -580,21 +575,23 @@ static __le32 __iomem *xhci_get_port_io_addr(struct usb_hcd *hcd, int index)
 static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
  u16 index, bool on, unsigned long *flags)
 {
- __le32 __iomem *addr;
+ struct xhci_hub *rhub;
+ struct xhci_port *port;
  u32 temp;
 
- addr = xhci_get_port_io_addr(hcd, index);
- temp = readl(addr);
+ rhub = xhci_get_rhub(hcd);
+ port = rhub->ports[index];
+ temp = readl(port->addr);
  temp = xhci_port_state_to_neutral(temp);
  if (on) {
  /* Power on */
- writel(temp | PORT_POWER, addr);
- temp = readl(addr);
+ writel(temp | PORT_POWER, port->addr);
+ temp = readl(port->addr);
  xhci_dbg(xhci, "set port power, actual port %d status  = 0x%x\n",
  index, temp);
  } else {
  /* Power off */
- writel(temp & ~PORT_POWER, addr);
+ writel(temp & ~PORT_POWER, port->addr);
  }
 
  spin_unlock_irqrestore(&xhci->lock, *flags);
@@ -610,13 +607,13 @@ static void xhci_port_set_test_mode(struct xhci_hcd *xhci,
  u16 test_mode, u16 wIndex)
 {
  u32 temp;
- __le32 __iomem *addr;
+ struct xhci_port *port;
 
- /* xhci only supports test mode for usb2 ports, i.e. xhci->main_hcd */
- addr = xhci_get_port_io_addr(xhci->main_hcd, wIndex);
- temp = readl(addr + PORTPMSC);
+ /* xhci only supports test mode for usb2 ports */
+ port = xhci->usb2_rhub.ports[wIndex];
+ temp = readl(port->addr + PORTPMSC);
  temp |= test_mode << PORT_TEST_MODE_SHIFT;
- writel(temp, addr + PORTPMSC);
+ writel(temp, port->addr + PORTPMSC);
  xhci->test_mode = test_mode;
  if (test_mode == TEST_FORCE_EN)
  xhci_start(xhci);
@@ -643,10 +640,10 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
  /* Put all ports to the Disable state by clear PP */
  xhci_dbg(xhci, "Disable all port (PP = 0)\n");
  /* Power off USB3 ports*/
- for (i = 0; i < xhci->num_usb3_ports; i++)
+ for (i = 0; i < xhci->usb3_rhub.num_ports; i++)
  xhci_set_port_power(xhci, xhci->shared_hcd, i, false, flags);
  /* Power off USB2 ports*/
- for (i = 0; i < xhci->num_usb2_ports; i++)
+ for (i = 0; i < xhci->usb2_rhub.num_ports; i++)
  xhci_set_port_power(xhci, xhci->main_hcd, i, false, flags);
  /* Stop the controller */
  xhci_dbg(xhci, "Stop controller\n");
@@ -804,7 +801,7 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
 static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status,
     u16 wIndex)
 {
- u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1);
+ u32 all_ports_seen_u0 = ((1 << xhci->usb3_rhub.num_ports) - 1);
  bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0);
 
  if (!(xhci->quirks & XHCI_COMP_MODE_QUIRK))
@@ -859,6 +856,11 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
  struct xhci_hcd *xhci = hcd_to_xhci(hcd);
  u32 status = 0;
  int slot_id;
+ struct xhci_hub *rhub;
+ struct xhci_port *port;
+
+ rhub = xhci_get_rhub(hcd);
+ port = rhub->ports[wIndex];
 
  /* wPortChange bits */
  if (raw_port_status & PORT_CSC)
@@ -950,7 +952,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
  }
  xhci_ring_device(xhci, slot_id);
  } else {
- int port_status = readl(port_array[wIndex]);
+ int port_status = readl(port->addr);
  xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n",
  XHCI_MAX_REXIT_TIMEOUT,
  port_status);
@@ -1041,7 +1043,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  u16 wake_mask = 0;
  u16 timeout = 0;
  u16 test_mode = 0;
+ struct xhci_hub *rhub;
+ struct xhci_port **ports;
 
+ rhub = xhci_get_rhub(hcd);
+ ports = rhub->ports;
  max_ports = xhci_get_ports(hcd, &port_array);
  bus_state = &xhci->bus_state[hcd_index(hcd)];
 
@@ -1080,7 +1086,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  if (!wIndex || wIndex > max_ports)
  goto error;
  wIndex--;
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  if (temp == ~(u32)0) {
  xhci_hc_died(xhci);
  retval = -ENODEV;
@@ -1105,7 +1111,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  retval = -EINVAL;
  break;
  }
- port_li = readl(port_array[wIndex] + PORTLI);
+ port_li = readl(ports[wIndex]->addr + PORTLI);
  status = xhci_get_ext_port_status(temp, port_li);
  put_unaligned_le32(cpu_to_le32(status), &buf[4]);
  }
@@ -1123,7 +1129,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  if (!wIndex || wIndex > max_ports)
  goto error;
  wIndex--;
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  if (temp == ~(u32)0) {
  xhci_hc_died(xhci);
  retval = -ENODEV;
@@ -1133,7 +1139,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  /* FIXME: What new port features do we need to support? */
  switch (wValue) {
  case USB_PORT_FEAT_SUSPEND:
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  if ((temp & PORT_PLS_MASK) != XDEV_U0) {
  /* Resume the port to U0 first */
  xhci_set_link_state(xhci, port_array, wIndex,
@@ -1146,7 +1152,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  * a port unless the port reports that it is in the
  * enabled (PED = ‘1’,PLS < ‘3’) state.
  */
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
  || (temp & PORT_PLS_MASK) >= XDEV_U3) {
  xhci_warn(xhci, "USB core suspending device not in U0/U1/U2.\n");
@@ -1170,12 +1176,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  msleep(10); /* wait device to enter */
  spin_lock_irqsave(&xhci->lock, flags);
 
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  bus_state->suspended_ports |= 1 << wIndex;
  break;
  case USB_PORT_FEAT_LINK_STATE:
- temp = readl(port_array[wIndex]);
-
+ temp = readl(ports[wIndex]->addr);
  /* Disable port */
  if (link_state == USB_SS_PORT_LS_SS_DISABLED) {
  xhci_dbg(xhci, "Disable port %d\n", wIndex);
@@ -1187,8 +1192,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  temp |= PORT_CSC | PORT_PEC | PORT_WRC |
  PORT_OCC | PORT_RC | PORT_PLC |
  PORT_CEC;
- writel(temp | PORT_PE, port_array[wIndex]);
- temp = readl(port_array[wIndex]);
+ writel(temp | PORT_PE, ports[wIndex]->addr);
+ temp = readl(ports[wIndex]->addr);
  break;
  }
 
@@ -1197,7 +1202,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  xhci_dbg(xhci, "Enable port %d\n", wIndex);
  xhci_set_link_state(xhci, port_array, wIndex,
  link_state);
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  break;
  }
 
@@ -1230,7 +1235,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  wIndex);
  xhci_set_link_state(xhci, port_array, wIndex,
  link_state);
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  break;
  }
 
@@ -1264,7 +1269,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  msleep(20); /* wait device to enter */
  spin_lock_irqsave(&xhci->lock, flags);
 
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  if (link_state == USB_SS_PORT_LS_U3)
  bus_state->suspended_ports |= 1 << wIndex;
  break;
@@ -1279,40 +1284,39 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  break;
  case USB_PORT_FEAT_RESET:
  temp = (temp | PORT_RESET);
- writel(temp, port_array[wIndex]);
+ writel(temp, ports[wIndex]->addr);
 
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  xhci_dbg(xhci, "set port reset, actual port %d status  = 0x%x\n", wIndex, temp);
  break;
  case USB_PORT_FEAT_REMOTE_WAKE_MASK:
  xhci_set_remote_wake_mask(xhci, port_array,
  wIndex, wake_mask);
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  xhci_dbg(xhci, "set port remote wake mask, "
  "actual port %d status  = 0x%x\n",
  wIndex, temp);
  break;
  case USB_PORT_FEAT_BH_PORT_RESET:
  temp |= PORT_WR;
- writel(temp, port_array[wIndex]);
-
- temp = readl(port_array[wIndex]);
+ writel(temp, ports[wIndex]->addr);
+ temp = readl(ports[wIndex]->addr);
  break;
  case USB_PORT_FEAT_U1_TIMEOUT:
  if (hcd->speed < HCD_USB3)
  goto error;
- temp = readl(port_array[wIndex] + PORTPMSC);
+ temp = readl(ports[wIndex]->addr + PORTPMSC);
  temp &= ~PORT_U1_TIMEOUT_MASK;
  temp |= PORT_U1_TIMEOUT(timeout);
- writel(temp, port_array[wIndex] + PORTPMSC);
+ writel(temp, ports[wIndex]->addr + PORTPMSC);
  break;
  case USB_PORT_FEAT_U2_TIMEOUT:
  if (hcd->speed < HCD_USB3)
  goto error;
- temp = readl(port_array[wIndex] + PORTPMSC);
+ temp = readl(ports[wIndex]->addr + PORTPMSC);
  temp &= ~PORT_U2_TIMEOUT_MASK;
  temp |= PORT_U2_TIMEOUT(timeout);
- writel(temp, port_array[wIndex] + PORTPMSC);
+ writel(temp, ports[wIndex]->addr + PORTPMSC);
  break;
  case USB_PORT_FEAT_TEST:
  /* 4.19.6 Port Test Modes (USB2 Test Mode) */
@@ -1327,13 +1331,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  goto error;
  }
  /* unblock any posted writes */
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  break;
  case ClearPortFeature:
  if (!wIndex || wIndex > max_ports)
  goto error;
  wIndex--;
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  if (temp == ~(u32)0) {
  xhci_hc_died(xhci);
  retval = -ENODEV;
@@ -1343,7 +1347,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  temp = xhci_port_state_to_neutral(temp);
  switch (wValue) {
  case USB_PORT_FEAT_SUSPEND:
- temp = readl(port_array[wIndex]);
+ temp = readl(ports[wIndex]->addr);
  xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
  xhci_dbg(xhci, "PORTSC %04x\n", temp);
  if (temp & PORT_RESET)
@@ -1383,11 +1387,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  case USB_PORT_FEAT_C_PORT_LINK_STATE:
  case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
  xhci_clear_port_change_bit(xhci, wValue, wIndex,
- port_array[wIndex], temp);
+ ports[wIndex]->addr, temp);
  break;
  case USB_PORT_FEAT_ENABLE:
  xhci_disable_port(hcd, xhci, wIndex,
- port_array[wIndex], temp);
+ ports[wIndex]->addr, temp);
  break;
  case USB_PORT_FEAT_POWER:
  xhci_set_port_power(xhci, hcd, wIndex, false, &flags);
@@ -1427,7 +1431,11 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
  __le32 __iomem **port_array;
  struct xhci_bus_state *bus_state;
  bool reset_change = false;
+ struct xhci_hub *rhub;
+ struct xhci_port **ports;
 
+ rhub = xhci_get_rhub(hcd);
+ ports = rhub->ports;
  max_ports = xhci_get_ports(hcd, &port_array);
  bus_state = &xhci->bus_state[hcd_index(hcd)];
 
@@ -1446,7 +1454,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
  spin_lock_irqsave(&xhci->lock, flags);
  /* For each port, did anything change?  If so, set that bit in buf. */
  for (i = 0; i < max_ports; i++) {
- temp = readl(port_array[i]);
+ temp = readl(ports[i]->addr);
  if (temp == ~(u32)0) {
  xhci_hc_died(xhci);
  retval = -ENODEV;
@@ -1479,7 +1487,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
  __le32 __iomem **port_array;
  struct xhci_bus_state *bus_state;
  unsigned long flags;
+ struct xhci_hub *rhub;
+ struct xhci_port **ports;
 
+ rhub = xhci_get_rhub(hcd);
+ ports = rhub->ports;
  max_ports = xhci_get_ports(hcd, &port_array);
  bus_state = &xhci->bus_state[hcd_index(hcd)];
 
@@ -1501,7 +1513,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
  u32 t1, t2;
  int slot_id;
 
- t1 = readl(port_array[port_index]);
+ t1 = readl(ports[port_index]->addr);
  t2 = xhci_port_state_to_neutral(t1);
 
  if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) {
@@ -1534,7 +1546,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
 
  t1 = xhci_port_state_to_neutral(t1);
  if (t1 != t2)
- writel(t2, port_array[port_index]);
+ writel(t2, ports[port_index]->addr);
  }
  hcd->state = HC_STATE_SUSPENDED;
  bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
@@ -1582,7 +1594,11 @@ int xhci_bus_resume(struct usb_hcd *hcd)
  int sret;
  u32 next_state;
  u32 temp, portsc;
+ struct xhci_hub *rhub;
+ struct xhci_port **ports;
 
+ rhub = xhci_get_rhub(hcd);
+ ports = rhub->ports;
  max_ports = xhci_get_ports(hcd, &port_array);
  bus_state = &xhci->bus_state[hcd_index(hcd)];
 
@@ -1608,7 +1624,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
 
  port_index = max_ports;
  while (port_index--) {
- portsc = readl(port_array[port_index]);
+ portsc = readl(ports[port_index]->addr);
 
  /* warm reset CAS limited ports stuck in polling/compliance */
  if ((xhci->quirks & XHCI_MISSING_CAS) &&
@@ -1637,7 +1653,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
  }
  /* disable wake for all ports, write new link state if needed */
  portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
- writel(portsc, port_array[port_index]);
+ writel(portsc, ports[port_index]->addr);
  }
 
  /* USB2 specific resume signaling delay and U0 link state transition */
@@ -1659,7 +1675,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
 
  /* poll for U0 link state complete, both USB2 and USB3 */
  for_each_set_bit(port_index, &bus_state->bus_suspended, BITS_PER_LONG) {
- sret = xhci_handshake(port_array[port_index], PORT_PLC,
+ sret = xhci_handshake(ports[port_index]->addr, PORT_PLC,
       PORT_PLC, 10 * 1000);
  if (sret) {
  xhci_warn(xhci, "port %d resume PLC timeout\n",
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 05/16] xhci: xhci-hub: use new port structures for cas and wake mask functions.

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

Use port structures instead of mmio port arrays for
xhci_port_missing_cas_quirk() and xhci_set_remote_wake_mask() in
xhci-hub.c

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit fdcf74ffef640fd30402863877d442c8bada7582)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-hub.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 557c16b81b58..e0f45be1acea 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -692,11 +692,11 @@ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
 }
 
 static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
- __le32 __iomem **port_array, int port_id, u16 wake_mask)
+      struct xhci_port *port, u16 wake_mask)
 {
  u32 temp;
 
- temp = readl(port_array[port_id]);
+ temp = readl(port->addr);
  temp = xhci_port_state_to_neutral(temp);
 
  if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT)
@@ -714,7 +714,7 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
  else
  temp &= ~PORT_WKOC_E;
 
- writel(temp, port_array[port_id]);
+ writel(temp, port->addr);
 }
 
 /* Test and clear port RWC bit */
@@ -1290,8 +1290,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  xhci_dbg(xhci, "set port reset, actual port %d status  = 0x%x\n", wIndex, temp);
  break;
  case USB_PORT_FEAT_REMOTE_WAKE_MASK:
- xhci_set_remote_wake_mask(xhci, port_array,
- wIndex, wake_mask);
+ xhci_set_remote_wake_mask(xhci, ports[wIndex],
+  wake_mask);
  temp = readl(ports[wIndex]->addr);
  xhci_dbg(xhci, "set port remote wake mask, "
  "actual port %d status  = 0x%x\n",
@@ -1559,12 +1559,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
  * warm reset a USB3 device stuck in polling or compliance mode after resume.
  * See Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8
  */
-static bool xhci_port_missing_cas_quirk(int port_index,
-     __le32 __iomem **port_array)
+static bool xhci_port_missing_cas_quirk(struct xhci_port *port)
 {
  u32 portsc;
 
- portsc = readl(port_array[port_index]);
+ portsc = readl(port->addr);
 
  /* if any of these are set we are not stuck */
  if (portsc & (PORT_CONNECT | PORT_CAS))
@@ -1577,9 +1576,9 @@ static bool xhci_port_missing_cas_quirk(int port_index,
  /* clear wakeup/change bits, and do a warm port reset */
  portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
  portsc |= PORT_WR;
- writel(portsc, port_array[port_index]);
+ writel(portsc, port->addr);
  /* flush write */
- readl(port_array[port_index]);
+ readl(port->addr);
  return true;
 }
 
@@ -1629,7 +1628,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
  /* warm reset CAS limited ports stuck in polling/compliance */
  if ((xhci->quirks & XHCI_MISSING_CAS) &&
     (hcd->speed >= HCD_USB3) &&
-    xhci_port_missing_cas_quirk(port_index, port_array)) {
+    xhci_port_missing_cas_quirk(ports[port_index])) {
  xhci_dbg(xhci, "reset stuck port %d\n", port_index);
  clear_bit(port_index, &bus_state->bus_suspended);
  continue;
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 06/16] xhci: xhci-ring: use port structures for port event handler

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

use port structures in the port event handler.
Getting the right hcd and hcd portnumber from the hardware port number
is a lot easier with port structures, and allows us to remove a lot
of the previous code, including the find_faked_portnum_from_hw_index()
function

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit 52c7755ba19ee2ae97fe5bfea7627bb27d5d7602)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-ring.c | 79 ++++--------------------------------
 1 file changed, 8 insertions(+), 71 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 43409ae24ac4..6b8cccef239b 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1496,44 +1496,6 @@ static void handle_vendor_event(struct xhci_hcd *xhci,
  handle_cmd_completion(xhci, &event->event_cmd);
 }
 
-/* @port_id: the one-based port ID from the hardware (indexed from array of all
- * port registers -- USB 3.0 and USB 2.0).
- *
- * Returns a zero-based port number, which is suitable for indexing into each of
- * the split roothubs' port arrays and bus state arrays.
- * Add one to it in order to call xhci_find_slot_id_by_port.
- */
-static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
- struct xhci_hcd *xhci, u32 port_id)
-{
- unsigned int i;
- unsigned int num_similar_speed_ports = 0;
-
- /* port_id from the hardware is 1-based, but port_array[], usb3_ports[],
- * and usb2_ports are 0-based indexes.  Count the number of similar
- * speed ports, up to 1 port before this port.
- */
- for (i = 0; i < (port_id - 1); 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) == (hcd->speed >= HCD_USB3))
- num_similar_speed_ports++;
- }
- return num_similar_speed_ports;
-}
-
 static void handle_device_notification(struct xhci_hcd *xhci,
  union xhci_trb *event)
 {
@@ -1563,10 +1525,10 @@ static void handle_port_status(struct xhci_hcd *xhci,
  int max_ports;
  int slot_id;
  unsigned int faked_port_index;
- u8 major_revision;
  struct xhci_bus_state *bus_state;
  __le32 __iomem **port_array;
  bool bogus_port_status = false;
+ struct xhci_port *port;
 
  /* Port status change events always have a successful completion code */
  if (GET_COMP_CODE(le32_to_cpu(event->generic.field[2])) != COMP_SUCCESS)
@@ -1583,47 +1545,22 @@ static void handle_port_status(struct xhci_hcd *xhci,
  return;
  }
 
- /* Figure out which usb_hcd this port is attached to:
- * is it a USB 3.0 port or a USB 2.0/1.1 port?
- */
- major_revision = xhci->port_array[port_id - 1];
-
- /* Find the right roothub. */
- hcd = xhci_to_hcd(xhci);
- if ((major_revision == 0x03) != (hcd->speed >= HCD_USB3))
- hcd = xhci->shared_hcd;
-
- if (major_revision == 0) {
- xhci_warn(xhci, "Event for port %u not in "
- "Extended Capabilities, ignoring.\n",
- port_id);
- bogus_port_status = true;
- goto cleanup;
- }
- if (major_revision == DUPLICATE_ENTRY) {
- xhci_warn(xhci, "Event for port %u duplicated in"
- "Extended Capabilities, ignoring.\n",
- port_id);
+ port = &xhci->hw_ports[port_id - 1];
+ if (!port || !port->rhub || port->hcd_portnum == DUPLICATE_ENTRY) {
+ xhci_warn(xhci, "Event for invalid port %u\n", port_id);
  bogus_port_status = true;
  goto cleanup;
  }
 
- /*
- * Hardware port IDs reported by a Port Status Change Event include USB
- * 3.0 and USB 2.0 ports.  We want to check if the port has reported a
- * resume event, but we first need to translate the hardware port ID
- * into the index into the ports on the correct split roothub, and the
- * correct bus_state structure.
- */
+ hcd = port->rhub->hcd;
  bus_state = &xhci->bus_state[hcd_index(hcd)];
  if (hcd->speed >= HCD_USB3)
  port_array = xhci->usb3_ports;
  else
  port_array = xhci->usb2_ports;
- /* Find the faked port hub number */
- faked_port_index = find_faked_portnum_from_hw_portnum(hcd, xhci,
- port_id);
- portsc = readl(port_array[faked_port_index]);
+
+ faked_port_index = port->hcd_portnum;
+ portsc = readl(port->addr);
 
  trace_xhci_handle_port_status(faked_port_index, portsc);
 
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 07/16] xhci: rename faked_port_index to hcd_portnum

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

hcd_portnum is a better desctiption than faked_port_index, and
is in line with the name the port structure uses.

No functional changes

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit 74e6ad583aa34a8de3ab3bc209256c3b53a1af4b)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-ring.c | 41 +++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 6b8cccef239b..3d58780fc6c3 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1524,7 +1524,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
  u32 portsc, cmd_reg;
  int max_ports;
  int slot_id;
- unsigned int faked_port_index;
+ unsigned int hcd_portnum;
  struct xhci_bus_state *bus_state;
  __le32 __iomem **port_array;
  bool bogus_port_status = false;
@@ -1559,10 +1559,10 @@ static void handle_port_status(struct xhci_hcd *xhci,
  else
  port_array = xhci->usb2_ports;
 
- faked_port_index = port->hcd_portnum;
+ hcd_portnum = port->hcd_portnum;
  portsc = readl(port->addr);
 
- trace_xhci_handle_port_status(faked_port_index, portsc);
+ trace_xhci_handle_port_status(hcd_portnum, portsc);
 
  if (hcd->state == HC_STATE_SUSPENDED) {
  xhci_dbg(xhci, "resume root hub\n");
@@ -1570,7 +1570,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
  }
 
  if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE)
- bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
+ bus_state->port_remote_wakeup &= ~(1 << hcd_portnum);
 
  if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
  xhci_dbg(xhci, "port resume event for port %d\n", port_id);
@@ -1587,29 +1587,28 @@ static void handle_port_status(struct xhci_hcd *xhci,
  * so we can tell the difference between the end of
  * device and host initiated resume.
  */
- bus_state->port_remote_wakeup |= 1 << faked_port_index;
+ bus_state->port_remote_wakeup |= 1 << hcd_portnum;
  xhci_test_and_clear_bit(xhci, port_array,
- faked_port_index, PORT_PLC);
- xhci_set_link_state(xhci, port_array, faked_port_index,
+ hcd_portnum, PORT_PLC);
+ xhci_set_link_state(xhci, port_array, hcd_portnum,
  XDEV_U0);
  /* Need to wait until the next link state change
  * indicates the device is actually in U0.
  */
  bogus_port_status = true;
  goto cleanup;
- } else if (!test_bit(faked_port_index,
-     &bus_state->resuming_ports)) {
+ } else if (!test_bit(hcd_portnum, &bus_state->resuming_ports)) {
  xhci_dbg(xhci, "resume HS port %d\n", port_id);
- bus_state->resume_done[faked_port_index] = jiffies +
+ bus_state->resume_done[hcd_portnum] = jiffies +
  msecs_to_jiffies(USB_RESUME_TIMEOUT);
- set_bit(faked_port_index, &bus_state->resuming_ports);
+ set_bit(hcd_portnum, &bus_state->resuming_ports);
  /* Do the rest in GetPortStatus after resume time delay.
  * Avoid polling roothub status before that so that a
  * usb device auto-resume latency around ~40ms.
  */
  set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
  mod_timer(&hcd->rh_timer,
-  bus_state->resume_done[faked_port_index]);
+  bus_state->resume_done[hcd_portnum]);
  bogus_port_status = true;
  }
  }
@@ -1624,17 +1623,15 @@ static void handle_port_status(struct xhci_hcd *xhci,
  * so the roothub behavior is consistent with external
  * USB 3.0 hub behavior.
  */
- slot_id = xhci_find_slot_id_by_port(hcd, xhci,
- faked_port_index + 1);
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1);
  if (slot_id && xhci->devs[slot_id])
  xhci_ring_device(xhci, slot_id);
- if (bus_state->port_remote_wakeup & (1 << faked_port_index)) {
- bus_state->port_remote_wakeup &=
- ~(1 << faked_port_index);
+ if (bus_state->port_remote_wakeup & (1 << hcd_portnum)) {
+ bus_state->port_remote_wakeup &= ~(1 << hcd_portnum);
  xhci_test_and_clear_bit(xhci, port_array,
- faked_port_index, PORT_PLC);
+ hcd_portnum, PORT_PLC);
  usb_wakeup_notification(hcd->self.root_hub,
- faked_port_index + 1);
+ hcd_portnum + 1);
  bogus_port_status = true;
  goto cleanup;
  }
@@ -1646,15 +1643,15 @@ static void handle_port_status(struct xhci_hcd *xhci,
  * out of the RExit state.
  */
  if (!DEV_SUPERSPEED_ANY(portsc) &&
- test_and_clear_bit(faked_port_index,
+ test_and_clear_bit(hcd_portnum,
  &bus_state->rexit_ports)) {
- complete(&bus_state->rexit_done[faked_port_index]);
+ complete(&bus_state->rexit_done[hcd_portnum]);
  bogus_port_status = true;
  goto cleanup;
  }
 
  if (hcd->speed < HCD_USB3)
- xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
+ xhci_test_and_clear_bit(xhci, port_array, hcd_portnum,
  PORT_PLC);
 
 cleanup:
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 08/16] xhci: change xhci_set_link_state() to work with port structures

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

Remove old iomem port array and index as parameters, just
send a ponter to a port strucure instread

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit 6b7f40f712344ec8fdca10450834825094e797fb)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-hub.c  | 34 ++++++++++++++++------------------
 drivers/usb/host/xhci-ring.c |  3 +--
 drivers/usb/host/xhci.h      |  4 ++--
 3 files changed, 19 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index e0f45be1acea..00490e4ada68 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -679,16 +679,16 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
  return xhci_reset(xhci);
 }
 
-void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
- int port_id, u32 link_state)
+void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
+ u32 link_state)
 {
  u32 temp;
 
- temp = readl(port_array[port_id]);
+ temp = readl(port->addr);
  temp = xhci_port_state_to_neutral(temp);
  temp &= ~PORT_PLS_MASK;
  temp |= PORT_LINK_STROBE | link_state;
- writel(temp, port_array[port_id]);
+ writel(temp, port->addr);
 }
 
 static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
@@ -933,8 +933,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
 
  xhci_test_and_clear_bit(xhci, port_array, wIndex,
  PORT_PLC);
- xhci_set_link_state(xhci, port_array, wIndex,
- XDEV_U0);
+ xhci_set_link_state(xhci, port, XDEV_U0);
 
  spin_unlock_irqrestore(&xhci->lock, flags);
  time_left = wait_for_completion_timeout(
@@ -1142,7 +1141,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  temp = readl(ports[wIndex]->addr);
  if ((temp & PORT_PLS_MASK) != XDEV_U0) {
  /* Resume the port to U0 first */
- xhci_set_link_state(xhci, port_array, wIndex,
+ xhci_set_link_state(xhci, ports[wIndex],
  XDEV_U0);
  spin_unlock_irqrestore(&xhci->lock, flags);
  msleep(10);
@@ -1170,7 +1169,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  xhci_stop_device(xhci, slot_id, 1);
  spin_lock_irqsave(&xhci->lock, flags);
 
- xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3);
+ xhci_set_link_state(xhci, ports[wIndex], XDEV_U3);
 
  spin_unlock_irqrestore(&xhci->lock, flags);
  msleep(10); /* wait device to enter */
@@ -1200,8 +1199,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  /* Put link in RxDetect (enable port) */
  if (link_state == USB_SS_PORT_LS_RX_DETECT) {
  xhci_dbg(xhci, "Enable port %d\n", wIndex);
- xhci_set_link_state(xhci, port_array, wIndex,
- link_state);
+ xhci_set_link_state(xhci, ports[wIndex],
+ link_state);
  temp = readl(ports[wIndex]->addr);
  break;
  }
@@ -1233,8 +1232,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 
  xhci_dbg(xhci, "Enable compliance mode transition for port %d\n",
  wIndex);
- xhci_set_link_state(xhci, port_array, wIndex,
+ xhci_set_link_state(xhci, ports[wIndex],
  link_state);
+
  temp = readl(ports[wIndex]->addr);
  break;
  }
@@ -1262,8 +1262,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  }
  }
 
- xhci_set_link_state(xhci, port_array, wIndex,
- link_state);
+ xhci_set_link_state(xhci, ports[wIndex], link_state);
 
  spin_unlock_irqrestore(&xhci->lock, flags);
  msleep(20); /* wait device to enter */
@@ -1357,12 +1356,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  goto error;
 
  set_bit(wIndex, &bus_state->resuming_ports);
- xhci_set_link_state(xhci, port_array, wIndex,
- XDEV_RESUME);
+ xhci_set_link_state(xhci, ports[wIndex],
+    XDEV_RESUME);
  spin_unlock_irqrestore(&xhci->lock, flags);
  msleep(USB_RESUME_TIMEOUT);
  spin_lock_irqsave(&xhci->lock, flags);
- xhci_set_link_state(xhci, port_array, wIndex,
+ xhci_set_link_state(xhci, ports[wIndex],
  XDEV_U0);
  clear_bit(wIndex, &bus_state->resuming_ports);
  }
@@ -1667,8 +1666,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
  /* Clear PLC to poll it later for U0 transition */
  xhci_test_and_clear_bit(xhci, port_array, port_index,
  PORT_PLC);
- xhci_set_link_state(xhci, port_array, port_index,
-    XDEV_U0);
+ xhci_set_link_state(xhci, ports[port_index], XDEV_U0);
  }
  }
 
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 3d58780fc6c3..2bd34a2cfad5 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1590,8 +1590,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
  bus_state->port_remote_wakeup |= 1 << hcd_portnum;
  xhci_test_and_clear_bit(xhci, port_array,
  hcd_portnum, PORT_PLC);
- xhci_set_link_state(xhci, port_array, hcd_portnum,
- XDEV_U0);
+ xhci_set_link_state(xhci, port, XDEV_U0);
  /* Need to wait until the next link state change
  * indicates the device is actually in U0.
  */
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 59c7ff346d9b..cc21282c8bac 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -2100,8 +2100,8 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring);
 unsigned int count_trbs(u64 addr, u64 len);
 
 /* xHCI roothub code */
-void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
- int port_id, u32 link_state);
+void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
+ u32 link_state);
 void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
  int port_id, u32 port_bit);
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 09/16] xhci: change xhci_test_and_clear_bit() to use new port structure

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

Don't use pointers to port array and port index as function parameters
in xhci_test_and_clear_bit(), just use a pointer to the right port
structure.

xhci_test_and_clear_bit() was the last port_array user in
xhci_get_port_status() and handle_port_status(), so remove the
port_array from them as well.

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(backported from commit eaefcf246b56ec888ccbbb6b39da688166d4d4fb)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-hub.c  | 22 ++++++++++------------
 drivers/usb/host/xhci-ring.c | 15 +++------------
 drivers/usb/host/xhci.h      |  4 ++--
 3 files changed, 15 insertions(+), 26 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 00490e4ada68..42b7de72b2d5 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -718,16 +718,16 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
 }
 
 /* Test and clear port RWC bit */
-void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
- int port_id, u32 port_bit)
+void xhci_test_and_clear_bit(struct xhci_hcd *xhci, struct xhci_port *port,
+     u32 port_bit)
 {
  u32 temp;
 
- temp = readl(port_array[port_id]);
+ temp = readl(port->addr);
  if (temp & port_bit) {
  temp = xhci_port_state_to_neutral(temp);
  temp |= port_bit;
- writel(temp, port_array[port_id]);
+ writel(temp, port->addr);
  }
 }
 
@@ -847,8 +847,7 @@ static u32 xhci_get_ext_port_status(u32 raw_port_status, u32 port_li)
  */
 static u32 xhci_get_port_status(struct usb_hcd *hcd,
  struct xhci_bus_state *bus_state,
- __le32 __iomem **port_array,
- u16 wIndex, u32 raw_port_status,
+ u16 wIndex, u32 raw_port_status,
  unsigned long flags)
  __releases(&xhci->lock)
  __acquires(&xhci->lock)
@@ -931,8 +930,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
 
  set_bit(wIndex, &bus_state->rexit_ports);
 
- xhci_test_and_clear_bit(xhci, port_array, wIndex,
- PORT_PLC);
+ xhci_test_and_clear_bit(xhci, port, PORT_PLC);
  xhci_set_link_state(xhci, port, XDEV_U0);
 
  spin_unlock_irqrestore(&xhci->lock, flags);
@@ -1091,8 +1089,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  retval = -ENODEV;
  break;
  }
- status = xhci_get_port_status(hcd, bus_state, port_array,
- wIndex, temp, flags);
+ status = xhci_get_port_status(hcd, bus_state, wIndex, temp,
+      flags);
  if (status == 0xffffffff)
  goto error;
 
@@ -1664,7 +1662,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
  for_each_set_bit(port_index, &bus_state->bus_suspended,
  BITS_PER_LONG) {
  /* Clear PLC to poll it later for U0 transition */
- xhci_test_and_clear_bit(xhci, port_array, port_index,
+ xhci_test_and_clear_bit(xhci, ports[port_index],
  PORT_PLC);
  xhci_set_link_state(xhci, ports[port_index], XDEV_U0);
  }
@@ -1679,7 +1677,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
   port_index);
  continue;
  }
- xhci_test_and_clear_bit(xhci, port_array, port_index, PORT_PLC);
+ xhci_test_and_clear_bit(xhci, ports[port_index], PORT_PLC);
  slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1);
  if (slot_id)
  xhci_ring_device(xhci, slot_id);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 2bd34a2cfad5..01f5aed3271a 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1526,7 +1526,6 @@ static void handle_port_status(struct xhci_hcd *xhci,
  int slot_id;
  unsigned int hcd_portnum;
  struct xhci_bus_state *bus_state;
- __le32 __iomem **port_array;
  bool bogus_port_status = false;
  struct xhci_port *port;
 
@@ -1554,11 +1553,6 @@ static void handle_port_status(struct xhci_hcd *xhci,
 
  hcd = port->rhub->hcd;
  bus_state = &xhci->bus_state[hcd_index(hcd)];
- if (hcd->speed >= HCD_USB3)
- port_array = xhci->usb3_ports;
- else
- port_array = xhci->usb2_ports;
-
  hcd_portnum = port->hcd_portnum;
  portsc = readl(port->addr);
 
@@ -1588,8 +1582,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
  * device and host initiated resume.
  */
  bus_state->port_remote_wakeup |= 1 << hcd_portnum;
- xhci_test_and_clear_bit(xhci, port_array,
- hcd_portnum, PORT_PLC);
+ xhci_test_and_clear_bit(xhci, port, PORT_PLC);
  xhci_set_link_state(xhci, port, XDEV_U0);
  /* Need to wait until the next link state change
  * indicates the device is actually in U0.
@@ -1627,8 +1620,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
  xhci_ring_device(xhci, slot_id);
  if (bus_state->port_remote_wakeup & (1 << hcd_portnum)) {
  bus_state->port_remote_wakeup &= ~(1 << hcd_portnum);
- xhci_test_and_clear_bit(xhci, port_array,
- hcd_portnum, PORT_PLC);
+ xhci_test_and_clear_bit(xhci, port, PORT_PLC);
  usb_wakeup_notification(hcd->self.root_hub,
  hcd_portnum + 1);
  bogus_port_status = true;
@@ -1650,8 +1642,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
  }
 
  if (hcd->speed < HCD_USB3)
- xhci_test_and_clear_bit(xhci, port_array, hcd_portnum,
- PORT_PLC);
+ xhci_test_and_clear_bit(xhci, port, PORT_PLC);
 
 cleanup:
  /* Update event ring dequeue pointer before dropping the lock */
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index cc21282c8bac..abd712e4acf9 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -2102,8 +2102,8 @@ unsigned int count_trbs(u64 addr, u64 len);
 /* xHCI roothub code */
 void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
  u32 link_state);
-void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
- int port_id, u32 port_bit);
+void xhci_test_and_clear_bit(struct xhci_hcd *xhci, struct xhci_port *port,
+ u32 port_bit);
 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);
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 10/16] xhci: use port structures instead of port arrays in xhci.c functions

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

get rid of port iomem arrays and use port structures in the following
functions:
xhci_find_raw_port_number()
xhci_disable_port_wake_on_bits()
xhci_set_usb2_hardware_lpm()
xhci_all_ports_seen_u0()
compliance_mode_recovery()

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit 38986ffa6a74899be83126d55f043a1c034cba7d)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci.c | 50 ++++++++++++++++++-----------------------
 1 file changed, 22 insertions(+), 28 deletions(-)

diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 61f2eb9f0217..0d915f6b6835 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -400,13 +400,15 @@ static void compliance_mode_recovery(struct timer_list *t)
 {
  struct xhci_hcd *xhci;
  struct usb_hcd *hcd;
+ struct xhci_hub *rhub;
  u32 temp;
  int i;
 
  xhci = from_timer(xhci, t, comp_mode_recovery_timer);
+ rhub = &xhci->usb3_rhub;
 
- for (i = 0; i < xhci->num_usb3_ports; i++) {
- temp = readl(xhci->usb3_ports[i]);
+ for (i = 0; i < rhub->num_ports; i++) {
+ temp = readl(rhub->ports[i]->addr);
  if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) {
  /*
  * Compliance Mode Detected. Letting USB Core
@@ -426,7 +428,7 @@ static void compliance_mode_recovery(struct timer_list *t)
  }
  }
 
- if (xhci->port_status_u0 != ((1 << xhci->num_usb3_ports)-1))
+ if (xhci->port_status_u0 != ((1 << rhub->num_ports) - 1))
  mod_timer(&xhci->comp_mode_recovery_timer,
  jiffies + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
 }
@@ -483,7 +485,7 @@ static bool xhci_compliance_mode_recovery_timer_quirk_check(void)
 
 static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci)
 {
- return (xhci->port_status_u0 == ((1 << xhci->num_usb3_ports)-1));
+ return (xhci->port_status_u0 == ((1 << xhci->usb3_rhub.num_ports) - 1));
 }
 
 
@@ -822,33 +824,33 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
 
 static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
 {
+ struct xhci_port **ports;
  int port_index;
- __le32 __iomem **port_array;
  unsigned long flags;
  u32 t1, t2;
 
  spin_lock_irqsave(&xhci->lock, flags);
 
  /* disable usb3 ports Wake bits */
- port_index = xhci->num_usb3_ports;
- port_array = xhci->usb3_ports;
+ port_index = xhci->usb3_rhub.num_ports;
+ ports = xhci->usb3_rhub.ports;
  while (port_index--) {
- t1 = readl(port_array[port_index]);
+ t1 = readl(ports[port_index]->addr);
  t1 = xhci_port_state_to_neutral(t1);
  t2 = t1 & ~PORT_WAKE_BITS;
  if (t1 != t2)
- writel(t2, port_array[port_index]);
+ writel(t2, ports[port_index]->addr);
  }
 
  /* disable usb2 ports Wake bits */
- port_index = xhci->num_usb2_ports;
- port_array = xhci->usb2_ports;
+ port_index = xhci->usb2_rhub.num_ports;
+ ports = xhci->usb2_rhub.ports;
  while (port_index--) {
- t1 = readl(port_array[port_index]);
+ t1 = readl(ports[port_index]->addr);
  t1 = xhci_port_state_to_neutral(t1);
  t2 = t1 & ~PORT_WAKE_BITS;
  if (t1 != t2)
- writel(t2, port_array[port_index]);
+ writel(t2, ports[port_index]->addr);
  }
 
  spin_unlock_irqrestore(&xhci->lock, flags);
@@ -3919,18 +3921,10 @@ static int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev)
  */
 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];
+ struct xhci_hub *rhub;
 
- raw_port = (addr - base_addr)/NUM_PORT_REGS + 1;
- return raw_port;
+ rhub = xhci_get_rhub(hcd);
+ return rhub->ports[port1 - 1]->hw_portnum + 1;
 }
 
 /*
@@ -4063,7 +4057,7 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
  struct usb_device *udev, int enable)
 {
  struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- __le32 __iomem **port_array;
+ struct xhci_port **ports;
  __le32 __iomem *pm_addr, *hlpm_addr;
  u32 pm_val, hlpm_val, field;
  unsigned int port_num;
@@ -4084,11 +4078,11 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
 
  spin_lock_irqsave(&xhci->lock, flags);
 
- port_array = xhci->usb2_ports;
+ ports = xhci->usb2_rhub.ports;
  port_num = udev->portnum - 1;
- pm_addr = port_array[port_num] + PORTPMSC;
+ pm_addr = ports[port_num]->addr + PORTPMSC;
  pm_val = readl(pm_addr);
- hlpm_addr = port_array[port_num] + PORTHLPMC;
+ hlpm_addr = ports[port_num]->addr + PORTHLPMC;
  field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
 
  xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 11/16] xhci: xhci-hub: use port structure members instead of xhci_get_ports()

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

xhci_get_ports() is one of the last functions using port_arrays in
xhci-hub.c. We get the same data directly from hub and port structures
instead, so convert and remove both xhci_get_ports() and port_arrays from
all function that no longer need it.

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit 925f349d4dca1357813efdc37ec08134d79b3288)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-hub.c | 28 ++++------------------------
 1 file changed, 4 insertions(+), 24 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 42b7de72b2d5..fd9865987f09 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -542,22 +542,6 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
  port_change_bit, wIndex, port_status);
 }
 
-static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
-{
- int max_ports;
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-
- if (hcd->speed >= HCD_USB3) {
- max_ports = xhci->num_usb3_ports;
- *port_array = xhci->usb3_ports;
- } else {
- max_ports = xhci->num_usb2_ports;
- *port_array = xhci->usb2_ports;
- }
-
- return max_ports;
-}
-
 struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd)
 {
  struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -1033,7 +1017,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  unsigned long flags;
  u32 temp, status;
  int retval = 0;
- __le32 __iomem **port_array;
  int slot_id;
  struct xhci_bus_state *bus_state;
  u16 link_state = 0;
@@ -1045,7 +1028,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 
  rhub = xhci_get_rhub(hcd);
  ports = rhub->ports;
- max_ports = xhci_get_ports(hcd, &port_array);
+ max_ports = rhub->num_ports;
  bus_state = &xhci->bus_state[hcd_index(hcd)];
 
  spin_lock_irqsave(&xhci->lock, flags);
@@ -1425,7 +1408,6 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
  int i, retval;
  struct xhci_hcd *xhci = hcd_to_xhci(hcd);
  int max_ports;
- __le32 __iomem **port_array;
  struct xhci_bus_state *bus_state;
  bool reset_change = false;
  struct xhci_hub *rhub;
@@ -1433,7 +1415,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
 
  rhub = xhci_get_rhub(hcd);
  ports = rhub->ports;
- max_ports = xhci_get_ports(hcd, &port_array);
+ max_ports = rhub->num_ports;
  bus_state = &xhci->bus_state[hcd_index(hcd)];
 
  /* Initial status is no changes */
@@ -1481,7 +1463,6 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
 {
  struct xhci_hcd *xhci = hcd_to_xhci(hcd);
  int max_ports, port_index;
- __le32 __iomem **port_array;
  struct xhci_bus_state *bus_state;
  unsigned long flags;
  struct xhci_hub *rhub;
@@ -1489,7 +1470,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
 
  rhub = xhci_get_rhub(hcd);
  ports = rhub->ports;
- max_ports = xhci_get_ports(hcd, &port_array);
+ max_ports = rhub->num_ports;
  bus_state = &xhci->bus_state[hcd_index(hcd)];
 
  spin_lock_irqsave(&xhci->lock, flags);
@@ -1583,7 +1564,6 @@ int xhci_bus_resume(struct usb_hcd *hcd)
 {
  struct xhci_hcd *xhci = hcd_to_xhci(hcd);
  struct xhci_bus_state *bus_state;
- __le32 __iomem **port_array;
  unsigned long flags;
  int max_ports, port_index;
  int slot_id;
@@ -1595,7 +1575,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
 
  rhub = xhci_get_rhub(hcd);
  ports = rhub->ports;
- max_ports = xhci_get_ports(hcd, &port_array);
+ max_ports = rhub->num_ports;
  bus_state = &xhci->bus_state[hcd_index(hcd)];
 
  if (time_before(jiffies, bus_state->next_statechange))
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 12/16] xhci-mtk: use xhci hub structures to get number of ports in roothubs

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit edaa30f878e4586828f74c30f8dfe02ddbfe5251)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-mtk-sch.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index eea7360a18fc..fa33d6e5b1cb 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -58,7 +58,7 @@ static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev,
  bw_index = (virt_dev->real_port - 1) * 2 + 1;
  } else {
  /* add one more for each SS port */
- bw_index = virt_dev->real_port + xhci->num_usb3_ports - 1;
+ bw_index = virt_dev->real_port + xhci->usb3_rhub.num_ports - 1;
  }
 
  return bw_index;
@@ -284,7 +284,7 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
  int i;
 
  /* ss IN and OUT are separated */
- num_usb_bus = xhci->num_usb3_ports * 2 + xhci->num_usb2_ports;
+ num_usb_bus = xhci->usb3_rhub.num_ports * 2 + xhci->usb2_rhub.num_ports;
 
  sch_array = kcalloc(num_usb_bus, sizeof(*sch_array), GFP_KERNEL);
  if (sch_array == NULL)
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 13/16] xhci: xhci-mem: remove port_arrays and the code initializing them

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

As we are now using the new port strtuctes the port_arrays
are no longer needed, remove them completely

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit 07f7619053874ba60d620367b965b8a0ae38a696)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-mem.c | 100 ++++--------------------------------
 drivers/usb/host/xhci.h     |   8 ---
 2 files changed, 11 insertions(+), 97 deletions(-)

diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index dbe36cbbf3af..253d1990622a 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1052,8 +1052,7 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
 
 /*
  * The xHCI roothub may have ports of differing speeds in any order in the port
- * status registers.  xhci->port_array provides an array of the port speed for
- * each offset into the port status registers.
+ * status registers.
  *
  * The xHCI hardware wants to know the roothub port number that the USB device
  * is attached to (or the roothub port its ancestor hub is attached to).  All we
@@ -1884,23 +1883,15 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 
 no_bw:
  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;
@@ -2190,25 +2181,15 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
  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 ||
-    hw_port->rhub) {
+ if (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, "
  "duplicated as USB %u\n",
- xhci->port_array[i], major_revision);
+ hw_port->rhub->maj_rev, major_revision);
  /* Only adjust the roothub port counts if we haven't
  * found a similar duplicate.
  */
- if (xhci->port_array[i] != major_revision &&
- xhci->port_array[i] != DUPLICATE_ENTRY) {
- if (xhci->port_array[i] == 0x03)
- xhci->num_usb3_ports--;
- else
- xhci->num_usb2_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--;
@@ -2216,13 +2197,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
  }
  continue;
  }
- xhci->port_array[i] = major_revision;
  hw_port->rhub = rhub;
  rhub->num_ports++;
- if (major_revision == 0x03)
- xhci->num_usb3_ports++;
- else
- xhci->num_usb2_ports++;
  }
  /* FIXME: Should we disable ports not in the Extended Capabilities? */
 }
@@ -2260,14 +2236,13 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
  void __iomem *base;
  u32 offset;
  unsigned int num_ports;
- int i, j, port_index;
+ int i, j;
  int cap_count = 0;
  u32 cap_start;
 
  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)
+ if (!xhci->hw_ports)
  return -ENOMEM;
 
  for (i = 0; i < num_ports; i++) {
@@ -2311,41 +2286,34 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
 
  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;
  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);
  }
-
- if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) {
- 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);
+       "Found %u USB 2.0 ports and %u USB 3.0 ports.",
+       xhci->usb2_rhub.num_ports, xhci->usb3_rhub.num_ports);
 
  /* Place limits on the number of roothub ports so that the hub
  * descriptors aren't longer than the USB core will allocate.
  */
- if (xhci->num_usb3_ports > USB_SS_MAXPORTS) {
+ if (xhci->usb3_rhub.num_ports > USB_SS_MAXPORTS) {
  xhci_dbg_trace(xhci, trace_xhci_dbg_init,
  "Limiting USB 3.0 roothub ports to %u.",
  USB_SS_MAXPORTS);
- xhci->num_usb3_ports = USB_SS_MAXPORTS;
+ xhci->usb3_rhub.num_ports = USB_SS_MAXPORTS;
  }
- if (xhci->num_usb2_ports > USB_MAXCHILDREN) {
+ if (xhci->usb2_rhub.num_ports > USB_MAXCHILDREN) {
  xhci_dbg_trace(xhci, trace_xhci_dbg_init,
  "Limiting USB 2.0 roothub ports to %u.",
  USB_MAXCHILDREN);
- xhci->num_usb2_ports = USB_MAXCHILDREN;
+ xhci->usb2_rhub.num_ports = USB_MAXCHILDREN;
  }
 
  /*
@@ -2356,52 +2324,6 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
  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);
- if (!xhci->usb2_ports)
- return -ENOMEM;
-
- port_index = 0;
- for (i = 0; i < num_ports; i++) {
- if (xhci->port_array[i] == 0x03 ||
- xhci->port_array[i] == 0 ||
- xhci->port_array[i] == DUPLICATE_ENTRY)
- continue;
-
- xhci->usb2_ports[port_index] =
- &xhci->op_regs->port_status_base +
- NUM_PORT_REGS*i;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "USB 2.0 port at index %u, "
- "addr = %p", i,
- xhci->usb2_ports[port_index]);
- port_index++;
- if (port_index == xhci->num_usb2_ports)
- break;
- }
- }
- if (xhci->num_usb3_ports) {
- xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)*
- xhci->num_usb3_ports, flags);
- if (!xhci->usb3_ports)
- return -ENOMEM;
-
- port_index = 0;
- for (i = 0; i < num_ports; i++)
- if (xhci->port_array[i] == 0x03) {
- xhci->usb3_ports[port_index] =
- &xhci->op_regs->port_status_base +
- NUM_PORT_REGS*i;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "USB 3.0 port at index %u, "
- "addr = %p", i,
- xhci->usb3_ports[port_index]);
- port_index++;
- if (port_index == xhci->num_usb3_ports)
- break;
- }
- }
  return 0;
 }
 
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index abd712e4acf9..125614e06845 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1840,17 +1840,9 @@ struct xhci_hcd {
  unsigned int limit_active_eps;
  /* There are two roothubs to keep track of bus suspend info for */
  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;
- /* Array of pointers to USB 2.0 PORTSC registers */
- __le32 __iomem **usb2_ports;
  struct xhci_hub usb2_rhub;
  struct xhci_hub usb3_rhub;
- unsigned int num_usb2_ports;
  /* support xHCI 0.96 spec USB2 software LPM */
  unsigned sw_lpm_support:1;
  /* support xHCI 1.0 spec USB2 hardware LPM */
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 14/16] xhci: debugfs: add usb ports to xhci debugfs

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

Add ports/portxx/portsc for each xHC hardware usb port to debugfs.
Showing the content of the port status and control register for
each port (PORTSC)

Portxx is numbered starting from 1 for historical reasons to better
match port numbering shown by lsusb and other places.

Ports in debugfs are in the order XHC controller has them,
In most cases USB2 ports come first, followed by USB3 ports.
i.e. USB2 ports are port01-portxx, and USB3 portxx-portmax.

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit 65475023928bce90a98aa4e44047fd17afead050)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-debugfs.c | 48 +++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index 5851052d4668..76e446a889bd 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -333,6 +333,31 @@ static const struct file_operations xhci_context_fops = {
  .release = single_release,
 };
 
+
+
+static int xhci_portsc_show(struct seq_file *s, void *unused)
+{
+ struct xhci_port *port = s->private;
+ u32 portsc;
+
+ portsc = readl(port->addr);
+ seq_printf(s, "%s\n", xhci_decode_portsc(portsc));
+
+ return 0;
+}
+
+static int xhci_port_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, xhci_portsc_show, inode->i_private);
+}
+
+static const struct file_operations port_fops = {
+ .open = xhci_port_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
 static void xhci_debugfs_create_files(struct xhci_hcd *xhci,
       struct xhci_file_map *files,
       size_t nentries, void *data,
@@ -449,6 +474,27 @@ void xhci_debugfs_remove_slot(struct xhci_hcd *xhci, int slot_id)
  dev->debugfs_private = NULL;
 }
 
+static void xhci_debugfs_create_ports(struct xhci_hcd *xhci,
+      struct dentry *parent)
+{
+ unsigned int num_ports;
+ char port_name[8];
+ struct xhci_port *port;
+ struct dentry *dir;
+
+ num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
+
+ parent = debugfs_create_dir("ports", parent);
+
+ while (num_ports--) {
+ scnprintf(port_name, sizeof(port_name), "port%02d",
+  num_ports + 1);
+ dir = debugfs_create_dir(port_name, parent);
+ port = &xhci->hw_ports[num_ports];
+ debugfs_create_file("portsc", 0444, dir, port, &port_fops);
+ }
+}
+
 void xhci_debugfs_init(struct xhci_hcd *xhci)
 {
  struct device *dev = xhci_to_hcd(xhci)->self.controller;
@@ -497,6 +543,8 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
      xhci->debugfs_root);
 
  xhci->debugfs_slots = debugfs_create_dir("devices", xhci->debugfs_root);
+
+ xhci_debugfs_create_ports(xhci, xhci->debugfs_root);
 }
 
 void xhci_debugfs_exit(struct xhci_hcd *xhci)
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 15/16] xhci: debugfs: add debugfs interface to enable compliance mode for a port

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

Enable compliance transition for a port by writing "compliance" to the
ports portsc file in debugfs.
port must be "Not-connected" and Link must be in RxDetect state to enable
compliance mode.

Only needed for host that have CTC flag set.
Allows state transitioning to compliance at 1st LFPS timeout.

Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit 87a03802184c866af35a8fcdd5fd14d94e9bf9eb)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci-debugfs.c | 39 ++++++++++++++++++++++++++++++++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index 76e446a889bd..cadc01336bf8 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 
 #include "xhci.h"
 #include "xhci-debugfs.h"
@@ -351,8 +352,44 @@ static int xhci_port_open(struct inode *inode, struct file *file)
  return single_open(file, xhci_portsc_show, inode->i_private);
 }
 
+static ssize_t xhci_port_write(struct file *file,  const char __user *ubuf,
+       size_t count, loff_t *ppos)
+{
+ struct seq_file         *s = file->private_data;
+ struct xhci_port *port = s->private;
+ struct xhci_hcd *xhci = hcd_to_xhci(port->rhub->hcd);
+ char                    buf[32];
+ u32 portsc;
+ unsigned long flags;
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "compliance", 10)) {
+ /* If CTC is clear, compliance is enabled by default */
+ if (!HCC2_CTC(xhci->hcc_params2))
+ return count;
+ spin_lock_irqsave(&xhci->lock, flags);
+ /* compliance mode can only be enabled on ports in RxDetect */
+ portsc = readl(port->addr);
+ if ((portsc & PORT_PLS_MASK) != XDEV_RXDETECT) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return -EPERM;
+ }
+ portsc = xhci_port_state_to_neutral(portsc);
+ portsc &= ~PORT_PLS_MASK;
+ portsc |= PORT_LINK_STROBE | XDEV_COMP_MODE;
+ writel(portsc, port->addr);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ } else {
+ return -EINVAL;
+ }
+ return count;
+}
+
 static const struct file_operations port_fops = {
  .open = xhci_port_open,
+ .write                  = xhci_port_write,
  .read = seq_read,
  .llseek = seq_lseek,
  .release = single_release,
@@ -491,7 +528,7 @@ static void xhci_debugfs_create_ports(struct xhci_hcd *xhci,
   num_ports + 1);
  dir = debugfs_create_dir(port_name, parent);
  port = &xhci->hw_ports[num_ports];
- debugfs_create_file("portsc", 0444, dir, port, &port_fops);
+ debugfs_create_file("portsc", 0644, dir, port, &port_fops);
  }
 }
 
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 16/16] xhci: Fix perceived dead host due to runtime suspend race with event handler

Kai-Heng Feng
In reply to this post by Kai-Heng Feng
From: Mathias Nyman <[hidden email]>

BugLink: https://bugs.launchpad.net/bugs/1763594

Don't rely on event interrupt (EINT) bit alone to detect pending port
change in resume. If no change event is detected the host may be suspended
again, oterwise roothubs are resumed.

There is a lag in xHC setting EINT. If we don't notice the pending change
in resume, and the controller is runtime suspeded again, it causes the
event handler to assume host is dead as it will fail to read xHC registers
once PCI puts the controller to D3 state.

[  268.520969] xhci_hcd: xhci_resume: starting port polling.
[  268.520985] xhci_hcd: xhci_hub_status_data: stopping port polling.
[  268.521030] xhci_hcd: xhci_suspend: stopping port polling.
[  268.521040] xhci_hcd: // Setting command ring address to 0x349bd001
[  268.521139] xhci_hcd: Port Status Change Event for port 3
[  268.521149] xhci_hcd: resume root hub
[  268.521163] xhci_hcd: port resume event for port 3
[  268.521168] xhci_hcd: xHC is not running.
[  268.521174] xhci_hcd: handle_port_status: starting port polling.
[  268.596322] xhci_hcd: xhci_hc_died: xHCI host controller not responding, assume dead

The EINT lag is described in a additional note in xhci specs 4.19.2:

"Due to internal xHC scheduling and system delays, there will be a lag
between a change bit being set and the Port Status Change Event that it
generated being written to the Event Ring. If SW reads the PORTSC and
sees a change bit set, there is no guarantee that the corresponding Port
Status Change Event has already been written into the Event Ring."

Cc: <[hidden email]>
Signed-off-by: Mathias Nyman <[hidden email]>
Signed-off-by: Greg Kroah-Hartman <[hidden email]>
(cherry picked from commit 229bc19fd7aca4f37964af06e3583c1c8f36b5d6)
Signed-off-by: Kai-Heng Feng <[hidden email]>
---
 drivers/usb/host/xhci.c | 40 +++++++++++++++++++++++++++++++++++++---
 drivers/usb/host/xhci.h |  4 ++++
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 0d915f6b6835..06f5a85592c5 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -856,6 +856,41 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
  spin_unlock_irqrestore(&xhci->lock, flags);
 }
 
+static bool xhci_pending_portevent(struct xhci_hcd *xhci)
+{
+ struct xhci_port **ports;
+ int port_index;
+ u32 status;
+ u32 portsc;
+
+ status = readl(&xhci->op_regs->status);
+ if (status & STS_EINT)
+ return true;
+ /*
+ * Checking STS_EINT is not enough as there is a lag between a change
+ * bit being set and the Port Status Change Event that it generated
+ * being written to the Event Ring. See note in xhci 1.1 section 4.19.2.
+ */
+
+ port_index = xhci->usb2_rhub.num_ports;
+ ports = xhci->usb2_rhub.ports;
+ while (port_index--) {
+ portsc = readl(ports[port_index]->addr);
+ if (portsc & PORT_CHANGE_MASK ||
+    (portsc & PORT_PLS_MASK) == XDEV_RESUME)
+ return true;
+ }
+ port_index = xhci->usb3_rhub.num_ports;
+ ports = xhci->usb3_rhub.ports;
+ while (port_index--) {
+ portsc = readl(ports[port_index]->addr);
+ if (portsc & PORT_CHANGE_MASK ||
+    (portsc & PORT_PLS_MASK) == XDEV_RESUME)
+ return true;
+ }
+ return false;
+}
+
 /*
  * Stop HC (not bus-specific)
  *
@@ -957,7 +992,7 @@ EXPORT_SYMBOL_GPL(xhci_suspend);
  */
 int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 {
- u32 command, temp = 0, status;
+ u32 command, temp = 0;
  struct usb_hcd *hcd = xhci_to_hcd(xhci);
  struct usb_hcd *secondary_hcd;
  int retval = 0;
@@ -1082,8 +1117,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
  done:
  if (retval == 0) {
  /* Resume root hubs only when have pending events. */
- status = readl(&xhci->op_regs->status);
- if (status & STS_EINT) {
+ if (xhci_pending_portevent(xhci)) {
  usb_hcd_resume_root_hub(xhci->shared_hcd);
  usb_hcd_resume_root_hub(hcd);
  }
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 125614e06845..8cde038e0d01 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -382,6 +382,10 @@ struct xhci_op_regs {
 #define PORT_PLC (1 << 22)
 /* port configure error change - port failed to configure its link partner */
 #define PORT_CEC (1 << 23)
+#define PORT_CHANGE_MASK (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
+ PORT_RC | PORT_PLC | PORT_CEC)
+
+
 /* Cold Attach Status - xHC can set this bit to report device attached during
  * Sx state. Warm port reset should be perfomed to clear this bit and move port
  * to connected state.
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

APPLIED/OEM-B: Re: [SRU] [Bionic] [OEM-B] [PATCH 00/16] Fix "xHCI host controller not responding, assume dead"

Timo Aaltonen-6
In reply to this post by Kai-Heng Feng
On 03.07.2018 10:20, Kai-Heng Feng wrote:

> BugLink: https://bugs.launchpad.net/bugs/1763594
>
> [Impact]
> xHC stops to work after some time. This happens when the xHC gets
> runtime resumed/suspended constantly.
>
> [Test]
> User reports this backport fixes the issue.
>
> [Fix]
> In addition to check EINT, also check ports' status.
>
> [Regression Potential]
> Low. It fixes a known bug and it's in -stable.
>
> Mathias Nyman (16):
>   xhci: Create new structures to store xhci port information
>   xhci: set hcd pointers for xhci usb2 and usb3 roothub structures
>   xhci: Add helper to get xhci roothub from hcd
>   xhci: xhci-hub: use new port structures to get port address instead of
>     port array
>   xhci: xhci-hub: use new port structures for cas and wake mask
>     functions.
>   xhci: xhci-ring: use port structures for port event handler
>   xhci: rename faked_port_index to hcd_portnum
>   xhci: change xhci_set_link_state() to work with port structures
>   xhci: change xhci_test_and_clear_bit() to use new port structure
>   xhci: use port structures instead of port arrays in xhci.c functions
>   xhci: xhci-hub: use port structure members instead of xhci_get_ports()
>   xhci-mtk: use xhci hub structures to get number of ports in roothubs
>   xhci: xhci-mem: remove port_arrays and the code initializing them
>   xhci: debugfs: add usb ports to xhci debugfs
>   xhci: debugfs: add debugfs interface to enable compliance mode for a
>     port
>   xhci: Fix perceived dead host due to runtime suspend race with event
>     handler
>
>  drivers/usb/host/xhci-debugfs.c |  85 +++++++++++
>  drivers/usb/host/xhci-hub.c     | 244 ++++++++++++++++----------------
>  drivers/usb/host/xhci-mem.c     | 140 ++++++++----------
>  drivers/usb/host/xhci-mtk-sch.c |   4 +-
>  drivers/usb/host/xhci-ring.c    | 126 ++++-------------
>  drivers/usb/host/xhci.c         |  93 ++++++++----
>  drivers/usb/host/xhci.h         |  43 +++---
>  7 files changed, 381 insertions(+), 354 deletions(-)

applied to oem-b master-next, thanks

--
t

--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

Re: [SRU] [Bionic] [OEM-B] [PATCH 00/16] Fix "xHCI host controller not responding, assume dead"

Kleber Souza
In reply to this post by Kai-Heng Feng
On 07/03/18 09:20, Kai-Heng Feng wrote:

> BugLink: https://bugs.launchpad.net/bugs/1763594
>
> [Impact]
> xHC stops to work after some time. This happens when the xHC gets
> runtime resumed/suspended constantly.
>
> [Test]
> User reports this backport fixes the issue.
>
> [Fix]
> In addition to check EINT, also check ports' status.
>
> [Regression Potential]
> Low. It fixes a known bug and it's in -stable.
>
> Mathias Nyman (16):
>   xhci: Create new structures to store xhci port information
>   xhci: set hcd pointers for xhci usb2 and usb3 roothub structures
>   xhci: Add helper to get xhci roothub from hcd
>   xhci: xhci-hub: use new port structures to get port address instead of
>     port array
>   xhci: xhci-hub: use new port structures for cas and wake mask
>     functions.
>   xhci: xhci-ring: use port structures for port event handler
>   xhci: rename faked_port_index to hcd_portnum
>   xhci: change xhci_set_link_state() to work with port structures
>   xhci: change xhci_test_and_clear_bit() to use new port structure
>   xhci: use port structures instead of port arrays in xhci.c functions
>   xhci: xhci-hub: use port structure members instead of xhci_get_ports()
>   xhci-mtk: use xhci hub structures to get number of ports in roothubs
>   xhci: xhci-mem: remove port_arrays and the code initializing them
>   xhci: debugfs: add usb ports to xhci debugfs
>   xhci: debugfs: add debugfs interface to enable compliance mode for a
>     port
>   xhci: Fix perceived dead host due to runtime suspend race with event
>     handler
>
>  drivers/usb/host/xhci-debugfs.c |  85 +++++++++++
>  drivers/usb/host/xhci-hub.c     | 244 ++++++++++++++++----------------
>  drivers/usb/host/xhci-mem.c     | 140 ++++++++----------
>  drivers/usb/host/xhci-mtk-sch.c |   4 +-
>  drivers/usb/host/xhci-ring.c    | 126 ++++-------------
>  drivers/usb/host/xhci.c         |  93 ++++++++----
>  drivers/usb/host/xhci.h         |  43 +++---
>  7 files changed, 381 insertions(+), 354 deletions(-)
>

Hi Kai-Heng,

Why is this patchset being requested for bionic/linux *and*
bionic/linux-oem? bionic/linux-oem is a derivative of bionic/linux, so
everything that goes to the latter will automatically land on the former.

But since Timo already picked up these patches for -oem, is still still
required to be considered for bionic/linux?

Thanks,
Kleber

--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

Re: [SRU] [Bionic] [OEM-B] [PATCH 00/16] Fix "xHCI host controller not responding, assume dead"

Kai-Heng Feng
at 19:56, Kleber Souza <[hidden email]> wrote:

> On 07/03/18 09:20, Kai-Heng Feng wrote:
>> BugLink: https://bugs.launchpad.net/bugs/1763594
>>
>> [Impact]
>> xHC stops to work after some time. This happens when the xHC gets
>> runtime resumed/suspended constantly.
>>
>> [Test]
>> User reports this backport fixes the issue.
>>
>> [Fix]
>> In addition to check EINT, also check ports' status.
>>
>> [Regression Potential]
>> Low. It fixes a known bug and it's in -stable.
>>
>> Mathias Nyman (16):
>>   xhci: Create new structures to store xhci port information
>>   xhci: set hcd pointers for xhci usb2 and usb3 roothub structures
>>   xhci: Add helper to get xhci roothub from hcd
>>   xhci: xhci-hub: use new port structures to get port address instead of
>>     port array
>>   xhci: xhci-hub: use new port structures for cas and wake mask
>>     functions.
>>   xhci: xhci-ring: use port structures for port event handler
>>   xhci: rename faked_port_index to hcd_portnum
>>   xhci: change xhci_set_link_state() to work with port structures
>>   xhci: change xhci_test_and_clear_bit() to use new port structure
>>   xhci: use port structures instead of port arrays in xhci.c functions
>>   xhci: xhci-hub: use port structure members instead of xhci_get_ports()
>>   xhci-mtk: use xhci hub structures to get number of ports in roothubs
>>   xhci: xhci-mem: remove port_arrays and the code initializing them
>>   xhci: debugfs: add usb ports to xhci debugfs
>>   xhci: debugfs: add debugfs interface to enable compliance mode for a
>>     port
>>   xhci: Fix perceived dead host due to runtime suspend race with event
>>     handler
>>
>>  drivers/usb/host/xhci-debugfs.c |  85 +++++++++++
>>  drivers/usb/host/xhci-hub.c     | 244 ++++++++++++++++----------------
>>  drivers/usb/host/xhci-mem.c     | 140 ++++++++----------
>>  drivers/usb/host/xhci-mtk-sch.c |   4 +-
>>  drivers/usb/host/xhci-ring.c    | 126 ++++-------------
>>  drivers/usb/host/xhci.c         |  93 ++++++++----
>>  drivers/usb/host/xhci.h         |  43 +++---
>>  7 files changed, 381 insertions(+), 354 deletions(-)
>
> Hi Kai-Heng,
>
> Why is this patchset being requested for bionic/linux *and*
> bionic/linux-oem? bionic/linux-oem is a derivative of bionic/linux, so
> everything that goes to the latter will automatically land on the former.

Broadly speaking, it's for more flexible cadence.

Project managers and customers get grumpy when a fix can't meet a schedule  
deadline... -

>
> But since Timo already picked up these patches for -oem, is still still
> required to be considered for bionic/linux?

Yes, the fix is applicable for all users, not just for OEM projects.
The user confirmed this also works for him [1].

[1] https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1763594/comments/35

Kai-Heng

>
> Thanks,
> Kleber



--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
12