diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2009-04-27 19:53:56 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-15 21:44:48 -0700 |
commit | 7f84eef0dafb1d318263d8b71c38700aaf2d530d (patch) | |
tree | d7de1ac3d91fb206a5cec2e85b0ad7f4a7b78b21 /drivers/usb/host/xhci.h | |
parent | a74588f94655263b96dacbbf14aac0958d8b7409 (diff) |
USB: xhci: No-op command queueing and irq handler.
xHCI host controllers can optionally implement a no-op test. This
simple test ensures the OS has correctly setup all basic data structures
and can correctly respond to interrupts from the host controller
hardware.
There are two rings exercised by the no-op test: the command ring, and
the event ring.
The host controller driver writes a no-op command TRB to the command
ring, and rings the doorbell for the command ring (the first entry in
the doorbell array). The hardware receives this event, places a command
completion event on the event ring, and fires an interrupt.
The host controller driver sees the interrupt, and checks the event ring
for TRBs it can process, and sees the command completion event. (See
the rules in xhci-ring.c for who "owns" a TRB. This is a simplified set
of rules, and may not contain all the details that are in the xHCI 0.95
spec.)
A timer fires every 60 seconds to debug the state of the hardware and
command and event rings. This timer only runs if
CONFIG_USB_XHCI_HCD_DEBUGGING is 'y'.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci.h')
-rw-r--r-- | drivers/usb/host/xhci.h | 53 |
1 files changed, 49 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f168fcac599..66be134b892 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -24,6 +24,7 @@ #define __LINUX_XHCI_HCD_H #include <linux/usb.h> +#include <linux/timer.h> #include "../core/hcd.h" /* Code sharing between pci-quirks and xhci hcd */ @@ -377,6 +378,7 @@ struct intr_reg { /* irq_pending bitmasks */ #define ER_IRQ_PENDING(p) ((p) & 0x1) /* bits 2:31 need to be preserved */ +/* THIS IS BUGGY - FIXME - IP IS WRITE 1 TO CLEAR */ #define ER_IRQ_CLEAR(p) ((p) & 0xfffffffe) #define ER_IRQ_ENABLE(p) ((ER_IRQ_CLEAR(p)) | 0x2) #define ER_IRQ_DISABLE(p) ((ER_IRQ_CLEAR(p)) & ~(0x2)) @@ -699,11 +701,14 @@ struct xhci_link_trb { /* control bitfields */ #define LINK_TOGGLE (0x1<<1) +/* Command completion event TRB */ +struct xhci_event_cmd { + /* Pointer to command TRB, or the value passed by the event data trb */ + u32 cmd_trb[2]; + u32 status; + u32 flags; +} __attribute__ ((packed)); -union xhci_trb { - struct xhci_link_trb link; - struct xhci_transfer_event trans_event; -}; /* Normal TRB fields */ /* transfer_len bitmasks - bits 0:16 */ @@ -737,6 +742,17 @@ union xhci_trb { /* Control transfer TRB specific fields */ #define TRB_DIR_IN (1<<16) +struct xhci_generic_trb { + u32 field[4]; +} __attribute__ ((packed)); + +union xhci_trb { + struct xhci_link_trb link; + struct xhci_transfer_event trans_event; + struct xhci_event_cmd event_cmd; + struct xhci_generic_trb generic; +}; + /* TRB bit mask */ #define TRB_TYPE_BITMASK (0xfc00) #define TRB_TYPE(p) ((p) << 10) @@ -825,7 +841,11 @@ struct xhci_segment { struct xhci_ring { struct xhci_segment *first_seg; union xhci_trb *enqueue; + struct xhci_segment *enq_seg; + unsigned int enq_updates; union xhci_trb *dequeue; + struct xhci_segment *deq_seg; + unsigned int deq_updates; /* * Write the cycle state into the TRB cycle field to give ownership of * the TRB to the host controller (if we are the producer), or to check @@ -861,6 +881,8 @@ struct xhci_erst { #define ERST_SIZE 64 /* Initial number of event segment rings allocated */ #define ERST_ENTRIES 1 +/* Poll every 60 seconds */ +#define POLL_TIMEOUT 60 /* XXX: Make these module parameters */ @@ -907,8 +929,21 @@ struct xhci_hcd { /* DMA pools */ struct dma_pool *device_pool; struct dma_pool *segment_pool; + +#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING + /* Poll the rings - for debugging */ + struct timer_list event_ring_timer; + int zombie; +#endif + /* Statistics */ + int noops_submitted; + int noops_handled; + int error_bitmask; }; +/* For testing purposes */ +#define NUM_TEST_NOOPS 0 + /* convert between an HCD pointer and the corresponding EHCI_HCD */ static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd) { @@ -956,9 +991,11 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct intr_reg *ir_set, int set_n void xhci_print_registers(struct xhci_hcd *xhci); void xhci_dbg_regs(struct xhci_hcd *xhci); void xhci_print_run_regs(struct xhci_hcd *xhci); +void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg); void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring); void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci); +void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); /* xHCI memory managment */ void xhci_mem_cleanup(struct xhci_hcd *xhci); @@ -978,5 +1015,13 @@ int xhci_run(struct usb_hcd *hcd); void xhci_stop(struct usb_hcd *hcd); void xhci_shutdown(struct usb_hcd *hcd); int xhci_get_frame(struct usb_hcd *hcd); +irqreturn_t xhci_irq(struct usb_hcd *hcd); + +/* xHCI ring, segment, TRB, and TD functions */ +dma_addr_t trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); +void ring_cmd_db(struct xhci_hcd *xhci); +void *setup_one_noop(struct xhci_hcd *xhci); +void handle_event(struct xhci_hcd *xhci); +void set_hc_event_deq(struct xhci_hcd *xhci); #endif /* __LINUX_XHCI_HCD_H */ |