Commit 47189098 authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman

xhci: parse xhci protocol speed ID list for usb 3.1 usage

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: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3220befd
......@@ -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);
......@@ -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;
......
......@@ -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.
......@@ -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;
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment