diff options
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r-- | drivers/usb/host/xhci-hcd.c | 82 |
1 files changed, 52 insertions, 30 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 9c985d1245f3..2fcc360f0648 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -612,8 +612,8 @@ int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev, } static int xhci_configure_endpoint(struct xhci_hcd *xhci, - struct usb_device *udev, struct xhci_virt_device *virt_dev, - bool ctx_change); + struct usb_device *udev, struct xhci_command *command, + bool ctx_change, bool must_succeed); /* * Full speed devices may have a max packet size greater than 8 bytes, but the @@ -645,7 +645,8 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, 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); + xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx, + xhci->devs[slot_id]->out_ctx, 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; @@ -664,8 +665,8 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, 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); + ret = xhci_configure_endpoint(xhci, urb->dev, NULL, + true, false); /* Clean up the input context for later use by bandwidth * functions. @@ -1038,11 +1039,11 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir } static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, - struct usb_device *udev, struct xhci_virt_device *virt_dev) + struct usb_device *udev, int *cmd_status) { int ret; - switch (virt_dev->cmd_status) { + switch (*cmd_status) { case COMP_ENOMEM: dev_warn(&udev->dev, "Not enough host controller resources " "for new device state.\n"); @@ -1068,7 +1069,7 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, break; default: xhci_err(xhci, "ERROR: unexpected command completion " - "code 0x%x.\n", virt_dev->cmd_status); + "code 0x%x.\n", *cmd_status); ret = -EINVAL; break; } @@ -1076,11 +1077,12 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, } static int xhci_evaluate_context_result(struct xhci_hcd *xhci, - struct usb_device *udev, struct xhci_virt_device *virt_dev) + struct usb_device *udev, int *cmd_status) { int ret; + struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id]; - switch (virt_dev->cmd_status) { + switch (*cmd_status) { case COMP_EINVAL: dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate " "context command.\n"); @@ -1101,7 +1103,7 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, break; default: xhci_err(xhci, "ERROR: unexpected command completion " - "code 0x%x.\n", virt_dev->cmd_status); + "code 0x%x.\n", *cmd_status); ret = -EINVAL; break; } @@ -1112,19 +1114,37 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, * and wait for it to finish. */ static int xhci_configure_endpoint(struct xhci_hcd *xhci, - struct usb_device *udev, struct xhci_virt_device *virt_dev, - bool ctx_change) + struct usb_device *udev, + struct xhci_command *command, + bool ctx_change, bool must_succeed) { int ret; int timeleft; unsigned long flags; + struct xhci_container_ctx *in_ctx; + struct completion *cmd_completion; + int *cmd_status; + struct xhci_virt_device *virt_dev; spin_lock_irqsave(&xhci->lock, flags); + virt_dev = xhci->devs[udev->slot_id]; + if (command) { + in_ctx = command->in_ctx; + cmd_completion = command->completion; + cmd_status = &command->status; + command->command_trb = xhci->cmd_ring->enqueue; + list_add_tail(&command->cmd_list, &virt_dev->cmd_list); + } else { + in_ctx = virt_dev->in_ctx; + cmd_completion = &virt_dev->cmd_completion; + cmd_status = &virt_dev->cmd_status; + } + if (!ctx_change) - ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma, - udev->slot_id); + ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma, + udev->slot_id, must_succeed); else - ret = xhci_queue_evaluate_context(xhci, virt_dev->in_ctx->dma, + ret = xhci_queue_evaluate_context(xhci, in_ctx->dma, udev->slot_id); if (ret < 0) { spin_unlock_irqrestore(&xhci->lock, flags); @@ -1136,7 +1156,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, /* Wait for the configure endpoint command to complete */ timeleft = wait_for_completion_interruptible_timeout( - &virt_dev->cmd_completion, + cmd_completion, USB_CTRL_SET_TIMEOUT); if (timeleft <= 0) { xhci_warn(xhci, "%s while waiting for %s command\n", @@ -1149,8 +1169,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, } if (!ctx_change) - return xhci_configure_endpoint_result(xhci, udev, virt_dev); - return xhci_evaluate_context_result(xhci, udev, virt_dev); + return xhci_configure_endpoint_result(xhci, udev, cmd_status); + return xhci_evaluate_context_result(xhci, udev, cmd_status); } /* Called after one or more calls to xhci_add_endpoint() or @@ -1196,7 +1216,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) xhci_dbg_ctx(xhci, virt_dev->in_ctx, LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); - ret = xhci_configure_endpoint(xhci, udev, virt_dev, false); + ret = xhci_configure_endpoint(xhci, udev, NULL, + false, false); if (ret) { /* Callee should call reset_bandwidth() */ return ret; @@ -1248,19 +1269,19 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) } static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci, - unsigned int slot_id, u32 add_flags, u32 drop_flags) + struct xhci_container_ctx *in_ctx, + struct xhci_container_ctx *out_ctx, + u32 add_flags, u32 drop_flags) { struct xhci_input_control_ctx *ctrl_ctx; - ctrl_ctx = xhci_get_input_control_ctx(xhci, - xhci->devs[slot_id]->in_ctx); + ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); ctrl_ctx->add_flags = add_flags; ctrl_ctx->drop_flags = drop_flags; - xhci_slot_copy(xhci, xhci->devs[slot_id]); + xhci_slot_copy(xhci, in_ctx, out_ctx); ctrl_ctx->add_flags |= SLOT_FLAG; - xhci_dbg(xhci, "Slot ID %d Input Context:\n", slot_id); - xhci_dbg_ctx(xhci, xhci->devs[slot_id]->in_ctx, - xhci_last_valid_endpoint(add_flags)); + xhci_dbg(xhci, "Input Context:\n"); + xhci_dbg_ctx(xhci, in_ctx, xhci_last_valid_endpoint(add_flags)); } void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci, @@ -1272,7 +1293,8 @@ void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci, u32 added_ctxs; dma_addr_t addr; - xhci_endpoint_copy(xhci, xhci->devs[slot_id], ep_index); + xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx, + xhci->devs[slot_id]->out_ctx, ep_index); in_ctx = xhci->devs[slot_id]->in_ctx; ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index); addr = xhci_trb_virt_to_dma(deq_state->new_deq_seg, @@ -1288,8 +1310,8 @@ void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci, ep_ctx->deq = addr | deq_state->new_cycle_state; added_ctxs = xhci_get_endpoint_flag_from_index(ep_index); - xhci_setup_input_ctx_for_config_ep(xhci, slot_id, - added_ctxs, added_ctxs); + xhci_setup_input_ctx_for_config_ep(xhci, xhci->devs[slot_id]->in_ctx, + xhci->devs[slot_id]->out_ctx, added_ctxs, added_ctxs); } void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, |