diff options
Diffstat (limited to 'drivers/usb/host/xhci-mem.c')
| -rw-r--r-- | drivers/usb/host/xhci-mem.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d178761c3981..1d0f45f0e7a6 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
| @@ -1443,6 +1443,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) | |||
| 1443 | xhci->dcbaa = NULL; | 1443 | xhci->dcbaa = NULL; |
| 1444 | 1444 | ||
| 1445 | scratchpad_free(xhci); | 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 | xhci->page_size = 0; | 1453 | xhci->page_size = 0; |
| 1447 | xhci->page_shift = 0; | 1454 | xhci->page_shift = 0; |
| 1448 | xhci->bus_suspended = 0; | 1455 | xhci->bus_suspended = 0; |
| @@ -1627,6 +1634,166 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci) | |||
| 1627 | &xhci->ir_set->erst_dequeue); | 1634 | &xhci->ir_set->erst_dequeue); |
| 1628 | } | 1635 | } |
| 1629 | 1636 | ||
| 1637 | static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, | ||
| 1638 | u32 __iomem *addr, u8 major_revision) | ||
| 1639 | { | ||
| 1640 | u32 temp, port_offset, port_count; | ||
| 1641 | int i; | ||
| 1642 | |||
| 1643 | if (major_revision > 0x03) { | ||
| 1644 | xhci_warn(xhci, "Ignoring unknown port speed, " | ||
| 1645 | "Ext Cap %p, revision = 0x%x\n", | ||
| 1646 | addr, major_revision); | ||
| 1647 | /* Ignoring port protocol we can't understand. FIXME */ | ||
| 1648 | return; | ||
| 1649 | } | ||
| 1650 | |||
| 1651 | /* Port offset and count in the third dword, see section 7.2 */ | ||
| 1652 | temp = xhci_readl(xhci, addr + 2); | ||
| 1653 | port_offset = XHCI_EXT_PORT_OFF(temp); | ||
| 1654 | port_count = XHCI_EXT_PORT_COUNT(temp); | ||
| 1655 | xhci_dbg(xhci, "Ext Cap %p, port offset = %u, " | ||
| 1656 | "count = %u, revision = 0x%x\n", | ||
| 1657 | addr, port_offset, port_count, major_revision); | ||
| 1658 | /* Port count includes the current port offset */ | ||
| 1659 | if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) | ||
| 1660 | /* WTF? "Valid values are ‘1’ to MaxPorts" */ | ||
| 1661 | return; | ||
| 1662 | port_offset--; | ||
| 1663 | for (i = port_offset; i < (port_offset + port_count); i++) { | ||
| 1664 | /* Duplicate entry. Ignore the port if the revisions differ. */ | ||
| 1665 | if (xhci->port_array[i] != 0) { | ||
| 1666 | xhci_warn(xhci, "Duplicate port entry, Ext Cap %p," | ||
| 1667 | " port %u\n", addr, i); | ||
| 1668 | xhci_warn(xhci, "Port was marked as USB %u, " | ||
| 1669 | "duplicated as USB %u\n", | ||
| 1670 | xhci->port_array[i], major_revision); | ||
| 1671 | /* Only adjust the roothub port counts if we haven't | ||
| 1672 | * found a similar duplicate. | ||
| 1673 | */ | ||
| 1674 | if (xhci->port_array[i] != major_revision && | ||
| 1675 | xhci->port_array[i] != (u8) -1) { | ||
| 1676 | if (xhci->port_array[i] == 0x03) | ||
| 1677 | xhci->num_usb3_ports--; | ||
| 1678 | else | ||
| 1679 | xhci->num_usb2_ports--; | ||
| 1680 | xhci->port_array[i] = (u8) -1; | ||
| 1681 | } | ||
| 1682 | /* FIXME: Should we disable the port? */ | ||
| 1683 | continue; | ||
| 1684 | } | ||
| 1685 | xhci->port_array[i] = major_revision; | ||
| 1686 | if (major_revision == 0x03) | ||
| 1687 | xhci->num_usb3_ports++; | ||
| 1688 | else | ||
| 1689 | xhci->num_usb2_ports++; | ||
| 1690 | } | ||
| 1691 | /* FIXME: Should we disable ports not in the Extended Capabilities? */ | ||
| 1692 | } | ||
| 1693 | |||
| 1694 | /* | ||
| 1695 | * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that | ||
| 1696 | * specify what speeds each port is supposed to be. We can't count on the port | ||
| 1697 | * speed bits in the PORTSC register being correct until a device is connected, | ||
| 1698 | * but we need to set up the two fake roothubs with the correct number of USB | ||
| 1699 | * 3.0 and USB 2.0 ports at host controller initialization time. | ||
| 1700 | */ | ||
| 1701 | static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) | ||
| 1702 | { | ||
| 1703 | u32 __iomem *addr; | ||
| 1704 | u32 offset; | ||
| 1705 | unsigned int num_ports; | ||
| 1706 | int i, port_index; | ||
| 1707 | |||
| 1708 | addr = &xhci->cap_regs->hcc_params; | ||
| 1709 | offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr)); | ||
| 1710 | if (offset == 0) { | ||
| 1711 | xhci_err(xhci, "No Extended Capability registers, " | ||
| 1712 | "unable to set up roothub.\n"); | ||
| 1713 | return -ENODEV; | ||
| 1714 | } | ||
| 1715 | |||
| 1716 | num_ports = HCS_MAX_PORTS(xhci->hcs_params1); | ||
| 1717 | xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags); | ||
| 1718 | if (!xhci->port_array) | ||
| 1719 | return -ENOMEM; | ||
| 1720 | |||
| 1721 | /* | ||
| 1722 | * For whatever reason, the first capability offset is from the | ||
| 1723 | * capability register base, not from the HCCPARAMS register. | ||
| 1724 | * See section 5.3.6 for offset calculation. | ||
| 1725 | */ | ||
| 1726 | addr = &xhci->cap_regs->hc_capbase + offset; | ||
| 1727 | while (1) { | ||
| 1728 | u32 cap_id; | ||
| 1729 | |||
| 1730 | cap_id = xhci_readl(xhci, addr); | ||
| 1731 | if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) | ||
| 1732 | xhci_add_in_port(xhci, num_ports, addr, | ||
| 1733 | (u8) XHCI_EXT_PORT_MAJOR(cap_id)); | ||
| 1734 | offset = XHCI_EXT_CAPS_NEXT(cap_id); | ||
| 1735 | if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports) | ||
| 1736 | == num_ports) | ||
| 1737 | break; | ||
| 1738 | /* | ||
| 1739 | * Once you're into the Extended Capabilities, the offset is | ||
| 1740 | * always relative to the register holding the offset. | ||
| 1741 | */ | ||
| 1742 | addr += offset; | ||
| 1743 | } | ||
| 1744 | |||
| 1745 | if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) { | ||
| 1746 | xhci_warn(xhci, "No ports on the roothubs?\n"); | ||
| 1747 | return -ENODEV; | ||
| 1748 | } | ||
| 1749 | xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n", | ||
| 1750 | xhci->num_usb2_ports, xhci->num_usb3_ports); | ||
| 1751 | /* | ||
| 1752 | * Note we could have all USB 3.0 ports, or all USB 2.0 ports. | ||
| 1753 | * Not sure how the USB core will handle a hub with no ports... | ||
| 1754 | */ | ||
| 1755 | if (xhci->num_usb2_ports) { | ||
| 1756 | xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)* | ||
| 1757 | xhci->num_usb2_ports, flags); | ||
| 1758 | if (!xhci->usb2_ports) | ||
| 1759 | return -ENOMEM; | ||
| 1760 | |||
| 1761 | port_index = 0; | ||
| 1762 | for (i = 0; i < num_ports; i++) { | ||
| 1763 | if (xhci->port_array[i] == 0x03 || | ||
| 1764 | xhci->port_array[i] == 0 || | ||
| 1765 | xhci->port_array[i] == -1) | ||
| 1766 | continue; | ||
| 1767 | |||
| 1768 | xhci->usb2_ports[port_index] = | ||
| 1769 | &xhci->op_regs->port_status_base + | ||
| 1770 | NUM_PORT_REGS*i; | ||
| 1771 | xhci_dbg(xhci, "USB 2.0 port at index %u, " | ||
| 1772 | "addr = %p\n", i, | ||
| 1773 | xhci->usb2_ports[port_index]); | ||
| 1774 | port_index++; | ||
| 1775 | } | ||
| 1776 | } | ||
| 1777 | if (xhci->num_usb3_ports) { | ||
| 1778 | xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)* | ||
| 1779 | xhci->num_usb3_ports, flags); | ||
| 1780 | if (!xhci->usb3_ports) | ||
| 1781 | return -ENOMEM; | ||
| 1782 | |||
| 1783 | port_index = 0; | ||
| 1784 | for (i = 0; i < num_ports; i++) | ||
| 1785 | if (xhci->port_array[i] == 0x03) { | ||
| 1786 | xhci->usb3_ports[port_index] = | ||
| 1787 | &xhci->op_regs->port_status_base + | ||
| 1788 | NUM_PORT_REGS*i; | ||
| 1789 | xhci_dbg(xhci, "USB 3.0 port at index %u, " | ||
| 1790 | "addr = %p\n", i, | ||
| 1791 | xhci->usb3_ports[port_index]); | ||
| 1792 | port_index++; | ||
| 1793 | } | ||
| 1794 | } | ||
| 1795 | return 0; | ||
| 1796 | } | ||
| 1630 | 1797 | ||
| 1631 | int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) | 1798 | int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) |
| 1632 | { | 1799 | { |
| @@ -1809,6 +1976,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) | |||
| 1809 | 1976 | ||
| 1810 | if (scratchpad_alloc(xhci, flags)) | 1977 | if (scratchpad_alloc(xhci, flags)) |
| 1811 | goto fail; | 1978 | goto fail; |
| 1979 | if (xhci_setup_port_arrays(xhci, flags)) | ||
| 1980 | goto fail; | ||
| 1812 | 1981 | ||
| 1813 | return 0; | 1982 | return 0; |
| 1814 | 1983 | ||
