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

xhci: Use completion and status in global command queue

Remove the per-device command list and handle_cmd_in_cmd_wait_list()
and use the completion and status variables found in the
command structure in the global command list.
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c9aa1a2d
...@@ -299,7 +299,6 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) ...@@ -299,7 +299,6 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
suspend); suspend);
} }
} }
list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list);
xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend); xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
xhci_ring_cmd_db(xhci); xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
...@@ -311,18 +310,8 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) ...@@ -311,18 +310,8 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
if (timeleft <= 0) { if (timeleft <= 0) {
xhci_warn(xhci, "%s while waiting for stop endpoint command\n", xhci_warn(xhci, "%s while waiting for stop endpoint command\n",
timeleft == 0 ? "Timeout" : "Signal"); timeleft == 0 ? "Timeout" : "Signal");
spin_lock_irqsave(&xhci->lock, flags);
/* The timeout might have raced with the event ring handler, so
* only delete from the list if the item isn't poisoned.
*/
if (cmd->cmd_list.next != LIST_POISON1)
list_del(&cmd->cmd_list);
spin_unlock_irqrestore(&xhci->lock, flags);
ret = -ETIME; ret = -ETIME;
goto command_cleanup;
} }
command_cleanup:
xhci_free_command(xhci, cmd); xhci_free_command(xhci, cmd);
return ret; return ret;
} }
......
...@@ -1020,7 +1020,6 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, ...@@ -1020,7 +1020,6 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
dev->num_rings_cached = 0; dev->num_rings_cached = 0;
init_completion(&dev->cmd_completion); init_completion(&dev->cmd_completion);
INIT_LIST_HEAD(&dev->cmd_list);
dev->udev = udev; dev->udev = udev;
/* Point to output device context in dcbaa. */ /* Point to output device context in dcbaa. */
......
...@@ -69,10 +69,6 @@ ...@@ -69,10 +69,6 @@
#include "xhci.h" #include "xhci.h"
#include "xhci-trace.h" #include "xhci-trace.h"
static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
struct xhci_event_cmd *event);
/* /*
* Returns zero if the TRB isn't in this segment, otherwise it returns the DMA * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
* address of the TRB. * address of the TRB.
...@@ -765,7 +761,6 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, ...@@ -765,7 +761,6 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
union xhci_trb *trb, struct xhci_event_cmd *event) union xhci_trb *trb, struct xhci_event_cmd *event)
{ {
unsigned int ep_index; unsigned int ep_index;
struct xhci_virt_device *virt_dev;
struct xhci_ring *ep_ring; struct xhci_ring *ep_ring;
struct xhci_virt_ep *ep; struct xhci_virt_ep *ep;
struct list_head *entry; struct list_head *entry;
...@@ -775,11 +770,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, ...@@ -775,11 +770,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
struct xhci_dequeue_state deq_state; struct xhci_dequeue_state deq_state;
if (unlikely(TRB_TO_SUSPEND_PORT(le32_to_cpu(trb->generic.field[3])))) { if (unlikely(TRB_TO_SUSPEND_PORT(le32_to_cpu(trb->generic.field[3])))) {
virt_dev = xhci->devs[slot_id]; if (!xhci->devs[slot_id])
if (virt_dev)
handle_cmd_in_cmd_wait_list(xhci, virt_dev,
event);
else
xhci_warn(xhci, "Stop endpoint command " xhci_warn(xhci, "Stop endpoint command "
"completion for disabled slot %u\n", "completion for disabled slot %u\n",
slot_id); slot_id);
...@@ -1229,29 +1220,6 @@ static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, ...@@ -1229,29 +1220,6 @@ static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
} }
/* Check to see if a command in the device's command queue matches this one.
* Signal the completion or free the command, and return 1. Return 0 if the
* completed command isn't at the head of the command list.
*/
static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
struct xhci_event_cmd *event)
{
struct xhci_command *command;
if (list_empty(&virt_dev->cmd_list))
return 0;
command = list_entry(virt_dev->cmd_list.next,
struct xhci_command, cmd_list);
if (xhci->cmd_ring->dequeue != command->command_trb)
return 0;
xhci_complete_cmd_in_cmd_wait_list(xhci, command,
GET_COMP_CODE(le32_to_cpu(event->status)));
return 1;
}
/* /*
* Finding the command trb need to be cancelled and modifying it to * Finding the command trb need to be cancelled and modifying it to
* NO OP command. And if the command is in device's command wait * NO OP command. And if the command is in device's command wait
...@@ -1403,7 +1371,6 @@ static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id, ...@@ -1403,7 +1371,6 @@ static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id,
xhci->slot_id = slot_id; xhci->slot_id = slot_id;
else else
xhci->slot_id = 0; xhci->slot_id = 0;
complete(&xhci->addr_dev);
} }
static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id) static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id)
...@@ -1428,9 +1395,6 @@ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id, ...@@ -1428,9 +1395,6 @@ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_state; unsigned int ep_state;
u32 add_flags, drop_flags; u32 add_flags, drop_flags;
virt_dev = xhci->devs[slot_id];
if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event))
return;
/* /*
* Configure endpoint commands can come from the USB core * Configure endpoint commands can come from the USB core
* configuration or alt setting changes, or because the HW * configuration or alt setting changes, or because the HW
...@@ -1439,6 +1403,7 @@ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id, ...@@ -1439,6 +1403,7 @@ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
* If the command was for a halted endpoint, the xHCI driver * If the command was for a halted endpoint, the xHCI driver
* is not waiting on the configure endpoint command. * is not waiting on the configure endpoint command.
*/ */
virt_dev = xhci->devs[slot_id];
ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
if (!ctrl_ctx) { if (!ctrl_ctx) {
xhci_warn(xhci, "Could not get input context, bad type.\n"); xhci_warn(xhci, "Could not get input context, bad type.\n");
...@@ -1474,35 +1439,11 @@ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id, ...@@ -1474,35 +1439,11 @@ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
return; return;
} }
static void xhci_handle_cmd_eval_ctx(struct xhci_hcd *xhci, int slot_id,
struct xhci_event_cmd *event, u32 cmd_comp_code)
{
struct xhci_virt_device *virt_dev;
virt_dev = xhci->devs[slot_id];
if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event))
return;
virt_dev->cmd_status = cmd_comp_code;
complete(&virt_dev->cmd_completion);
}
static void xhci_handle_cmd_addr_dev(struct xhci_hcd *xhci, int slot_id,
u32 cmd_comp_code)
{
xhci->devs[slot_id]->cmd_status = cmd_comp_code;
complete(&xhci->addr_dev);
}
static void xhci_handle_cmd_reset_dev(struct xhci_hcd *xhci, int slot_id, static void xhci_handle_cmd_reset_dev(struct xhci_hcd *xhci, int slot_id,
struct xhci_event_cmd *event) struct xhci_event_cmd *event)
{ {
struct xhci_virt_device *virt_dev;
xhci_dbg(xhci, "Completed reset device command.\n"); xhci_dbg(xhci, "Completed reset device command.\n");
virt_dev = xhci->devs[slot_id]; if (!xhci->devs[slot_id])
if (virt_dev)
handle_cmd_in_cmd_wait_list(xhci, virt_dev, event);
else
xhci_warn(xhci, "Reset device command completion " xhci_warn(xhci, "Reset device command completion "
"for disabled slot %u\n", slot_id); "for disabled slot %u\n", slot_id);
} }
...@@ -1520,18 +1461,23 @@ static void xhci_handle_cmd_nec_get_fw(struct xhci_hcd *xhci, ...@@ -1520,18 +1461,23 @@ static void xhci_handle_cmd_nec_get_fw(struct xhci_hcd *xhci,
NEC_FW_MINOR(le32_to_cpu(event->status))); NEC_FW_MINOR(le32_to_cpu(event->status)));
} }
static void xhci_del_and_free_cmd(struct xhci_command *cmd) static void xhci_complete_del_and_free_cmd(struct xhci_command *cmd, u32 status)
{ {
list_del(&cmd->cmd_list); list_del(&cmd->cmd_list);
if (!cmd->completion)
if (cmd->completion) {
cmd->status = status;
complete(cmd->completion);
} else {
kfree(cmd); kfree(cmd);
}
} }
void xhci_cleanup_command_queue(struct xhci_hcd *xhci) void xhci_cleanup_command_queue(struct xhci_hcd *xhci)
{ {
struct xhci_command *cur_cmd, *tmp_cmd; struct xhci_command *cur_cmd, *tmp_cmd;
list_for_each_entry_safe(cur_cmd, tmp_cmd, &xhci->cmd_list, cmd_list) list_for_each_entry_safe(cur_cmd, tmp_cmd, &xhci->cmd_list, cmd_list)
xhci_del_and_free_cmd(cur_cmd); xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT);
} }
static void handle_cmd_completion(struct xhci_hcd *xhci, static void handle_cmd_completion(struct xhci_hcd *xhci,
...@@ -1598,13 +1544,13 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, ...@@ -1598,13 +1544,13 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
xhci_handle_cmd_disable_slot(xhci, slot_id); xhci_handle_cmd_disable_slot(xhci, slot_id);
break; break;
case TRB_CONFIG_EP: case TRB_CONFIG_EP:
xhci_handle_cmd_config_ep(xhci, slot_id, event, cmd_comp_code); if (!cmd->completion)
xhci_handle_cmd_config_ep(xhci, slot_id, event,
cmd_comp_code);
break; break;
case TRB_EVAL_CONTEXT: case TRB_EVAL_CONTEXT:
xhci_handle_cmd_eval_ctx(xhci, slot_id, event, cmd_comp_code);
break; break;
case TRB_ADDR_DEV: case TRB_ADDR_DEV:
xhci_handle_cmd_addr_dev(xhci, slot_id, cmd_comp_code);
break; break;
case TRB_STOP_RING: case TRB_STOP_RING:
WARN_ON(slot_id != TRB_TO_SLOT_ID( WARN_ON(slot_id != TRB_TO_SLOT_ID(
...@@ -1637,7 +1583,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, ...@@ -1637,7 +1583,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
break; break;
} }
xhci_del_and_free_cmd(cmd); xhci_complete_del_and_free_cmd(cmd, cmd_comp_code);
inc_deq(xhci, xhci->cmd_ring); inc_deq(xhci, xhci->cmd_ring);
} }
......
...@@ -2626,8 +2626,6 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, ...@@ -2626,8 +2626,6 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
return -ENOMEM; return -ENOMEM;
} }
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
if (!ctx_change) if (!ctx_change)
ret = xhci_queue_configure_endpoint(xhci, command, ret = xhci_queue_configure_endpoint(xhci, command,
command->in_ctx->dma, command->in_ctx->dma,
...@@ -2637,7 +2635,6 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, ...@@ -2637,7 +2635,6 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
command->in_ctx->dma, command->in_ctx->dma,
udev->slot_id, must_succeed); udev->slot_id, must_succeed);
if (ret < 0) { if (ret < 0) {
list_del(&command->cmd_list);
if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK))
xhci_free_host_resources(xhci, ctrl_ctx); xhci_free_host_resources(xhci, ctrl_ctx);
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
...@@ -3499,11 +3496,9 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -3499,11 +3496,9 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
/* Attempt to submit the Reset Device command to the command ring */ /* Attempt to submit the Reset Device command to the command ring */
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
ret = xhci_queue_reset_device(xhci, reset_device_cmd, slot_id); ret = xhci_queue_reset_device(xhci, reset_device_cmd, slot_id);
if (ret) { if (ret) {
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
list_del(&reset_device_cmd->cmd_list);
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
goto command_cleanup; goto command_cleanup;
} }
...@@ -3517,13 +3512,6 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -3517,13 +3512,6 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
if (timeleft <= 0) { if (timeleft <= 0) {
xhci_warn(xhci, "%s while waiting for reset device command\n", xhci_warn(xhci, "%s while waiting for reset device command\n",
timeleft == 0 ? "Timeout" : "Signal"); timeleft == 0 ? "Timeout" : "Signal");
spin_lock_irqsave(&xhci->lock, flags);
/* The timeout might have raced with the event ring handler, so
* only delete from the list if the item isn't poisoned.
*/
if (reset_device_cmd->cmd_list.next != LIST_POISON1)
list_del(&reset_device_cmd->cmd_list);
spin_unlock_irqrestore(&xhci->lock, flags);
ret = -ETIME; ret = -ETIME;
goto command_cleanup; goto command_cleanup;
} }
...@@ -3895,7 +3883,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, ...@@ -3895,7 +3883,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
return -ETIME; return -ETIME;
} }
switch (virt_dev->cmd_status) { switch (command->status) {
case COMP_CTX_STATE: case COMP_CTX_STATE:
case COMP_EBADSLT: case COMP_EBADSLT:
xhci_err(xhci, "Setup ERROR: setup %s command for slot %d.\n", xhci_err(xhci, "Setup ERROR: setup %s command for slot %d.\n",
...@@ -3918,7 +3906,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, ...@@ -3918,7 +3906,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
default: default:
xhci_err(xhci, xhci_err(xhci,
"ERROR: unexpected setup %s command completion code 0x%x.\n", "ERROR: unexpected setup %s command completion code 0x%x.\n",
act, virt_dev->cmd_status); act, command->status);
xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
trace_xhci_address_ctx(xhci, virt_dev->out_ctx, 1); trace_xhci_address_ctx(xhci, virt_dev->out_ctx, 1);
......
...@@ -937,9 +937,6 @@ struct xhci_virt_device { ...@@ -937,9 +937,6 @@ struct xhci_virt_device {
#define XHCI_MAX_RINGS_CACHED 31 #define XHCI_MAX_RINGS_CACHED 31
struct xhci_virt_ep eps[31]; struct xhci_virt_ep eps[31];
struct completion cmd_completion; struct completion cmd_completion;
/* Status of the last command issued for this device */
u32 cmd_status;
struct list_head cmd_list;
u8 fake_port; u8 fake_port;
u8 real_port; u8 real_port;
struct xhci_interval_bw_table *bw_table; struct xhci_interval_bw_table *bw_table;
......
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