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