forked from Minki/linux
Merge branch 'for-usb-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into work
This commit is contained in:
commit
8244272341
@ -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);
|
||||
|
@ -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;
|
||||
@ -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)
|
||||
{
|
||||
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
@ -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) {
|
||||
|
@ -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.
|
||||
@ -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…
Reference in New Issue
Block a user