I made a stupid mistake. After I used checkpatch.pl to check this patch, I added some annotations and forgot to check it again. So the patch has a trailing whitespace. Sorry. I will send it again. Best Regards, Elric 2012/6/27 Elric Fu <elricfu1@xxxxxxxxx>: > According to xHCI spec section 4.6.1.1 and section 4.6.1.2, > after aborting a command on the command ring, xHC will > generate a command completion event with its completion > code set to Command Ring Stopped at least. If a command is > currently executing at the time of aborting a command, xHC > also generate a command completion event with its completion > code set to Command Abort. When the command ring is stopped, > software may remove, add, or rearrage Command Descriptors. > > To cancel a command, software will initialize a command > descriptor for the cancel command, and add it into a > cancel_cmd_list of xhci. When the command ring is stopped, > software will find the command trbs described by command > descriptors in cancel_cmd_list and modify it to No Op > command. If software can't find the matched trbs, we can > think it had been finished. > > Signed-off-by: Elric Fu <elricfu1@xxxxxxxxx> > --- > drivers/usb/host/xhci-ring.c | 171 ++++++++++++++++++++++++++++++++++++++++-- > 1 files changed, 165 insertions(+), 6 deletions(-) > > diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c > index aa514cc..9aec89f 100644 > --- a/drivers/usb/host/xhci-ring.c > +++ b/drivers/usb/host/xhci-ring.c > @@ -1151,6 +1151,20 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci, > } > } > > +/* 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. > @@ -1169,15 +1183,144 @@ static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, > 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) > { > @@ -1203,6 +1346,22 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, > 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); > + return; > + } > + } > + > switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3]) > & TRB_TYPE_BITMASK) { > case TRB_TYPE(TRB_ENABLE_SLOT): > -- > 1.7.9.1 > -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html