Commit 80602b6b authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman
Browse files

xhci: Fix null pointer dereference during S4 resume when resetting ep0



During device enumeration usb core resets endpoint 0 if the max packet
size value differs from the one read from the device descriptor.

usb core will additionally reset endpoint 0 during S4 resume, before
re-enumerating the device, if the device has a reset-resume flag set.

In this case the xhci device representation vdev may be lost due to
xHC restore error and re-initialization during S4 resume.

Make sure slot_id and vdev are valid before trying to re-configure max
packet size during endpoint 0 reset.
max packet size will be re-configured later during re-enumeration.

This fixes commit e34900f4 ("xhci: Reconfigure endpoint 0 max packet
size only during endpoint reset") which is currently in usb-next,
on its way to 6.8

Fixes: e34900f4 ("xhci: Reconfigure endpoint 0 max packet size only during endpoint reset")
Tested-by: default avatarWendy Wang <wendy.wang@intel.com>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20231215125707.1732989-2-mathias.nyman@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c084af69
Loading
Loading
Loading
Loading
+13 −7
Original line number Diff line number Diff line
@@ -3077,6 +3077,9 @@ static void xhci_endpoint_disable(struct usb_hcd *hcd,
 * of an endpoint that isn't in the halted state this function will issue a
 * configure endpoint command with the Drop and Add bits set for the target
 * endpoint. Refer to the additional note in xhci spcification section 4.6.8.
 *
 * vdev may be lost due to xHC restore error and re-initialization during S3/S4
 * resume. A new vdev will be allocated later by xhci_discover_or_reset_device()
 */

static void xhci_endpoint_reset(struct usb_hcd *hcd,
@@ -3102,9 +3105,17 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
	 * 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]);
		if (udev->speed != USB_SPEED_FULL || !udev->slot_id)
			return;

		vdev = xhci->devs[udev->slot_id];
		if (!vdev || vdev->udev != udev)
			return;

		xhci_check_ep0_maxpacket(xhci, vdev);

		/* Nothing else should be done here for ep0 during ep reset */
		return;
	}
@@ -3114,11 +3125,6 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
	udev = (struct usb_device *) host_ep->hcpriv;
	vdev = xhci->devs[udev->slot_id];

	/*
	 * vdev may be lost due to xHC restore error and re-initialization
	 * during S3/S4 resume. A new vdev will be allocated later by
	 * xhci_discover_or_reset_device()
	 */
	if (!udev->slot_id || !vdev)
		return;