diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-11-30 18:38:41 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-11-30 18:38:41 -0500 |
| commit | 8244272341f00cab845cabc445dbd3665fc01f87 (patch) | |
| tree | 3a0d426b2aaf24c78e5b3b1f7c31e9210186aa8d | |
| parent | abf03184a31a3286fc0ab30f838ddee8ba9f9b7b (diff) | |
| parent | 6dd0a3a7e0793dbeae1b951f091025d8cf896cb4 (diff) | |
Merge branch 'for-usb-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into work
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 7 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-mem.c | 164 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.c | 18 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.h | 26 |
4 files changed, 215 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index fef5a1f9d483..5d963e350494 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
| @@ -229,6 +229,13 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id) | |||
| 229 | static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex, | 229 | static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex, |
| 230 | u32 __iomem *addr, u32 port_status) | 230 | u32 __iomem *addr, u32 port_status) |
| 231 | { | 231 | { |
| 232 | /* Don't allow the USB core to disable SuperSpeed ports. */ | ||
| 233 | if (xhci->port_array[wIndex] == 0x03) { | ||
| 234 | xhci_dbg(xhci, "Ignoring request to disable " | ||
| 235 | "SuperSpeed port.\n"); | ||
| 236 | return; | ||
| 237 | } | ||
| 238 | |||
| 232 | /* Write 1 to disable the port */ | 239 | /* Write 1 to disable the port */ |
| 233 | xhci_writel(xhci, port_status | PORT_PE, addr); | 240 | xhci_writel(xhci, port_status | PORT_PE, addr); |
| 234 | port_status = xhci_readl(xhci, addr); | 241 | port_status = xhci_readl(xhci, addr); |
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d178761c3981..0fae58ef8afe 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,161 @@ 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 | } | ||
| 1684 | xhci->port_array[i] = major_revision; | ||
| 1685 | if (major_revision == 0x03) | ||
| 1686 | xhci->num_usb3_ports++; | ||
| 1687 | else | ||
| 1688 | xhci->num_usb2_ports++; | ||
| 1689 | } | ||
| 1690 | /* FIXME: Should we disable ports not in the Extended Capabilities? */ | ||
| 1691 | } | ||
| 1692 | |||
| 1693 | /* | ||
| 1694 | * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that | ||
| 1695 | * specify what speeds each port is supposed to be. We can't count on the port | ||
| 1696 | * speed bits in the PORTSC register being correct until a device is connected, | ||
| 1697 | * but we need to set up the two fake roothubs with the correct number of USB | ||
| 1698 | * 3.0 and USB 2.0 ports at host controller initialization time. | ||
| 1699 | */ | ||
| 1700 | static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) | ||
| 1701 | { | ||
| 1702 | u32 __iomem *addr; | ||
| 1703 | u32 offset; | ||
| 1704 | unsigned int num_ports; | ||
| 1705 | int i, port_index; | ||
| 1706 | |||
| 1707 | addr = &xhci->cap_regs->hcc_params; | ||
| 1708 | offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr)); | ||
| 1709 | if (offset == 0) { | ||
| 1710 | xhci_err(xhci, "No Extended Capability registers, " | ||
| 1711 | "unable to set up roothub.\n"); | ||
| 1712 | return -ENODEV; | ||
| 1713 | } | ||
| 1714 | |||
| 1715 | num_ports = HCS_MAX_PORTS(xhci->hcs_params1); | ||
| 1716 | xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags); | ||
| 1717 | if (!xhci->port_array) | ||
| 1718 | return -ENOMEM; | ||
| 1719 | |||
| 1720 | /* | ||
| 1721 | * For whatever reason, the first capability offset is from the | ||
| 1722 | * capability register base, not from the HCCPARAMS register. | ||
| 1723 | * See section 5.3.6 for offset calculation. | ||
| 1724 | */ | ||
| 1725 | addr = &xhci->cap_regs->hc_capbase + offset; | ||
| 1726 | while (1) { | ||
| 1727 | u32 cap_id; | ||
| 1728 | |||
| 1729 | cap_id = xhci_readl(xhci, addr); | ||
| 1730 | if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) | ||
| 1731 | xhci_add_in_port(xhci, num_ports, addr, | ||
| 1732 | (u8) XHCI_EXT_PORT_MAJOR(cap_id)); | ||
| 1733 | offset = XHCI_EXT_CAPS_NEXT(cap_id); | ||
| 1734 | if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports) | ||
| 1735 | == num_ports) | ||
| 1736 | break; | ||
| 1737 | /* | ||
| 1738 | * Once you're into the Extended Capabilities, the offset is | ||
| 1739 | * always relative to the register holding the offset. | ||
| 1740 | */ | ||
| 1741 | addr += offset; | ||
| 1742 | } | ||
| 1743 | |||
| 1744 | if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) { | ||
| 1745 | xhci_warn(xhci, "No ports on the roothubs?\n"); | ||
| 1746 | return -ENODEV; | ||
| 1747 | } | ||
| 1748 | xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n", | ||
| 1749 | xhci->num_usb2_ports, xhci->num_usb3_ports); | ||
| 1750 | /* | ||
| 1751 | * Note we could have all USB 3.0 ports, or all USB 2.0 ports. | ||
| 1752 | * Not sure how the USB core will handle a hub with no ports... | ||
| 1753 | */ | ||
| 1754 | if (xhci->num_usb2_ports) { | ||
| 1755 | xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)* | ||
| 1756 | xhci->num_usb2_ports, flags); | ||
| 1757 | if (!xhci->usb2_ports) | ||
| 1758 | return -ENOMEM; | ||
| 1759 | |||
| 1760 | port_index = 0; | ||
| 1761 | for (i = 0; i < num_ports; i++) | ||
| 1762 | if (xhci->port_array[i] != 0x03) { | ||
| 1763 | xhci->usb2_ports[port_index] = | ||
| 1764 | &xhci->op_regs->port_status_base + | ||
| 1765 | NUM_PORT_REGS*i; | ||
| 1766 | xhci_dbg(xhci, "USB 2.0 port at index %u, " | ||
| 1767 | "addr = %p\n", i, | ||
| 1768 | xhci->usb2_ports[port_index]); | ||
| 1769 | port_index++; | ||
| 1770 | } | ||
| 1771 | } | ||
| 1772 | if (xhci->num_usb3_ports) { | ||
| 1773 | xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)* | ||
| 1774 | xhci->num_usb3_ports, flags); | ||
| 1775 | if (!xhci->usb3_ports) | ||
| 1776 | return -ENOMEM; | ||
| 1777 | |||
| 1778 | port_index = 0; | ||
| 1779 | for (i = 0; i < num_ports; i++) | ||
| 1780 | if (xhci->port_array[i] == 0x03) { | ||
| 1781 | xhci->usb3_ports[port_index] = | ||
| 1782 | &xhci->op_regs->port_status_base + | ||
| 1783 | NUM_PORT_REGS*i; | ||
| 1784 | xhci_dbg(xhci, "USB 3.0 port at index %u, " | ||
| 1785 | "addr = %p\n", i, | ||
| 1786 | xhci->usb3_ports[port_index]); | ||
| 1787 | port_index++; | ||
| 1788 | } | ||
| 1789 | } | ||
| 1790 | return 0; | ||
| 1791 | } | ||
| 1630 | 1792 | ||
| 1631 | int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) | 1793 | int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) |
| 1632 | { | 1794 | { |
| @@ -1809,6 +1971,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) | |||
| 1809 | 1971 | ||
| 1810 | if (scratchpad_alloc(xhci, flags)) | 1972 | if (scratchpad_alloc(xhci, flags)) |
| 1811 | goto fail; | 1973 | goto fail; |
| 1974 | if (xhci_setup_port_arrays(xhci, flags)) | ||
| 1975 | goto fail; | ||
| 1812 | 1976 | ||
| 1813 | return 0; | 1977 | return 0; |
| 1814 | 1978 | ||
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 06fca0835b52..45e4a3108cc3 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
| @@ -1549,6 +1549,15 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, | |||
| 1549 | cmd_completion = command->completion; | 1549 | cmd_completion = command->completion; |
| 1550 | cmd_status = &command->status; | 1550 | cmd_status = &command->status; |
| 1551 | command->command_trb = xhci->cmd_ring->enqueue; | 1551 | command->command_trb = xhci->cmd_ring->enqueue; |
| 1552 | |||
| 1553 | /* Enqueue pointer can be left pointing to the link TRB, | ||
| 1554 | * we must handle that | ||
| 1555 | */ | ||
| 1556 | if ((command->command_trb->link.control & TRB_TYPE_BITMASK) | ||
| 1557 | == TRB_TYPE(TRB_LINK)) | ||
| 1558 | command->command_trb = | ||
| 1559 | xhci->cmd_ring->enq_seg->next->trbs; | ||
| 1560 | |||
| 1552 | list_add_tail(&command->cmd_list, &virt_dev->cmd_list); | 1561 | list_add_tail(&command->cmd_list, &virt_dev->cmd_list); |
| 1553 | } else { | 1562 | } else { |
| 1554 | in_ctx = virt_dev->in_ctx; | 1563 | in_ctx = virt_dev->in_ctx; |
| @@ -2272,6 +2281,15 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) | |||
| 2272 | /* Attempt to submit the Reset Device command to the command ring */ | 2281 | /* Attempt to submit the Reset Device command to the command ring */ |
| 2273 | spin_lock_irqsave(&xhci->lock, flags); | 2282 | spin_lock_irqsave(&xhci->lock, flags); |
| 2274 | reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; | 2283 | reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; |
| 2284 | |||
| 2285 | /* Enqueue pointer can be left pointing to the link TRB, | ||
| 2286 | * we must handle that | ||
| 2287 | */ | ||
| 2288 | if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK) | ||
| 2289 | == TRB_TYPE(TRB_LINK)) | ||
| 2290 | reset_device_cmd->command_trb = | ||
| 2291 | xhci->cmd_ring->enq_seg->next->trbs; | ||
| 2292 | |||
| 2275 | list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); | 2293 | list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); |
| 2276 | ret = xhci_queue_reset_device(xhci, slot_id); | 2294 | ret = xhci_queue_reset_device(xhci, slot_id); |
| 2277 | if (ret) { | 2295 | if (ret) { |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 85e65647d445..170c367112d2 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
| @@ -454,6 +454,24 @@ struct xhci_doorbell_array { | |||
| 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 | * struct xhci_container_ctx | 475 | * struct xhci_container_ctx |
| 458 | * @type: Type of context. Used to calculated offsets to contained contexts. | 476 | * @type: Type of context. Used to calculated offsets to contained contexts. |
| 459 | * @size: Size of the context data | 477 | * @size: Size of the context data |
| @@ -1240,6 +1258,14 @@ struct xhci_hcd { | |||
| 1240 | u32 suspended_ports[8]; /* which ports are | 1258 | u32 suspended_ports[8]; /* which ports are |
| 1241 | suspended */ | 1259 | suspended */ |
| 1242 | unsigned long resume_done[MAX_HC_PORTS]; | 1260 | unsigned long resume_done[MAX_HC_PORTS]; |
| 1261 | /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */ | ||
| 1262 | u8 *port_array; | ||
| 1263 | /* Array of pointers to USB 3.0 PORTSC registers */ | ||
| 1264 | u32 __iomem **usb3_ports; | ||
| 1265 | unsigned int num_usb3_ports; | ||
| 1266 | /* Array of pointers to USB 2.0 PORTSC registers */ | ||
| 1267 | u32 __iomem **usb2_ports; | ||
| 1268 | unsigned int num_usb2_ports; | ||
| 1243 | }; | 1269 | }; |
| 1244 | 1270 | ||
| 1245 | /* For testing purposes */ | 1271 | /* For testing purposes */ |
