Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7032df57 authored by Hardik Gajjar's avatar Hardik Gajjar Committed by Greg Kroah-Hartman
Browse files

usb: xhci: Add timeout argument in address_device USB HCD callback



[ Upstream commit a769154c7cac037914ba375ae88aae55b2c853e0 ]

- The HCD address_device callback now accepts a user-defined timeout value
  in milliseconds, providing better control over command execution times.
- The default timeout value for the address_device command has been set
  to 5000 ms, aligning with the USB 3.2 specification. However, this
  timeout can be adjusted as needed.
- The xhci_setup_device function has been updated to accept the timeout
  value, allowing it to specify the maximum wait time for the command
  operation to complete.
- The hub driver has also been updated to accommodate the newly added
  timeout parameter during the SET_ADDRESS request.

Signed-off-by: default avatarHardik Gajjar <hgajjar@de.adit-jv.com>
Reviewed-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20231027152029.104363-1-hgajjar@de.adit-jv.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: 1e0a19912adb ("usb: xhci: Fix NULL pointer dereference on certain command aborts")
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 431be4f7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -4551,7 +4551,7 @@ static int hub_set_address(struct usb_device *udev, int devnum)
	if (udev->state != USB_STATE_DEFAULT)
		return -EINVAL;
	if (hcd->driver->address_device)
		retval = hcd->driver->address_device(hcd, udev);
		retval = hcd->driver->address_device(hcd, udev, USB_CTRL_SET_TIMEOUT);
	else
		retval = usb_control_msg(udev, usb_sndaddr0pipe(),
				USB_REQ_SET_ADDRESS, 0, devnum, 0,
+2 −0
Original line number Diff line number Diff line
@@ -1766,6 +1766,8 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
	}

	command->status = 0;
	/* set default timeout to 5000 ms */
	command->timeout_ms = XHCI_CMD_DEFAULT_TIMEOUT;
	INIT_LIST_HEAD(&command->cmd_list);
	return command;
}
+6 −5
Original line number Diff line number Diff line
@@ -285,9 +285,10 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
	readl(&xhci->dba->doorbell[0]);
}

static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci, unsigned long delay)
static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci)
{
	return mod_delayed_work(system_wq, &xhci->cmd_timer, delay);
	return mod_delayed_work(system_wq, &xhci->cmd_timer,
			msecs_to_jiffies(xhci->current_cmd->timeout_ms));
}

static struct xhci_command *xhci_next_queued_cmd(struct xhci_hcd *xhci)
@@ -331,7 +332,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
	if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) &&
	    !(xhci->xhc_state & XHCI_STATE_DYING)) {
		xhci->current_cmd = cur_cmd;
		xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
		xhci_mod_cmd_timer(xhci);
		xhci_ring_cmd_db(xhci);
	}
}
@@ -1561,7 +1562,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
	if (!list_is_singular(&xhci->cmd_list)) {
		xhci->current_cmd = list_first_entry(&cmd->cmd_list,
						struct xhci_command, cmd_list);
		xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
		xhci_mod_cmd_timer(xhci);
	} else if (xhci->current_cmd == cmd) {
		xhci->current_cmd = NULL;
	}
@@ -4096,7 +4097,7 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
	/* if there are no other commands queued we start the timeout timer */
	if (list_empty(&xhci->cmd_list)) {
		xhci->current_cmd = cmd;
		xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
		xhci_mod_cmd_timer(xhci);
	}

	list_add_tail(&cmd->cmd_list, &xhci->cmd_list);
+16 −7
Original line number Diff line number Diff line
@@ -4105,12 +4105,18 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
	return 0;
}

/*
 * Issue an Address Device command and optionally send a corresponding
 * SetAddress request to the device.
/**
 * xhci_setup_device - issues an Address Device command to assign a unique
 *			USB bus address.
 * @hcd: USB host controller data structure.
 * @udev: USB dev structure representing the connected device.
 * @setup: Enum specifying setup mode: address only or with context.
 * @timeout_ms: Max wait time (ms) for the command operation to complete.
 *
 * Return: 0 if successful; otherwise, negative error code.
 */
static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
			     enum xhci_setup_dev setup)
			     enum xhci_setup_dev setup, unsigned int timeout_ms)
{
	const char *act = setup == SETUP_CONTEXT_ONLY ? "context" : "address";
	unsigned long flags;
@@ -4167,6 +4173,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
	}

	command->in_ctx = virt_dev->in_ctx;
	command->timeout_ms = timeout_ms;

	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
	ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
@@ -4295,14 +4302,16 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
	return ret;
}

static int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
static int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev,
			       unsigned int timeout_ms)
{
	return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS);
	return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS, timeout_ms);
}

static int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev)
{
	return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY);
	return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY,
				 XHCI_CMD_DEFAULT_TIMEOUT);
}

/*
+7 −2
Original line number Diff line number Diff line
@@ -815,6 +815,8 @@ struct xhci_command {
	struct completion		*completion;
	union xhci_trb			*command_trb;
	struct list_head		cmd_list;
	/* xHCI command response timeout in milliseconds */
	unsigned int			timeout_ms;
};

/* drop context bitmasks */
@@ -1550,8 +1552,11 @@ struct xhci_td {
	bool			urb_length_set;
};

/* xHCI command default timeout value */
#define XHCI_CMD_DEFAULT_TIMEOUT	(5 * HZ)
/*
 * xHCI command default timeout value in milliseconds.
 * USB 3.2 spec, section 9.2.6.1
 */
#define XHCI_CMD_DEFAULT_TIMEOUT	5000

/* command descriptor */
struct xhci_cd {
Loading