xhci: Use command structures when queuing commands on the command ring
To create a global command queue we require that each command put on the
command ring is submitted with a command structure.
Functions that queue commands and wait for completion need to allocate a command
before submitting it, and free it once completed. The following command queuing
functions need to be modified.
xhci_configure_endpoint()
xhci_address_device()
xhci_queue_slot_control()
xhci_queue_stop_endpoint()
xhci_queue_new_dequeue_state()
xhci_queue_reset_ep()
xhci_configure_endpoint()
xhci_configure_endpoint() could already be called with a command structure,
and only xhci_check_maxpacket and xhci_check_bandwidth did not do so. These
are changed and a command structure is now required. This change also simplifies
the configure endpoint command completion handling and the "goto bandwidth_change"
handling code can be removed.
In some cases the command queuing function is called in interrupt context.
These commands needs to be allocated atomically, and they can't wait for
completion. These commands will in this patch be freed directly after queuing,
but freeing will be moved to the command completion event handler in a later
patch once we get the global command queue up.(Just so that we won't leak
memory in the middle of the patch set)
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 1ad6bc1..3ce9c0a 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -20,7 +20,8 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/gfp.h>
+
+#include <linux/slab.h>
#include <asm/unaligned.h>
#include "xhci.h"
@@ -284,12 +285,22 @@
spin_lock_irqsave(&xhci->lock, flags);
for (i = LAST_EP_INDEX; i > 0; i--) {
- if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue)
- xhci_queue_stop_endpoint(xhci, slot_id, i, suspend);
+ if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) {
+ struct xhci_command *command;
+ command = xhci_alloc_command(xhci, false, false,
+ GFP_NOIO);
+ if (!command) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_free_command(xhci, cmd);
+ return -ENOMEM;
+
+ }
+ xhci_queue_stop_endpoint(xhci, command, slot_id, i,
+ suspend);
+ }
}
- cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring);
list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list);
- xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend);
+ xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);