Skip to content

Commit 0ebbab3

Browse files
Sarah Sharpgregkh
authored andcommitted
USB: xhci: Ring allocation and initialization.
Allocate basic xHCI host controller data structures. For every xHC, there is a command ring, an event ring, and a doorbell array. The doorbell array is used to notify the host controller that work has been enqueued onto one of the rings. The host controller driver enqueues commands on the command ring. The HW enqueues command completion events on the event ring and interrupts the system (currently using PCI interrupts, although the xHCI HW will use MSI interrupts eventually). All rings and the doorbell array must be allocated by the xHCI host controller driver. Each ring is comprised of one or more segments, which consists of 16-byte Transfer Request Blocks (TRBs) that can be chained to form a Transfer Descriptor (TD) that represents a multiple-buffer request. Segments are linked into a ring using Link TRBs, which means they are dynamically growable. The producer of the ring enqueues a TD by writing one or more TRBs in the ring and toggling the TRB cycle bit for each TRB. The consumer knows it can process the TRB when the cycle bit matches its internal consumer cycle state for the ring. The consumer cycle state is toggled an odd amount of times in the ring. An example ring (a ring must have a minimum of 16 TRBs on it, but that's too big to draw in ASCII art): chain cycle bit bit ------------------------ | TD A TRB 1 | 1 | 1 |<------------- <-- consumer dequeue ptr ------------------------ | consumer cycle state = 1 | TD A TRB 2 | 1 | 1 | | ------------------------ | | TD A TRB 3 | 0 | 1 | segment 1 | ------------------------ | | TD B TRB 1 | 1 | 1 | | ------------------------ | | TD B TRB 2 | 0 | 1 | | ------------------------ | | Link TRB | 0 | 1 |----- | ------------------------ | | | | chain cycle | | bit bit | | ------------------------ | | | TD C TRB 1 | 0 | 1 |<---- | ------------------------ | | TD D TRB 1 | 1 | 1 | | ------------------------ | | TD D TRB 2 | 1 | 1 | segment 2 | ------------------------ | | TD D TRB 3 | 1 | 1 | | ------------------------ | | TD D TRB 4 | 1 | 1 | | ------------------------ | | Link TRB | 1 | 1 |----- | ------------------------ | | | | chain cycle | | bit bit | | ------------------------ | | | TD D TRB 5 | 1 | 1 |<---- | ------------------------ | | TD D TRB 6 | 0 | 1 | | ------------------------ | | TD E TRB 1 | 0 | 1 | segment 3 | ------------------------ | | | 0 | 0 | | <-- producer enqueue ptr ------------------------ | | | 0 | 0 | | ------------------------ | | Link TRB | 0 | 0 |--------------- ------------------------ Signed-off-by: Sarah Sharp <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 66d4ead commit 0ebbab3

File tree

4 files changed

+686
-1
lines changed

4 files changed

+686
-1
lines changed

drivers/usb/host/xhci-dbg.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ void xhci_dbg_regs(struct xhci_hcd *xhci)
5656
temp = xhci_readl(xhci, &xhci->cap_regs->db_off);
5757
xhci_dbg(xhci, "// @%x = 0x%x DBOFF\n",
5858
(unsigned int) &xhci->cap_regs->db_off, temp);
59+
xhci_dbg(xhci, "// Doorbell array at 0x%x:\n",
60+
(unsigned int) xhci->dba);
5961
}
6062

6163
void xhci_print_cap_regs(struct xhci_hcd *xhci)
@@ -227,3 +229,82 @@ void xhci_print_registers(struct xhci_hcd *xhci)
227229
xhci_print_cap_regs(xhci);
228230
xhci_print_op_regs(xhci);
229231
}
232+
233+
234+
/**
235+
* Debug a segment with an xHCI ring.
236+
*
237+
* @return The Link TRB of the segment, or NULL if there is no Link TRB
238+
* (which is a bug, since all segments must have a Link TRB).
239+
*
240+
* Prints out all TRBs in the segment, even those after the Link TRB.
241+
*
242+
* XXX: should we print out TRBs that the HC owns? As long as we don't
243+
* write, that should be fine... We shouldn't expect that the memory pointed to
244+
* by the TRB is valid at all. Do we care about ones the HC owns? Probably,
245+
* for HC debugging.
246+
*/
247+
void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
248+
{
249+
int i;
250+
u32 addr = (u32) seg->dma;
251+
union xhci_trb *trb = seg->trbs;
252+
253+
for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
254+
trb = &seg->trbs[i];
255+
xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr,
256+
(unsigned int) trb->link.segment_ptr[0],
257+
(unsigned int) trb->link.segment_ptr[1],
258+
(unsigned int) trb->link.intr_target,
259+
(unsigned int) trb->link.control);
260+
addr += sizeof(*trb);
261+
}
262+
}
263+
264+
/**
265+
* Debugging for an xHCI ring, which is a queue broken into multiple segments.
266+
*
267+
* Print out each segment in the ring. Check that the DMA address in
268+
* each link segment actually matches the segment's stored DMA address.
269+
* Check that the link end bit is only set at the end of the ring.
270+
* Check that the dequeue and enqueue pointers point to real data in this ring
271+
* (not some other ring).
272+
*/
273+
void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring)
274+
{
275+
/* FIXME: Throw an error if any segment doesn't have a Link TRB */
276+
struct xhci_segment *seg;
277+
struct xhci_segment *first_seg = ring->first_seg;
278+
xhci_debug_segment(xhci, first_seg);
279+
280+
for (seg = first_seg->next; seg != first_seg; seg = seg->next)
281+
xhci_debug_segment(xhci, seg);
282+
}
283+
284+
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
285+
{
286+
u32 addr = (u32) erst->erst_dma_addr;
287+
int i;
288+
struct xhci_erst_entry *entry;
289+
290+
for (i = 0; i < erst->num_entries; ++i) {
291+
entry = &erst->entries[i];
292+
xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n",
293+
(unsigned int) addr,
294+
(unsigned int) entry->seg_addr[0],
295+
(unsigned int) entry->seg_addr[1],
296+
(unsigned int) entry->seg_size,
297+
(unsigned int) entry->rsvd);
298+
addr += sizeof(*entry);
299+
}
300+
}
301+
302+
void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
303+
{
304+
u32 val;
305+
306+
val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
307+
xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = 0x%x\n", val);
308+
val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]);
309+
xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val);
310+
}

drivers/usb/host/xhci-hcd.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,11 @@ int xhci_run(struct usb_hcd *hcd)
266266
&xhci->ir_set->irq_pending);
267267
xhci_print_ir_set(xhci, xhci->ir_set, 0);
268268

269+
xhci_dbg(xhci, "Command ring memory map follows:\n");
270+
xhci_debug_ring(xhci, xhci->cmd_ring);
271+
xhci_dbg(xhci, "ERST memory map follows:\n");
272+
xhci_dbg_erst(xhci, &xhci->erst);
273+
269274
temp = xhci_readl(xhci, &xhci->op_regs->command);
270275
temp |= (CMD_RUN);
271276
xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",

0 commit comments

Comments
 (0)