Loading drivers/usb/host/xhci-hub.c +7 −0 Original line number Diff line number Diff line Loading @@ -229,6 +229,13 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id) static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex, u32 __iomem *addr, u32 port_status) { /* Don't allow the USB core to disable SuperSpeed ports. */ if (xhci->port_array[wIndex] == 0x03) { xhci_dbg(xhci, "Ignoring request to disable " "SuperSpeed port.\n"); return; } /* Write 1 to disable the port */ xhci_writel(xhci, port_status | PORT_PE, addr); port_status = xhci_readl(xhci, addr); Loading drivers/usb/host/xhci-mem.c +164 −0 Original line number Diff line number Diff line Loading @@ -1443,6 +1443,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->dcbaa = NULL; scratchpad_free(xhci); xhci->num_usb2_ports = 0; xhci->num_usb3_ports = 0; kfree(xhci->usb2_ports); kfree(xhci->usb3_ports); kfree(xhci->port_array); xhci->page_size = 0; xhci->page_shift = 0; xhci->bus_suspended = 0; Loading Loading @@ -1627,6 +1634,161 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci) &xhci->ir_set->erst_dequeue); } static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, u32 __iomem *addr, u8 major_revision) { u32 temp, port_offset, port_count; int i; if (major_revision > 0x03) { 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; } /* Port offset and count in the third dword, see section 7.2 */ temp = xhci_readl(xhci, addr + 2); port_offset = XHCI_EXT_PORT_OFF(temp); port_count = XHCI_EXT_PORT_COUNT(temp); xhci_dbg(xhci, "Ext Cap %p, port offset = %u, " "count = %u, revision = 0x%x\n", addr, port_offset, port_count, major_revision); /* Port count includes the current port offset */ if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) /* WTF? "Valid values are ‘1’ to MaxPorts" */ return; port_offset--; for (i = port_offset; i < (port_offset + port_count); i++) { /* Duplicate entry. Ignore the port if the revisions differ. */ if (xhci->port_array[i] != 0) { xhci_warn(xhci, "Duplicate port entry, Ext Cap %p," " port %u\n", addr, i); xhci_warn(xhci, "Port was marked as USB %u, " "duplicated as USB %u\n", xhci->port_array[i], major_revision); /* Only adjust the roothub port counts if we haven't * found a similar duplicate. */ if (xhci->port_array[i] != major_revision && xhci->port_array[i] != (u8) -1) { if (xhci->port_array[i] == 0x03) xhci->num_usb3_ports--; else xhci->num_usb2_ports--; xhci->port_array[i] = (u8) -1; } /* FIXME: Should we disable the port? */ } xhci->port_array[i] = major_revision; if (major_revision == 0x03) xhci->num_usb3_ports++; else xhci->num_usb2_ports++; } /* FIXME: Should we disable ports not in the Extended Capabilities? */ } /* * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that * specify what speeds each port is supposed to be. We can't count on the port * speed bits in the PORTSC register being correct until a device is connected, * but we need to set up the two fake roothubs with the correct number of USB * 3.0 and USB 2.0 ports at host controller initialization time. */ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) { u32 __iomem *addr; u32 offset; unsigned int num_ports; int i, port_index; addr = &xhci->cap_regs->hcc_params; offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr)); if (offset == 0) { xhci_err(xhci, "No Extended Capability registers, " "unable to set up roothub.\n"); return -ENODEV; } num_ports = HCS_MAX_PORTS(xhci->hcs_params1); xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags); if (!xhci->port_array) return -ENOMEM; /* * For whatever reason, the first capability offset is from the * capability register base, not from the HCCPARAMS register. * See section 5.3.6 for offset calculation. */ addr = &xhci->cap_regs->hc_capbase + offset; while (1) { u32 cap_id; cap_id = xhci_readl(xhci, addr); if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) xhci_add_in_port(xhci, num_ports, addr, (u8) XHCI_EXT_PORT_MAJOR(cap_id)); offset = XHCI_EXT_CAPS_NEXT(cap_id); if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports) == num_ports) break; /* * Once you're into the Extended Capabilities, the offset is * always relative to the register holding the offset. */ addr += offset; } if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) { xhci_warn(xhci, "No ports on the roothubs?\n"); return -ENODEV; } xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n", xhci->num_usb2_ports, xhci->num_usb3_ports); /* * Note we could have all USB 3.0 ports, or all USB 2.0 ports. * Not sure how the USB core will handle a hub with no ports... */ if (xhci->num_usb2_ports) { xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)* xhci->num_usb2_ports, flags); if (!xhci->usb2_ports) return -ENOMEM; port_index = 0; for (i = 0; i < num_ports; i++) if (xhci->port_array[i] != 0x03) { xhci->usb2_ports[port_index] = &xhci->op_regs->port_status_base + NUM_PORT_REGS*i; xhci_dbg(xhci, "USB 2.0 port at index %u, " "addr = %p\n", i, xhci->usb2_ports[port_index]); port_index++; } } if (xhci->num_usb3_ports) { xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)* xhci->num_usb3_ports, flags); if (!xhci->usb3_ports) return -ENOMEM; port_index = 0; for (i = 0; i < num_ports; i++) if (xhci->port_array[i] == 0x03) { xhci->usb3_ports[port_index] = &xhci->op_regs->port_status_base + NUM_PORT_REGS*i; xhci_dbg(xhci, "USB 3.0 port at index %u, " "addr = %p\n", i, xhci->usb3_ports[port_index]); port_index++; } } return 0; } int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) { Loading Loading @@ -1809,6 +1971,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) if (scratchpad_alloc(xhci, flags)) goto fail; if (xhci_setup_port_arrays(xhci, flags)) goto fail; return 0; Loading drivers/usb/host/xhci.c +18 −0 Original line number Diff line number Diff line Loading @@ -1549,6 +1549,15 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, cmd_completion = command->completion; cmd_status = &command->status; command->command_trb = xhci->cmd_ring->enqueue; /* Enqueue pointer can be left pointing to the link TRB, * we must handle that */ if ((command->command_trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)) command->command_trb = xhci->cmd_ring->enq_seg->next->trbs; list_add_tail(&command->cmd_list, &virt_dev->cmd_list); } else { in_ctx = virt_dev->in_ctx; Loading Loading @@ -2272,6 +2281,15 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Attempt to submit the Reset Device command to the command ring */ spin_lock_irqsave(&xhci->lock, flags); reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; /* Enqueue pointer can be left pointing to the link TRB, * we must handle that */ if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)) reset_device_cmd->command_trb = xhci->cmd_ring->enq_seg->next->trbs; list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); ret = xhci_queue_reset_device(xhci, slot_id); if (ret) { Loading drivers/usb/host/xhci.h +26 −0 Original line number Diff line number Diff line Loading @@ -453,6 +453,24 @@ struct xhci_doorbell_array { #define STREAM_ID_TO_DB(p) (((p) & 0xffff) << 16) /** * struct xhci_protocol_caps * @revision: major revision, minor revision, capability ID, * and next capability pointer. * @name_string: Four ASCII characters to say which spec this xHC * follows, typically "USB ". * @port_info: Port offset, count, and protocol-defined information. */ struct xhci_protocol_caps { u32 revision; u32 name_string; u32 port_info; }; #define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff) #define XHCI_EXT_PORT_OFF(x) ((x) & 0xff) #define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff) /** * struct xhci_container_ctx * @type: Type of context. Used to calculated offsets to contained contexts. Loading Loading @@ -1240,6 +1258,14 @@ struct xhci_hcd { u32 suspended_ports[8]; /* which ports are suspended */ unsigned long resume_done[MAX_HC_PORTS]; /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */ u8 *port_array; /* Array of pointers to USB 3.0 PORTSC registers */ u32 __iomem **usb3_ports; unsigned int num_usb3_ports; /* Array of pointers to USB 2.0 PORTSC registers */ u32 __iomem **usb2_ports; unsigned int num_usb2_ports; }; /* For testing purposes */ Loading Loading
drivers/usb/host/xhci-hub.c +7 −0 Original line number Diff line number Diff line Loading @@ -229,6 +229,13 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id) static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex, u32 __iomem *addr, u32 port_status) { /* Don't allow the USB core to disable SuperSpeed ports. */ if (xhci->port_array[wIndex] == 0x03) { xhci_dbg(xhci, "Ignoring request to disable " "SuperSpeed port.\n"); return; } /* Write 1 to disable the port */ xhci_writel(xhci, port_status | PORT_PE, addr); port_status = xhci_readl(xhci, addr); Loading
drivers/usb/host/xhci-mem.c +164 −0 Original line number Diff line number Diff line Loading @@ -1443,6 +1443,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->dcbaa = NULL; scratchpad_free(xhci); xhci->num_usb2_ports = 0; xhci->num_usb3_ports = 0; kfree(xhci->usb2_ports); kfree(xhci->usb3_ports); kfree(xhci->port_array); xhci->page_size = 0; xhci->page_shift = 0; xhci->bus_suspended = 0; Loading Loading @@ -1627,6 +1634,161 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci) &xhci->ir_set->erst_dequeue); } static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, u32 __iomem *addr, u8 major_revision) { u32 temp, port_offset, port_count; int i; if (major_revision > 0x03) { 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; } /* Port offset and count in the third dword, see section 7.2 */ temp = xhci_readl(xhci, addr + 2); port_offset = XHCI_EXT_PORT_OFF(temp); port_count = XHCI_EXT_PORT_COUNT(temp); xhci_dbg(xhci, "Ext Cap %p, port offset = %u, " "count = %u, revision = 0x%x\n", addr, port_offset, port_count, major_revision); /* Port count includes the current port offset */ if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) /* WTF? "Valid values are ‘1’ to MaxPorts" */ return; port_offset--; for (i = port_offset; i < (port_offset + port_count); i++) { /* Duplicate entry. Ignore the port if the revisions differ. */ if (xhci->port_array[i] != 0) { xhci_warn(xhci, "Duplicate port entry, Ext Cap %p," " port %u\n", addr, i); xhci_warn(xhci, "Port was marked as USB %u, " "duplicated as USB %u\n", xhci->port_array[i], major_revision); /* Only adjust the roothub port counts if we haven't * found a similar duplicate. */ if (xhci->port_array[i] != major_revision && xhci->port_array[i] != (u8) -1) { if (xhci->port_array[i] == 0x03) xhci->num_usb3_ports--; else xhci->num_usb2_ports--; xhci->port_array[i] = (u8) -1; } /* FIXME: Should we disable the port? */ } xhci->port_array[i] = major_revision; if (major_revision == 0x03) xhci->num_usb3_ports++; else xhci->num_usb2_ports++; } /* FIXME: Should we disable ports not in the Extended Capabilities? */ } /* * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that * specify what speeds each port is supposed to be. We can't count on the port * speed bits in the PORTSC register being correct until a device is connected, * but we need to set up the two fake roothubs with the correct number of USB * 3.0 and USB 2.0 ports at host controller initialization time. */ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) { u32 __iomem *addr; u32 offset; unsigned int num_ports; int i, port_index; addr = &xhci->cap_regs->hcc_params; offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr)); if (offset == 0) { xhci_err(xhci, "No Extended Capability registers, " "unable to set up roothub.\n"); return -ENODEV; } num_ports = HCS_MAX_PORTS(xhci->hcs_params1); xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags); if (!xhci->port_array) return -ENOMEM; /* * For whatever reason, the first capability offset is from the * capability register base, not from the HCCPARAMS register. * See section 5.3.6 for offset calculation. */ addr = &xhci->cap_regs->hc_capbase + offset; while (1) { u32 cap_id; cap_id = xhci_readl(xhci, addr); if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) xhci_add_in_port(xhci, num_ports, addr, (u8) XHCI_EXT_PORT_MAJOR(cap_id)); offset = XHCI_EXT_CAPS_NEXT(cap_id); if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports) == num_ports) break; /* * Once you're into the Extended Capabilities, the offset is * always relative to the register holding the offset. */ addr += offset; } if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) { xhci_warn(xhci, "No ports on the roothubs?\n"); return -ENODEV; } xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n", xhci->num_usb2_ports, xhci->num_usb3_ports); /* * Note we could have all USB 3.0 ports, or all USB 2.0 ports. * Not sure how the USB core will handle a hub with no ports... */ if (xhci->num_usb2_ports) { xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)* xhci->num_usb2_ports, flags); if (!xhci->usb2_ports) return -ENOMEM; port_index = 0; for (i = 0; i < num_ports; i++) if (xhci->port_array[i] != 0x03) { xhci->usb2_ports[port_index] = &xhci->op_regs->port_status_base + NUM_PORT_REGS*i; xhci_dbg(xhci, "USB 2.0 port at index %u, " "addr = %p\n", i, xhci->usb2_ports[port_index]); port_index++; } } if (xhci->num_usb3_ports) { xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)* xhci->num_usb3_ports, flags); if (!xhci->usb3_ports) return -ENOMEM; port_index = 0; for (i = 0; i < num_ports; i++) if (xhci->port_array[i] == 0x03) { xhci->usb3_ports[port_index] = &xhci->op_regs->port_status_base + NUM_PORT_REGS*i; xhci_dbg(xhci, "USB 3.0 port at index %u, " "addr = %p\n", i, xhci->usb3_ports[port_index]); port_index++; } } return 0; } int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) { Loading Loading @@ -1809,6 +1971,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) if (scratchpad_alloc(xhci, flags)) goto fail; if (xhci_setup_port_arrays(xhci, flags)) goto fail; return 0; Loading
drivers/usb/host/xhci.c +18 −0 Original line number Diff line number Diff line Loading @@ -1549,6 +1549,15 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, cmd_completion = command->completion; cmd_status = &command->status; command->command_trb = xhci->cmd_ring->enqueue; /* Enqueue pointer can be left pointing to the link TRB, * we must handle that */ if ((command->command_trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)) command->command_trb = xhci->cmd_ring->enq_seg->next->trbs; list_add_tail(&command->cmd_list, &virt_dev->cmd_list); } else { in_ctx = virt_dev->in_ctx; Loading Loading @@ -2272,6 +2281,15 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Attempt to submit the Reset Device command to the command ring */ spin_lock_irqsave(&xhci->lock, flags); reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; /* Enqueue pointer can be left pointing to the link TRB, * we must handle that */ if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)) reset_device_cmd->command_trb = xhci->cmd_ring->enq_seg->next->trbs; list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); ret = xhci_queue_reset_device(xhci, slot_id); if (ret) { Loading
drivers/usb/host/xhci.h +26 −0 Original line number Diff line number Diff line Loading @@ -453,6 +453,24 @@ struct xhci_doorbell_array { #define STREAM_ID_TO_DB(p) (((p) & 0xffff) << 16) /** * struct xhci_protocol_caps * @revision: major revision, minor revision, capability ID, * and next capability pointer. * @name_string: Four ASCII characters to say which spec this xHC * follows, typically "USB ". * @port_info: Port offset, count, and protocol-defined information. */ struct xhci_protocol_caps { u32 revision; u32 name_string; u32 port_info; }; #define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff) #define XHCI_EXT_PORT_OFF(x) ((x) & 0xff) #define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff) /** * struct xhci_container_ctx * @type: Type of context. Used to calculated offsets to contained contexts. Loading Loading @@ -1240,6 +1258,14 @@ struct xhci_hcd { u32 suspended_ports[8]; /* which ports are suspended */ unsigned long resume_done[MAX_HC_PORTS]; /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */ u8 *port_array; /* Array of pointers to USB 3.0 PORTSC registers */ u32 __iomem **usb3_ports; unsigned int num_usb3_ports; /* Array of pointers to USB 2.0 PORTSC registers */ u32 __iomem **usb2_ports; unsigned int num_usb2_ports; }; /* For testing purposes */ Loading