Commit 731c177a authored by Sarah Sharp's avatar Sarah Sharp Committed by Stephen Rothwell

USB: xhci: Support full speed devices.

Full speed devices have varying max packet sizes (8, 16, 32, or 64) for
endpoint 0.  The xHCI hardware needs to know the real max packet size
that the USB core discovers after it fetches the first 8 bytes of the
device descriptor.

In order to fix this without adding a new hook to host controller drivers,
the xHCI driver looks for an updated max packet size for control
endpoints.  If it finds an updated size, it issues an evaluate context
command and waits for that command to finish.  This should only happen in
the initialization and device descriptor fetching steps in the khubd
thread, so blocking should be fine.
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 29d4eedd
...@@ -601,6 +601,70 @@ int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev, ...@@ -601,6 +601,70 @@ int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
return 1; return 1;
} }
static int xhci_configure_endpoint(struct xhci_hcd *xhci,
struct usb_device *udev, struct xhci_virt_device *virt_dev,
bool ctx_change);
/*
* Full speed devices may have a max packet size greater than 8 bytes, but the
* USB core doesn't know that until it reads the first 8 bytes of the
* descriptor. If the usb_device's max packet size changes after that point,
* we need to issue an evaluate context command and wait on it.
*/
static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
unsigned int ep_index, struct urb *urb)
{
struct xhci_container_ctx *in_ctx;
struct xhci_container_ctx *out_ctx;
struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_ep_ctx *ep_ctx;
int max_packet_size;
int hw_max_packet_size;
int ret = 0;
out_ctx = xhci->devs[slot_id]->out_ctx;
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
hw_max_packet_size = MAX_PACKET_DECODED(ep_ctx->ep_info2);
max_packet_size = urb->dev->ep0.desc.wMaxPacketSize;
if (hw_max_packet_size != max_packet_size) {
xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
max_packet_size);
xhci_dbg(xhci, "Max packet size in xHCI HW = %d\n",
hw_max_packet_size);
xhci_dbg(xhci, "Issuing evaluate context command.\n");
/* Set up the modified control endpoint 0 */
xhci_endpoint_copy(xhci, xhci->devs[slot_id], ep_index);
in_ctx = xhci->devs[slot_id]->in_ctx;
ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
ep_ctx->ep_info2 &= ~MAX_PACKET_MASK;
ep_ctx->ep_info2 |= MAX_PACKET(max_packet_size);
/* Set up the input context flags for the command */
/* FIXME: This won't work if a non-default control endpoint
* changes max packet sizes.
*/
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
ctrl_ctx->add_flags = EP0_FLAG;
ctrl_ctx->drop_flags = 0;
xhci_dbg(xhci, "Slot %d input context\n", slot_id);
xhci_dbg_ctx(xhci, in_ctx, ep_index);
xhci_dbg(xhci, "Slot %d output context\n", slot_id);
xhci_dbg_ctx(xhci, out_ctx, ep_index);
ret = xhci_configure_endpoint(xhci, urb->dev,
xhci->devs[slot_id], true);
/* Clean up the input context for later use by bandwidth
* functions.
*/
ctrl_ctx->add_flags = SLOT_FLAG;
}
return ret;
}
/* /*
* non-error returns are a promise to giveback() the urb later * non-error returns are a promise to giveback() the urb later
* we drop ownership so next owner (or urb unlink) can get it * we drop ownership so next owner (or urb unlink) can get it
...@@ -612,13 +676,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) ...@@ -612,13 +676,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
int ret = 0; int ret = 0;
unsigned int slot_id, ep_index; unsigned int slot_id, ep_index;
if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0) if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
return -EINVAL; return -EINVAL;
slot_id = urb->dev->slot_id; slot_id = urb->dev->slot_id;
ep_index = xhci_get_endpoint_index(&urb->ep->desc); ep_index = xhci_get_endpoint_index(&urb->ep->desc);
spin_lock_irqsave(&xhci->lock, flags);
if (!xhci->devs || !xhci->devs[slot_id]) { if (!xhci->devs || !xhci->devs[slot_id]) {
if (!in_interrupt()) if (!in_interrupt())
dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n"); dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n");
...@@ -631,19 +695,33 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) ...@@ -631,19 +695,33 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
ret = -ESHUTDOWN; ret = -ESHUTDOWN;
goto exit; goto exit;
} }
if (usb_endpoint_xfer_control(&urb->ep->desc)) if (usb_endpoint_xfer_control(&urb->ep->desc)) {
/* Check to see if the max packet size for the default control
* endpoint changed during FS device enumeration
*/
if (urb->dev->speed == USB_SPEED_FULL) {
ret = xhci_check_maxpacket(xhci, slot_id,
ep_index, urb);
if (ret < 0)
return ret;
}
/* We have a spinlock and interrupts disabled, so we must pass /* We have a spinlock and interrupts disabled, so we must pass
* atomic context to this function, which may allocate memory. * atomic context to this function, which may allocate memory.
*/ */
spin_lock_irqsave(&xhci->lock, flags);
ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb, ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index); slot_id, ep_index);
else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) spin_unlock_irqrestore(&xhci->lock, flags);
} else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) {
spin_lock_irqsave(&xhci->lock, flags);
ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index); slot_id, ep_index);
else spin_unlock_irqrestore(&xhci->lock, flags);
} else {
ret = -EINVAL; ret = -EINVAL;
}
exit: exit:
spin_unlock_irqrestore(&xhci->lock, flags);
return ret; return ret;
} }
......
...@@ -701,6 +701,10 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, ...@@ -701,6 +701,10 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status); xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status);
complete(&xhci->devs[slot_id]->cmd_completion); complete(&xhci->devs[slot_id]->cmd_completion);
break; break;
case TRB_TYPE(TRB_EVAL_CONTEXT):
xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status);
complete(&xhci->devs[slot_id]->cmd_completion);
break;
case TRB_TYPE(TRB_ADDR_DEV): case TRB_TYPE(TRB_ADDR_DEV):
xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status); xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status);
complete(&xhci->addr_dev); complete(&xhci->addr_dev);
......
...@@ -601,6 +601,8 @@ struct xhci_ep_ctx { ...@@ -601,6 +601,8 @@ struct xhci_ep_ctx {
/* bit 7 is Host Initiate Disable - for disabling stream selection */ /* bit 7 is Host Initiate Disable - for disabling stream selection */
#define MAX_BURST(p) (((p)&0xff) << 8) #define MAX_BURST(p) (((p)&0xff) << 8)
#define MAX_PACKET(p) (((p)&0xffff) << 16) #define MAX_PACKET(p) (((p)&0xffff) << 16)
#define MAX_PACKET_MASK (0xffff << 16)
#define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff)
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment