From: Greg Kroah-Hartman Date: Fri, 26 Oct 2012 19:51:04 +0000 (-0700) Subject: 3.0-stable patches X-Git-Tag: v3.0.49~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5fd2ef29e181fae39ea6a021b976b204ba8c26e8;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0-stable patches added patches: xhci-handle-command-after-aborting-the-command-ring.patch --- 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 index 00000000000..ac435f25e2c --- /dev/null +++ b/queue-3.0/xhci-handle-command-after-aborting-the-command-ring.patch @@ -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. */