mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
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: Hardik Gajjar <hgajjar@de.adit-jv.com> Reviewed-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20231027152029.104363-1-hgajjar@de.adit-jv.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Stable-dep-of: 5a1ccf0c72cf ("usb: new quirk to reduce the SET_ADDRESS request timeout") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
1d011d972f
commit
5f9b63193b
@@ -4661,7 +4661,7 @@ static int hub_set_address(struct usb_device *udev, int devnum)
|
|||||||
if (udev->state != USB_STATE_DEFAULT)
|
if (udev->state != USB_STATE_DEFAULT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (hcd->driver->address_device)
|
if (hcd->driver->address_device)
|
||||||
retval = hcd->driver->address_device(hcd, udev);
|
retval = hcd->driver->address_device(hcd, udev, USB_CTRL_SET_TIMEOUT);
|
||||||
else
|
else
|
||||||
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
|
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
|
||||||
USB_REQ_SET_ADDRESS, 0, devnum, 0,
|
USB_REQ_SET_ADDRESS, 0, devnum, 0,
|
||||||
|
|||||||
@@ -1752,6 +1752,8 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
|
|||||||
}
|
}
|
||||||
|
|
||||||
command->status = 0;
|
command->status = 0;
|
||||||
|
/* set default timeout to 5000 ms */
|
||||||
|
command->timeout_ms = XHCI_CMD_DEFAULT_TIMEOUT;
|
||||||
INIT_LIST_HEAD(&command->cmd_list);
|
INIT_LIST_HEAD(&command->cmd_list);
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,9 +332,10 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
|
|||||||
readl(&xhci->dba->doorbell[0]);
|
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)
|
static struct xhci_command *xhci_next_queued_cmd(struct xhci_hcd *xhci)
|
||||||
@@ -378,7 +379,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
|
|||||||
if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) &&
|
if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) &&
|
||||||
!(xhci->xhc_state & XHCI_STATE_DYING)) {
|
!(xhci->xhc_state & XHCI_STATE_DYING)) {
|
||||||
xhci->current_cmd = cur_cmd;
|
xhci->current_cmd = cur_cmd;
|
||||||
xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
|
xhci_mod_cmd_timer(xhci);
|
||||||
xhci_ring_cmd_db(xhci);
|
xhci_ring_cmd_db(xhci);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1762,7 +1763,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|||||||
if (!list_is_singular(&xhci->cmd_list)) {
|
if (!list_is_singular(&xhci->cmd_list)) {
|
||||||
xhci->current_cmd = list_first_entry(&cmd->cmd_list,
|
xhci->current_cmd = list_first_entry(&cmd->cmd_list,
|
||||||
struct xhci_command, 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) {
|
} else if (xhci->current_cmd == cmd) {
|
||||||
xhci->current_cmd = NULL;
|
xhci->current_cmd = NULL;
|
||||||
}
|
}
|
||||||
@@ -4339,7 +4340,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 there are no other commands queued we start the timeout timer */
|
||||||
if (list_empty(&xhci->cmd_list)) {
|
if (list_empty(&xhci->cmd_list)) {
|
||||||
xhci->current_cmd = cmd;
|
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);
|
list_add_tail(&cmd->cmd_list, &xhci->cmd_list);
|
||||||
|
|||||||
@@ -4170,12 +4170,18 @@ disable_slot:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Issue an Address Device command and optionally send a corresponding
|
* xhci_setup_device - issues an Address Device command to assign a unique
|
||||||
* SetAddress request to the device.
|
* 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,
|
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";
|
const char *act = setup == SETUP_CONTEXT_ONLY ? "context" : "address";
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@@ -4232,6 +4238,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
command->in_ctx = virt_dev->in_ctx;
|
command->in_ctx = virt_dev->in_ctx;
|
||||||
|
command->timeout_ms = timeout_ms;
|
||||||
|
|
||||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
|
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
|
||||||
ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
|
ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
|
||||||
@@ -4358,14 +4365,16 @@ out:
|
|||||||
return ret;
|
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)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -815,6 +815,8 @@ struct xhci_command {
|
|||||||
struct completion *completion;
|
struct completion *completion;
|
||||||
union xhci_trb *command_trb;
|
union xhci_trb *command_trb;
|
||||||
struct list_head cmd_list;
|
struct list_head cmd_list;
|
||||||
|
/* xHCI command response timeout in milliseconds */
|
||||||
|
unsigned int timeout_ms;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* drop context bitmasks */
|
/* drop context bitmasks */
|
||||||
@@ -1574,8 +1576,11 @@ struct xhci_td {
|
|||||||
unsigned int num_trbs;
|
unsigned int num_trbs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 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 */
|
/* command descriptor */
|
||||||
struct xhci_cd {
|
struct xhci_cd {
|
||||||
|
|||||||
@@ -371,8 +371,9 @@ struct hc_driver {
|
|||||||
* or bandwidth constraints.
|
* or bandwidth constraints.
|
||||||
*/
|
*/
|
||||||
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
|
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
|
||||||
/* Returns the hardware-chosen device address */
|
/* Set the hardware-chosen device address */
|
||||||
int (*address_device)(struct usb_hcd *, struct usb_device *udev);
|
int (*address_device)(struct usb_hcd *, struct usb_device *udev,
|
||||||
|
unsigned int timeout_ms);
|
||||||
/* prepares the hardware to send commands to the device */
|
/* prepares the hardware to send commands to the device */
|
||||||
int (*enable_device)(struct usb_hcd *, struct usb_device *udev);
|
int (*enable_device)(struct usb_hcd *, struct usb_device *udev);
|
||||||
/* Notifies the HCD after a hub descriptor is fetched.
|
/* Notifies the HCD after a hub descriptor is fetched.
|
||||||
|
|||||||
Reference in New Issue
Block a user