diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 2ea1c7dc1574..35679e445a39 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -4421,11 +4421,11 @@ int xhci_queue_reset_device(struct xhci_hcd *xhci, struct xhci_command *cmd, /* Queue a configure endpoint command TRB */ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd, dma_addr_t in_ctx_ptr, - u32 slot_id, bool command_must_succeed) + u32 slot_id, bool dc, bool command_must_succeed) { return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr), upper_32_bits(in_ctx_ptr), 0, - TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id), + TRB_TYPE(TRB_CONFIG_EP) | (dc ? TRB_DC : 0) | SLOT_ID_FOR_TRB(slot_id), command_must_succeed); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 34f342d2c7d7..035885903807 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3052,11 +3052,25 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, trace_xhci_configure_endpoint_ctrl_ctx(ctrl_ctx); trace_xhci_configure_endpoint(slot_ctx); - if (!ctx_change) + if (!ctx_change) { + bool dc = true; + u32 add = le32_to_cpu(ctrl_ctx->add_flags) >> 2; + u32 drop = le32_to_cpu(ctrl_ctx->drop_flags) >> 2; + + for (int i = 1; i <= 30; i++) { + if (add & 1 || !(drop & 1 || EP_STATE_DISABLED == + GET_EP_CTX_STATE(xhci_get_ep_ctx(xhci, virt_dev->out_ctx, i)))) + dc = false; + add >>= 1; + drop >>= 1; + } + if (dc) + xhci_err(xhci, "deconfigure slot %d\n", udev->slot_id); + ret = xhci_queue_configure_endpoint(xhci, command, command->in_ctx->dma, - udev->slot_id, must_succeed); - else + udev->slot_id, dc, must_succeed); + } else ret = xhci_queue_evaluate_context(xhci, command, command->in_ctx->dma, udev->slot_id, must_succeed); @@ -3486,7 +3500,7 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, xhci_endpoint_copy(xhci, cfg_cmd->in_ctx, vdev->out_ctx, ep_index); err = xhci_queue_configure_endpoint(xhci, cfg_cmd, cfg_cmd->in_ctx->dma, - udev->slot_id, false); + udev->slot_id, false, false); if (err < 0) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_free_command(xhci, cfg_cmd); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3de22e4928b4..c6d771a399a7 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1929,7 +1929,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index); int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u32 slot_id, - bool command_must_succeed); + bool dc, bool command_must_succeed); int xhci_queue_get_port_bw(struct xhci_hcd *xhci, struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u8 dev_speed, bool command_must_succeed);