From f99298bfa7c42da8d27c2b42050941471c0866ab Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 12 Dec 2011 16:45:28 +0800 Subject: [PATCH 01/12] xHCI: BESL calculation based on USB2.0 LPM errata The latest released errata for USB2.0 ECN LPM adds new fields to USB2.0 extension descriptor, defines two BESL values for device: baseline BESL and deep BESL. Baseline BESL value communicates a nominal power savings design point and the deep BESL value communicates a significant power savings design point. If device indicates BESL value, driver will use a value count in both host BESL and device BESL. Use baseline BESL value as default. Signed-off-by: Andiry Xu Tested-by: Jason Fan Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci.c | 51 ++++++++++++++++++++++------------------- include/linux/usb/ch9.h | 5 ++++ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index a629ad860329..262400c10075 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3614,26 +3614,38 @@ static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000}; /* Calculate HIRD/BESL for USB2 PORTPMSC*/ -static int xhci_calculate_hird_besl(int u2del, bool use_besl) +static int xhci_calculate_hird_besl(struct xhci_hcd *xhci, + struct usb_device *udev) { - int hird; + int u2del, besl, besl_host; + int besl_device = 0; + u32 field; + + u2del = HCS_U2_LATENCY(xhci->hcs_params3); + field = le32_to_cpu(udev->bos->ext_cap->bmAttributes); - if (use_besl) { - for (hird = 0; hird < 16; hird++) { - if (xhci_besl_encoding[hird] >= u2del) + if (field & USB_BESL_SUPPORT) { + for (besl_host = 0; besl_host < 16; besl_host++) { + if (xhci_besl_encoding[besl_host] >= u2del) break; } + /* Use baseline BESL value as default */ + if (field & USB_BESL_BASELINE_VALID) + besl_device = USB_GET_BESL_BASELINE(field); + else if (field & USB_BESL_DEEP_VALID) + besl_device = USB_GET_BESL_DEEP(field); } else { if (u2del <= 50) - hird = 0; + besl_host = 0; else - hird = (u2del - 51) / 75 + 1; - - if (hird > 15) - hird = 15; + besl_host = (u2del - 51) / 75 + 1; } - return hird; + besl = besl_host + besl_device; + if (besl > 15) + besl = 15; + + return besl; } static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, @@ -3646,7 +3658,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, u32 temp, dev_id; unsigned int port_num; unsigned long flags; - int u2del, hird; + int hird; int ret; if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || @@ -3692,12 +3704,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, * HIRD or BESL shoule be used. See USB2.0 LPM errata. */ pm_addr = port_array[port_num] + 1; - u2del = HCS_U2_LATENCY(xhci->hcs_params3); - if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2)) - hird = xhci_calculate_hird_besl(u2del, 1); - else - hird = xhci_calculate_hird_besl(u2del, 0); - + hird = xhci_calculate_hird_besl(xhci, udev); temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird); xhci_writel(xhci, temp, pm_addr); @@ -3776,7 +3783,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, u32 temp; unsigned int port_num; unsigned long flags; - int u2del, hird; + int hird; if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support || !udev->lpm_capable) @@ -3799,11 +3806,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n", enable ? "enable" : "disable", port_num); - u2del = HCS_U2_LATENCY(xhci->hcs_params3); - if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2)) - hird = xhci_calculate_hird_besl(u2del, 1); - else - hird = xhci_calculate_hird_besl(u2del, 0); + hird = xhci_calculate_hird_besl(xhci, udev); if (enable) { temp &= ~PORT_HIRD_MASK; diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index 3b6f628880f8..af21f3115919 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -789,6 +789,11 @@ struct usb_ext_cap_descriptor { /* Link Power Management */ __u8 bDevCapabilityType; __le32 bmAttributes; #define USB_LPM_SUPPORT (1 << 1) /* supports LPM */ +#define USB_BESL_SUPPORT (1 << 2) /* supports BESL */ +#define USB_BESL_BASELINE_VALID (1 << 3) /* Baseline BESL valid*/ +#define USB_BESL_DEEP_VALID (1 << 4) /* Deep BESL valid */ +#define USB_GET_BESL_BASELINE(p) (((p) & (0xf << 8)) >> 8) +#define USB_GET_BESL_DEEP(p) (((p) & (0xf << 12)) >> 12) } __attribute__((packed)); #define USB_DT_USB_EXT_CAP_SIZE 7 From 8d3709f3dd41769338cc383bec23673fd1ce34e7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 27 Jan 2012 16:19:15 +0200 Subject: [PATCH 02/12] usb: host: xhci: use __ffs() instead of hardcoding shift __ffs() can tell us which is the SEGMENT_SHIFT value to be used. This will prevent problems when users are too fast and don't pay attention to the need of fixing the Shift after changing TRBS_PER_SEGMENT. Signed-off-by: Felipe Balbi Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 0f4936956103..9a7138c29030 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1223,10 +1223,7 @@ union xhci_trb { /* Allow two commands + a link TRB, along with any reserved command TRBs */ #define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3) #define SEGMENT_SIZE (TRBS_PER_SEGMENT*16) -/* SEGMENT_SHIFT should be log2(SEGMENT_SIZE). - * Change this if you change TRBS_PER_SEGMENT! - */ -#define SEGMENT_SHIFT 10 +#define SEGMENT_SHIFT (__ffs(SEGMENT_SIZE)) /* TRB buffer pointers can't cross 64KB boundaries */ #define TRB_MAX_BUFF_SHIFT 16 #define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT) From 3b72fca09d7aed0c1a390370eb3f3f4f0480702a Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 5 Mar 2012 17:49:32 +0800 Subject: [PATCH 03/12] xHCI: store ring's type When allocate a ring, store its type - four transfer types for endpoint, TYPE_STREAM for stream transfer, and TYPE_COMMAND/TYPE_EVENT for xHCI host. This helps to get rid of three bool function parameters: link_trbs, isoc and consumer. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Tested-by: Paul Zimmerman --- drivers/usb/host/xhci-mem.c | 38 ++++++----- drivers/usb/host/xhci-ring.c | 118 +++++++++++++++++------------------ drivers/usb/host/xhci.h | 11 ++++ 3 files changed, 92 insertions(+), 75 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 8339d826ce58..1699df9f2568 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -73,14 +73,14 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg) * related flags, such as End TRB, Toggle Cycle, and no snoop. */ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, - struct xhci_segment *next, bool link_trbs, bool isoc) + struct xhci_segment *next, enum xhci_ring_type type) { u32 val; if (!prev || !next) return; prev->next = next; - if (link_trbs) { + if (type != TYPE_EVENT) { prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = cpu_to_le64(next->dma); @@ -91,7 +91,8 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, /* Always set the chain bit with 0.95 hardware */ /* Set chain bit for isoc rings on AMD 0.96 host */ if (xhci_link_trb_quirk(xhci) || - (isoc && (xhci->quirks & XHCI_AMD_0x96_HOST))) + (type == TYPE_ISOC && + (xhci->quirks & XHCI_AMD_0x96_HOST))) val |= TRB_CHAIN; prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val); } @@ -144,7 +145,7 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring) * See section 4.9.1 and figures 15 and 16. */ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, - unsigned int num_segs, bool link_trbs, bool isoc, gfp_t flags) + unsigned int num_segs, enum xhci_ring_type type, gfp_t flags) { struct xhci_ring *ring; struct xhci_segment *prev; @@ -154,6 +155,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, return NULL; INIT_LIST_HEAD(&ring->td_list); + ring->type = type; if (num_segs == 0) return ring; @@ -169,14 +171,15 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, next = xhci_segment_alloc(xhci, flags); if (!next) goto fail; - xhci_link_segments(xhci, prev, next, link_trbs, isoc); + xhci_link_segments(xhci, prev, next, type); prev = next; num_segs--; } - xhci_link_segments(xhci, prev, ring->first_seg, link_trbs, isoc); + xhci_link_segments(xhci, prev, ring->first_seg, type); - if (link_trbs) { + /* Only event ring does not use link TRB */ + if (type != TYPE_EVENT) { /* See section 4.9.2.1 and 6.4.4.1 */ prev->trbs[TRBS_PER_SEGMENT-1].link.control |= cpu_to_le32(LINK_TOGGLE); @@ -217,16 +220,17 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci, * pointers to the beginning of the ring. */ static void xhci_reinit_cached_ring(struct xhci_hcd *xhci, - struct xhci_ring *ring, bool isoc) + struct xhci_ring *ring, enum xhci_ring_type type) { struct xhci_segment *seg = ring->first_seg; do { memset(seg->trbs, 0, sizeof(union xhci_trb)*TRBS_PER_SEGMENT); /* All endpoint rings have link TRBs */ - xhci_link_segments(xhci, seg, seg->next, 1, isoc); + xhci_link_segments(xhci, seg, seg->next, type); seg = seg->next; } while (seg != ring->first_seg); + ring->type = type; xhci_initialize_ring_info(ring); /* td list should be empty since all URBs have been cancelled, * but just in case... @@ -528,7 +532,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, */ for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { stream_info->stream_rings[cur_stream] = - xhci_ring_alloc(xhci, 1, true, false, mem_flags); + xhci_ring_alloc(xhci, 1, TYPE_STREAM, mem_flags); cur_ring = stream_info->stream_rings[cur_stream]; if (!cur_ring) goto cleanup_rings; @@ -862,7 +866,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, } /* Allocate endpoint 0 ring */ - dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, false, flags); + dev->eps[0].ring = xhci_ring_alloc(xhci, 1, TYPE_CTRL, flags); if (!dev->eps[0].ring) goto fail; @@ -1300,11 +1304,13 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_ring *ep_ring; unsigned int max_packet; unsigned int max_burst; + enum xhci_ring_type type; u32 max_esit_payload; ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); + type = usb_endpoint_type(&ep->desc); /* Set up the endpoint ring */ /* * Isochronous endpoint ring needs bigger size because one isoc URB @@ -1314,10 +1320,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, */ if (usb_endpoint_xfer_isoc(&ep->desc)) virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 8, true, true, mem_flags); + xhci_ring_alloc(xhci, 8, type, mem_flags); else virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 1, true, false, mem_flags); + xhci_ring_alloc(xhci, 1, type, mem_flags); if (!virt_dev->eps[ep_index].new_ring) { /* Attempt to use the ring cache */ if (virt_dev->num_rings_cached == 0) @@ -1327,7 +1333,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; virt_dev->num_rings_cached--; xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring, - usb_endpoint_xfer_isoc(&ep->desc) ? true : false); + type); } virt_dev->eps[ep_index].skip = false; ep_ring = virt_dev->eps[ep_index].new_ring; @@ -2235,7 +2241,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; /* Set up the command ring to have one segments for now. */ - xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, false, flags); + xhci->cmd_ring = xhci_ring_alloc(xhci, 1, TYPE_COMMAND, flags); if (!xhci->cmd_ring) goto fail; xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); @@ -2266,7 +2272,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) * the event ring segment table (ERST). Section 4.9.3. */ xhci_dbg(xhci, "// Allocating event ring\n"); - xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, false, + xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, TYPE_EVENT, flags); if (!xhci->event_ring) goto fail; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9e71f7c46a85..ad68a28d8fe6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -143,7 +143,7 @@ static void next_trb(struct xhci_hcd *xhci, * See Cycle bit rules. SW is the consumer for the event ring only. * Don't make a ring full of link TRBs. That would be dumb and this would loop. */ -static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer) +static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) { union xhci_trb *next = ++(ring->dequeue); unsigned long long addr; @@ -153,7 +153,8 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer * the end of an event ring segment (which doesn't have link TRBS) */ while (last_trb(xhci, ring, ring->deq_seg, next)) { - if (consumer && last_trb_on_last_seg(xhci, ring, ring->deq_seg, next)) { + if (ring->type == TYPE_EVENT && last_trb_on_last_seg(xhci, + ring, ring->deq_seg, next)) { ring->cycle_state = (ring->cycle_state ? 0 : 1); } ring->deq_seg = ring->deq_seg->next; @@ -181,7 +182,7 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer * prepare_transfer()? */ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, - bool consumer, bool more_trbs_coming, bool isoc) + bool more_trbs_coming) { u32 chain; union xhci_trb *next; @@ -195,35 +196,35 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, * the end of an event ring segment (which doesn't have link TRBS) */ while (last_trb(xhci, ring, ring->enq_seg, next)) { - if (!consumer) { - if (ring != xhci->event_ring) { - /* - * If the caller doesn't plan on enqueueing more - * TDs before ringing the doorbell, then we - * don't want to give the link TRB to the - * hardware just yet. We'll give the link TRB - * back in prepare_ring() just before we enqueue - * the TD at the top of the ring. - */ - if (!chain && !more_trbs_coming) - break; + if (ring->type != TYPE_EVENT) { + /* + * If the caller doesn't plan on enqueueing more + * TDs before ringing the doorbell, then we + * don't want to give the link TRB to the + * hardware just yet. We'll give the link TRB + * back in prepare_ring() just before we enqueue + * the TD at the top of the ring. + */ + if (!chain && !more_trbs_coming) + break; - /* If we're not dealing with 0.95 hardware or - * isoc rings on AMD 0.96 host, - * carry over the chain bit of the previous TRB - * (which may mean the chain bit is cleared). - */ - if (!(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST)) + /* If we're not dealing with 0.95 hardware or + * isoc rings on AMD 0.96 host, + * carry over the chain bit of the previous TRB + * (which may mean the chain bit is cleared). + */ + if (!(ring->type == TYPE_ISOC && + (xhci->quirks & XHCI_AMD_0x96_HOST)) && !xhci_link_trb_quirk(xhci)) { - next->link.control &= - cpu_to_le32(~TRB_CHAIN); - next->link.control |= - cpu_to_le32(chain); - } - /* Give this link TRB to the hardware */ - wmb(); - next->link.control ^= cpu_to_le32(TRB_CYCLE); + next->link.control &= + cpu_to_le32(~TRB_CHAIN); + next->link.control |= + cpu_to_le32(chain); } + /* Give this link TRB to the hardware */ + wmb(); + next->link.control ^= cpu_to_le32(TRB_CYCLE); + /* Toggle the cycle bit after the last ring segment. */ if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { ring->cycle_state = (ring->cycle_state ? 0 : 1); @@ -1185,7 +1186,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, xhci->error_bitmask |= 1 << 6; break; } - inc_deq(xhci, xhci->cmd_ring, false); + inc_deq(xhci, xhci->cmd_ring); } static void handle_vendor_event(struct xhci_hcd *xhci, @@ -1398,7 +1399,7 @@ static void handle_port_status(struct xhci_hcd *xhci, cleanup: /* Update event ring dequeue pointer before dropping the lock */ - inc_deq(xhci, xhci->event_ring, true); + inc_deq(xhci, xhci->event_ring); /* Don't make the USB core poll the roothub if we got a bad port status * change event. Besides, at that point we can't tell which roothub @@ -1593,8 +1594,8 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, } else { /* Update ring dequeue pointer */ while (ep_ring->dequeue != td->last_trb) - inc_deq(xhci, ep_ring, false); - inc_deq(xhci, ep_ring, false); + inc_deq(xhci, ep_ring); + inc_deq(xhci, ep_ring); } td_cleanup: @@ -1842,8 +1843,8 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* Update ring dequeue pointer */ while (ep_ring->dequeue != td->last_trb) - inc_deq(xhci, ep_ring, false); - inc_deq(xhci, ep_ring, false); + inc_deq(xhci, ep_ring); + inc_deq(xhci, ep_ring); return finish_td(xhci, td, NULL, event, ep, status, true); } @@ -2230,7 +2231,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, * Will roll back to continue process missed tds. */ if (trb_comp_code == COMP_MISSED_INT || !ep->skip) { - inc_deq(xhci, xhci->event_ring, true); + inc_deq(xhci, xhci->event_ring); } if (ret) { @@ -2345,7 +2346,7 @@ static int xhci_handle_event(struct xhci_hcd *xhci) if (update_ptrs) /* Update SW event ring dequeue pointer */ - inc_deq(xhci, xhci->event_ring, true); + inc_deq(xhci, xhci->event_ring); /* Are there more items on the event ring? Caller will call us again to * check. @@ -2461,7 +2462,7 @@ irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd) * prepare_transfer()? */ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, - bool consumer, bool more_trbs_coming, bool isoc, + bool more_trbs_coming, u32 field1, u32 field2, u32 field3, u32 field4) { struct xhci_generic_trb *trb; @@ -2471,7 +2472,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, trb->field[1] = cpu_to_le32(field2); trb->field[2] = cpu_to_le32(field3); trb->field[3] = cpu_to_le32(field4); - inc_enq(xhci, ring, consumer, more_trbs_coming, isoc); + inc_enq(xhci, ring, more_trbs_coming); } /* @@ -2479,7 +2480,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, * FIXME allocate segments if the ring is full. */ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, - u32 ep_state, unsigned int num_trbs, bool isoc, gfp_t mem_flags) + u32 ep_state, unsigned int num_trbs, gfp_t mem_flags) { /* Make sure the endpoint has been added to xHC schedule */ switch (ep_state) { @@ -2524,8 +2525,9 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, /* If we're not dealing with 0.95 hardware or isoc rings * on AMD 0.96 host, clear the chain bit. */ - if (!xhci_link_trb_quirk(xhci) && !(isoc && - (xhci->quirks & XHCI_AMD_0x96_HOST))) + if (!xhci_link_trb_quirk(xhci) && + !(ring->type == TYPE_ISOC && + (xhci->quirks & XHCI_AMD_0x96_HOST))) next->link.control &= cpu_to_le32(~TRB_CHAIN); else next->link.control |= cpu_to_le32(TRB_CHAIN); @@ -2553,7 +2555,6 @@ static int prepare_transfer(struct xhci_hcd *xhci, unsigned int num_trbs, struct urb *urb, unsigned int td_index, - bool isoc, gfp_t mem_flags) { int ret; @@ -2571,7 +2572,7 @@ static int prepare_transfer(struct xhci_hcd *xhci, ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK, - num_trbs, isoc, mem_flags); + num_trbs, mem_flags); if (ret) return ret; @@ -2781,7 +2782,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, - num_trbs, urb, 0, false, mem_flags); + num_trbs, urb, 0, mem_flags); if (trb_buff_len < 0) return trb_buff_len; @@ -2869,7 +2870,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, more_trbs_coming = true; else more_trbs_coming = false; - queue_trb(xhci, ep_ring, false, more_trbs_coming, false, + queue_trb(xhci, ep_ring, more_trbs_coming, lower_32_bits(addr), upper_32_bits(addr), length_field, @@ -2951,7 +2952,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, - num_trbs, urb, 0, false, mem_flags); + num_trbs, urb, 0, mem_flags); if (ret < 0) return ret; @@ -3023,7 +3024,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, more_trbs_coming = true; else more_trbs_coming = false; - queue_trb(xhci, ep_ring, false, more_trbs_coming, false, + queue_trb(xhci, ep_ring, more_trbs_coming, lower_32_bits(addr), upper_32_bits(addr), length_field, @@ -3080,7 +3081,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, num_trbs++; ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, - num_trbs, urb, 0, false, mem_flags); + num_trbs, urb, 0, mem_flags); if (ret < 0) return ret; @@ -3113,7 +3114,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } } - queue_trb(xhci, ep_ring, false, true, false, + queue_trb(xhci, ep_ring, true, setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16, le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16, TRB_LEN(8) | TRB_INTR_TARGET(0), @@ -3133,7 +3134,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (urb->transfer_buffer_length > 0) { if (setup->bRequestType & USB_DIR_IN) field |= TRB_DIR_IN; - queue_trb(xhci, ep_ring, false, true, false, + queue_trb(xhci, ep_ring, true, lower_32_bits(urb->transfer_dma), upper_32_bits(urb->transfer_dma), length_field, @@ -3149,7 +3150,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field = 0; else field = TRB_DIR_IN; - queue_trb(xhci, ep_ring, false, false, false, + queue_trb(xhci, ep_ring, false, 0, 0, TRB_INTR_TARGET(0), @@ -3289,8 +3290,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trbs_per_td = count_isoc_trbs_needed(xhci, urb, i); ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, - urb->stream_id, trbs_per_td, urb, i, true, - mem_flags); + urb->stream_id, trbs_per_td, urb, i, mem_flags); if (ret < 0) { if (i == 0) return ret; @@ -3360,7 +3360,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, remainder | TRB_INTR_TARGET(0); - queue_trb(xhci, ep_ring, false, more_trbs_coming, true, + queue_trb(xhci, ep_ring, more_trbs_coming, lower_32_bits(addr), upper_32_bits(addr), length_field, @@ -3443,7 +3443,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, * Do not insert any td of the urb to the ring if the check failed. */ ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK, - num_trbs, true, mem_flags); + num_trbs, mem_flags); if (ret) return ret; @@ -3502,7 +3502,7 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, reserved_trbs++; ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING, - reserved_trbs, false, GFP_ATOMIC); + reserved_trbs, GFP_ATOMIC); if (ret < 0) { xhci_err(xhci, "ERR: No room for command on command ring\n"); if (command_must_succeed) @@ -3510,8 +3510,8 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, "unfailable commands failed.\n"); return ret; } - queue_trb(xhci, xhci->cmd_ring, false, false, false, field1, field2, - field3, field4 | xhci->cmd_ring->cycle_state); + queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3, + field4 | xhci->cmd_ring->cycle_state); return 0; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 9a7138c29030..eb369a1723b1 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1250,6 +1250,16 @@ struct xhci_dequeue_state { int new_cycle_state; }; +enum xhci_ring_type { + TYPE_CTRL = 0, + TYPE_ISOC, + TYPE_BULK, + TYPE_INTR, + TYPE_STREAM, + TYPE_COMMAND, + TYPE_EVENT, +}; + struct xhci_ring { struct xhci_segment *first_seg; union xhci_trb *enqueue; @@ -1266,6 +1276,7 @@ struct xhci_ring { */ u32 cycle_state; unsigned int stream_id; + enum xhci_ring_type type; bool last_td_was_short; }; From 3fe4fe083d3355537565b2b0a678807513dfa013 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 5 Mar 2012 17:49:33 +0800 Subject: [PATCH 04/12] xHCI: store ring's last segment and segment numbers Store the ring's last segment pointer and number of segments for ring expansion usage. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Tested-by: Paul Zimmerman --- drivers/usb/host/xhci-mem.c | 2 ++ drivers/usb/host/xhci.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 1699df9f2568..bdea4de867b4 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -154,6 +154,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, if (!ring) return NULL; + ring->num_segs = num_segs; INIT_LIST_HEAD(&ring->td_list); ring->type = type; if (num_segs == 0) @@ -177,6 +178,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, num_segs--; } xhci_link_segments(xhci, prev, ring->first_seg, type); + ring->last_seg = prev; /* Only event ring does not use link TRB */ if (type != TYPE_EVENT) { diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index eb369a1723b1..2337a8e80b60 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1262,6 +1262,7 @@ enum xhci_ring_type { struct xhci_ring { struct xhci_segment *first_seg; + struct xhci_segment *last_seg; union xhci_trb *enqueue; struct xhci_segment *enq_seg; unsigned int enq_updates; @@ -1276,6 +1277,7 @@ struct xhci_ring { */ u32 cycle_state; unsigned int stream_id; + unsigned int num_segs; enum xhci_ring_type type; bool last_td_was_short; }; From b008df60c6369ba0290fa7daa177375407a12e07 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 5 Mar 2012 17:49:34 +0800 Subject: [PATCH 05/12] xHCI: count free TRBs on transfer ring In the past, the room_on_ring() check was implemented by walking all over the ring, which is wasteful and complicated. Count the number of free TRBs instead. The free TRBs number should be updated when enqueue/dequeue pointer is updated, or upon the completion of a set dequeue pointer command. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Tested-by: Paul Zimmerman --- drivers/usb/host/xhci-mem.c | 6 ++ drivers/usb/host/xhci-ring.c | 105 +++++++++++++++++++---------------- drivers/usb/host/xhci.c | 1 + drivers/usb/host/xhci.h | 2 + 4 files changed, 67 insertions(+), 47 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index bdea4de867b4..212012c97df3 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -135,6 +135,12 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring) /* Not necessary for new rings, but needed for re-initialized rings */ ring->enq_updates = 0; ring->deq_updates = 0; + + /* + * Each segment has a link TRB, and leave an extra TRB for SW + * accounting purpose + */ + ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; } /** diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ad68a28d8fe6..f9b6fa364f22 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -145,10 +145,17 @@ static void next_trb(struct xhci_hcd *xhci, */ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) { - union xhci_trb *next = ++(ring->dequeue); + union xhci_trb *next; unsigned long long addr; ring->deq_updates++; + + /* If this is not event ring, there is one more usable TRB */ + if (ring->type != TYPE_EVENT && + !last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) + ring->num_trbs_free++; + next = ++(ring->dequeue); + /* Update the dequeue pointer further if that was a link TRB or we're at * the end of an event ring segment (which doesn't have link TRBS) */ @@ -189,6 +196,10 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, unsigned long long addr; chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN; + /* If this is not event ring, there is one less usable TRB */ + if (ring->type != TYPE_EVENT && + !last_trb(xhci, ring, ring->enq_seg, ring->enqueue)) + ring->num_trbs_free--; next = ++(ring->enqueue); ring->enq_updates++; @@ -240,54 +251,14 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, /* * Check to see if there's room to enqueue num_trbs on the ring. See rules * above. - * FIXME: this would be simpler and faster if we just kept track of the number - * of free TRBs in a ring. */ -static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, +static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, unsigned int num_trbs) { - int i; - union xhci_trb *enq = ring->enqueue; - struct xhci_segment *enq_seg = ring->enq_seg; - struct xhci_segment *cur_seg; - unsigned int left_on_ring; - - /* If we are currently pointing to a link TRB, advance the - * enqueue pointer before checking for space */ - while (last_trb(xhci, ring, enq_seg, enq)) { - enq_seg = enq_seg->next; - enq = enq_seg->trbs; - } - - /* Check if ring is empty */ - if (enq == ring->dequeue) { - /* Can't use link trbs */ - left_on_ring = TRBS_PER_SEGMENT - 1; - for (cur_seg = enq_seg->next; cur_seg != enq_seg; - cur_seg = cur_seg->next) - left_on_ring += TRBS_PER_SEGMENT - 1; - - /* Always need one TRB free in the ring. */ - left_on_ring -= 1; - if (num_trbs > left_on_ring) { - xhci_warn(xhci, "Not enough room on ring; " - "need %u TRBs, %u TRBs left\n", - num_trbs, left_on_ring); - return 0; - } + if (ring->num_trbs_free >= num_trbs) return 1; - } - /* Make sure there's an extra empty TRB available */ - for (i = 0; i <= num_trbs; ++i) { - if (enq == ring->dequeue) - return 0; - enq++; - while (last_trb(xhci, ring, enq_seg, enq)) { - enq_seg = enq_seg->next; - enq = enq_seg->trbs; - } - } - return 1; + + return 0; } /* Ring the host controller doorbell after placing a command on the ring */ @@ -893,6 +864,43 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) xhci_dbg(xhci, "xHCI host controller is dead.\n"); } + +static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, + struct xhci_virt_device *dev, + struct xhci_ring *ep_ring, + unsigned int ep_index) +{ + union xhci_trb *dequeue_temp; + int num_trbs_free_temp; + bool revert = false; + + num_trbs_free_temp = ep_ring->num_trbs_free; + dequeue_temp = ep_ring->dequeue; + + while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) { + /* We have more usable TRBs */ + ep_ring->num_trbs_free++; + ep_ring->dequeue++; + if (last_trb(xhci, ep_ring, ep_ring->deq_seg, + ep_ring->dequeue)) { + if (ep_ring->dequeue == + dev->eps[ep_index].queued_deq_ptr) + break; + ep_ring->deq_seg = ep_ring->deq_seg->next; + ep_ring->dequeue = ep_ring->deq_seg->trbs; + } + if (ep_ring->dequeue == dequeue_temp) { + revert = true; + break; + } + } + + if (revert) { + xhci_dbg(xhci, "Unable to find new dequeue pointer\n"); + ep_ring->num_trbs_free = num_trbs_free_temp; + } +} + /* * When we get a completion for a Set Transfer Ring Dequeue Pointer command, * we need to clear the set deq pending flag in the endpoint ring state, so that @@ -974,8 +982,8 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, /* Update the ring's dequeue segment and dequeue pointer * to reflect the new position. */ - ep_ring->deq_seg = dev->eps[ep_index].queued_deq_seg; - ep_ring->dequeue = dev->eps[ep_index].queued_deq_ptr; + update_ring_for_set_deq_completion(xhci, dev, + ep_ring, ep_index); } else { xhci_warn(xhci, "Mismatch between completed Set TR Deq " "Ptr command & xHCI internal state.\n"); @@ -3407,6 +3415,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ep_ring->enqueue = urb_priv->td[0]->first_trb; ep_ring->enq_seg = urb_priv->td[0]->start_seg; ep_ring->cycle_state = start_cycle; + ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp; usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); return ret; } @@ -3479,6 +3488,8 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, urb->dev->speed == USB_SPEED_FULL) urb->interval /= 8; } + ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free; + return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 262400c10075..dec5b2dc298c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -729,6 +729,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) ring->enq_seg = ring->deq_seg; ring->enqueue = ring->dequeue; + ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; /* * Ring is now zeroed, so the HW should look for change of ownership * when the cycle bit is set to 1. diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2337a8e80b60..ea8fc237d158 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1278,6 +1278,8 @@ struct xhci_ring { u32 cycle_state; unsigned int stream_id; unsigned int num_segs; + unsigned int num_trbs_free; + unsigned int num_trbs_free_temp; enum xhci_ring_type type; bool last_td_was_short; }; From 70d43601773b9f270b62867a51495846d746b5d4 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 5 Mar 2012 17:49:35 +0800 Subject: [PATCH 06/12] xHCI: factor out segments allocation and free function Factor out the segments allocation and free part from ring allocation and free routines since driver may call them directly when try to expand a ring. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Tested-by: Paul Zimmerman --- drivers/usb/host/xhci-mem.c | 89 +++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 212012c97df3..47b762994ae9 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -65,6 +65,20 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg) kfree(seg); } +static void xhci_free_segments_for_ring(struct xhci_hcd *xhci, + struct xhci_segment *first) +{ + struct xhci_segment *seg; + + seg = first->next; + while (seg != first) { + struct xhci_segment *next = seg->next; + xhci_segment_free(xhci, seg); + seg = next; + } + xhci_segment_free(xhci, first); +} + /* * Make the prev segment point to the next segment. * @@ -101,22 +115,12 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, /* XXX: Do we need the hcd structure in all these functions? */ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) { - struct xhci_segment *seg; - struct xhci_segment *first_seg; - if (!ring) return; - if (ring->first_seg) { - first_seg = ring->first_seg; - seg = first_seg->next; - while (seg != first_seg) { - struct xhci_segment *next = seg->next; - xhci_segment_free(xhci, seg); - seg = next; - } - xhci_segment_free(xhci, first_seg); - ring->first_seg = NULL; - } + + if (ring->first_seg) + xhci_free_segments_for_ring(xhci, ring->first_seg); + kfree(ring); } @@ -143,6 +147,38 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring) ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; } +/* Allocate segments and link them for a ring */ +static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, + struct xhci_segment **first, struct xhci_segment **last, + unsigned int num_segs, enum xhci_ring_type type, gfp_t flags) +{ + struct xhci_segment *prev; + + prev = xhci_segment_alloc(xhci, flags); + if (!prev) + return -ENOMEM; + num_segs--; + + *first = prev; + while (num_segs > 0) { + struct xhci_segment *next; + + next = xhci_segment_alloc(xhci, flags); + if (!next) { + xhci_free_segments_for_ring(xhci, *first); + return -ENOMEM; + } + xhci_link_segments(xhci, prev, next, type); + + prev = next; + num_segs--; + } + xhci_link_segments(xhci, prev, *first, type); + *last = prev; + + return 0; +} + /** * Create a new ring with zero or more segments. * @@ -154,7 +190,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, unsigned int num_segs, enum xhci_ring_type type, gfp_t flags) { struct xhci_ring *ring; - struct xhci_segment *prev; + int ret; ring = kzalloc(sizeof *(ring), flags); if (!ring) @@ -166,30 +202,15 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, if (num_segs == 0) return ring; - ring->first_seg = xhci_segment_alloc(xhci, flags); - if (!ring->first_seg) + ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, + &ring->last_seg, num_segs, type, flags); + if (ret) goto fail; - num_segs--; - - prev = ring->first_seg; - while (num_segs > 0) { - struct xhci_segment *next; - - next = xhci_segment_alloc(xhci, flags); - if (!next) - goto fail; - xhci_link_segments(xhci, prev, next, type); - - prev = next; - num_segs--; - } - xhci_link_segments(xhci, prev, ring->first_seg, type); - ring->last_seg = prev; /* Only event ring does not use link TRB */ if (type != TYPE_EVENT) { /* See section 4.9.2.1 and 6.4.4.1 */ - prev->trbs[TRBS_PER_SEGMENT-1].link.control |= + ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= cpu_to_le32(LINK_TOGGLE); } xhci_initialize_ring_info(ring); From 186a7ef13a8fa3bc7cca1ccd33bd469b931e46de Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 5 Mar 2012 17:49:36 +0800 Subject: [PATCH 07/12] xHCI: set cycle state when allocate rings In the past all the rings were allocated with cycle state equal to 1. Now the driver may expand an existing ring, and the new segments shall be allocated with the same cycle state as the old one. This affects ring allocation and cached ring re-initialization. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Tested-by: Paul Zimmerman --- drivers/usb/host/xhci-mem.c | 56 +++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 47b762994ae9..c1800c7582b7 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -34,10 +34,12 @@ * Section 4.11.1.1: * "All components of all Command and Transfer TRBs shall be initialized to '0'" */ -static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flags) +static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, + unsigned int cycle_state, gfp_t flags) { struct xhci_segment *seg; dma_addr_t dma; + int i; seg = kzalloc(sizeof *seg, flags); if (!seg) @@ -50,6 +52,11 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flag } memset(seg->trbs, 0, SEGMENT_SIZE); + /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */ + if (cycle_state == 0) { + for (i = 0; i < TRBS_PER_SEGMENT; i++) + seg->trbs[i].link.control |= TRB_CYCLE; + } seg->dma = dma; seg->next = NULL; @@ -124,7 +131,8 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) kfree(ring); } -static void xhci_initialize_ring_info(struct xhci_ring *ring) +static void xhci_initialize_ring_info(struct xhci_ring *ring, + unsigned int cycle_state) { /* The ring is empty, so the enqueue pointer == dequeue pointer */ ring->enqueue = ring->first_seg->trbs; @@ -134,8 +142,11 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring) /* The ring is initialized to 0. The producer must write 1 to the cycle * bit to handover ownership of the TRB, so PCS = 1. The consumer must * compare CCS to the cycle bit to check ownership, so CCS = 1. + * + * New rings are initialized with cycle state equal to 1; if we are + * handling ring expansion, set the cycle state equal to the old ring. */ - ring->cycle_state = 1; + ring->cycle_state = cycle_state; /* Not necessary for new rings, but needed for re-initialized rings */ ring->enq_updates = 0; ring->deq_updates = 0; @@ -150,11 +161,12 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring) /* Allocate segments and link them for a ring */ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, struct xhci_segment **first, struct xhci_segment **last, - unsigned int num_segs, enum xhci_ring_type type, gfp_t flags) + unsigned int num_segs, unsigned int cycle_state, + enum xhci_ring_type type, gfp_t flags) { struct xhci_segment *prev; - prev = xhci_segment_alloc(xhci, flags); + prev = xhci_segment_alloc(xhci, cycle_state, flags); if (!prev) return -ENOMEM; num_segs--; @@ -163,7 +175,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, while (num_segs > 0) { struct xhci_segment *next; - next = xhci_segment_alloc(xhci, flags); + next = xhci_segment_alloc(xhci, cycle_state, flags); if (!next) { xhci_free_segments_for_ring(xhci, *first); return -ENOMEM; @@ -187,7 +199,8 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, * See section 4.9.1 and figures 15 and 16. */ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, - unsigned int num_segs, enum xhci_ring_type type, gfp_t flags) + unsigned int num_segs, unsigned int cycle_state, + enum xhci_ring_type type, gfp_t flags) { struct xhci_ring *ring; int ret; @@ -203,7 +216,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, return ring; ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, - &ring->last_seg, num_segs, type, flags); + &ring->last_seg, num_segs, cycle_state, type, flags); if (ret) goto fail; @@ -213,7 +226,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= cpu_to_le32(LINK_TOGGLE); } - xhci_initialize_ring_info(ring); + xhci_initialize_ring_info(ring, cycle_state); return ring; fail: @@ -249,18 +262,25 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci, * pointers to the beginning of the ring. */ static void xhci_reinit_cached_ring(struct xhci_hcd *xhci, - struct xhci_ring *ring, enum xhci_ring_type type) + struct xhci_ring *ring, unsigned int cycle_state, + enum xhci_ring_type type) { struct xhci_segment *seg = ring->first_seg; + int i; + do { memset(seg->trbs, 0, sizeof(union xhci_trb)*TRBS_PER_SEGMENT); + if (cycle_state == 0) { + for (i = 0; i < TRBS_PER_SEGMENT; i++) + seg->trbs[i].link.control |= TRB_CYCLE; + } /* All endpoint rings have link TRBs */ xhci_link_segments(xhci, seg, seg->next, type); seg = seg->next; } while (seg != ring->first_seg); ring->type = type; - xhci_initialize_ring_info(ring); + xhci_initialize_ring_info(ring, cycle_state); /* td list should be empty since all URBs have been cancelled, * but just in case... */ @@ -561,7 +581,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, */ for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { stream_info->stream_rings[cur_stream] = - xhci_ring_alloc(xhci, 1, TYPE_STREAM, mem_flags); + xhci_ring_alloc(xhci, 1, 1, TYPE_STREAM, mem_flags); cur_ring = stream_info->stream_rings[cur_stream]; if (!cur_ring) goto cleanup_rings; @@ -895,7 +915,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, } /* Allocate endpoint 0 ring */ - dev->eps[0].ring = xhci_ring_alloc(xhci, 1, TYPE_CTRL, flags); + dev->eps[0].ring = xhci_ring_alloc(xhci, 1, 1, TYPE_CTRL, flags); if (!dev->eps[0].ring) goto fail; @@ -1349,10 +1369,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, */ if (usb_endpoint_xfer_isoc(&ep->desc)) virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 8, type, mem_flags); + xhci_ring_alloc(xhci, 8, 1, type, mem_flags); else virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 1, type, mem_flags); + xhci_ring_alloc(xhci, 1, 1, type, mem_flags); if (!virt_dev->eps[ep_index].new_ring) { /* Attempt to use the ring cache */ if (virt_dev->num_rings_cached == 0) @@ -1362,7 +1382,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; virt_dev->num_rings_cached--; xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring, - type); + 1, type); } virt_dev->eps[ep_index].skip = false; ep_ring = virt_dev->eps[ep_index].new_ring; @@ -2270,7 +2290,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; /* Set up the command ring to have one segments for now. */ - xhci->cmd_ring = xhci_ring_alloc(xhci, 1, TYPE_COMMAND, flags); + xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags); if (!xhci->cmd_ring) goto fail; xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); @@ -2301,7 +2321,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) * the event ring segment table (ERST). Section 4.9.3. */ xhci_dbg(xhci, "// Allocating event ring\n"); - xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, TYPE_EVENT, + xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, flags); if (!xhci->event_ring) goto fail; From 8dfec6140fc617b932cf9a09ba46d0ee3f3a7d87 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 5 Mar 2012 17:49:37 +0800 Subject: [PATCH 08/12] xHCI: dynamic ring expansion If room_on_ring() check fails, try to expand the ring and check again. When expand a ring, use a cached ring or allocate new segments, link the original ring and the new ring or segments, update the original ring's segment numbers and the last segment pointer. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Tested-by: Paul Zimmerman --- drivers/usb/host/xhci-mem.c | 75 ++++++++++++++++++++++++++++++------ drivers/usb/host/xhci-ring.c | 33 +++++++++++++--- drivers/usb/host/xhci.h | 2 + 3 files changed, 93 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index c1800c7582b7..c37aa1ba9126 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -119,6 +119,34 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, } } +/* + * Link the ring to the new segments. + * Set Toggle Cycle for the new ring if needed. + */ +static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring, + struct xhci_segment *first, struct xhci_segment *last, + unsigned int num_segs) +{ + struct xhci_segment *next; + + if (!ring || !first || !last) + return; + + next = ring->enq_seg->next; + xhci_link_segments(xhci, ring->enq_seg, first, ring->type); + xhci_link_segments(xhci, last, next, ring->type); + ring->num_segs += num_segs; + ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs; + + if (ring->type != TYPE_EVENT && ring->enq_seg == ring->last_seg) { + ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control + &= ~cpu_to_le32(LINK_TOGGLE); + last->trbs[TRBS_PER_SEGMENT-1].link.control + |= cpu_to_le32(LINK_TOGGLE); + ring->last_seg = last; + } +} + /* XXX: Do we need the hcd structure in all these functions? */ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) { @@ -287,6 +315,39 @@ static void xhci_reinit_cached_ring(struct xhci_hcd *xhci, INIT_LIST_HEAD(&ring->td_list); } +/* + * Expand an existing ring. + * Look for a cached ring or allocate a new ring which has same segment numbers + * and link the two rings. + */ +int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, + unsigned int num_trbs, gfp_t flags) +{ + struct xhci_segment *first; + struct xhci_segment *last; + unsigned int num_segs; + unsigned int num_segs_needed; + int ret; + + num_segs_needed = (num_trbs + (TRBS_PER_SEGMENT - 1) - 1) / + (TRBS_PER_SEGMENT - 1); + + /* Allocate number of segments we needed, or double the ring size */ + num_segs = ring->num_segs > num_segs_needed ? + ring->num_segs : num_segs_needed; + + ret = xhci_alloc_segments_for_ring(xhci, &first, &last, + num_segs, ring->cycle_state, ring->type, flags); + if (ret) + return -ENOMEM; + + xhci_link_rings(xhci, ring, first, last, num_segs); + xhci_dbg(xhci, "ring expansion succeed, now has %d segments\n", + ring->num_segs); + + return 0; +} + #define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32) static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, @@ -1361,18 +1422,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, type = usb_endpoint_type(&ep->desc); /* Set up the endpoint ring */ - /* - * Isochronous endpoint ring needs bigger size because one isoc URB - * carries multiple packets and it will insert multiple tds to the - * ring. - * This should be replaced with dynamic ring resizing in the future. - */ - if (usb_endpoint_xfer_isoc(&ep->desc)) - virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 8, 1, type, mem_flags); - else - virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 1, 1, type, mem_flags); + virt_dev->eps[ep_index].new_ring = + xhci_ring_alloc(xhci, 1, 1, type, mem_flags); if (!virt_dev->eps[ep_index].new_ring) { /* Attempt to use the ring cache */ if (virt_dev->num_rings_cached == 0) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f9b6fa364f22..4194f348e3a7 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2490,6 +2490,8 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, u32 ep_state, unsigned int num_trbs, gfp_t mem_flags) { + unsigned int num_trbs_needed; + /* Make sure the endpoint has been added to xHC schedule */ switch (ep_state) { case EP_STATE_DISABLED: @@ -2517,11 +2519,32 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, */ return -EINVAL; } - if (!room_on_ring(xhci, ep_ring, num_trbs)) { - /* FIXME allocate more room */ - xhci_err(xhci, "ERROR no room on ep ring\n"); - return -ENOMEM; - } + + while (1) { + if (room_on_ring(xhci, ep_ring, num_trbs)) + break; + + if (ep_ring == xhci->cmd_ring) { + xhci_err(xhci, "Do not support expand command ring\n"); + return -ENOMEM; + } + + if (ep_ring->enq_seg == ep_ring->deq_seg && + ep_ring->dequeue > ep_ring->enqueue) { + xhci_err(xhci, "Can not expand the ring while dequeue " + "pointer has not passed the link TRB\n"); + return -ENOMEM; + } + + xhci_dbg(xhci, "ERROR no room on ep ring, " + "try ring expansion\n"); + num_trbs_needed = num_trbs - ep_ring->num_trbs_free; + if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed, + mem_flags)) { + xhci_err(xhci, "Ring expansion failed\n"); + return -ENOMEM; + } + }; if (enqueue_is_link_trb(ep_ring)) { struct xhci_ring *ring = ep_ring; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ea8fc237d158..57cd632064b4 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1622,6 +1622,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_device *udev, struct usb_host_endpoint *ep, gfp_t mem_flags); void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring); +int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, + unsigned int num_trbs, gfp_t flags); void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, unsigned int ep_index); From 2fdcd47b6980f4e26a97811a17f5be7cb919ef90 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 5 Mar 2012 17:49:39 +0800 Subject: [PATCH 09/12] xHCI: Allocate 2 segments for transfer ring Allocate 2 segments for transfer ring by default, so we can expand the ring when the enqueue pointer and dequeue pointer are in different segments. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Tested-by: Paul Zimmerman --- drivers/usb/host/xhci-mem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index c37aa1ba9126..cae4c6f2845a 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -642,7 +642,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, */ for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { stream_info->stream_rings[cur_stream] = - xhci_ring_alloc(xhci, 1, 1, TYPE_STREAM, mem_flags); + xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, mem_flags); cur_ring = stream_info->stream_rings[cur_stream]; if (!cur_ring) goto cleanup_rings; @@ -976,7 +976,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, } /* Allocate endpoint 0 ring */ - dev->eps[0].ring = xhci_ring_alloc(xhci, 1, 1, TYPE_CTRL, flags); + dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, flags); if (!dev->eps[0].ring) goto fail; @@ -1423,7 +1423,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, type = usb_endpoint_type(&ep->desc); /* Set up the endpoint ring */ virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 1, 1, type, mem_flags); + xhci_ring_alloc(xhci, 2, 1, type, mem_flags); if (!virt_dev->eps[ep_index].new_ring) { /* Attempt to use the ring cache */ if (virt_dev->num_rings_cached == 0) From 085deb16845ee0b25385274b39c70cc07e6e4140 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 5 Mar 2012 17:49:40 +0800 Subject: [PATCH 10/12] xHCI: check enqueue pointer advance into dequeue seg When a urb is submitted to xHCI driver, check if queueing the urb will make the enqueue pointer advance into dequeue seg and expand the ring if it occurs. This is to guarantee the safety of ring expansion. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Tested-by: Paul Zimmerman --- drivers/usb/host/xhci-ring.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 4194f348e3a7..6bd9d53062eb 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -249,16 +249,24 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, } /* - * Check to see if there's room to enqueue num_trbs on the ring. See rules - * above. + * Check to see if there's room to enqueue num_trbs on the ring and make sure + * enqueue pointer will not advance into dequeue segment. See rules above. */ static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, unsigned int num_trbs) { - if (ring->num_trbs_free >= num_trbs) - return 1; + int num_trbs_in_deq_seg; - return 0; + if (ring->num_trbs_free < num_trbs) + return 0; + + if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) { + num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs; + if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg) + return 0; + } + + return 1; } /* Ring the host controller doorbell after placing a command on the ring */ @@ -2529,13 +2537,6 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, return -ENOMEM; } - if (ep_ring->enq_seg == ep_ring->deq_seg && - ep_ring->dequeue > ep_ring->enqueue) { - xhci_err(xhci, "Can not expand the ring while dequeue " - "pointer has not passed the link TRB\n"); - return -ENOMEM; - } - xhci_dbg(xhci, "ERROR no room on ep ring, " "try ring expansion\n"); num_trbs_needed = num_trbs - ep_ring->num_trbs_free; From fdaf8b3183d126d70f19e13c690c762c65b28a5d Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 5 Mar 2012 17:49:38 +0800 Subject: [PATCH 11/12] xHCI: update sg tablesize Update sg tablesize as we can expand the ring now. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Tested-by: Paul Zimmerman --- drivers/usb/host/xhci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index dec5b2dc298c..f9f161fa66ad 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3968,7 +3968,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) int retval; u32 temp; - hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; + /* Accept arbitrarily long scatter-gather lists */ + hcd->self.sg_tablesize = ~0; if (usb_hcd_is_primary_hcd(hcd)) { xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL); From 3429e91a661e1f383aecc86c6bbcf65afb15c892 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 13 Mar 2012 16:57:41 +0200 Subject: [PATCH 12/12] usb: host: xhci: add platform driver support This adds a fairly simple xhci-platform driver support. Currently it is used by the dwc3 driver for supporting host mode. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Sarah Sharp --- drivers/usb/host/Kconfig | 4 + drivers/usb/host/Makefile | 4 + drivers/usb/host/xhci-plat.c | 205 +++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.c | 9 ++ drivers/usb/host/xhci.h | 11 ++ 5 files changed, 233 insertions(+) create mode 100644 drivers/usb/host/xhci-plat.c diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index dd045173ab79..b17995829514 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -27,6 +27,10 @@ config USB_XHCI_HCD To compile this driver as a module, choose M here: the module will be called xhci-hcd. +config USB_XHCI_PLATFORM + tristate + depends on USB_XHCI_HCD + config USB_XHCI_HCD_DEBUGGING bool "Debugging for the xHCI host controller" depends on USB_XHCI_HCD diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 7ca290fcb070..0982bcc140bd 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -15,6 +15,10 @@ xhci-hcd-y := xhci.o xhci-mem.o xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o xhci-hcd-$(CONFIG_PCI) += xhci-pci.o +ifneq ($(CONFIG_USB_XHCI_PLATFORM), ) + xhci-hcd-y += xhci-plat.o +endif + obj-$(CONFIG_USB_WHCI_HCD) += whci/ obj-$(CONFIG_PCI) += pci-quirks.o diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c new file mode 100644 index 000000000000..689bc18b051d --- /dev/null +++ b/drivers/usb/host/xhci-plat.c @@ -0,0 +1,205 @@ +/* + * xhci-plat.c - xHCI host controller driver platform Bus Glue. + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * Author: Sebastian Andrzej Siewior + * + * A lot of code borrowed from the Linux xHCI driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include + +#include "xhci.h" + +static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) +{ + /* + * As of now platform drivers don't provide MSI support so we ensure + * here that the generic code does not try to make a pci_dev from our + * dev struct in order to setup MSI + */ + xhci->quirks |= XHCI_BROKEN_MSI; +} + +/* called during probe() after chip reset completes */ +static int xhci_plat_setup(struct usb_hcd *hcd) +{ + return xhci_gen_setup(hcd, xhci_plat_quirks); +} + +static const struct hc_driver xhci_plat_xhci_driver = { + .description = "xhci-hcd", + .product_desc = "xHCI Host Controller", + .hcd_priv_size = sizeof(struct xhci_hcd *), + + /* + * generic hardware linkage + */ + .irq = xhci_irq, + .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, + + /* + * basic lifecycle operations + */ + .reset = xhci_plat_setup, + .start = xhci_run, + .stop = xhci_stop, + .shutdown = xhci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = xhci_urb_enqueue, + .urb_dequeue = xhci_urb_dequeue, + .alloc_dev = xhci_alloc_dev, + .free_dev = xhci_free_dev, + .alloc_streams = xhci_alloc_streams, + .free_streams = xhci_free_streams, + .add_endpoint = xhci_add_endpoint, + .drop_endpoint = xhci_drop_endpoint, + .endpoint_reset = xhci_endpoint_reset, + .check_bandwidth = xhci_check_bandwidth, + .reset_bandwidth = xhci_reset_bandwidth, + .address_device = xhci_address_device, + .update_hub_device = xhci_update_hub_device, + .reset_device = xhci_discover_or_reset_device, + + /* + * scheduling support + */ + .get_frame_number = xhci_get_frame, + + /* Root hub support */ + .hub_control = xhci_hub_control, + .hub_status_data = xhci_hub_status_data, + .bus_suspend = xhci_bus_suspend, + .bus_resume = xhci_bus_resume, +}; + +static int xhci_plat_probe(struct platform_device *pdev) +{ + const struct hc_driver *driver; + struct xhci_hcd *xhci; + struct resource *res; + struct usb_hcd *hcd; + int ret; + int irq; + + if (usb_disabled()) + return -ENODEV; + + driver = &xhci_plat_xhci_driver; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENODEV; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + driver->description)) { + dev_dbg(&pdev->dev, "controller already in use\n"); + ret = -EBUSY; + goto put_hcd; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + dev_dbg(&pdev->dev, "error mapping memory\n"); + ret = -EFAULT; + goto release_mem_region; + } + + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) + goto unmap_registers; + + /* USB 2.0 roothub is stored in the platform_device now. */ + hcd = dev_get_drvdata(&pdev->dev); + xhci = hcd_to_xhci(hcd); + xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, + dev_name(&pdev->dev), hcd); + if (!xhci->shared_hcd) { + ret = -ENOMEM; + goto dealloc_usb2_hcd; + } + + /* + * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset) + * is called by usb_add_hcd(). + */ + *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; + + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); + if (ret) + goto put_usb3_hcd; + + return 0; + +put_usb3_hcd: + usb_put_hcd(xhci->shared_hcd); + +dealloc_usb2_hcd: + usb_remove_hcd(hcd); + +unmap_registers: + iounmap(hcd->regs); + +release_mem_region: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + +put_hcd: + usb_put_hcd(hcd); + + return ret; +} + +static int xhci_plat_remove(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + usb_remove_hcd(xhci->shared_hcd); + usb_put_hcd(xhci->shared_hcd); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + usb_put_hcd(hcd); + kfree(xhci); + + return 0; +} + +static struct platform_driver usb_xhci_driver = { + .probe = xhci_plat_probe, + .remove = xhci_plat_remove, + .driver = { + .name = "xhci-hcd", + }, +}; +MODULE_ALIAS("platform:xhci-hcd"); + +int xhci_register_plat(void) +{ + return platform_driver_register(&usb_xhci_driver); +} + +void xhci_unregister_plat(void) +{ + platform_driver_unregister(&usb_xhci_driver); +} diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f9f161fa66ad..e1963d4a430f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4064,6 +4064,11 @@ static int __init xhci_hcd_init(void) printk(KERN_DEBUG "Problem registering PCI driver."); return retval; } + retval = xhci_register_plat(); + if (retval < 0) { + printk(KERN_DEBUG "Problem registering platform driver."); + goto unreg_pci; + } /* * Check the compiler generated sizes of structures that must be laid * out in specific ways for hardware access. @@ -4083,11 +4088,15 @@ static int __init xhci_hcd_init(void) BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8); return 0; +unreg_pci: + xhci_unregister_pci(); + return retval; } module_init(xhci_hcd_init); static void __exit xhci_hcd_cleanup(void) { xhci_unregister_pci(); + xhci_unregister_plat(); } module_exit(xhci_hcd_cleanup); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 57cd632064b4..91074fdab3eb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1663,6 +1663,17 @@ static inline int xhci_register_pci(void) { return 0; } static inline void xhci_unregister_pci(void) {} #endif +#if defined(CONFIG_USB_XHCI_PLATFORM) \ + || defined(CONFIG_USB_XHCI_PLATFORM_MODULE) +int xhci_register_plat(void); +void xhci_unregister_plat(void); +#else +static inline int xhci_register_plat(void) +{ return 0; } +static inline void xhci_unregister_plat(void) +{ } +#endif + /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); void xhci_quiesce(struct xhci_hcd *xhci);