]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 26 Oct 2012 19:51:04 +0000 (12:51 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 26 Oct 2012 19:51:04 +0000 (12:51 -0700)
added patches:
xhci-handle-command-after-aborting-the-command-ring.patch

queue-3.0/xhci-handle-command-after-aborting-the-command-ring.patch [new file with mode: 0644]

diff --git a/queue-3.0/xhci-handle-command-after-aborting-the-command-ring.patch b/queue-3.0/xhci-handle-command-after-aborting-the-command-ring.patch
new file mode 100644 (file)
index 0000000..ac435f2
--- /dev/null
@@ -0,0 +1,214 @@
+---
+ drivers/usb/host/xhci-ring.c |  171 +++++++++++++++++++++++++++++++++++++++++--
+ drivers/usb/host/xhci.h      |    3 
+ 2 files changed, 168 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1157,6 +1157,20 @@ static void handle_reset_ep_completion(s
+       }
+ }
++/* Complete the command and detele it from the devcie's command queue.
++ */
++static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
++              struct xhci_command *command, u32 status)
++{
++      command->status = status;
++      list_del(&command->cmd_list);
++      if (command->completion)
++              complete(command->completion);
++      else
++              xhci_free_command(xhci, command);
++}
++
++
+ /* 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.
+@@ -1175,15 +1189,144 @@ static int handle_cmd_in_cmd_wait_list(s
+       if (xhci->cmd_ring->dequeue != command->command_trb)
+               return 0;
+-      command->status = GET_COMP_CODE(le32_to_cpu(event->status));
+-      list_del(&command->cmd_list);
+-      if (command->completion)
+-              complete(command->completion);
+-      else
+-              xhci_free_command(xhci, command);
++      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
++ * NO OP command. And if the command is in device's command wait
++ * list, finishing and freeing it.
++ *
++ * If we can't find the command trb, we think it had already been
++ * executed.
++ */
++static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd)
++{
++      struct xhci_segment *cur_seg;
++      union xhci_trb *cmd_trb;
++      u32 cycle_state;
++
++      if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue)
++              return;
++
++      /* find the current segment of command ring */
++      cur_seg = find_trb_seg(xhci->cmd_ring->first_seg,
++                      xhci->cmd_ring->dequeue, &cycle_state);
++
++      /* find the command trb matched by cd from command ring */
++      for (cmd_trb = xhci->cmd_ring->dequeue;
++                      cmd_trb != xhci->cmd_ring->enqueue;
++                      next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) {
++              /* If the trb is link trb, continue */
++              if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3]))
++                      continue;
++
++              if (cur_cd->cmd_trb == cmd_trb) {
++
++                      /* If the command in device's command list, we should
++                       * finish it and free the command structure.
++                       */
++                      if (cur_cd->command)
++                              xhci_complete_cmd_in_cmd_wait_list(xhci,
++                                      cur_cd->command, COMP_CMD_STOP);
++
++                      /* get cycle state from the origin command trb */
++                      cycle_state = le32_to_cpu(cmd_trb->generic.field[3])
++                              & TRB_CYCLE;
++
++                      /* modify the command trb to NO OP command */
++                      cmd_trb->generic.field[0] = 0;
++                      cmd_trb->generic.field[1] = 0;
++                      cmd_trb->generic.field[2] = 0;
++                      cmd_trb->generic.field[3] = cpu_to_le32(
++                                      TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
++                      break;
++              }
++      }
++}
++
++static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci)
++{
++      struct xhci_cd *cur_cd, *next_cd;
++
++      if (list_empty(&xhci->cancel_cmd_list))
++              return;
++
++      list_for_each_entry_safe(cur_cd, next_cd,
++                      &xhci->cancel_cmd_list, cancel_cmd_list) {
++              xhci_cmd_to_noop(xhci, cur_cd);
++              list_del(&cur_cd->cancel_cmd_list);
++              kfree(cur_cd);
++      }
++}
++
++/*
++ * traversing the cancel_cmd_list. If the command descriptor according
++ * to cmd_trb is found, the function free it and return 1, otherwise
++ * return 0.
++ */
++static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci,
++              union xhci_trb *cmd_trb)
++{
++      struct xhci_cd *cur_cd, *next_cd;
++
++      if (list_empty(&xhci->cancel_cmd_list))
++              return 0;
++
++      list_for_each_entry_safe(cur_cd, next_cd,
++                      &xhci->cancel_cmd_list, cancel_cmd_list) {
++              if (cur_cd->cmd_trb == cmd_trb) {
++                      if (cur_cd->command)
++                              xhci_complete_cmd_in_cmd_wait_list(xhci,
++                                      cur_cd->command, COMP_CMD_STOP);
++                      list_del(&cur_cd->cancel_cmd_list);
++                      kfree(cur_cd);
++                      return 1;
++              }
++      }
++
++      return 0;
++}
++
++/*
++ * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the
++ * trb pointed by the command ring dequeue pointer is the trb we want to
++ * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will
++ * traverse the cancel_cmd_list to trun the all of the commands according
++ * to command descriptor to NO-OP trb.
++ */
++static int handle_stopped_cmd_ring(struct xhci_hcd *xhci,
++              int cmd_trb_comp_code)
++{
++      int cur_trb_is_good = 0;
++
++      /* Searching the cmd trb pointed by the command ring dequeue
++       * pointer in command descriptor list. If it is found, free it.
++       */
++      cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci,
++                      xhci->cmd_ring->dequeue);
++
++      if (cmd_trb_comp_code == COMP_CMD_ABORT)
++              xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
++      else if (cmd_trb_comp_code == COMP_CMD_STOP) {
++              /* traversing the cancel_cmd_list and canceling
++               * the command according to command descriptor
++               */
++              xhci_cancel_cmd_in_cd_list(xhci);
++
++              xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
++              /*
++               * ring command ring doorbell again to restart the
++               * command ring
++               */
++              if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue)
++                      xhci_ring_cmd_db(xhci);
++      }
++      return cur_trb_is_good;
++}
++
+ static void handle_cmd_completion(struct xhci_hcd *xhci,
+               struct xhci_event_cmd *event)
+ {
+@@ -1209,6 +1352,22 @@ static void handle_cmd_completion(struct
+               xhci->error_bitmask |= 1 << 5;
+               return;
+       }
++
++      if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) ||
++              (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) {
++              /* If the return value is 0, we think the trb pointed by
++               * command ring dequeue pointer is a good trb. The good
++               * trb means we don't want to cancel the trb, but it have
++               * been stopped by host. So we should handle it normally.
++               * Otherwise, driver should invoke inc_deq() and return.
++               */
++              if (handle_stopped_cmd_ring(xhci,
++                              GET_COMP_CODE(le32_to_cpu(event->status)))) {
++                      inc_deq(xhci, xhci->cmd_ring, false);
++                      return;
++              }
++      }
++
+       switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
+               & TRB_TYPE_BITMASK) {
+       case TRB_TYPE(TRB_ENABLE_SLOT):
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1070,6 +1070,9 @@ union xhci_trb {
+ #define TRB_MFINDEX_WRAP      39
+ /* TRB IDs 40-47 reserved, 48-63 is vendor-defined */
++#define TRB_TYPE_LINK_LE32(x)   (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \
++              cpu_to_le32(TRB_TYPE(TRB_LINK)))
++
+ /* Nec vendor-specific command completion event. */
+ #define       TRB_NEC_CMD_COMP        48
+ /* Get NEC firmware revision. */