Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xhci: Setup array of USB 2.0 and USB 3.0 ports.

An xHCI host controller contains USB 2.0 and USB 3.0 ports, which can
occur in any order in the PORTSC registers. We cannot read the port speed
bits in the PORTSC registers at init time to determine the port speed,
since those bits are only valid when a USB device is plugged into the
port.

Instead, we read the "Supported Protocol Capability" registers in the xHC
Extended Capabilities space. Those describe the protocol, port offset in
the PORTSC registers, and port count. We use those registers to create
two arrays of pointers to the PORTSC registers, one for USB 3.0 ports, and
another for USB 2.0 ports. A third array keeps track of the port protocol
major revision, and is indexed with the internal xHCI port number.

This commit is a bit big, but it should be queued for stable because the "Don't
let the USB core disable SuperSpeed ports" patch depends on it. There is no
other way to determine which ports are SuperSpeed ports without this patch.

Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Tested-by: Don Zickus <dzickus@redhat.com>
Cc: stable@kernel.org

+190
+164
drivers/usb/host/xhci-mem.c
··· 1443 1443 xhci->dcbaa = NULL; 1444 1444 1445 1445 scratchpad_free(xhci); 1446 + 1447 + xhci->num_usb2_ports = 0; 1448 + xhci->num_usb3_ports = 0; 1449 + kfree(xhci->usb2_ports); 1450 + kfree(xhci->usb3_ports); 1451 + kfree(xhci->port_array); 1452 + 1446 1453 xhci->page_size = 0; 1447 1454 xhci->page_shift = 0; 1448 1455 xhci->bus_suspended = 0; ··· 1634 1627 &xhci->ir_set->erst_dequeue); 1635 1628 } 1636 1629 1630 + static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, 1631 + u32 __iomem *addr, u8 major_revision) 1632 + { 1633 + u32 temp, port_offset, port_count; 1634 + int i; 1635 + 1636 + if (major_revision > 0x03) { 1637 + xhci_warn(xhci, "Ignoring unknown port speed, " 1638 + "Ext Cap %p, revision = 0x%x\n", 1639 + addr, major_revision); 1640 + /* Ignoring port protocol we can't understand. FIXME */ 1641 + return; 1642 + } 1643 + 1644 + /* Port offset and count in the third dword, see section 7.2 */ 1645 + temp = xhci_readl(xhci, addr + 2); 1646 + port_offset = XHCI_EXT_PORT_OFF(temp); 1647 + port_count = XHCI_EXT_PORT_COUNT(temp); 1648 + xhci_dbg(xhci, "Ext Cap %p, port offset = %u, " 1649 + "count = %u, revision = 0x%x\n", 1650 + addr, port_offset, port_count, major_revision); 1651 + /* Port count includes the current port offset */ 1652 + if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) 1653 + /* WTF? "Valid values are ‘1’ to MaxPorts" */ 1654 + return; 1655 + port_offset--; 1656 + for (i = port_offset; i < (port_offset + port_count); i++) { 1657 + /* Duplicate entry. Ignore the port if the revisions differ. */ 1658 + if (xhci->port_array[i] != 0) { 1659 + xhci_warn(xhci, "Duplicate port entry, Ext Cap %p," 1660 + " port %u\n", addr, i); 1661 + xhci_warn(xhci, "Port was marked as USB %u, " 1662 + "duplicated as USB %u\n", 1663 + xhci->port_array[i], major_revision); 1664 + /* Only adjust the roothub port counts if we haven't 1665 + * found a similar duplicate. 1666 + */ 1667 + if (xhci->port_array[i] != major_revision && 1668 + xhci->port_array[i] != (u8) -1) { 1669 + if (xhci->port_array[i] == 0x03) 1670 + xhci->num_usb3_ports--; 1671 + else 1672 + xhci->num_usb2_ports--; 1673 + xhci->port_array[i] = (u8) -1; 1674 + } 1675 + /* FIXME: Should we disable the port? */ 1676 + } 1677 + xhci->port_array[i] = major_revision; 1678 + if (major_revision == 0x03) 1679 + xhci->num_usb3_ports++; 1680 + else 1681 + xhci->num_usb2_ports++; 1682 + } 1683 + /* FIXME: Should we disable ports not in the Extended Capabilities? */ 1684 + } 1685 + 1686 + /* 1687 + * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that 1688 + * specify what speeds each port is supposed to be. We can't count on the port 1689 + * speed bits in the PORTSC register being correct until a device is connected, 1690 + * but we need to set up the two fake roothubs with the correct number of USB 1691 + * 3.0 and USB 2.0 ports at host controller initialization time. 1692 + */ 1693 + static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) 1694 + { 1695 + u32 __iomem *addr; 1696 + u32 offset; 1697 + unsigned int num_ports; 1698 + int i, port_index; 1699 + 1700 + addr = &xhci->cap_regs->hcc_params; 1701 + offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr)); 1702 + if (offset == 0) { 1703 + xhci_err(xhci, "No Extended Capability registers, " 1704 + "unable to set up roothub.\n"); 1705 + return -ENODEV; 1706 + } 1707 + 1708 + num_ports = HCS_MAX_PORTS(xhci->hcs_params1); 1709 + xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags); 1710 + if (!xhci->port_array) 1711 + return -ENOMEM; 1712 + 1713 + /* 1714 + * For whatever reason, the first capability offset is from the 1715 + * capability register base, not from the HCCPARAMS register. 1716 + * See section 5.3.6 for offset calculation. 1717 + */ 1718 + addr = &xhci->cap_regs->hc_capbase + offset; 1719 + while (1) { 1720 + u32 cap_id; 1721 + 1722 + cap_id = xhci_readl(xhci, addr); 1723 + if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) 1724 + xhci_add_in_port(xhci, num_ports, addr, 1725 + (u8) XHCI_EXT_PORT_MAJOR(cap_id)); 1726 + offset = XHCI_EXT_CAPS_NEXT(cap_id); 1727 + if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports) 1728 + == num_ports) 1729 + break; 1730 + /* 1731 + * Once you're into the Extended Capabilities, the offset is 1732 + * always relative to the register holding the offset. 1733 + */ 1734 + addr += offset; 1735 + } 1736 + 1737 + if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) { 1738 + xhci_warn(xhci, "No ports on the roothubs?\n"); 1739 + return -ENODEV; 1740 + } 1741 + xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n", 1742 + xhci->num_usb2_ports, xhci->num_usb3_ports); 1743 + /* 1744 + * Note we could have all USB 3.0 ports, or all USB 2.0 ports. 1745 + * Not sure how the USB core will handle a hub with no ports... 1746 + */ 1747 + if (xhci->num_usb2_ports) { 1748 + xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)* 1749 + xhci->num_usb2_ports, flags); 1750 + if (!xhci->usb2_ports) 1751 + return -ENOMEM; 1752 + 1753 + port_index = 0; 1754 + for (i = 0; i < num_ports; i++) 1755 + if (xhci->port_array[i] != 0x03) { 1756 + xhci->usb2_ports[port_index] = 1757 + &xhci->op_regs->port_status_base + 1758 + NUM_PORT_REGS*i; 1759 + xhci_dbg(xhci, "USB 2.0 port at index %u, " 1760 + "addr = %p\n", i, 1761 + xhci->usb2_ports[port_index]); 1762 + port_index++; 1763 + } 1764 + } 1765 + if (xhci->num_usb3_ports) { 1766 + xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)* 1767 + xhci->num_usb3_ports, flags); 1768 + if (!xhci->usb3_ports) 1769 + return -ENOMEM; 1770 + 1771 + port_index = 0; 1772 + for (i = 0; i < num_ports; i++) 1773 + if (xhci->port_array[i] == 0x03) { 1774 + xhci->usb3_ports[port_index] = 1775 + &xhci->op_regs->port_status_base + 1776 + NUM_PORT_REGS*i; 1777 + xhci_dbg(xhci, "USB 3.0 port at index %u, " 1778 + "addr = %p\n", i, 1779 + xhci->usb3_ports[port_index]); 1780 + port_index++; 1781 + } 1782 + } 1783 + return 0; 1784 + } 1637 1785 1638 1786 int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) 1639 1787 { ··· 1970 1808 xhci->resume_done[i] = 0; 1971 1809 1972 1810 if (scratchpad_alloc(xhci, flags)) 1811 + goto fail; 1812 + if (xhci_setup_port_arrays(xhci, flags)) 1973 1813 goto fail; 1974 1814 1975 1815 return 0;
+26
drivers/usb/host/xhci.h
··· 454 454 455 455 456 456 /** 457 + * struct xhci_protocol_caps 458 + * @revision: major revision, minor revision, capability ID, 459 + * and next capability pointer. 460 + * @name_string: Four ASCII characters to say which spec this xHC 461 + * follows, typically "USB ". 462 + * @port_info: Port offset, count, and protocol-defined information. 463 + */ 464 + struct xhci_protocol_caps { 465 + u32 revision; 466 + u32 name_string; 467 + u32 port_info; 468 + }; 469 + 470 + #define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff) 471 + #define XHCI_EXT_PORT_OFF(x) ((x) & 0xff) 472 + #define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff) 473 + 474 + /** 457 475 * struct xhci_container_ctx 458 476 * @type: Type of context. Used to calculated offsets to contained contexts. 459 477 * @size: Size of the context data ··· 1258 1240 u32 suspended_ports[8]; /* which ports are 1259 1241 suspended */ 1260 1242 unsigned long resume_done[MAX_HC_PORTS]; 1243 + /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */ 1244 + u8 *port_array; 1245 + /* Array of pointers to USB 3.0 PORTSC registers */ 1246 + u32 __iomem **usb3_ports; 1247 + unsigned int num_usb3_ports; 1248 + /* Array of pointers to USB 2.0 PORTSC registers */ 1249 + u32 __iomem **usb2_ports; 1250 + unsigned int num_usb2_ports; 1261 1251 }; 1262 1252 1263 1253 /* For testing purposes */