This patch added some code to the xHCI driver to make it stall every other Set Address command, and stop ringing the doorbells of bulk endpoints after two URBs were submitted to the host. This made it easy to test the command cancellation code, to ensure that: 1. Commands that weren't at the dequeue of the command ring would wait on the previously submitted command. 2. The Stop Endpoint watchdog timer would re-queue itself the command wasn't the first on the command ring. This code is NOT to be merged, it simply shows what I've tested. Not-signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx> --- drivers/usb/host/xhci-ring.c | 11 +++++++++++ drivers/usb/host/xhci.c | 12 ++++++++++-- drivers/usb/host/xhci.h | 2 ++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 3601cdf..6a984d4 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3345,6 +3345,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, int running_total, trb_buff_len, ret; unsigned int total_packet_count; u64 addr; + unsigned int ep_state; + struct xhci_virt_ep *ep; if (urb->num_sgs) return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index); @@ -3352,6 +3354,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ep_ring = xhci_urb_to_transfer_ring(xhci, urb); if (!ep_ring) return -EINVAL; + ep = &xhci->devs[slot_id]->eps[ep_index]; num_trbs = 0; /* How much data is (potentially) left before the 64KB boundary? */ @@ -3462,8 +3465,16 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } while (running_total < urb->transfer_buffer_length); check_trb_math(urb, num_trbs, running_total); + if (xhci->num_bulk_urbs > 2) { + ep_state = ep->ep_state; + ep->ep_state |= EP_HALTED; + xhci_dbg(xhci, "TEST, TEST! Don't ring bulk doorbell.\n"); + } giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, start_cycle, start_trb); + if (xhci->num_bulk_urbs > 2) + ep->ep_state = ep_state; + xhci->num_bulk_urbs++; return 0; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 51a8c55..390ef93 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3732,11 +3732,19 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); return ret; } - xhci_ring_cmd_db(xhci); + /* XXX: testing purposes: stall Set Address on every other command. */ + if ((xhci->num_set_addrs % 2) == 0) + xhci_ring_cmd_db(xhci); + else { + xhci->cmd_ring_state = CMD_RING_STATE_ABORTED; + xhci_dbg(xhci, "TEST, TEST! Stalling Set Address for 60 seconds.\n"); + } + xhci->num_set_addrs++; spin_unlock_irqrestore(&xhci->lock, flags); timeleft = xhci_wait_for_command(xhci, &xhci->addr_dev, cmd_trb, - "set address", XHCI_CMD_DEFAULT_TIMEOUT); + "set address", 60 * HZ); + xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; /* FIXME: From section 4.3.4: "Software shall be responsible for timing * the SetAddress() "recovery interval" required by USB and aborting the * command on a timeout. diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f66ce67..f5a64e7 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1534,6 +1534,8 @@ struct xhci_hcd { u32 port_status_u0; /* Compliance Mode Timer Triggered every 2 seconds */ #define COMP_MODE_RCVRY_MSECS 2000 + unsigned int num_set_addrs; + unsigned int num_bulk_urbs; }; /* convert between an HCD pointer and the corresponding EHCI_HCD */ -- 1.7.9 -- 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