Skip to content

Commit

Permalink
xhci: parse xhci protocol speed ID list for usb 3.1 usage
Browse files Browse the repository at this point in the history
xhci 1.1 controllers that support USB 3.1 must provide a protocol speed ID
(PSI) list to inform the driver of the supported speeds.

The PSI list can be read from the xhci supported protocol extended
capabilities.
The PSI values will be used to create a USB 3.1 SuperSpeedPlus capability
descriptor for the xhci USB 3.1 roothub.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Mathias Nyman authored and Greg Kroah-Hartman committed Oct 4, 2015
1 parent 3220bef commit 4718909
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 1 deletion.
38 changes: 37 additions & 1 deletion drivers/usb/host/xhci-mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -2072,14 +2072,23 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
{
u32 temp, port_offset, port_count;
int i;
struct xhci_hub *rhub;

if (major_revision > 0x03) {
temp = readl(addr);

if (XHCI_EXT_PORT_MAJOR(temp) == 0x03) {
rhub = &xhci->usb3_rhub;
} else if (XHCI_EXT_PORT_MAJOR(temp) <= 0x02) {
rhub = &xhci->usb2_rhub;
} else {
xhci_warn(xhci, "Ignoring unknown port speed, "
"Ext Cap %p, revision = 0x%x\n",
addr, major_revision);
/* Ignoring port protocol we can't understand. FIXME */
return;
}
rhub->maj_rev = XHCI_EXT_PORT_MAJOR(temp);
rhub->min_rev = XHCI_EXT_PORT_MINOR(temp);

/* Port offset and count in the third dword, see section 7.2 */
temp = readl(addr + 2);
Expand All @@ -2094,6 +2103,33 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
/* WTF? "Valid values are ‘1’ to MaxPorts" */
return;

rhub->psi_count = XHCI_EXT_PORT_PSIC(temp);
if (rhub->psi_count) {
rhub->psi = kcalloc(rhub->psi_count, sizeof(*rhub->psi),
GFP_KERNEL);
if (!rhub->psi)
rhub->psi_count = 0;

rhub->psi_uid_count++;
for (i = 0; i < rhub->psi_count; i++) {
rhub->psi[i] = readl(addr + 4 + i);

/* count unique ID values, two consecutive entries can
* have the same ID if link is assymetric
*/
if (i && (XHCI_EXT_PORT_PSIV(rhub->psi[i]) !=
XHCI_EXT_PORT_PSIV(rhub->psi[i - 1])))
rhub->psi_uid_count++;

xhci_dbg(xhci, "PSIV:%d PSIE:%d PLT:%d PFD:%d LP:%d PSIM:%d\n",
XHCI_EXT_PORT_PSIV(rhub->psi[i]),
XHCI_EXT_PORT_PSIE(rhub->psi[i]),
XHCI_EXT_PORT_PLT(rhub->psi[i]),
XHCI_EXT_PORT_PFD(rhub->psi[i]),
XHCI_EXT_PORT_LP(rhub->psi[i]),
XHCI_EXT_PORT_PSIM(rhub->psi[i]));
}
}
/* cache usb2 port capabilities */
if (major_revision < 0x03 && xhci->num_ext_caps < max_caps)
xhci->ext_caps[xhci->num_ext_caps++] = temp;
Expand Down
24 changes: 24 additions & 0 deletions drivers/usb/host/xhci.h
Original file line number Diff line number Diff line change
Expand Up @@ -540,9 +540,23 @@ struct xhci_protocol_caps {
};

#define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff)
#define XHCI_EXT_PORT_MINOR(x) (((x) >> 16) & 0xff)
#define XHCI_EXT_PORT_PSIC(x) (((x) >> 28) & 0x0f)
#define XHCI_EXT_PORT_OFF(x) ((x) & 0xff)
#define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff)

#define XHCI_EXT_PORT_PSIV(x) (((x) >> 0) & 0x0f)
#define XHCI_EXT_PORT_PSIE(x) (((x) >> 4) & 0x03)
#define XHCI_EXT_PORT_PLT(x) (((x) >> 6) & 0x03)
#define XHCI_EXT_PORT_PFD(x) (((x) >> 8) & 0x01)
#define XHCI_EXT_PORT_LP(x) (((x) >> 14) & 0x03)
#define XHCI_EXT_PORT_PSIM(x) (((x) >> 16) & 0xffff)

#define PLT_MASK (0x03 << 6)
#define PLT_SYM (0x00 << 6)
#define PLT_ASYM_RX (0x02 << 6)
#define PLT_ASYM_TX (0x03 << 6)

/**
* struct xhci_container_ctx
* @type: Type of context. Used to calculated offsets to contained contexts.
Expand Down Expand Up @@ -1469,6 +1483,14 @@ static inline unsigned int hcd_index(struct usb_hcd *hcd)
return 1;
}

struct xhci_hub {
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 */
struct xhci_hcd {
struct usb_hcd *main_hcd;
Expand Down Expand Up @@ -1608,6 +1630,8 @@ struct xhci_hcd {
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;
Expand Down

0 comments on commit 4718909

Please sign in to comment.