Commit e34900f4 authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman

xhci: Reconfigure endpoint 0 max packet size only during endpoint reset

The max packet size for full speed control endpoint 0 may vary. It is
defined in the device descriptor, which is read using the same endpoint.
Usb core sets a temporary max packet size value until the real value is
read.

xhci driver needs to reconfigure the endpoint context seen by the
controller if the max packet size changes.
It makes more sense to do this reconfiguration in xhci_endpoint_reset()
instead of urb enqueue as usb core will call endpoint reset during
enumeration if the max packet values differ.
Max packet size adjustment for endpoint 0 can only happen once per
device enumeration.

Previously the max packet size was checked during every urb enqueue.
This is an additional check for every enqueued urb, and also turned out
to have locking issues as urbs may be queued in any context while xhci
max packet size reconfiguration requires memory allocation, locking, and
sleeping.

Tested with a full speed device using both old and new scheme enumeration
and an intentionally incorrect preliminary max packet size value.
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20231201150647.1307406-19-mathias.nyman@linux.intel.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 36b24ebf
...@@ -1438,10 +1438,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, ...@@ -1438,10 +1438,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
* descriptor. If the usb_device's max packet size changes after that point, * 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. * 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, static int xhci_check_ep0_maxpacket(struct xhci_hcd *xhci, struct xhci_virt_device *vdev)
unsigned int ep_index, struct urb *urb, gfp_t mem_flags)
{ {
struct xhci_container_ctx *out_ctx;
struct xhci_input_control_ctx *ctrl_ctx; struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_ep_ctx *ep_ctx; struct xhci_ep_ctx *ep_ctx;
struct xhci_command *command; struct xhci_command *command;
...@@ -1449,11 +1447,15 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, ...@@ -1449,11 +1447,15 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
int hw_max_packet_size; int hw_max_packet_size;
int ret = 0; int ret = 0;
out_ctx = xhci->devs[slot_id]->out_ctx; ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, 0);
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc); max_packet_size = usb_endpoint_maxp(&vdev->udev->ep0.desc);
if (hw_max_packet_size != max_packet_size) {
if (hw_max_packet_size == max_packet_size)
return 0;
switch (max_packet_size) {
case 8: case 16: case 32: case 64: case 9:
xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
"Max Packet Size for ep 0 changed."); "Max Packet Size for ep 0 changed.");
xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
...@@ -1465,28 +1467,22 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, ...@@ -1465,28 +1467,22 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
xhci_dbg_trace(xhci, trace_xhci_dbg_context_change, xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
"Issuing evaluate context command."); "Issuing evaluate context command.");
/* Set up the input context flags for the command */ command = xhci_alloc_command(xhci, true, GFP_KERNEL);
/* FIXME: This won't work if a non-default control endpoint
* changes max packet sizes.
*/
command = xhci_alloc_command(xhci, true, mem_flags);
if (!command) if (!command)
return -ENOMEM; return -ENOMEM;
command->in_ctx = xhci->devs[slot_id]->in_ctx; command->in_ctx = vdev->in_ctx;
ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx); ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
if (!ctrl_ctx) { if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n", xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__); __func__);
ret = -ENOMEM; ret = -ENOMEM;
goto command_cleanup; break;
} }
/* Set up the modified control endpoint 0 */ /* Set up the modified control endpoint 0 */
xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx, xhci_endpoint_copy(xhci, vdev->in_ctx, vdev->out_ctx, 0);
xhci->devs[slot_id]->out_ctx, ep_index);
ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, ep_index); ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, 0);
ep_ctx->ep_info &= cpu_to_le32(~EP_STATE_MASK);/* must clear */ ep_ctx->ep_info &= cpu_to_le32(~EP_STATE_MASK);/* must clear */
ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK); ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK);
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size)); ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size));
...@@ -1494,17 +1490,20 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, ...@@ -1494,17 +1490,20 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
ctrl_ctx->add_flags = cpu_to_le32(EP0_FLAG); ctrl_ctx->add_flags = cpu_to_le32(EP0_FLAG);
ctrl_ctx->drop_flags = 0; ctrl_ctx->drop_flags = 0;
ret = xhci_configure_endpoint(xhci, urb->dev, command, ret = xhci_configure_endpoint(xhci, vdev->udev, command,
true, false); true, false);
/* Clean up the input context for later use by bandwidth functions */
/* Clean up the input context for later use by bandwidth
* functions.
*/
ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG); ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG);
command_cleanup: break;
kfree(command->completion); default:
kfree(command); dev_dbg(&vdev->udev->dev, "incorrect max packet size %d for ep0\n",
max_packet_size);
return -EINVAL;
} }
kfree(command->completion);
kfree(command);
return ret; return ret;
} }
...@@ -1561,21 +1560,6 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag ...@@ -1561,21 +1560,6 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
trace_xhci_urb_enqueue(urb); trace_xhci_urb_enqueue(urb);
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, mem_flags);
if (ret < 0) {
xhci_urb_free_priv(urb_priv);
urb->hcpriv = NULL;
return ret;
}
}
}
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
if (xhci->xhc_state & XHCI_STATE_DYING) { if (xhci->xhc_state & XHCI_STATE_DYING) {
...@@ -3104,6 +3088,21 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, ...@@ -3104,6 +3088,21 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
int err; int err;
xhci = hcd_to_xhci(hcd); xhci = hcd_to_xhci(hcd);
ep_index = xhci_get_endpoint_index(&host_ep->desc);
/*
* Usb core assumes a max packet value for ep0 on FS devices until the
* real value is read from the descriptor. Core resets Ep0 if values
* mismatch. Reconfigure the xhci ep0 endpoint context here in that case
*/
if (usb_endpoint_xfer_control(&host_ep->desc) && ep_index == 0) {
udev = container_of(host_ep, struct usb_device, ep0);
if (udev->speed == USB_SPEED_FULL)
xhci_check_ep0_maxpacket(xhci, xhci->devs[udev->slot_id]);
/* Nothing else should be done here for ep0 during ep reset */
return;
}
if (!host_ep->hcpriv) if (!host_ep->hcpriv)
return; return;
udev = (struct usb_device *) host_ep->hcpriv; udev = (struct usb_device *) host_ep->hcpriv;
...@@ -3116,7 +3115,7 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, ...@@ -3116,7 +3115,7 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
*/ */
if (!udev->slot_id || !vdev) if (!udev->slot_id || !vdev)
return; return;
ep_index = xhci_get_endpoint_index(&host_ep->desc);
ep = &vdev->eps[ep_index]; ep = &vdev->eps[ep_index];
/* Bail out if toggle is already being cleared by a endpoint reset */ /* Bail out if toggle is already being cleared by a endpoint reset */
......
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