iPXE
Defines | Functions | Variables
xhci.c File Reference

USB eXtensible Host Controller Interface (xHCI) driver. More...

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/malloc.h>
#include <ipxe/umalloc.h>
#include <ipxe/pci.h>
#include <ipxe/usb.h>
#include <ipxe/init.h>
#include <ipxe/profile.h>
#include "xhci.h"

Go to the source code of this file.

Defines

#define EIO_DATA   __einfo_error ( EINFO_EIO_DATA )
#define EINFO_EIO_DATA
#define EIO_BABBLE   __einfo_error ( EINFO_EIO_BABBLE )
#define EINFO_EIO_BABBLE
#define EIO_USB   __einfo_error ( EINFO_EIO_USB )
#define EINFO_EIO_USB
#define EIO_TRB   __einfo_error ( EINFO_EIO_TRB )
#define EINFO_EIO_TRB
#define EIO_STALL   __einfo_error ( EINFO_EIO_STALL )
#define EINFO_EIO_STALL
#define EIO_RESOURCE   __einfo_error ( EINFO_EIO_RESOURCE )
#define EINFO_EIO_RESOURCE
#define EIO_BANDWIDTH   __einfo_error ( EINFO_EIO_BANDWIDTH )
#define EINFO_EIO_BANDWIDTH
#define EIO_NO_SLOTS   __einfo_error ( EINFO_EIO_NO_SLOTS )
#define EINFO_EIO_NO_SLOTS
#define EIO_STREAM_TYPE   __einfo_error ( EINFO_EIO_STREAM_TYPE )
#define EINFO_EIO_STREAM_TYPE
#define EIO_SLOT   __einfo_error ( EINFO_EIO_SLOT )
#define EINFO_EIO_SLOT
#define EIO_ENDPOINT   __einfo_error ( EINFO_EIO_ENDPOINT )
#define EINFO_EIO_ENDPOINT
#define EIO_SHORT   __einfo_error ( EINFO_EIO_SHORT )
#define EINFO_EIO_SHORT
#define EIO_UNDERRUN   __einfo_error ( EINFO_EIO_UNDERRUN )
#define EINFO_EIO_UNDERRUN
#define EIO_OVERRUN   __einfo_error ( EINFO_EIO_OVERRUN )
#define EINFO_EIO_OVERRUN
#define EIO_VF_RING_FULL   __einfo_error ( EINFO_EIO_VF_RING_FULL )
#define EINFO_EIO_VF_RING_FULL
#define EIO_PARAMETER   __einfo_error ( EINFO_EIO_PARAMETER )
#define EINFO_EIO_PARAMETER
#define EIO_BANDWIDTH_OVERRUN   __einfo_error ( EINFO_EIO_BANDWIDTH_OVERRUN )
#define EINFO_EIO_BANDWIDTH_OVERRUN
#define EIO_CONTEXT   __einfo_error ( EINFO_EIO_CONTEXT )
#define EINFO_EIO_CONTEXT
#define EIO_NO_PING   __einfo_error ( EINFO_EIO_NO_PING )
#define EINFO_EIO_NO_PING
#define EIO_RING_FULL   __einfo_error ( EINFO_EIO_RING_FULL )
#define EINFO_EIO_RING_FULL
#define EIO_INCOMPATIBLE   __einfo_error ( EINFO_EIO_INCOMPATIBLE )
#define EINFO_EIO_INCOMPATIBLE
#define EIO_MISSED   __einfo_error ( EINFO_EIO_MISSED )
#define EINFO_EIO_MISSED
#define EIO_CMD_STOPPED   __einfo_error ( EINFO_EIO_CMD_STOPPED )
#define EINFO_EIO_CMD_STOPPED
#define EIO_CMD_ABORTED   __einfo_error ( EINFO_EIO_CMD_ABORTED )
#define EINFO_EIO_CMD_ABORTED
#define EIO_STOP   __einfo_error ( EINFO_EIO_STOP )
#define EINFO_EIO_STOP
#define EIO_STOP_LEN   __einfo_error ( EINFO_EIO_STOP_LEN )
#define EINFO_EIO_STOP_LEN
#define EIO_STOP_SHORT   __einfo_error ( EINFO_EIO_STOP_SHORT )
#define EINFO_EIO_STOP_SHORT
#define EIO_LATENCY   __einfo_error ( EINFO_EIO_LATENCY )
#define EINFO_EIO_LATENCY
#define EIO_ISOCH   __einfo_error ( EINFO_EIO_ISOCH )
#define EINFO_EIO_ISOCH
#define EPROTO_LOST   __einfo_error ( EINFO_EPROTO_LOST )
#define EINFO_EPROTO_LOST
#define EPROTO_UNDEFINED   __einfo_error ( EINFO_EPROTO_UNDEFINED )
#define EINFO_EPROTO_UNDEFINED
#define EPROTO_STREAM_ID   __einfo_error ( EINFO_EPROTO_STREAM_ID )
#define EINFO_EPROTO_STREAM_ID
#define EPROTO_SECONDARY   __einfo_error ( EINFO_EPROTO_SECONDARY )
#define EINFO_EPROTO_SECONDARY
#define EPROTO_SPLIT   __einfo_error ( EINFO_EPROTO_SPLIT )
#define EINFO_EPROTO_SPLIT
#define ECODE(code)

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void xhci_init (struct xhci_device *xhci, void *regs)
 Initialise device.
static unsigned int xhci_extended_capability (struct xhci_device *xhci, unsigned int id, unsigned int offset)
 Find extended capability.
static int xhci_writeq (struct xhci_device *xhci, physaddr_t value, void *reg)
 Write potentially 64-bit register.
static size_t xhci_align (size_t len)
 Calculate buffer alignment.
static size_t xhci_device_context_offset (struct xhci_device *xhci, unsigned int ctx)
 Calculate device context offset.
static size_t xhci_input_context_offset (struct xhci_device *xhci, unsigned int ctx)
 Calculate input context offset.
static void xhci_dump (struct xhci_device *xhci)
 Dump host controller registers.
static void xhci_dump_port (struct xhci_device *xhci, unsigned int port)
 Dump port registers.
static void xhci_legacy_init (struct xhci_device *xhci)
 Initialise USB legacy support.
static void xhci_legacy_claim (struct xhci_device *xhci)
 Claim ownership from BIOS.
static void xhci_legacy_release (struct xhci_device *xhci)
 Release ownership back to BIOS.
static const char * xhci_speed_name (uint32_t psi)
 Transcribe port speed (for debugging)
static unsigned int xhci_supported_protocol (struct xhci_device *xhci, unsigned int port)
 Find supported protocol extended capability for a port.
static unsigned int xhci_port_protocol (struct xhci_device *xhci, unsigned int port)
 Find port protocol.
static int xhci_port_slot_type (struct xhci_device *xhci, unsigned int port)
 Find port slot type.
static int xhci_port_speed (struct xhci_device *xhci, unsigned int port, unsigned int psiv)
 Find port speed.
static int xhci_port_psiv (struct xhci_device *xhci, unsigned int port, unsigned int speed)
 Find protocol speed ID value.
static int xhci_dcbaa_alloc (struct xhci_device *xhci)
 Allocate device context base address array.
static void xhci_dcbaa_free (struct xhci_device *xhci)
 Free device context base address array.
static int xhci_scratchpad_alloc (struct xhci_device *xhci)
 Allocate scratchpad buffers.
static void xhci_scratchpad_free (struct xhci_device *xhci)
 Free scratchpad buffers.
static void xhci_run (struct xhci_device *xhci)
 Start xHCI device.
static int xhci_stop (struct xhci_device *xhci)
 Stop xHCI device.
static int xhci_reset (struct xhci_device *xhci)
 Reset xHCI device.
static int xhci_ring_alloc (struct xhci_device *xhci, struct xhci_trb_ring *ring, unsigned int shift, unsigned int slot, unsigned int target, unsigned int stream)
 Allocate transfer request block ring.
static void xhci_ring_reset (struct xhci_trb_ring *ring)
 Reset transfer request block ring.
static void xhci_ring_free (struct xhci_trb_ring *ring)
 Free transfer request block ring.
static int xhci_enqueue (struct xhci_trb_ring *ring, struct io_buffer *iobuf, const union xhci_trb *trb)
 Enqueue a transfer request block.
static struct io_bufferxhci_dequeue (struct xhci_trb_ring *ring)
 Dequeue a transfer request block.
static int xhci_enqueue_multi (struct xhci_trb_ring *ring, struct io_buffer *iobuf, const union xhci_trb *trbs, unsigned int count)
 Enqueue multiple transfer request blocks.
static struct io_bufferxhci_dequeue_multi (struct xhci_trb_ring *ring)
 Dequeue multiple transfer request blocks.
static void xhci_doorbell (struct xhci_trb_ring *ring)
 Ring doorbell register.
static int xhci_command_alloc (struct xhci_device *xhci)
 Allocate command ring.
static void xhci_command_free (struct xhci_device *xhci)
 Free command ring.
static int xhci_event_alloc (struct xhci_device *xhci)
 Allocate event ring.
static void xhci_event_free (struct xhci_device *xhci)
 Free event ring.
static void xhci_transfer (struct xhci_device *xhci, struct xhci_trb_transfer *trb)
 Handle transfer event.
static void xhci_complete (struct xhci_device *xhci, struct xhci_trb_complete *trb)
 Handle command completion event.
static void xhci_port_status (struct xhci_device *xhci, struct xhci_trb_port_status *trb)
 Handle port status event.
static void xhci_host_controller (struct xhci_device *xhci, struct xhci_trb_host_controller *trb)
 Handle host controller event.
static void xhci_event_poll (struct xhci_device *xhci)
 Poll event ring.
static void xhci_abort (struct xhci_device *xhci)
 Abort command.
static int xhci_command (struct xhci_device *xhci, union xhci_trb *trb)
 Issue command and wait for completion.
static int xhci_nop (struct xhci_device *xhci)
 Issue NOP and wait for completion.
static int xhci_enable_slot (struct xhci_device *xhci, unsigned int type)
 Enable slot.
static int xhci_disable_slot (struct xhci_device *xhci, unsigned int slot)
 Disable slot.
static int xhci_context (struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint, unsigned int type, void(*populate)(struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint, void *input))
 Issue context-based command and wait for completion.
static void xhci_address_device_input (struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint, void *input)
 Populate address device input context.
static int xhci_address_device (struct xhci_device *xhci, struct xhci_slot *slot)
 Address device.
static void xhci_configure_endpoint_input (struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint, void *input)
 Populate configure endpoint input context.
static int xhci_configure_endpoint (struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint)
 Configure endpoint.
static void xhci_deconfigure_endpoint_input (struct xhci_device *xhci __unused, struct xhci_slot *slot __unused, struct xhci_endpoint *endpoint, void *input)
 Populate deconfigure endpoint input context.
static int xhci_deconfigure_endpoint (struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint)
 Deconfigure endpoint.
static void xhci_evaluate_context_input (struct xhci_device *xhci, struct xhci_slot *slot __unused, struct xhci_endpoint *endpoint, void *input)
 Populate evaluate context input context.
static int xhci_evaluate_context (struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint)
 Evaluate context.
static int xhci_reset_endpoint (struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint)
 Reset endpoint.
static int xhci_stop_endpoint (struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint)
 Stop endpoint.
static int xhci_set_tr_dequeue_pointer (struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint)
 Set transfer ring dequeue pointer.
static int xhci_endpoint_open (struct usb_endpoint *ep)
 Open endpoint.
static void xhci_endpoint_close (struct usb_endpoint *ep)
 Close endpoint.
static int xhci_endpoint_reset (struct usb_endpoint *ep)
 Reset endpoint.
static int xhci_endpoint_mtu (struct usb_endpoint *ep)
 Update MTU.
static int xhci_endpoint_message (struct usb_endpoint *ep, struct io_buffer *iobuf)
 Enqueue message transfer.
static unsigned int xhci_endpoint_count (size_t len, int zlp)
 Calculate number of TRBs.
static int xhci_endpoint_stream (struct usb_endpoint *ep, struct io_buffer *iobuf, int zlp)
 Enqueue stream transfer.
static int xhci_device_open (struct usb_device *usb)
 Open device.
static void xhci_device_close (struct usb_device *usb)
 Close device.
static int xhci_device_address (struct usb_device *usb)
 Assign device address.
static int xhci_bus_open (struct usb_bus *bus)
 Open USB bus.
static void xhci_bus_close (struct usb_bus *bus)
 Close USB bus.
static void xhci_bus_poll (struct usb_bus *bus)
 Poll USB bus.
static int xhci_hub_open (struct usb_hub *hub)
 Open hub.
static void xhci_hub_close (struct usb_hub *hub __unused)
 Close hub.
static int xhci_root_open (struct usb_hub *hub)
 Open root hub.
static void xhci_root_close (struct usb_hub *hub)
 Close root hub.
static int xhci_root_enable (struct usb_hub *hub, struct usb_port *port)
 Enable port.
static int xhci_root_disable (struct usb_hub *hub, struct usb_port *port)
 Disable port.
static int xhci_root_speed (struct usb_hub *hub, struct usb_port *port)
 Update root hub port speed.
static int xhci_root_clear_tt (struct usb_hub *hub, struct usb_port *port, struct usb_endpoint *ep)
 Clear transaction translator buffer.
static void xhci_pch_fix (struct xhci_device *xhci, struct pci_device *pci)
 Fix Intel PCH-specific quirks.
static void xhci_pch_undo (struct xhci_device *xhci, struct pci_device *pci)
 Undo Intel PCH-specific quirk fixes.
static int xhci_probe (struct pci_device *pci)
 Probe PCI device.
static void xhci_remove (struct pci_device *pci)
 Remove PCI device.
static void xhci_shutdown (int booting)
 Prepare for exit.
struct startup_fn xhci_startup __startup_fn (STARTUP_LATE)
 Startup/shutdown function.

Variables

static struct profiler
xhci_message_profiler 
__profiler
 Message transfer profiler.
static int xhci_legacy_prevent_release
 Prevent the release of ownership back to BIOS.
static struct usb_host_operations xhci_operations
 USB host controller operations.
static struct pci_device_id xhci_ids []
 XHCI PCI device IDs.
struct pci_driver xhci_driver __pci_driver
 XHCI PCI driver.

Detailed Description

USB eXtensible Host Controller Interface (xHCI) driver.

Definition in file xhci.c.


Define Documentation

Definition at line 64 of file xhci.c.

#define EINFO_EIO_DATA
Value:
__einfo_uniqify ( EINFO_EIO, ( 2 - 0 ),                         \
                          "Data buffer error" )

Definition at line 66 of file xhci.c.

Definition at line 69 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 3 - 0 ),                         \
                          "Babble detected" )

Definition at line 71 of file xhci.c.

Definition at line 74 of file xhci.c.

#define EINFO_EIO_USB
Value:
__einfo_uniqify ( EINFO_EIO, ( 4 - 0 ),                         \
                          "USB transaction error" )

Definition at line 76 of file xhci.c.

Definition at line 79 of file xhci.c.

#define EINFO_EIO_TRB
Value:
__einfo_uniqify ( EINFO_EIO, ( 5 - 0 ),                         \
                          "TRB error" )

Definition at line 81 of file xhci.c.

Definition at line 84 of file xhci.c.

#define EINFO_EIO_STALL
Value:
__einfo_uniqify ( EINFO_EIO, ( 6 - 0 ),                         \
                          "Stall error" )

Definition at line 86 of file xhci.c.

Definition at line 89 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 7 - 0 ),                         \
                          "Resource error" )

Definition at line 91 of file xhci.c.

Definition at line 94 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 8 - 0 ),                         \
                          "Bandwidth error" )

Definition at line 96 of file xhci.c.

Definition at line 99 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 9 - 0 ),                         \
                          "No slots available" )

Definition at line 101 of file xhci.c.

Definition at line 104 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 10 - 0 ),                        \
                          "Invalid stream type" )

Definition at line 106 of file xhci.c.

Definition at line 109 of file xhci.c.

#define EINFO_EIO_SLOT
Value:
__einfo_uniqify ( EINFO_EIO, ( 11 - 0 ),                        \
                          "Slot not enabled" )

Definition at line 111 of file xhci.c.

Definition at line 114 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 12 - 0 ),                        \
                          "Endpoint not enabled" )

Definition at line 116 of file xhci.c.

Definition at line 119 of file xhci.c.

#define EINFO_EIO_SHORT
Value:
__einfo_uniqify ( EINFO_EIO, ( 13 - 0 ),                        \
                          "Short packet" )

Definition at line 121 of file xhci.c.

Definition at line 124 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 14 - 0 ),                        \
                          "Ring underrun" )

Definition at line 126 of file xhci.c.

Definition at line 129 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 15 - 0 ),                        \
                          "Ring overrun" )

Definition at line 131 of file xhci.c.

Definition at line 134 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 16 - 0 ),                        \
                          "Virtual function event ring full" )

Definition at line 136 of file xhci.c.

Definition at line 139 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 17 - 0 ),                        \
                          "Parameter error" )

Definition at line 141 of file xhci.c.

Definition at line 144 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 18 - 0 ),                        \
                          "Bandwidth overrun" )

Definition at line 146 of file xhci.c.

Definition at line 149 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 19 - 0 ),                        \
                          "Context state error" )

Definition at line 151 of file xhci.c.

Definition at line 154 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 20 - 0 ),                        \
                          "No ping response" )

Definition at line 156 of file xhci.c.

Definition at line 159 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 21 - 0 ),                        \
                          "Event ring full" )

Definition at line 161 of file xhci.c.

Definition at line 164 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 22 - 0 ),                        \
                          "Incompatible device" )

Definition at line 166 of file xhci.c.

Definition at line 169 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 23 - 0 ),                        \
                          "Missed service error" )

Definition at line 171 of file xhci.c.

Definition at line 174 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 24 - 0 ),                        \
                          "Command ring stopped" )

Definition at line 176 of file xhci.c.

Definition at line 179 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 25 - 0 ),                        \
                          "Command aborted" )

Definition at line 181 of file xhci.c.

Definition at line 184 of file xhci.c.

#define EINFO_EIO_STOP
Value:
__einfo_uniqify ( EINFO_EIO, ( 26 - 0 ),                        \
                          "Stopped" )

Definition at line 186 of file xhci.c.

Definition at line 189 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 27 - 0 ),                        \
                          "Stopped - length invalid" )

Definition at line 191 of file xhci.c.

Definition at line 194 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 28 - 0 ),                        \
                          "Stopped - short packet" )

Definition at line 196 of file xhci.c.

Definition at line 199 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EIO, ( 29 - 0 ),                        \
                          "Maximum exit latency too large" )

Definition at line 201 of file xhci.c.

Definition at line 204 of file xhci.c.

#define EINFO_EIO_ISOCH
Value:
__einfo_uniqify ( EINFO_EIO, ( 31 - 0 ),                        \
                          "Isochronous buffer overrun" )

Definition at line 206 of file xhci.c.

Definition at line 209 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EPROTO, ( 32 - 32 ),                    \
                          "Event lost" )

Definition at line 211 of file xhci.c.

Definition at line 214 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EPROTO, ( 33 - 32 ),                    \
                          "Undefined error" )

Definition at line 216 of file xhci.c.

Definition at line 219 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EPROTO, ( 34 - 32 ),                    \
                          "Invalid stream ID" )

Definition at line 221 of file xhci.c.

Definition at line 224 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EPROTO, ( 35 - 32 ),                    \
                          "Secondary bandwidth error" )

Definition at line 226 of file xhci.c.

Definition at line 229 of file xhci.c.

Value:
__einfo_uniqify ( EINFO_EPROTO, ( 36 - 32 ),                    \
                          "Split transaction error" )

Definition at line 231 of file xhci.c.

#define ECODE (   code)

Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void xhci_init ( struct xhci_device xhci,
void *  regs 
) [static]

Initialise device.

Parameters:
xhcixHCI device
regsMMIO registers

Definition at line 265 of file xhci.c.

References xhci_device::addr64, assert, xhci_device::cap, xhci_device::csz_shift, xhci_device::db, DBGC, DBGC2, xhci_device::intrs, xhci_device::name, xhci_device::op, xhci_device::pagesize, xhci_device::ports, readb(), readl(), regs, xhci_device::run, xhci_device::scratchpads, xhci_device::slots, virt_to_phys(), xhci_device::xecp, XHCI_CAP_CAPLENGTH, XHCI_CAP_DBOFF, XHCI_CAP_HCCPARAMS1, XHCI_CAP_HCSPARAMS1, XHCI_CAP_HCSPARAMS2, XHCI_CAP_RTSOFF, XHCI_HCCPARAMS1_ADDR64, XHCI_HCCPARAMS1_CSZ_SHIFT, XHCI_HCCPARAMS1_XECP, XHCI_HCSPARAMS1_INTRS, XHCI_HCSPARAMS1_PORTS, XHCI_HCSPARAMS1_SLOTS, XHCI_HCSPARAMS2_SCRATCHPADS, XHCI_OP_PAGESIZE, and XHCI_PAGESIZE.

Referenced by xhci_probe().

                                                               {
        uint32_t hcsparams1;
        uint32_t hcsparams2;
        uint32_t hccparams1;
        uint32_t pagesize;
        size_t caplength;
        size_t rtsoff;
        size_t dboff;

        /* Locate capability, operational, runtime, and doorbell registers */
        xhci->cap = regs;
        caplength = readb ( xhci->cap + XHCI_CAP_CAPLENGTH );
        rtsoff = readl ( xhci->cap + XHCI_CAP_RTSOFF );
        dboff = readl ( xhci->cap + XHCI_CAP_DBOFF );
        xhci->op = ( xhci->cap + caplength );
        xhci->run = ( xhci->cap + rtsoff );
        xhci->db = ( xhci->cap + dboff );
        DBGC2 ( xhci, "XHCI %s cap %08lx op %08lx run %08lx db %08lx\n",
                xhci->name, virt_to_phys ( xhci->cap ),
                virt_to_phys ( xhci->op ), virt_to_phys ( xhci->run ),
                virt_to_phys ( xhci->db ) );

        /* Read structural parameters 1 */
        hcsparams1 = readl ( xhci->cap + XHCI_CAP_HCSPARAMS1 );
        xhci->slots = XHCI_HCSPARAMS1_SLOTS ( hcsparams1 );
        xhci->intrs = XHCI_HCSPARAMS1_INTRS ( hcsparams1 );
        xhci->ports = XHCI_HCSPARAMS1_PORTS ( hcsparams1 );
        DBGC ( xhci, "XHCI %s has %d slots %d intrs %d ports\n",
               xhci->name, xhci->slots, xhci->intrs, xhci->ports );

        /* Read structural parameters 2 */
        hcsparams2 = readl ( xhci->cap + XHCI_CAP_HCSPARAMS2 );
        xhci->scratchpads = XHCI_HCSPARAMS2_SCRATCHPADS ( hcsparams2 );
        DBGC2 ( xhci, "XHCI %s needs %d scratchpads\n",
                xhci->name, xhci->scratchpads );

        /* Read capability parameters 1 */
        hccparams1 = readl ( xhci->cap + XHCI_CAP_HCCPARAMS1 );
        xhci->addr64 = XHCI_HCCPARAMS1_ADDR64 ( hccparams1 );
        xhci->csz_shift = XHCI_HCCPARAMS1_CSZ_SHIFT ( hccparams1 );
        xhci->xecp = XHCI_HCCPARAMS1_XECP ( hccparams1 );

        /* Read page size */
        pagesize = readl ( xhci->op + XHCI_OP_PAGESIZE );
        xhci->pagesize = XHCI_PAGESIZE ( pagesize );
        assert ( xhci->pagesize != 0 );
        assert ( ( ( xhci->pagesize ) & ( xhci->pagesize - 1 ) ) == 0 );
        DBGC2 ( xhci, "XHCI %s page size %zd bytes\n",
                xhci->name, xhci->pagesize );
}
static unsigned int xhci_extended_capability ( struct xhci_device xhci,
unsigned int  id,
unsigned int  offset 
) [static]

Find extended capability.

Parameters:
xhcixHCI device
idCapability ID
offsetOffset to previous extended capability instance, or zero
Return values:
offsetOffset to extended capability, or zero if not found

Definition at line 324 of file xhci.c.

References xhci_device::cap, next, offset, readl(), xhci_device::xecp, XHCI_XECP_ID, and XHCI_XECP_NEXT.

Referenced by xhci_legacy_init(), and xhci_supported_protocol().

                                                                     {
        uint32_t xecp;
        unsigned int next;

        /* Locate the extended capability */
        while ( 1 ) {

                /* Locate first or next capability as applicable */
                if ( offset ) {
                        xecp = readl ( xhci->cap + offset );
                        next = XHCI_XECP_NEXT ( xecp );
                } else {
                        next = xhci->xecp;
                }
                if ( ! next )
                        return 0;
                offset += next;

                /* Check if this is the requested capability */
                xecp = readl ( xhci->cap + offset );
                if ( XHCI_XECP_ID ( xecp ) == id )
                        return offset;
        }
}
static int xhci_writeq ( struct xhci_device xhci,
physaddr_t  value,
void *  reg 
) [inline, static]

Write potentially 64-bit register.

Parameters:
xhcixHCI device
valueValue
regRegister address
Return values:
rcReturn status code

Definition at line 360 of file xhci.c.

References DBGC, ENOTSUP, writel(), and writeq().

Referenced by xhci_abort(), xhci_command_alloc(), xhci_command_free(), xhci_dcbaa_alloc(), xhci_dcbaa_free(), xhci_event_alloc(), xhci_event_free(), and xhci_event_poll().

                                                                      {

        /* If this is a 32-bit build, then this can never fail
         * (allowing the compiler to optimise out the error path).
         */
        if ( sizeof ( value ) <= sizeof ( uint32_t ) ) {
                writel ( value, reg );
                writel ( 0, ( reg + sizeof ( uint32_t ) ) );
                return 0;
        }

        /* If the device does not support 64-bit addresses and this
         * address is outside the 32-bit address space, then fail.
         */
        if ( ( value & ~0xffffffffULL ) && ! xhci->addr64 ) {
                DBGC ( xhci, "XHCI %s cannot access address %lx\n",
                       xhci->name, value );
                return -ENOTSUP;
        }

        /* If this is a 64-bit build, then writeq() is available */
        writeq ( value, reg );
        return 0;
}
static size_t xhci_align ( size_t  len) [inline, static]

Calculate buffer alignment.

Parameters:
lenLength
Return values:
alignBuffer alignment

Determine alignment required for a buffer which must be aligned to at least XHCI_MIN_ALIGN and which must not cross a page boundary.

Definition at line 394 of file xhci.c.

References fls, and XHCI_MIN_ALIGN.

Referenced by xhci_context(), xhci_dcbaa_alloc(), xhci_device_open(), xhci_event_alloc(), xhci_ring_alloc(), and xhci_scratchpad_alloc().

                                               {
        size_t align;

        /* Align to own length (rounded up to a power of two) */
        align = ( 1 << fls ( len - 1 ) );

        /* Round up to XHCI_MIN_ALIGN if needed */
        if ( align < XHCI_MIN_ALIGN )
                align = XHCI_MIN_ALIGN;

        return align;
}
static size_t xhci_device_context_offset ( struct xhci_device xhci,
unsigned int  ctx 
) [inline, static]

Calculate device context offset.

Parameters:
xhcixHCI device
ctxContext index

Definition at line 413 of file xhci.c.

References xhci_device::csz_shift, and XHCI_DCI.

Referenced by xhci_address_device(), xhci_device_close(), xhci_device_open(), and xhci_endpoint_open().

                                                                     {

        return ( XHCI_DCI ( ctx ) << xhci->csz_shift );
}
static size_t xhci_input_context_offset ( struct xhci_device xhci,
unsigned int  ctx 
) [inline, static]

Calculate input context offset.

Parameters:
xhcixHCI device
ctxContext index

Definition at line 425 of file xhci.c.

References xhci_device::csz_shift, and XHCI_ICI.

Referenced by xhci_address_device_input(), xhci_configure_endpoint_input(), xhci_context(), xhci_deconfigure_endpoint_input(), and xhci_evaluate_context_input().

                                                                    {

        return ( XHCI_ICI ( ctx ) << xhci->csz_shift );
}
static void xhci_dump ( struct xhci_device xhci) [inline, static]

Dump host controller registers.

Parameters:
xhcixHCI device

Definition at line 443 of file xhci.c.

References DBG_LOG, DBGC, xhci_device::name, xhci_device::op, readl(), XHCI_OP_CONFIG, XHCI_OP_DNCTRL, XHCI_OP_PAGESIZE, XHCI_OP_USBCMD, XHCI_OP_USBSTS, XHCI_USBCMD_HCRST, XHCI_USBCMD_RUN, and XHCI_USBSTS_HCH.

                                                          {
        uint32_t usbcmd;
        uint32_t usbsts;
        uint32_t pagesize;
        uint32_t dnctrl;
        uint32_t config;

        /* Do nothing unless debugging is enabled */
        if ( ! DBG_LOG )
                return;

        /* Dump USBCMD */
        usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
        DBGC ( xhci, "XHCI %s USBCMD %08x%s%s\n", xhci->name, usbcmd,
               ( ( usbcmd & XHCI_USBCMD_RUN ) ? " run" : "" ),
               ( ( usbcmd & XHCI_USBCMD_HCRST ) ? " hcrst" : "" ) );

        /* Dump USBSTS */
        usbsts = readl ( xhci->op + XHCI_OP_USBSTS );
        DBGC ( xhci, "XHCI %s USBSTS %08x%s\n", xhci->name, usbsts,
               ( ( usbsts & XHCI_USBSTS_HCH ) ? " hch" : "" ) );

        /* Dump PAGESIZE */
        pagesize = readl ( xhci->op + XHCI_OP_PAGESIZE );
        DBGC ( xhci, "XHCI %s PAGESIZE %08x\n", xhci->name, pagesize );

        /* Dump DNCTRL */
        dnctrl = readl ( xhci->op + XHCI_OP_DNCTRL );
        DBGC ( xhci, "XHCI %s DNCTRL %08x\n", xhci->name, dnctrl );

        /* Dump CONFIG */
        config = readl ( xhci->op + XHCI_OP_CONFIG );
        DBGC ( xhci, "XHCI %s CONFIG %08x\n", xhci->name, config );
}
static void xhci_dump_port ( struct xhci_device xhci,
unsigned int  port 
) [inline, static]

Dump port registers.

Parameters:
xhcixHCI device
portPort number

Definition at line 484 of file xhci.c.

References DBG_LOG, DBGC, xhci_device::name, xhci_device::op, readl(), XHCI_OP_PORTHLPMC, XHCI_OP_PORTLI, XHCI_OP_PORTPMSC, XHCI_OP_PORTSC, XHCI_PORTSC_CCS, XHCI_PORTSC_PED, XHCI_PORTSC_PP, XHCI_PORTSC_PR, and XHCI_PORTSC_PSIV.

                                                        {
        uint32_t portsc;
        uint32_t portpmsc;
        uint32_t portli;
        uint32_t porthlpmc;

        /* Do nothing unless debugging is enabled */
        if ( ! DBG_LOG )
                return;

        /* Dump PORTSC */
        portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) );
        DBGC ( xhci, "XHCI %s-%d PORTSC %08x%s%s%s%s psiv=%d\n",
               xhci->name, port, portsc,
               ( ( portsc & XHCI_PORTSC_CCS ) ? " ccs" : "" ),
               ( ( portsc & XHCI_PORTSC_PED ) ? " ped" : "" ),
               ( ( portsc & XHCI_PORTSC_PR ) ? " pr" : "" ),
               ( ( portsc & XHCI_PORTSC_PP ) ? " pp" : "" ),
               XHCI_PORTSC_PSIV ( portsc ) );

        /* Dump PORTPMSC */
        portpmsc = readl ( xhci->op + XHCI_OP_PORTPMSC ( port ) );
        DBGC ( xhci, "XHCI %s-%d PORTPMSC %08x\n", xhci->name, port, portpmsc );

        /* Dump PORTLI */
        portli = readl ( xhci->op + XHCI_OP_PORTLI ( port ) );
        DBGC ( xhci, "XHCI %s-%d PORTLI %08x\n", xhci->name, port, portli );

        /* Dump PORTHLPMC */
        porthlpmc = readl ( xhci->op + XHCI_OP_PORTHLPMC ( port ) );
        DBGC ( xhci, "XHCI %s-%d PORTHLPMC %08x\n",
               xhci->name, port, porthlpmc );
}
static void xhci_legacy_init ( struct xhci_device xhci) [static]

Initialise USB legacy support.

Parameters:
xhcixHCI device

Definition at line 534 of file xhci.c.

References xhci_device::cap, DBGC, xhci_device::legacy, xhci_device::name, readb(), xhci_extended_capability(), XHCI_USBLEGSUP_BIOS, XHCI_USBLEGSUP_BIOS_OWNED, and XHCI_XECP_ID_LEGACY.

Referenced by xhci_probe().

                                                          {
        unsigned int legacy;
        uint8_t bios;

        /* Locate USB legacy support capability (if present) */
        legacy = xhci_extended_capability ( xhci, XHCI_XECP_ID_LEGACY, 0 );
        if ( ! legacy ) {
                /* Not an error; capability may not be present */
                DBGC ( xhci, "XHCI %s has no USB legacy support capability\n",
                       xhci->name );
                return;
        }

        /* Check if legacy USB support is enabled */
        bios = readb ( xhci->cap + legacy + XHCI_USBLEGSUP_BIOS );
        if ( ! ( bios & XHCI_USBLEGSUP_BIOS_OWNED ) ) {
                /* Not an error; already owned by OS */
                DBGC ( xhci, "XHCI %s USB legacy support already disabled\n",
                       xhci->name );
                return;
        }

        /* Record presence of USB legacy support capability */
        xhci->legacy = legacy;
}
static void xhci_legacy_claim ( struct xhci_device xhci) [static]

Claim ownership from BIOS.

Parameters:
xhcixHCI device

Definition at line 565 of file xhci.c.

References xhci_device::cap, DBGC, xhci_device::legacy, mdelay(), xhci_device::name, readb(), readl(), writeb(), writel(), XHCI_USBLEGSUP_BIOS, XHCI_USBLEGSUP_BIOS_OWNED, XHCI_USBLEGSUP_CTLSTS, XHCI_USBLEGSUP_MAX_WAIT_MS, XHCI_USBLEGSUP_OS, and XHCI_USBLEGSUP_OS_OWNED.

Referenced by xhci_probe().

                                                           {
        uint32_t ctlsts;
        uint8_t bios;
        unsigned int i;

        /* Do nothing unless legacy support capability is present */
        if ( ! xhci->legacy )
                return;

        /* Claim ownership */
        writeb ( XHCI_USBLEGSUP_OS_OWNED,
                 xhci->cap + xhci->legacy + XHCI_USBLEGSUP_OS );

        /* Wait for BIOS to release ownership */
        for ( i = 0 ; i < XHCI_USBLEGSUP_MAX_WAIT_MS ; i++ ) {

                /* Check if BIOS has released ownership */
                bios = readb ( xhci->cap + xhci->legacy + XHCI_USBLEGSUP_BIOS );
                if ( ! ( bios & XHCI_USBLEGSUP_BIOS_OWNED ) ) {
                        DBGC ( xhci, "XHCI %s claimed ownership from BIOS\n",
                               xhci->name );
                        ctlsts = readl ( xhci->cap + xhci->legacy +
                                         XHCI_USBLEGSUP_CTLSTS );
                        if ( ctlsts ) {
                                DBGC ( xhci, "XHCI %s warning: BIOS retained "
                                       "SMIs: %08x\n", xhci->name, ctlsts );
                        }
                        return;
                }

                /* Delay */
                mdelay ( 1 );
        }

        /* BIOS did not release ownership.  Claim it forcibly by
         * disabling all SMIs.
         */
        DBGC ( xhci, "XHCI %s could not claim ownership from BIOS: forcibly "
               "disabling SMIs\n", xhci->name );
        writel ( 0, xhci->cap + xhci->legacy + XHCI_USBLEGSUP_CTLSTS );
}
static void xhci_legacy_release ( struct xhci_device xhci) [static]

Release ownership back to BIOS.

Parameters:
xhcixHCI device

Definition at line 612 of file xhci.c.

References xhci_device::cap, DBGC, xhci_device::legacy, xhci_device::name, writeb(), and XHCI_USBLEGSUP_OS.

Referenced by xhci_probe(), and xhci_remove().

                                                             {

        /* Do nothing unless legacy support capability is present */
        if ( ! xhci->legacy )
                return;

        /* Do nothing if releasing ownership is prevented */
        if ( xhci_legacy_prevent_release ) {
                DBGC ( xhci, "XHCI %s not releasing ownership to BIOS\n",
                       xhci->name );
                return;
        }

        /* Release ownership */
        writeb ( 0, xhci->cap + xhci->legacy + XHCI_USBLEGSUP_OS );
        DBGC ( xhci, "XHCI %s released ownership to BIOS\n", xhci->name );
}
static const char* xhci_speed_name ( uint32_t  psi) [inline, static]

Transcribe port speed (for debugging)

Parameters:
psiProtocol speed ID
Return values:
speedTranscribed speed

Definition at line 643 of file xhci.c.

References snprintf(), XHCI_SUPPORTED_PSI_EXPONENT, and XHCI_SUPPORTED_PSI_MANTISSA.

Referenced by xhci_port_protocol().

                                                            {
        static const char *exponents[4] = { "", "k", "M", "G" };
        static char buf[ 10 /* "xxxxxXbps" + NUL */ ];
        unsigned int mantissa;
        unsigned int exponent;

        /* Extract mantissa and exponent */
        mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
        exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );

        /* Transcribe speed */
        snprintf ( buf, sizeof ( buf ), "%d%sbps",
                   mantissa, exponents[exponent] );
        return buf;
}
static unsigned int xhci_supported_protocol ( struct xhci_device xhci,
unsigned int  port 
) [static]

Find supported protocol extended capability for a port.

Parameters:
xhcixHCI device
portPort number
Return values:
supportedOffset to extended capability, or zero if not found

Definition at line 666 of file xhci.c.

References xhci_device::cap, count, DBGC, xhci_device::name, offset, readl(), xhci_extended_capability(), XHCI_SUPPORTED_PORTS, XHCI_SUPPORTED_PORTS_COUNT, XHCI_SUPPORTED_PORTS_OFFSET, and XHCI_XECP_ID_SUPPORTED.

Referenced by xhci_port_protocol(), xhci_port_psiv(), xhci_port_slot_type(), and xhci_port_speed().

                                                                  {
        unsigned int supported = 0;
        unsigned int offset;
        unsigned int count;
        uint32_t ports;

        /* Iterate over all supported protocol structures */
        while ( ( supported = xhci_extended_capability ( xhci,
                                                         XHCI_XECP_ID_SUPPORTED,
                                                         supported ) ) ) {

                /* Determine port range */
                ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
                offset = XHCI_SUPPORTED_PORTS_OFFSET ( ports );
                count = XHCI_SUPPORTED_PORTS_COUNT ( ports );

                /* Check if port lies within this range */
                if ( ( port - offset ) < count )
                        return supported;
        }

        DBGC ( xhci, "XHCI %s-%d has no supported protocol\n",
               xhci->name, port );
        return 0;
}
static unsigned int xhci_port_protocol ( struct xhci_device xhci,
unsigned int  port 
) [static]

Find port protocol.

Parameters:
xhcixHCI device
portPort number
Return values:
protocolUSB protocol, or zero if not found

Definition at line 700 of file xhci.c.

References xhci_device::cap, cpu_to_le32, DBG_EXTRA, DBGC2, xhci_device::name, name, protocol, xhci_device::quirks, raw, readl(), revision, slot, type, XHCI_BAD_PSIV, xhci_speed_name(), XHCI_SUPPORTED_NAME, XHCI_SUPPORTED_PORTS, XHCI_SUPPORTED_PORTS_PSIC, xhci_supported_protocol(), XHCI_SUPPORTED_PSI, XHCI_SUPPORTED_PSI_VALUE, XHCI_SUPPORTED_REVISION, XHCI_SUPPORTED_REVISION_VER, XHCI_SUPPORTED_SLOT, and XHCI_SUPPORTED_SLOT_TYPE.

Referenced by xhci_probe().

                                                             {
        unsigned int supported = xhci_supported_protocol ( xhci, port );
        union {
                uint32_t raw;
                char text[5];
        } name;
        unsigned int protocol;
        unsigned int type;
        unsigned int psic;
        unsigned int psiv;
        unsigned int i;
        uint32_t revision;
        uint32_t ports;
        uint32_t slot;
        uint32_t psi;

        /* Fail if there is no supported protocol */
        if ( ! supported )
                return 0;

        /* Determine protocol version */
        revision = readl ( xhci->cap + supported + XHCI_SUPPORTED_REVISION );
        protocol = XHCI_SUPPORTED_REVISION_VER ( revision );

        /* Describe port protocol */
        if ( DBG_EXTRA ) {
                name.raw = cpu_to_le32 ( readl ( xhci->cap + supported +
                                                 XHCI_SUPPORTED_NAME ) );
                name.text[4] = '\0';
                slot = readl ( xhci->cap + supported + XHCI_SUPPORTED_SLOT );
                type = XHCI_SUPPORTED_SLOT_TYPE ( slot );
                DBGC2 ( xhci, "XHCI %s-%d %sv%04x type %d",
                        xhci->name, port, name.text, protocol, type );
                ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
                psic = XHCI_SUPPORTED_PORTS_PSIC ( ports );
                if ( psic ) {
                        DBGC2 ( xhci, " speeds" );
                        for ( i = 0 ; i < psic ; i++ ) {
                                psi = readl ( xhci->cap + supported +
                                              XHCI_SUPPORTED_PSI ( i ) );
                                psiv = XHCI_SUPPORTED_PSI_VALUE ( psi );
                                DBGC2 ( xhci, " %d:%s", psiv,
                                        xhci_speed_name ( psi ) );
                        }
                }
                if ( xhci->quirks & XHCI_BAD_PSIV )
                        DBGC2 ( xhci, " (ignored)" );
                DBGC2 ( xhci, "\n" );
        }

        return protocol;
}
static int xhci_port_slot_type ( struct xhci_device xhci,
unsigned int  port 
) [static]

Find port slot type.

Parameters:
xhcixHCI device
portPort number
Return values:
typeSlot type, or negative error

Definition at line 761 of file xhci.c.

References xhci_device::cap, ENOTSUP, readl(), slot, type, xhci_supported_protocol(), XHCI_SUPPORTED_SLOT, and XHCI_SUPPORTED_SLOT_TYPE.

Referenced by xhci_device_open().

                                                                               {
        unsigned int supported = xhci_supported_protocol ( xhci, port );
        unsigned int type;
        uint32_t slot;

        /* Fail if there is no supported protocol */
        if ( ! supported )
                return -ENOTSUP;

        /* Get slot type */
        slot = readl ( xhci->cap + supported + XHCI_SUPPORTED_SLOT );
        type = XHCI_SUPPORTED_SLOT_TYPE ( slot );

        return type;
}
static int xhci_port_speed ( struct xhci_device xhci,
unsigned int  port,
unsigned int  psiv 
) [static]

Find port speed.

Parameters:
xhcixHCI device
portPort number
psivProtocol speed ID value
Return values:
speedPort speed, or negative error

Definition at line 785 of file xhci.c.

References xhci_device::cap, DBGC, ENOTSUP, xhci_device::name, xhci_device::quirks, readl(), speed, USB_SPEED, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_LOW, USB_SPEED_SUPER, XHCI_BAD_PSIV, XHCI_SPEED_FULL, XHCI_SPEED_HIGH, XHCI_SPEED_LOW, XHCI_SPEED_SUPER, XHCI_SUPPORTED_PORTS, XHCI_SUPPORTED_PORTS_PSIC, xhci_supported_protocol(), XHCI_SUPPORTED_PSI, XHCI_SUPPORTED_PSI_EXPONENT, XHCI_SUPPORTED_PSI_MANTISSA, and XHCI_SUPPORTED_PSI_VALUE.

Referenced by xhci_root_speed().

                                                 {
        unsigned int supported = xhci_supported_protocol ( xhci, port );
        unsigned int psic;
        unsigned int mantissa;
        unsigned int exponent;
        unsigned int speed;
        unsigned int i;
        uint32_t ports;
        uint32_t psi;

        /* Fail if there is no supported protocol */
        if ( ! supported )
                return -ENOTSUP;

        /* Get protocol speed ID count */
        ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
        psic = XHCI_SUPPORTED_PORTS_PSIC ( ports );

        /* Use protocol speed ID table unless device is known to be faulty */
        if ( ! ( xhci->quirks & XHCI_BAD_PSIV ) ) {

                /* Iterate over PSI dwords looking for a match */
                for ( i = 0 ; i < psic ; i++ ) {
                        psi = readl ( xhci->cap + supported +
                                      XHCI_SUPPORTED_PSI ( i ) );
                        if ( psiv == XHCI_SUPPORTED_PSI_VALUE ( psi ) ) {
                                mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
                                exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );
                                speed = USB_SPEED ( mantissa, exponent );
                                return speed;
                        }
                }

                /* Record device as faulty if no match is found */
                if ( psic != 0 ) {
                        DBGC ( xhci, "XHCI %s-%d spurious PSI value %d: "
                               "assuming PSI table is invalid\n",
                               xhci->name, port, psiv );
                        xhci->quirks |= XHCI_BAD_PSIV;
                }
        }

        /* Use the default mappings */
        switch ( psiv ) {
        case XHCI_SPEED_LOW :   return USB_SPEED_LOW;
        case XHCI_SPEED_FULL :  return USB_SPEED_FULL;
        case XHCI_SPEED_HIGH :  return USB_SPEED_HIGH;
        case XHCI_SPEED_SUPER : return USB_SPEED_SUPER;
        default:
                DBGC ( xhci, "XHCI %s-%d unrecognised PSI value %d\n",
                       xhci->name, port, psiv );
                return -ENOTSUP;
        }
}
static int xhci_port_psiv ( struct xhci_device xhci,
unsigned int  port,
unsigned int  speed 
) [static]

Find protocol speed ID value.

Parameters:
xhcixHCI device
portPort number
speedUSB speed
Return values:
psivProtocol speed ID value, or negative error

Definition at line 849 of file xhci.c.

References xhci_device::cap, DBGC, ENOENT, ENOTSUP, xhci_device::name, xhci_device::quirks, readl(), USB_SPEED, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_LOW, USB_SPEED_SUPER, XHCI_BAD_PSIV, XHCI_SPEED_FULL, XHCI_SPEED_HIGH, XHCI_SPEED_LOW, XHCI_SPEED_SUPER, XHCI_SUPPORTED_PORTS, XHCI_SUPPORTED_PORTS_PSIC, xhci_supported_protocol(), XHCI_SUPPORTED_PSI, XHCI_SUPPORTED_PSI_EXPONENT, XHCI_SUPPORTED_PSI_MANTISSA, and XHCI_SUPPORTED_PSI_VALUE.

Referenced by xhci_device_address().

                                                 {
        unsigned int supported = xhci_supported_protocol ( xhci, port );
        unsigned int psic;
        unsigned int mantissa;
        unsigned int exponent;
        unsigned int psiv;
        unsigned int i;
        uint32_t ports;
        uint32_t psi;

        /* Fail if there is no supported protocol */
        if ( ! supported )
                return -ENOTSUP;

        /* Get protocol speed ID count */
        ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
        psic = XHCI_SUPPORTED_PORTS_PSIC ( ports );

        /* Use the default mappings if applicable */
        if ( ( psic == 0 ) || ( xhci->quirks & XHCI_BAD_PSIV ) ) {
                switch ( speed ) {
                case USB_SPEED_LOW :    return XHCI_SPEED_LOW;
                case USB_SPEED_FULL :   return XHCI_SPEED_FULL;
                case USB_SPEED_HIGH :   return XHCI_SPEED_HIGH;
                case USB_SPEED_SUPER :  return XHCI_SPEED_SUPER;
                default:
                        DBGC ( xhci, "XHCI %s-%d non-standard speed %d\n",
                               xhci->name, port, speed );
                        return -ENOTSUP;
                }
        }

        /* Iterate over PSI dwords looking for a match */
        for ( i = 0 ; i < psic ; i++ ) {
                psi = readl ( xhci->cap + supported + XHCI_SUPPORTED_PSI ( i ));
                mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
                exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );
                if ( speed == USB_SPEED ( mantissa, exponent ) ) {
                        psiv = XHCI_SUPPORTED_PSI_VALUE ( psi );
                        return psiv;
                }
        }

        DBGC ( xhci, "XHCI %s-%d unrepresentable speed %#x\n",
               xhci->name, port, speed );
        return -ENOENT;
}
static int xhci_dcbaa_alloc ( struct xhci_device xhci) [static]

Allocate device context base address array.

Parameters:
xhcixHCI device
Return values:
rcReturn status code

Definition at line 911 of file xhci.c.

References DBGC, DBGC2, xhci_device::dcbaa, ENOMEM, free_dma(), len, malloc_dma(), memset(), xhci_device::name, xhci_device::op, rc, xhci_device::slots, virt_to_phys(), xhci_align(), XHCI_OP_DCBAAP, and xhci_writeq().

Referenced by xhci_bus_open().

                                                         {
        size_t len;
        physaddr_t dcbaap;
        int rc;

        /* Allocate and initialise structure.  Must be at least
         * 64-byte aligned and must not cross a page boundary, so
         * align on its own size (rounded up to a power of two and
         * with a minimum of 64 bytes).
         */
        len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) );
        xhci->dcbaa = malloc_dma ( len, xhci_align ( len ) );
        if ( ! xhci->dcbaa ) {
                DBGC ( xhci, "XHCI %s could not allocate DCBAA\n", xhci->name );
                rc = -ENOMEM;
                goto err_alloc;
        }
        memset ( xhci->dcbaa, 0, len );

        /* Program DCBAA pointer */
        dcbaap = virt_to_phys ( xhci->dcbaa );
        if ( ( rc = xhci_writeq ( xhci, dcbaap,
                                  xhci->op + XHCI_OP_DCBAAP ) ) != 0 )
                goto err_writeq;

        DBGC2 ( xhci, "XHCI %s DCBAA at [%08lx,%08lx)\n",
                xhci->name, dcbaap, ( dcbaap + len ) );
        return 0;

 err_writeq:
        free_dma ( xhci->dcbaa, len );
 err_alloc:
        return rc;
}
static void xhci_dcbaa_free ( struct xhci_device xhci) [static]

Free device context base address array.

Parameters:
xhcixHCI device

Definition at line 951 of file xhci.c.

References assert, xhci_device::dcbaa, free_dma(), len, xhci_device::op, xhci_device::slots, XHCI_OP_DCBAAP, and xhci_writeq().

Referenced by xhci_bus_close(), and xhci_bus_open().

                                                         {
        size_t len;
        unsigned int i;

        /* Sanity check */
        for ( i = 0 ; i <= xhci->slots ; i++ )
                assert ( xhci->dcbaa[i] == 0 );

        /* Clear DCBAA pointer */
        xhci_writeq ( xhci, 0, xhci->op + XHCI_OP_DCBAAP );

        /* Free DCBAA */
        len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) );
        free_dma ( xhci->dcbaa, len );
}
static int xhci_scratchpad_alloc ( struct xhci_device xhci) [static]

Allocate scratchpad buffers.

Parameters:
xhcixHCI device
Return values:
rcReturn status code

Definition at line 980 of file xhci.c.

References assert, cpu_to_le64, DBGC, DBGC2, xhci_device::dcbaa, ENOMEM, free_dma(), len, malloc_dma(), memset_user(), xhci_device::name, NULL, xhci_device::pagesize, phys, rc, xhci_device::scratchpad, xhci_device::scratchpad_array, xhci_device::scratchpads, ufree(), umalloc(), user_to_phys(), virt_to_phys(), and xhci_align().

Referenced by xhci_bus_open().

                                                              {
        size_t array_len;
        size_t len;
        physaddr_t phys;
        unsigned int i;
        int rc;

        /* Do nothing if no scratchpad buffers are used */
        if ( ! xhci->scratchpads )
                return 0;

        /* Allocate scratchpads */
        len = ( xhci->scratchpads * xhci->pagesize );
        xhci->scratchpad = umalloc ( len );
        if ( ! xhci->scratchpad ) {
                DBGC ( xhci, "XHCI %s could not allocate scratchpad buffers\n",
                       xhci->name );
                rc = -ENOMEM;
                goto err_alloc;
        }
        memset_user ( xhci->scratchpad, 0, 0, len );

        /* Allocate scratchpad array */
        array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] ));
        xhci->scratchpad_array =
                malloc_dma ( array_len, xhci_align ( array_len ) );
        if ( ! xhci->scratchpad_array ) {
                DBGC ( xhci, "XHCI %s could not allocate scratchpad buffer "
                       "array\n", xhci->name );
                rc = -ENOMEM;
                goto err_alloc_array;
        }

        /* Populate scratchpad array */
        for ( i = 0 ; i < xhci->scratchpads ; i++ ) {
                phys = user_to_phys ( xhci->scratchpad, ( i * xhci->pagesize ));
                xhci->scratchpad_array[i] = phys;
        }

        /* Set scratchpad array pointer */
        assert ( xhci->dcbaa != NULL );
        xhci->dcbaa[0] = cpu_to_le64 ( virt_to_phys ( xhci->scratchpad_array ));

        DBGC2 ( xhci, "XHCI %s scratchpad [%08lx,%08lx) array [%08lx,%08lx)\n",
                xhci->name, user_to_phys ( xhci->scratchpad, 0 ),
                user_to_phys ( xhci->scratchpad, len ),
                virt_to_phys ( xhci->scratchpad_array ),
                ( virt_to_phys ( xhci->scratchpad_array ) + array_len ) );
        return 0;

        free_dma ( xhci->scratchpad_array, array_len );
 err_alloc_array:
        ufree ( xhci->scratchpad );
 err_alloc:
        return rc;
}
static void xhci_scratchpad_free ( struct xhci_device xhci) [static]

Free scratchpad buffers.

Parameters:
xhcixHCI device

Definition at line 1042 of file xhci.c.

References assert, xhci_device::dcbaa, free_dma(), NULL, xhci_device::scratchpad, xhci_device::scratchpad_array, xhci_device::scratchpads, and ufree().

Referenced by xhci_bus_close(), and xhci_bus_open().

                                                              {
        size_t array_len;

        /* Do nothing if no scratchpad buffers are used */
        if ( ! xhci->scratchpads )
                return;

        /* Clear scratchpad array pointer */
        assert ( xhci->dcbaa != NULL );
        xhci->dcbaa[0] = 0;

        /* Free scratchpad array */
        array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] ));
        free_dma ( xhci->scratchpad_array, array_len );

        /* Free scratchpads */
        ufree ( xhci->scratchpad );
}
static void xhci_run ( struct xhci_device xhci) [static]

Start xHCI device.

Parameters:
xhcixHCI device

Definition at line 1073 of file xhci.c.

References xhci_device::op, readl(), xhci_device::slots, writel(), XHCI_CONFIG_MAX_SLOTS_EN, XHCI_CONFIG_MAX_SLOTS_EN_MASK, XHCI_OP_CONFIG, XHCI_OP_USBCMD, and XHCI_USBCMD_RUN.

Referenced by xhci_bus_open().

                                                  {
        uint32_t config;
        uint32_t usbcmd;

        /* Configure number of device slots */
        config = readl ( xhci->op + XHCI_OP_CONFIG );
        config &= ~XHCI_CONFIG_MAX_SLOTS_EN_MASK;
        config |= XHCI_CONFIG_MAX_SLOTS_EN ( xhci->slots );
        writel ( config, xhci->op + XHCI_OP_CONFIG );

        /* Set run/stop bit */
        usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
        usbcmd |= XHCI_USBCMD_RUN;
        writel ( usbcmd, xhci->op + XHCI_OP_USBCMD );
}
static int xhci_stop ( struct xhci_device xhci) [static]

Stop xHCI device.

Parameters:
xhcixHCI device
Return values:
rcReturn status code

Definition at line 1095 of file xhci.c.

References DBGC, ETIMEDOUT, mdelay(), xhci_device::name, xhci_device::op, readl(), writel(), XHCI_OP_USBCMD, XHCI_OP_USBSTS, XHCI_STOP_MAX_WAIT_MS, XHCI_USBCMD_RUN, and XHCI_USBSTS_HCH.

Referenced by xhci_bus_close(), xhci_bus_open(), and xhci_reset().

                                                  {
        uint32_t usbcmd;
        uint32_t usbsts;
        unsigned int i;

        /* Clear run/stop bit */
        usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
        usbcmd &= ~XHCI_USBCMD_RUN;
        writel ( usbcmd, xhci->op + XHCI_OP_USBCMD );

        /* Wait for device to stop */
        for ( i = 0 ; i < XHCI_STOP_MAX_WAIT_MS ; i++ ) {

                /* Check if device is stopped */
                usbsts = readl ( xhci->op + XHCI_OP_USBSTS );
                if ( usbsts & XHCI_USBSTS_HCH )
                        return 0;

                /* Delay */
                mdelay ( 1 );
        }

        DBGC ( xhci, "XHCI %s timed out waiting for stop\n", xhci->name );
        return -ETIMEDOUT;
}
static int xhci_reset ( struct xhci_device xhci) [static]

Reset xHCI device.

Parameters:
xhcixHCI device
Return values:
rcReturn status code

Definition at line 1127 of file xhci.c.

References DBGC, ETIMEDOUT, mdelay(), xhci_device::name, xhci_device::op, rc, readl(), writel(), XHCI_OP_USBCMD, XHCI_RESET_MAX_WAIT_MS, xhci_stop(), and XHCI_USBCMD_HCRST.

Referenced by xhci_probe(), and xhci_remove().

                                                   {
        uint32_t usbcmd;
        unsigned int i;
        int rc;

        /* The xHCI specification states that resetting a running
         * device may result in undefined behaviour, so try stopping
         * it first.
         */
        if ( ( rc = xhci_stop ( xhci ) ) != 0 ) {
                /* Ignore errors and attempt to reset the device anyway */
        }

        /* Reset device */
        writel ( XHCI_USBCMD_HCRST, xhci->op + XHCI_OP_USBCMD );

        /* Wait for reset to complete */
        for ( i = 0 ; i < XHCI_RESET_MAX_WAIT_MS ; i++ ) {

                /* Check if reset is complete */
                usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
                if ( ! ( usbcmd & XHCI_USBCMD_HCRST ) )
                        return 0;

                /* Delay */
                mdelay ( 1 );
        }

        DBGC ( xhci, "XHCI %s timed out waiting for reset\n", xhci->name );
        return -ETIMEDOUT;
}
static int xhci_ring_alloc ( struct xhci_device xhci,
struct xhci_trb_ring ring,
unsigned int  shift,
unsigned int  slot,
unsigned int  target,
unsigned int  stream 
) [static]

Allocate transfer request block ring.

Parameters:
xhcixHCI device
ringTRB ring
shiftRing size (log2)
slotDevice slot
targetDoorbell target
streamDoorbell stream ID
Return values:
rcReturn status code

Definition at line 1177 of file xhci.c.

References assert, count, cpu_to_le64, xhci_trb_ring::db, xhci_device::db, xhci_trb_ring::dbval, ENOMEM, xhci_trb_link::flags, free, free_dma(), xhci_trb_ring::iobuf, xhci_trb_ring::len, link, xhci_trb::link, xhci_trb_ring::link, malloc_dma(), xhci_trb_ring::mask, memset(), xhci_trb_link::next, rc, xhci_trb_ring::shift, xhci_trb_ring::trb, xhci_trb_link::type, virt_to_phys(), xhci_align(), XHCI_DBVAL, XHCI_TRB_LINK, XHCI_TRB_TC, and zalloc().

Referenced by xhci_command_alloc(), and xhci_endpoint_open().

                                                                        {
        struct xhci_trb_link *link;
        unsigned int count;
        int rc;

        /* Sanity check */
        assert ( shift > 0 );

        /* Initialise structure */
        memset ( ring, 0, sizeof ( *ring ) );
        ring->shift = shift;
        count = ( 1U << shift );
        ring->mask = ( count - 1 );
        ring->len = ( ( count + 1 /* Link TRB */ ) * sizeof ( ring->trb[0] ) );
        ring->db = ( xhci->db + ( slot * sizeof ( ring->dbval ) ) );
        ring->dbval = XHCI_DBVAL ( target, stream );

        /* Allocate I/O buffers */
        ring->iobuf = zalloc ( count * sizeof ( ring->iobuf[0] ) );
        if ( ! ring->iobuf ) {
                rc = -ENOMEM;
                goto err_alloc_iobuf;
        }

        /* Allocate TRBs */
        ring->trb = malloc_dma ( ring->len, xhci_align ( ring->len ) );
        if ( ! ring->trb ) {
                rc = -ENOMEM;
                goto err_alloc_trb;
        }
        memset ( ring->trb, 0, ring->len );

        /* Initialise Link TRB */
        link = &ring->trb[count].link;
        link->next = cpu_to_le64 ( virt_to_phys ( ring->trb ) );
        link->flags = XHCI_TRB_TC;
        link->type = XHCI_TRB_LINK;
        ring->link = link;

        return 0;

        free_dma ( ring->trb, ring->len );
 err_alloc_trb:
        free ( ring->iobuf );
 err_alloc_iobuf:
        return rc;
}
static void xhci_ring_reset ( struct xhci_trb_ring ring) [static]

Reset transfer request block ring.

Parameters:
ringTRB ring

Definition at line 1233 of file xhci.c.

References xhci_trb_ring::cons, count, memset(), xhci_trb_ring::prod, xhci_trb_ring::shift, and xhci_trb_ring::trb.

Referenced by xhci_abort().

                                                           {
        unsigned int count = ( 1U << ring->shift );

        /* Reset producer and consumer counters */
        ring->prod = 0;
        ring->cons = 0;

        /* Reset TRBs (except Link TRB) */
        memset ( ring->trb, 0, ( count * sizeof ( ring->trb[0] ) ) );
}
static void xhci_ring_free ( struct xhci_trb_ring ring) [static]

Free transfer request block ring.

Parameters:
ringTRB ring

Definition at line 1249 of file xhci.c.

References assert, xhci_trb_ring::cons, count, free, free_dma(), xhci_trb_ring::iobuf, xhci_trb_ring::len, NULL, xhci_trb_ring::prod, xhci_trb_ring::shift, and xhci_trb_ring::trb.

Referenced by xhci_command_alloc(), xhci_command_free(), xhci_endpoint_close(), and xhci_endpoint_open().

                                                          {
        unsigned int count = ( 1U << ring->shift );
        unsigned int i;

        /* Sanity checks */
        assert ( ring->cons == ring->prod );
        for ( i = 0 ; i < count ; i++ )
                assert ( ring->iobuf[i] == NULL );

        /* Free TRBs */
        free_dma ( ring->trb, ring->len );

        /* Free I/O buffers */
        free ( ring->iobuf );
}
static int xhci_enqueue ( struct xhci_trb_ring ring,
struct io_buffer iobuf,
const union xhci_trb trb 
) [static]

Enqueue a transfer request block.

Parameters:
ringTRB ring
iobufI/O buffer (if any)
trbTransfer request block (with empty Cycle flag)
Return values:
rcReturn status code

This operation does not implicitly ring the doorbell register.

Definition at line 1275 of file xhci.c.

References assert, xhci_trb::common, xhci_trb_template::control, cpu_to_le32, dest, ENOBUFS, xhci_trb_common::flags, xhci_trb_link::flags, index, xhci_trb_ring::iobuf, xhci_trb_ring::link, xhci_trb_ring::mask, xhci_trb_template::parameter, xhci_trb_ring::prod, xhci_trb_ring::shift, xhci_trb_template::status, xhci_trb::template, xhci_trb_ring::trb, wmb, xhci_ring_remaining(), XHCI_TRB_C, and XHCI_TRB_TC.

Referenced by xhci_command(), and xhci_enqueue_multi().

                                                      {
        union xhci_trb *dest;
        unsigned int prod;
        unsigned int mask;
        unsigned int index;
        unsigned int cycle;

        /* Sanity check */
        assert ( ! ( trb->common.flags & XHCI_TRB_C ) );

        /* Fail if ring is full */
        if ( ! xhci_ring_remaining ( ring ) )
                return -ENOBUFS;

        /* Update producer counter (and link TRB, if applicable) */
        prod = ring->prod++;
        mask = ring->mask;
        cycle = ( ( ~( prod >> ring->shift ) ) & XHCI_TRB_C );
        index = ( prod & mask );
        if ( index == 0 )
                ring->link->flags = ( XHCI_TRB_TC | ( cycle ^ XHCI_TRB_C ) );

        /* Record I/O buffer */
        ring->iobuf[index] = iobuf;

        /* Enqueue TRB */
        dest = &ring->trb[index];
        dest->template.parameter = trb->template.parameter;
        dest->template.status = trb->template.status;
        wmb();
        dest->template.control = ( trb->template.control |
                                   cpu_to_le32 ( cycle ) );

        return 0;
}
static struct io_buffer* xhci_dequeue ( struct xhci_trb_ring ring) [static, read]

Dequeue a transfer request block.

Parameters:
ringTRB ring
Return values:
iobufI/O buffer

Definition at line 1318 of file xhci.c.

References assert, cons, xhci_trb_ring::cons, index, xhci_trb_ring::iobuf, xhci_trb_ring::mask, NULL, and xhci_ring_fill().

Referenced by xhci_complete(), and xhci_dequeue_multi().

                                                                      {
        struct io_buffer *iobuf;
        unsigned int cons;
        unsigned int mask;
        unsigned int index;

        /* Sanity check */
        assert ( xhci_ring_fill ( ring ) != 0 );

        /* Update consumer counter */
        cons = ring->cons++;
        mask = ring->mask;
        index = ( cons & mask );

        /* Retrieve I/O buffer */
        iobuf = ring->iobuf[index];
        ring->iobuf[index] = NULL;

        return iobuf;
}
static int xhci_enqueue_multi ( struct xhci_trb_ring ring,
struct io_buffer iobuf,
const union xhci_trb trbs,
unsigned int  count 
) [static]

Enqueue multiple transfer request blocks.

Parameters:
ringTRB ring
iobufI/O buffer
trbsTransfer request blocks (with empty Cycle flag)
countNumber of transfer request blocks
Return values:
rcReturn status code

This operation does not implicitly ring the doorbell register.

Definition at line 1350 of file xhci.c.

References assert, ENOBUFS, NULL, rc, xhci_enqueue(), and xhci_ring_remaining().

Referenced by xhci_endpoint_message(), and xhci_endpoint_stream().

                                                     {
        const union xhci_trb *trb = trbs;
        int rc;

        /* Sanity check */
        assert ( iobuf != NULL );

        /* Fail if ring does not have sufficient space */
        if ( xhci_ring_remaining ( ring ) < count )
                return -ENOBUFS;

        /* Enqueue each TRB, recording the I/O buffer with the final TRB */
        while ( count-- ) {
                rc = xhci_enqueue ( ring, ( count ? NULL : iobuf ), trb++ );
                assert ( rc == 0 ); /* Should never be able to fail */
        }

        return 0;
}
static struct io_buffer* xhci_dequeue_multi ( struct xhci_trb_ring ring) [static, read]

Dequeue multiple transfer request blocks.

Parameters:
ringTRB ring
Return values:
iobufI/O buffer

Definition at line 1379 of file xhci.c.

References NULL, and xhci_dequeue().

Referenced by xhci_endpoint_close(), and xhci_transfer().

                                                                            {
        struct io_buffer *iobuf;

        /* Dequeue TRBs until we reach the final TRB for an I/O buffer */
        do {
                iobuf = xhci_dequeue ( ring );
        } while ( iobuf == NULL );

        return iobuf;
}
static void xhci_doorbell ( struct xhci_trb_ring ring) [inline, static]

Ring doorbell register.

Parameters:
ringTRB ring

Definition at line 1396 of file xhci.c.

References wmb, and writel().

Referenced by xhci_command(), xhci_endpoint_message(), xhci_endpoint_reset(), and xhci_endpoint_stream().

                                             {

        wmb();
        writel ( ring->dbval, ring->db );
}
static int xhci_command_alloc ( struct xhci_device xhci) [static]

Allocate command ring.

Parameters:
xhcixHCI device
Return values:
rcReturn status code

Definition at line 1415 of file xhci.c.

References xhci_device::command, DBGC2, xhci_trb_ring::len, xhci_device::name, xhci_device::op, rc, xhci_trb_ring::trb, virt_to_phys(), XHCI_CMD_TRBS_LOG2, XHCI_CRCR_RCS, XHCI_OP_CRCR, xhci_ring_alloc(), xhci_ring_free(), and xhci_writeq().

Referenced by xhci_bus_open().

                                                           {
        physaddr_t crp;
        int rc;

        /* Allocate TRB ring */
        if ( ( rc = xhci_ring_alloc ( xhci, &xhci->command, XHCI_CMD_TRBS_LOG2,
                                      0, 0, 0 ) ) != 0 )
                goto err_ring_alloc;

        /* Program command ring control register */
        crp = virt_to_phys ( xhci->command.trb );
        if ( ( rc = xhci_writeq ( xhci, ( crp | XHCI_CRCR_RCS ),
                                  xhci->op + XHCI_OP_CRCR ) ) != 0 )
                goto err_writeq;

        DBGC2 ( xhci, "XHCI %s CRCR at [%08lx,%08lx)\n",
                xhci->name, crp, ( crp + xhci->command.len ) );
        return 0;

 err_writeq:
        xhci_ring_free ( &xhci->command );
 err_ring_alloc:
        return rc;
}
static void xhci_command_free ( struct xhci_device xhci) [static]

Free command ring.

Parameters:
xhcixHCI device

Definition at line 1445 of file xhci.c.

References assert, xhci_device::command, xhci_device::op, readl(), XHCI_CRCR_CRR, XHCI_OP_CRCR, xhci_ring_free(), and xhci_writeq().

Referenced by xhci_bus_close(), and xhci_bus_open().

                                                           {

        /* Sanity check */
        assert ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 );

        /* Clear command ring control register */
        xhci_writeq ( xhci, 0, xhci->op + XHCI_OP_CRCR );

        /* Free TRB ring */
        xhci_ring_free ( &xhci->command );
}
static int xhci_event_alloc ( struct xhci_device xhci) [static]

Allocate event ring.

Parameters:
xhcixHCI device
Return values:
rcReturn status code

Definition at line 1463 of file xhci.c.

References count, cpu_to_le32, cpu_to_le64, DBGC2, ENOMEM, xhci_device::event, free_dma(), len, malloc_dma(), memset(), xhci_device::name, rc, xhci_device::run, virt_to_phys(), writel(), xhci_align(), XHCI_EVENT_TRBS_LOG2, XHCI_RUN_ERDP, XHCI_RUN_ERSTBA, XHCI_RUN_ERSTSZ, and xhci_writeq().

Referenced by xhci_bus_open().

                                                         {
        struct xhci_event_ring *event = &xhci->event;
        unsigned int count;
        size_t len;
        int rc;

        /* Allocate event ring */
        count = ( 1 << XHCI_EVENT_TRBS_LOG2 );
        len = ( count * sizeof ( event->trb[0] ) );
        event->trb = malloc_dma ( len, xhci_align ( len ) );
        if ( ! event->trb ) {
                rc = -ENOMEM;
                goto err_alloc_trb;
        }
        memset ( event->trb, 0, len );

        /* Allocate event ring segment table */
        event->segment = malloc_dma ( sizeof ( event->segment[0] ),
                                      xhci_align ( sizeof (event->segment[0])));
        if ( ! event->segment ) {
                rc = -ENOMEM;
                goto err_alloc_segment;
        }
        memset ( event->segment, 0, sizeof ( event->segment[0] ) );
        event->segment[0].base = cpu_to_le64 ( virt_to_phys ( event->trb ) );
        event->segment[0].count = cpu_to_le32 ( count );

        /* Program event ring registers */
        writel ( 1, xhci->run + XHCI_RUN_ERSTSZ ( 0 ) );
        if ( ( rc = xhci_writeq ( xhci, virt_to_phys ( event->trb ),
                                  xhci->run + XHCI_RUN_ERDP ( 0 ) ) ) != 0 )
                goto err_writeq_erdp;
        if ( ( rc = xhci_writeq ( xhci, virt_to_phys ( event->segment ),
                                  xhci->run + XHCI_RUN_ERSTBA ( 0 ) ) ) != 0 )
                goto err_writeq_erstba;

        DBGC2 ( xhci, "XHCI %s event ring [%08lx,%08lx) table [%08lx,%08lx)\n",
                xhci->name, virt_to_phys ( event->trb ),
                ( virt_to_phys ( event->trb ) + len ),
                virt_to_phys ( event->segment ),
                ( virt_to_phys ( event->segment ) +
                  sizeof (event->segment[0] ) ) );
        return 0;

        xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERSTBA ( 0 ) );
 err_writeq_erstba:
        xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) );
 err_writeq_erdp:
        free_dma ( event->trb, len );
 err_alloc_segment:
        free_dma ( event->segment, sizeof ( event->segment[0] ) );
 err_alloc_trb:
        return rc;
}
static void xhci_event_free ( struct xhci_device xhci) [static]

Free event ring.

Parameters:
xhcixHCI device

Definition at line 1523 of file xhci.c.

References count, xhci_device::event, free_dma(), len, xhci_device::run, writel(), XHCI_EVENT_TRBS_LOG2, XHCI_RUN_ERDP, XHCI_RUN_ERSTBA, XHCI_RUN_ERSTSZ, and xhci_writeq().

Referenced by xhci_bus_close(), and xhci_bus_open().

                                                         {
        struct xhci_event_ring *event = &xhci->event;
        unsigned int count;
        size_t len;

        /* Clear event ring registers */
        writel ( 0, xhci->run + XHCI_RUN_ERSTSZ ( 0 ) );
        xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERSTBA ( 0 ) );
        xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) );

        /* Free event ring segment table */
        free_dma ( event->segment, sizeof ( event->segment[0] ) );

        /* Free event ring */
        count = ( 1 << XHCI_EVENT_TRBS_LOG2 );
        len = ( count * sizeof ( event->trb[0] ) );
        free_dma ( event->trb, len );
}
static void xhci_transfer ( struct xhci_device xhci,
struct xhci_trb_transfer trb 
) [static]

Handle transfer event.

Parameters:
xhcixHCI device
trbTransfer event TRB

Definition at line 1548 of file xhci.c.

References assert, xhci_trb_transfer::code, xhci_endpoint::context, xhci_endpoint::ctx, DBGC, DBGC_HDA, ECODE, xhci_trb_transfer::endpoint, xhci_slot::endpoint, xhci_endpoint::ep, xhci_slot::id, iob_unput, le16_to_cpu, le64_to_cpu, xhci_device::name, NULL, profile_start(), profile_stop(), rc, xhci_trb_transfer::residual, xhci_endpoint::ring, slot, xhci_trb_transfer::slot, xhci_device::slot, xhci_device::slots, xhci_endpoint_context::state, strerror(), xhci_trb_transfer::transfer, usb_complete(), usb_complete_err(), XHCI_CMPLT_SHORT, XHCI_CMPLT_SUCCESS, XHCI_CTX_END, xhci_dequeue_multi(), XHCI_ENDPOINT_RUNNING, XHCI_ENDPOINT_STATE_MASK, and xhci_ring_consumed().

Referenced by xhci_event_poll().

                                                            {
        struct xhci_slot *slot;
        struct xhci_endpoint *endpoint;
        struct io_buffer *iobuf;
        int rc;

        /* Profile transfer events */
        profile_start ( &xhci_transfer_profiler );

        /* Identify slot */
        if ( ( trb->slot > xhci->slots ) ||
             ( ( slot = xhci->slot[trb->slot] ) == NULL ) ) {
                DBGC ( xhci, "XHCI %s transfer event invalid slot %d:\n",
                       xhci->name, trb->slot );
                DBGC_HDA ( xhci, 0, trb, sizeof ( *trb ) );
                return;
        }

        /* Identify endpoint */
        if ( ( trb->endpoint >= XHCI_CTX_END ) ||
             ( ( endpoint = slot->endpoint[trb->endpoint] ) == NULL ) ) {
                DBGC ( xhci, "XHCI %s slot %d transfer event invalid epid "
                       "%d:\n", xhci->name, slot->id, trb->endpoint );
                DBGC_HDA ( xhci, 0, trb, sizeof ( *trb ) );
                return;
        }

        /* Dequeue TRB(s) */
        iobuf = xhci_dequeue_multi ( &endpoint->ring );
        assert ( iobuf != NULL );

        /* Check for errors */
        if ( ! ( ( trb->code == XHCI_CMPLT_SUCCESS ) ||
                 ( trb->code == XHCI_CMPLT_SHORT ) ) ) {

                /* Construct error */
                rc = -ECODE ( trb->code );
                DBGC ( xhci, "XHCI %s slot %d ctx %d failed (code %d): %s\n",
                       xhci->name, slot->id, endpoint->ctx, trb->code,
                       strerror ( rc ) );
                DBGC_HDA ( xhci, 0, trb, sizeof ( *trb ) );

                /* Sanity check */
                assert ( ( endpoint->context->state & XHCI_ENDPOINT_STATE_MASK )
                         != XHCI_ENDPOINT_RUNNING );

                /* Report failure to USB core */
                usb_complete_err ( endpoint->ep, iobuf, rc );
                return;
        }

        /* Record actual transfer size */
        iob_unput ( iobuf, le16_to_cpu ( trb->residual ) );

        /* Sanity check (for successful completions only) */
        assert ( xhci_ring_consumed ( &endpoint->ring ) ==
                 le64_to_cpu ( trb->transfer ) );

        /* Report completion to USB core */
        usb_complete ( endpoint->ep, iobuf );
        profile_stop ( &xhci_transfer_profiler );
}
static void xhci_complete ( struct xhci_device xhci,
struct xhci_trb_complete trb 
) [static]

Handle command completion event.

Parameters:
xhcixHCI device
trbCommand completion event

Definition at line 1618 of file xhci.c.

References assert, xhci_trb_complete::code, xhci_trb_complete::command, xhci_device::command, DBGC, DBGC2, DBGC_HDA, ECODE, le64_to_cpu, memcpy(), xhci_device::name, NULL, xhci_device::pending, rc, strerror(), XHCI_CMPLT_CMD_STOPPED, xhci_dequeue(), and xhci_ring_consumed().

Referenced by xhci_event_poll().

                                                            {
        int rc;

        /* Ignore "command ring stopped" notifications */
        if ( trb->code == XHCI_CMPLT_CMD_STOPPED ) {
                DBGC2 ( xhci, "XHCI %s command ring stopped\n", xhci->name );
                return;
        }

        /* Ignore unexpected completions */
        if ( ! xhci->pending ) {
                rc = -ECODE ( trb->code );
                DBGC ( xhci, "XHCI %s unexpected completion (code %d): %s\n",
                       xhci->name, trb->code, strerror ( rc ) );
                DBGC_HDA ( xhci, 0, trb, sizeof ( *trb ) );
                return;
        }

        /* Dequeue command TRB */
        xhci_dequeue ( &xhci->command );

        /* Sanity check */
        assert ( xhci_ring_consumed ( &xhci->command ) ==
                 le64_to_cpu ( trb->command ) );

        /* Record completion */
        memcpy ( xhci->pending, trb, sizeof ( *xhci->pending ) );
        xhci->pending = NULL;
}
static void xhci_port_status ( struct xhci_device xhci,
struct xhci_trb_port_status trb 
) [static]

Handle port status event.

Parameters:
xhcixHCI device
trbPort status event

Definition at line 1655 of file xhci.c.

References assert, xhci_device::bus, usb_port::disconnected, usb_bus::hub, xhci_device::op, port, xhci_trb_port_status::port, xhci_device::ports, readl(), usb_port(), usb_port_changed(), writel(), XHCI_OP_PORTSC, XHCI_PORTSC_CHANGE, XHCI_PORTSC_CSC, and XHCI_PORTSC_PRESERVE.

Referenced by xhci_event_poll().

                                                                  {
        struct usb_port *port = usb_port ( xhci->bus->hub, trb->port );
        uint32_t portsc;

        /* Sanity check */
        assert ( ( trb->port > 0 ) && ( trb->port <= xhci->ports ) );

        /* Record disconnections and clear changes */
        portsc = readl ( xhci->op + XHCI_OP_PORTSC ( trb->port ) );
        port->disconnected |= ( portsc & XHCI_PORTSC_CSC );
        portsc &= ( XHCI_PORTSC_PRESERVE | XHCI_PORTSC_CHANGE );
        writel ( portsc, xhci->op + XHCI_OP_PORTSC ( trb->port ) );

        /* Report port status change */
        usb_port_changed ( port );
}
static void xhci_host_controller ( struct xhci_device xhci,
struct xhci_trb_host_controller trb 
) [static]

Handle host controller event.

Parameters:
xhcixHCI device
trbHost controller event

Definition at line 1679 of file xhci.c.

References xhci_trb_host_controller::code, DBGC, ECODE, xhci_device::name, rc, and strerror().

Referenced by xhci_event_poll().

                                                                          {
        int rc;

        /* Construct error */
        rc = -ECODE ( trb->code );
        DBGC ( xhci, "XHCI %s host controller event (code %d): %s\n",
               xhci->name, trb->code, strerror ( rc ) );
}
static void xhci_event_poll ( struct xhci_device xhci) [static]

Poll event ring.

Parameters:
xhcixHCI device

Definition at line 1694 of file xhci.c.

References xhci_trb::common, xhci_trb::complete, count, DBGC, DBGC_HDA, xhci_device::event, xhci_trb_common::flags, xhci_trb::host, xhci_device::name, xhci_trb::port, profile_start(), profile_stop(), rmb, xhci_device::run, xhci_trb::transfer, type, xhci_trb_common::type, virt_to_phys(), xhci_complete(), XHCI_EVENT_TRBS_LOG2, xhci_host_controller(), xhci_port_status(), XHCI_RUN_ERDP, xhci_transfer(), XHCI_TRB_C, XHCI_TRB_COMPLETE, XHCI_TRB_HOST_CONTROLLER, XHCI_TRB_PORT_STATUS, XHCI_TRB_TRANSFER, XHCI_TRB_TYPE_MASK, and xhci_writeq().

Referenced by xhci_abort(), xhci_bus_poll(), and xhci_command().

                                                         {
        struct xhci_event_ring *event = &xhci->event;
        union xhci_trb *trb;
        unsigned int shift = XHCI_EVENT_TRBS_LOG2;
        unsigned int count = ( 1 << shift );
        unsigned int mask = ( count - 1 );
        unsigned int consumed;
        unsigned int type;

        /* Poll for events */
        profile_start ( &xhci_event_profiler );
        for ( consumed = 0 ; ; consumed++ ) {

                /* Stop if we reach an empty TRB */
                rmb();
                trb = &event->trb[ event->cons & mask ];
                if ( ! ( ( trb->common.flags ^
                           ( event->cons >> shift ) ) & XHCI_TRB_C ) )
                        break;

                /* Consume this TRB */
                event->cons++;

                /* Handle TRB */
                type = ( trb->common.type & XHCI_TRB_TYPE_MASK );
                switch ( type ) {

                case XHCI_TRB_TRANSFER :
                        xhci_transfer ( xhci, &trb->transfer );
                        break;

                case XHCI_TRB_COMPLETE :
                        xhci_complete ( xhci, &trb->complete );
                        break;

                case XHCI_TRB_PORT_STATUS:
                        xhci_port_status ( xhci, &trb->port );
                        break;

                case XHCI_TRB_HOST_CONTROLLER:
                        xhci_host_controller ( xhci, &trb->host );
                        break;

                default:
                        DBGC ( xhci, "XHCI %s unrecognised event %#x\n:",
                               xhci->name, ( event->cons - 1 ) );
                        DBGC_HDA ( xhci, virt_to_phys ( trb ),
                                   trb, sizeof ( *trb ) );
                        break;
                }
        }

        /* Update dequeue pointer if applicable */
        if ( consumed ) {
                xhci_writeq ( xhci, virt_to_phys ( trb ),
                              xhci->run + XHCI_RUN_ERDP ( 0 ) );
                profile_stop ( &xhci_event_profiler );
        }
}
static void xhci_abort ( struct xhci_device xhci) [static]

Abort command.

Parameters:
xhcixHCI device

Definition at line 1759 of file xhci.c.

References assert, xhci_device::command, DBGC2, mdelay(), xhci_device::name, xhci_device::op, readl(), xhci_trb_ring::trb, virt_to_phys(), XHCI_COMMAND_ABORT_DELAY_MS, XHCI_CRCR_CA, XHCI_CRCR_CRR, XHCI_CRCR_RCS, xhci_event_poll(), XHCI_OP_CRCR, xhci_ring_reset(), and xhci_writeq().

Referenced by xhci_command().

                                                    {
        physaddr_t crp;

        /* Abort the command */
        DBGC2 ( xhci, "XHCI %s aborting command\n", xhci->name );
        xhci_writeq ( xhci, XHCI_CRCR_CA, xhci->op + XHCI_OP_CRCR );

        /* Allow time for command to abort */
        mdelay ( XHCI_COMMAND_ABORT_DELAY_MS );

        /* Sanity check */
        assert ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 );

        /* Consume (and ignore) any final command status */
        xhci_event_poll ( xhci );

        /* Reset the command ring control register */
        xhci_ring_reset ( &xhci->command );
        crp = virt_to_phys ( xhci->command.trb );
        xhci_writeq ( xhci, ( crp | XHCI_CRCR_RCS ), xhci->op + XHCI_OP_CRCR );
}
static int xhci_command ( struct xhci_device xhci,
union xhci_trb trb 
) [static]

Issue command and wait for completion.

Parameters:
xhcixHCI device
trbTransfer request block (with empty Cycle flag)
Return values:
rcReturn status code

On a successful completion, the TRB will be overwritten with the completion.

Definition at line 1791 of file xhci.c.

References xhci_trb_complete::code, xhci_device::command, xhci_trb::complete, DBGC, DBGC_HDA, ECODE, ETIMEDOUT, mdelay(), xhci_device::name, NULL, xhci_device::pending, rc, strerror(), xhci_abort(), XHCI_CMPLT_SUCCESS, XHCI_COMMAND_MAX_WAIT_MS, xhci_doorbell(), xhci_enqueue(), and xhci_event_poll().

Referenced by xhci_context(), xhci_disable_slot(), xhci_enable_slot(), xhci_nop(), xhci_reset_endpoint(), xhci_set_tr_dequeue_pointer(), and xhci_stop_endpoint().

                                                                          {
        struct xhci_trb_complete *complete = &trb->complete;
        unsigned int i;
        int rc;

        /* Record the pending command */
        xhci->pending = trb;

        /* Enqueue the command */
        if ( ( rc = xhci_enqueue ( &xhci->command, NULL, trb ) ) != 0 )
                goto err_enqueue;

        /* Ring the command doorbell */
        xhci_doorbell ( &xhci->command );

        /* Wait for the command to complete */
        for ( i = 0 ; i < XHCI_COMMAND_MAX_WAIT_MS ; i++ ) {

                /* Poll event ring */
                xhci_event_poll ( xhci );

                /* Check for completion */
                if ( ! xhci->pending ) {
                        if ( complete->code != XHCI_CMPLT_SUCCESS ) {
                                rc = -ECODE ( complete->code );
                                DBGC ( xhci, "XHCI %s command failed (code "
                                       "%d): %s\n", xhci->name, complete->code,
                                       strerror ( rc ) );
                                DBGC_HDA ( xhci, 0, trb, sizeof ( *trb ) );
                                return rc;
                        }
                        return 0;
                }

                /* Delay */
                mdelay ( 1 );
        }

        /* Timeout */
        DBGC ( xhci, "XHCI %s timed out waiting for completion\n", xhci->name );
        rc = -ETIMEDOUT;

        /* Abort command */
        xhci_abort ( xhci );

 err_enqueue:
        xhci->pending = NULL;
        return rc;
}
static int xhci_nop ( struct xhci_device xhci) [inline, static]

Issue NOP and wait for completion.

Parameters:
xhcixHCI device
Return values:
rcReturn status code

Definition at line 1847 of file xhci.c.

References xhci_trb::common, xhci_trb_common::flags, memset(), nop, rc, xhci_trb_common::type, xhci_command(), XHCI_TRB_IOC, and XHCI_TRB_NOP_CMD.

                                                        {
        union xhci_trb trb;
        struct xhci_trb_common *nop = &trb.common;
        int rc;

        /* Construct command */
        memset ( nop, 0, sizeof ( *nop ) );
        nop->flags = XHCI_TRB_IOC;
        nop->type = XHCI_TRB_NOP_CMD;

        /* Issue command and wait for completion */
        if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 )
                return rc;

        return 0;
}
static int xhci_enable_slot ( struct xhci_device xhci,
unsigned int  type 
) [inline, static]

Enable slot.

Parameters:
xhcixHCI device
typeSlot type
Return values:
slotDevice slot ID, or negative error

Definition at line 1871 of file xhci.c.

References xhci_trb::complete, DBGC, DBGC2, xhci_trb::enable, memset(), xhci_device::name, rc, slot, xhci_trb_enable_slot::slot, xhci_trb_complete::slot, strerror(), type, xhci_trb_enable_slot::type, xhci_command(), and XHCI_TRB_ENABLE_SLOT.

Referenced by xhci_device_open().

                                                         {
        union xhci_trb trb;
        struct xhci_trb_enable_slot *enable = &trb.enable;
        struct xhci_trb_complete *enabled = &trb.complete;
        unsigned int slot;
        int rc;

        /* Construct command */
        memset ( enable, 0, sizeof ( *enable ) );
        enable->slot = type;
        enable->type = XHCI_TRB_ENABLE_SLOT;

        /* Issue command and wait for completion */
        if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) {
                DBGC ( xhci, "XHCI %s could not enable new slot: %s\n",
                       xhci->name, strerror ( rc ) );
                return rc;
        }

        /* Extract slot number */
        slot = enabled->slot;

        DBGC2 ( xhci, "XHCI %s slot %d enabled\n", xhci->name, slot );
        return slot;
}
static int xhci_disable_slot ( struct xhci_device xhci,
unsigned int  slot 
) [inline, static]

Disable slot.

Parameters:
xhcixHCI device
slotDevice slot
Return values:
rcReturn status code

Definition at line 1905 of file xhci.c.

References DBGC, DBGC2, xhci_trb::disable, memset(), xhci_device::name, rc, slot, xhci_trb_disable_slot::slot, strerror(), xhci_trb_disable_slot::type, xhci_command(), and XHCI_TRB_DISABLE_SLOT.

Referenced by xhci_device_close(), and xhci_device_open().

                                                          {
        union xhci_trb trb;
        struct xhci_trb_disable_slot *disable = &trb.disable;
        int rc;

        /* Construct command */
        memset ( disable, 0, sizeof ( *disable ) );
        disable->type = XHCI_TRB_DISABLE_SLOT;
        disable->slot = slot;

        /* Issue command and wait for completion */
        if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) {
                DBGC ( xhci, "XHCI %s could not disable slot %d: %s\n",
                       xhci->name, slot, strerror ( rc ) );
                return rc;
        }

        DBGC2 ( xhci, "XHCI %s slot %d disabled\n", xhci->name, slot );
        return 0;
}
static int xhci_context ( struct xhci_device xhci,
struct xhci_slot slot,
struct xhci_endpoint endpoint,
unsigned int  type,
void(*)(struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint, void *input)  populate 
) [static]

Issue context-based command and wait for completion.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
typeTRB type
populateInput context populater
Return values:
rcReturn status code

Definition at line 1937 of file xhci.c.

References context, xhci_trb::context, cpu_to_le64, ENOMEM, free_dma(), xhci_slot::id, xhci_trb_context::input, len, malloc_dma(), memset(), rc, xhci_trb_context::slot, type, xhci_trb_context::type, virt_to_phys(), xhci_align(), xhci_command(), XHCI_CTX_END, and xhci_input_context_offset().

Referenced by xhci_address_device(), xhci_configure_endpoint(), xhci_deconfigure_endpoint(), and xhci_evaluate_context().

                                                                {
        union xhci_trb trb;
        struct xhci_trb_context *context = &trb.context;
        size_t len;
        void *input;
        int rc;

        /* Allocate an input context */
        len = xhci_input_context_offset ( xhci, XHCI_CTX_END );
        input = malloc_dma ( len, xhci_align ( len ) );
        if ( ! input ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        memset ( input, 0, len );

        /* Populate input context */
        populate ( xhci, slot, endpoint, input );

        /* Construct command */
        memset ( context, 0, sizeof ( *context ) );
        context->type = type;
        context->input = cpu_to_le64 ( virt_to_phys ( input ) );
        context->slot = slot->id;

        /* Issue command and wait for completion */
        if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 )
                goto err_command;

 err_command:
        free_dma ( input, len );
 err_alloc:
        return rc;
}
static void xhci_address_device_input ( struct xhci_device xhci,
struct xhci_slot slot,
struct xhci_endpoint endpoint,
void *  input 
) [static]

Populate address device input context.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
inputInput context

Definition at line 1985 of file xhci.c.

References xhci_control_context::add, assert, usb_endpoint::burst, xhci_endpoint_context::burst, cpu_to_le16, cpu_to_le32, cpu_to_le64, xhci_endpoint::ctx, xhci_endpoint_context::dequeue, xhci_endpoint::ep, xhci_slot_context::info, usb_endpoint::mtu, xhci_endpoint_context::mtu, xhci_slot_context::port, xhci_slot::port, xhci_slot::psiv, xhci_endpoint::ring, xhci_slot::route, xhci_trb_ring::trb, xhci_endpoint_context::trb_len, xhci_slot_context::tt_id, xhci_slot::tt_id, xhci_slot_context::tt_port, xhci_slot::tt_port, xhci_endpoint_context::type, virt_to_phys(), XHCI_CTX_EP0, XHCI_CTX_SLOT, XHCI_EP0_TRB_LEN, XHCI_EP_DCS, XHCI_EP_TYPE_CONTROL, xhci_input_context_offset(), and XHCI_SLOT_INFO.

Referenced by xhci_address_device().

                                                      {
        struct xhci_control_context *control_ctx;
        struct xhci_slot_context *slot_ctx;
        struct xhci_endpoint_context *ep_ctx;

        /* Sanity checks */
        assert ( endpoint->ctx == XHCI_CTX_EP0 );

        /* Populate control context */
        control_ctx = input;
        control_ctx->add = cpu_to_le32 ( ( 1 << XHCI_CTX_SLOT ) |
                                         ( 1 << XHCI_CTX_EP0 ) );

        /* Populate slot context */
        slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
        slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( 1, 0, slot->psiv,
                                                        slot->route ) );
        slot_ctx->port = slot->port;
        slot_ctx->tt_id = slot->tt_id;
        slot_ctx->tt_port = slot->tt_port;

        /* Populate control endpoint context */
        ep_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_EP0 ) );
        ep_ctx->type = XHCI_EP_TYPE_CONTROL;
        ep_ctx->burst = endpoint->ep->burst;
        ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu );
        ep_ctx->dequeue = cpu_to_le64 ( virt_to_phys ( endpoint->ring.trb ) |
                                        XHCI_EP_DCS );
        ep_ctx->trb_len = cpu_to_le16 ( XHCI_EP0_TRB_LEN );
}
static int xhci_address_device ( struct xhci_device xhci,
struct xhci_slot slot 
) [inline, static]

Address device.

Parameters:
xhcixHCI device
slotDevice slot
Return values:
rcReturn status code

Definition at line 2026 of file xhci.c.

References usb_device::address, xhci_slot_context::address, xhci_slot::context, DBGC2, xhci_slot::endpoint, usb_device::name, xhci_device::name, rc, xhci_slot::usb, xhci_address_device_input(), xhci_context(), XHCI_CTX_EP0, XHCI_CTX_SLOT, xhci_device_context_offset(), and XHCI_TRB_ADDRESS_DEVICE.

Referenced by xhci_device_address().

                                                                 {
        struct usb_device *usb = slot->usb;
        struct xhci_slot_context *slot_ctx;
        int rc;

        /* Assign device address */
        if ( ( rc = xhci_context ( xhci, slot, slot->endpoint[XHCI_CTX_EP0],
                                   XHCI_TRB_ADDRESS_DEVICE,
                                   xhci_address_device_input ) ) != 0 )
                return rc;

        /* Get assigned address */
        slot_ctx = ( slot->context +
                     xhci_device_context_offset ( xhci, XHCI_CTX_SLOT ) );
        usb->address = slot_ctx->address;
        DBGC2 ( xhci, "XHCI %s assigned address %d to %s\n",
                xhci->name, usb->address, usb->name );

        return 0;
}
static void xhci_configure_endpoint_input ( struct xhci_device xhci,
struct xhci_slot slot,
struct xhci_endpoint endpoint,
void *  input 
) [static]

Populate configure endpoint input context.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
inputInput context

Definition at line 2056 of file xhci.c.

References xhci_control_context::add, usb_endpoint::burst, xhci_endpoint_context::burst, cpu_to_le16, cpu_to_le32, cpu_to_le64, xhci_endpoint::ctx, xhci_endpoint_context::dequeue, xhci_endpoint::ep, xhci_slot_context::info, xhci_endpoint_context::interval, xhci_endpoint::interval, usb_endpoint::mtu, xhci_endpoint_context::mtu, xhci_slot_context::ports, xhci_slot::ports, xhci_slot::psiv, xhci_endpoint::ring, xhci_trb_ring::trb, xhci_endpoint_context::trb_len, xhci_endpoint_context::type, xhci_endpoint::type, virt_to_phys(), XHCI_CTX_END, XHCI_CTX_SLOT, XHCI_EP_DCS, xhci_input_context_offset(), and XHCI_SLOT_INFO.

Referenced by xhci_configure_endpoint().

                                                          {
        struct xhci_control_context *control_ctx;
        struct xhci_slot_context *slot_ctx;
        struct xhci_endpoint_context *ep_ctx;

        /* Populate control context */
        control_ctx = input;
        control_ctx->add = cpu_to_le32 ( ( 1 << XHCI_CTX_SLOT ) |
                                         ( 1 << endpoint->ctx ) );

        /* Populate slot context */
        slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
        slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
                                                        ( slot->ports ? 1 : 0 ),
                                                        slot->psiv, 0 ) );
        slot_ctx->ports = slot->ports;

        /* Populate endpoint context */
        ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) );
        ep_ctx->interval = endpoint->interval;
        ep_ctx->type = endpoint->type;
        ep_ctx->burst = endpoint->ep->burst;
        ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu );
        ep_ctx->dequeue = cpu_to_le64 ( virt_to_phys ( endpoint->ring.trb ) |
                                        XHCI_EP_DCS );
        ep_ctx->trb_len = cpu_to_le16 ( endpoint->ep->mtu ); /* best guess */
}
static int xhci_configure_endpoint ( struct xhci_device xhci,
struct xhci_slot slot,
struct xhci_endpoint endpoint 
) [inline, static]

Configure endpoint.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
Return values:
rcReturn status code

Definition at line 2095 of file xhci.c.

References xhci_endpoint::ctx, DBGC2, xhci_slot::id, xhci_device::name, rc, xhci_configure_endpoint_input(), xhci_context(), and XHCI_TRB_CONFIGURE_ENDPOINT.

Referenced by xhci_endpoint_open().

                                                                             {
        int rc;

        /* Configure endpoint */
        if ( ( rc = xhci_context ( xhci, slot, endpoint,
                                   XHCI_TRB_CONFIGURE_ENDPOINT,
                                   xhci_configure_endpoint_input ) ) != 0 )
                return rc;

        DBGC2 ( xhci, "XHCI %s slot %d ctx %d configured\n",
                xhci->name, slot->id, endpoint->ctx );
        return 0;
}
static void xhci_deconfigure_endpoint_input ( struct xhci_device *xhci  __unused,
struct xhci_slot *slot  __unused,
struct xhci_endpoint endpoint,
void *  input 
) [static]

Populate deconfigure endpoint input context.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
inputInput context

Definition at line 2120 of file xhci.c.

References xhci_control_context::add, cpu_to_le32, xhci_endpoint::ctx, xhci_control_context::drop, xhci_slot_context::info, XHCI_CTX_END, XHCI_CTX_SLOT, xhci_input_context_offset(), and XHCI_SLOT_INFO.

Referenced by xhci_deconfigure_endpoint().

                                                {
        struct xhci_control_context *control_ctx;
        struct xhci_slot_context *slot_ctx;

        /* Populate control context */
        control_ctx = input;
        control_ctx->add = cpu_to_le32 ( 1 << XHCI_CTX_SLOT );
        control_ctx->drop = cpu_to_le32 ( 1 << endpoint->ctx );

        /* Populate slot context */
        slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
        slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
                                                        0, 0, 0 ) );
}
static int xhci_deconfigure_endpoint ( struct xhci_device xhci,
struct xhci_slot slot,
struct xhci_endpoint endpoint 
) [inline, static]

Deconfigure endpoint.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
Return values:
rcReturn status code

Definition at line 2146 of file xhci.c.

References xhci_endpoint::ctx, DBGC2, xhci_slot::id, xhci_device::name, rc, xhci_context(), xhci_deconfigure_endpoint_input(), and XHCI_TRB_CONFIGURE_ENDPOINT.

Referenced by xhci_endpoint_close(), and xhci_endpoint_open().

                                                                               {
        int rc;

        /* Deconfigure endpoint */
        if ( ( rc = xhci_context ( xhci, slot, endpoint,
                                   XHCI_TRB_CONFIGURE_ENDPOINT,
                                   xhci_deconfigure_endpoint_input ) ) != 0 )
                return rc;

        DBGC2 ( xhci, "XHCI %s slot %d ctx %d deconfigured\n",
                xhci->name, slot->id, endpoint->ctx );
        return 0;
}
static void xhci_evaluate_context_input ( struct xhci_device xhci,
struct xhci_slot *slot  __unused,
struct xhci_endpoint endpoint,
void *  input 
) [static]

Populate evaluate context input context.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
inputInput context

Definition at line 2170 of file xhci.c.

References xhci_control_context::add, cpu_to_le16, cpu_to_le32, xhci_endpoint::ctx, xhci_endpoint::ep, xhci_slot_context::info, usb_endpoint::mtu, xhci_endpoint_context::mtu, XHCI_CTX_END, XHCI_CTX_SLOT, xhci_input_context_offset(), and XHCI_SLOT_INFO.

Referenced by xhci_evaluate_context().

                                                        {
        struct xhci_control_context *control_ctx;
        struct xhci_slot_context *slot_ctx;
        struct xhci_endpoint_context *ep_ctx;

        /* Populate control context */
        control_ctx = input;
        control_ctx->add = cpu_to_le32 ( ( 1 << XHCI_CTX_SLOT ) |
                                         ( 1 << endpoint->ctx ) );

        /* Populate slot context */
        slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
        slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
                                                        0, 0, 0 ) );

        /* Populate endpoint context */
        ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) );
        ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu );
}
static int xhci_evaluate_context ( struct xhci_device xhci,
struct xhci_slot slot,
struct xhci_endpoint endpoint 
) [inline, static]

Evaluate context.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
Return values:
rcReturn status code

Definition at line 2201 of file xhci.c.

References xhci_endpoint::ctx, DBGC2, xhci_slot::id, xhci_device::name, rc, xhci_context(), xhci_evaluate_context_input(), and XHCI_TRB_EVALUATE_CONTEXT.

Referenced by xhci_endpoint_mtu().

                                                                           {
        int rc;

        /* Configure endpoint */
        if ( ( rc = xhci_context ( xhci, slot, endpoint,
                                   XHCI_TRB_EVALUATE_CONTEXT,
                                   xhci_evaluate_context_input ) ) != 0 )
                return rc;

        DBGC2 ( xhci, "XHCI %s slot %d ctx %d (re-)evaluated\n",
                xhci->name, slot->id, endpoint->ctx );
        return 0;
}
static int xhci_reset_endpoint ( struct xhci_device xhci,
struct xhci_slot slot,
struct xhci_endpoint endpoint 
) [inline, static]

Reset endpoint.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
Return values:
rcReturn status code

Definition at line 2225 of file xhci.c.

References xhci_endpoint::context, xhci_endpoint::ctx, DBGC, xhci_trb_reset_endpoint::endpoint, xhci_slot::id, memset(), xhci_device::name, rc, xhci_trb::reset, xhci_trb_reset_endpoint::slot, xhci_endpoint_context::state, strerror(), xhci_trb_reset_endpoint::type, xhci_command(), and XHCI_TRB_RESET_ENDPOINT.

Referenced by xhci_endpoint_reset().

                                                                         {
        union xhci_trb trb;
        struct xhci_trb_reset_endpoint *reset = &trb.reset;
        int rc;

        /* Construct command */
        memset ( reset, 0, sizeof ( *reset ) );
        reset->slot = slot->id;
        reset->endpoint = endpoint->ctx;
        reset->type = XHCI_TRB_RESET_ENDPOINT;

        /* Issue command and wait for completion */
        if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) {
                DBGC ( xhci, "XHCI %s slot %d ctx %d could not reset endpoint "
                       "in state %d: %s\n", xhci->name, slot->id, endpoint->ctx,
                       endpoint->context->state, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int xhci_stop_endpoint ( struct xhci_device xhci,
struct xhci_slot slot,
struct xhci_endpoint endpoint 
) [inline, static]

Stop endpoint.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
Return values:
rcReturn status code

Definition at line 2257 of file xhci.c.

References xhci_endpoint::context, xhci_endpoint::ctx, DBGC, xhci_trb_stop_endpoint::endpoint, xhci_slot::id, memset(), xhci_device::name, rc, xhci_trb_stop_endpoint::slot, xhci_endpoint_context::state, xhci_trb::stop, strerror(), xhci_trb_stop_endpoint::type, xhci_command(), and XHCI_TRB_STOP_ENDPOINT.

                                                                        {
        union xhci_trb trb;
        struct xhci_trb_stop_endpoint *stop = &trb.stop;
        int rc;

        /* Construct command */
        memset ( stop, 0, sizeof ( *stop ) );
        stop->slot = slot->id;
        stop->endpoint = endpoint->ctx;
        stop->type = XHCI_TRB_STOP_ENDPOINT;

        /* Issue command and wait for completion */
        if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) {
                DBGC ( xhci, "XHCI %s slot %d ctx %d could not stop endpoint "
                       "in state %d: %s\n", xhci->name, slot->id, endpoint->ctx,
                       endpoint->context->state, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int xhci_set_tr_dequeue_pointer ( struct xhci_device xhci,
struct xhci_slot slot,
struct xhci_endpoint endpoint 
) [inline, static]

Set transfer ring dequeue pointer.

Parameters:
xhcixHCI device
slotDevice slot
endpointEndpoint
Return values:
rcReturn status code

Definition at line 2290 of file xhci.c.

References cons, xhci_trb_ring::cons, xhci_endpoint::context, cpu_to_le64, xhci_endpoint::ctx, DBGC, xhci_trb_set_tr_dequeue_pointer::dequeue, xhci_trb::dequeue, xhci_trb_set_tr_dequeue_pointer::endpoint, xhci_slot::id, index, xhci_trb_ring::mask, memset(), xhci_device::name, rc, xhci_endpoint::ring, xhci_trb_ring::shift, xhci_trb_set_tr_dequeue_pointer::slot, xhci_endpoint_context::state, strerror(), xhci_trb_ring::trb, xhci_trb_set_tr_dequeue_pointer::type, virt_to_phys(), xhci_command(), XHCI_EP_DCS, and XHCI_TRB_SET_TR_DEQUEUE_POINTER.

Referenced by xhci_endpoint_reset().

                                                               {
        union xhci_trb trb;
        struct xhci_trb_set_tr_dequeue_pointer *dequeue = &trb.dequeue;
        struct xhci_trb_ring *ring = &endpoint->ring;
        unsigned int cons;
        unsigned int mask;
        unsigned int index;
        unsigned int dcs;
        int rc;

        /* Construct command */
        memset ( dequeue, 0, sizeof ( *dequeue ) );
        cons = ring->cons;
        mask = ring->mask;
        dcs = ( ( ~( cons >> ring->shift ) ) & XHCI_EP_DCS );
        index = ( cons & mask );
        dequeue->dequeue =
                cpu_to_le64 ( virt_to_phys ( &ring->trb[index] ) | dcs );
        dequeue->slot = slot->id;
        dequeue->endpoint = endpoint->ctx;
        dequeue->type = XHCI_TRB_SET_TR_DEQUEUE_POINTER;

        /* Issue command and wait for completion */
        if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) {
                DBGC ( xhci, "XHCI %s slot %d ctx %d could not set TR dequeue "
                       "pointer in state %d: %s\n", xhci->name, slot->id,
                       endpoint->ctx, endpoint->context->state, strerror ( rc));
                return rc;
        }

        return 0;
}
static int xhci_endpoint_open ( struct usb_endpoint ep) [static]

Open endpoint.

Parameters:
epUSB endpoint
Return values:
rcReturn status code

Definition at line 2338 of file xhci.c.

References usb_endpoint::address, assert, usb_endpoint::attributes, xhci_slot::context, xhci_endpoint::context, ctx, xhci_endpoint::ctx, DBGC2, xhci_slot::endpoint, ENOMEM, xhci_endpoint::ep, fls, free, xhci_slot::id, usb_endpoint::interval, xhci_endpoint::interval, xhci_trb_ring::len, xhci_device::name, NULL, rc, xhci_endpoint::ring, slot, xhci_endpoint::slot, xhci_trb_ring::trb, type, xhci_endpoint::type, usb_endpoint::usb, USB_DIR_IN, USB_ENDPOINT_ATTR_CONTROL, USB_ENDPOINT_ATTR_TYPE_MASK, usb_endpoint_set_hostdata(), usb_get_hostdata(), virt_to_phys(), xhci_slot::xhci, xhci_endpoint::xhci, xhci_configure_endpoint(), XHCI_CTX, XHCI_CTX_EP0, xhci_deconfigure_endpoint(), xhci_device_context_offset(), XHCI_EP_TYPE, XHCI_EP_TYPE_CONTROL, XHCI_EP_TYPE_IN, XHCI_EP_TYPE_PERIODIC, xhci_ring_alloc(), xhci_ring_free(), XHCI_TRANSFER_TRBS_LOG2, and zalloc().

                                                          {
        struct usb_device *usb = ep->usb;
        struct xhci_slot *slot = usb_get_hostdata ( usb );
        struct xhci_device *xhci = slot->xhci;
        struct xhci_endpoint *endpoint;
        unsigned int ctx;
        unsigned int type;
        unsigned int interval;
        int rc;

        /* Calculate context index */
        ctx = XHCI_CTX ( ep->address );
        assert ( slot->endpoint[ctx] == NULL );

        /* Calculate endpoint type */
        type = XHCI_EP_TYPE ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
        if ( type == XHCI_EP_TYPE ( USB_ENDPOINT_ATTR_CONTROL ) )
                type = XHCI_EP_TYPE_CONTROL;
        if ( ep->address & USB_DIR_IN )
                type |= XHCI_EP_TYPE_IN;

        /* Calculate interval */
        if ( type & XHCI_EP_TYPE_PERIODIC ) {
                interval = ( fls ( ep->interval ) - 1 );
        } else {
                interval = ep->interval;
        }

        /* Allocate and initialise structure */
        endpoint = zalloc ( sizeof ( *endpoint ) );
        if ( ! endpoint ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        usb_endpoint_set_hostdata ( ep, endpoint );
        slot->endpoint[ctx] = endpoint;
        endpoint->xhci = xhci;
        endpoint->slot = slot;
        endpoint->ep = ep;
        endpoint->ctx = ctx;
        endpoint->type = type;
        endpoint->interval = interval;
        endpoint->context = ( ( ( void * ) slot->context ) +
                              xhci_device_context_offset ( xhci, ctx ) );

        /* Allocate transfer ring */
        if ( ( rc = xhci_ring_alloc ( xhci, &endpoint->ring,
                                      XHCI_TRANSFER_TRBS_LOG2,
                                      slot->id, ctx, 0 ) ) != 0 )
                goto err_ring_alloc;

        /* Configure endpoint, if applicable */
        if ( ( ctx != XHCI_CTX_EP0 ) &&
             ( ( rc = xhci_configure_endpoint ( xhci, slot, endpoint ) ) != 0 ))
                goto err_configure_endpoint;

        DBGC2 ( xhci, "XHCI %s slot %d ctx %d ring [%08lx,%08lx)\n",
                xhci->name, slot->id, ctx, virt_to_phys ( endpoint->ring.trb ),
                ( virt_to_phys ( endpoint->ring.trb ) + endpoint->ring.len ) );
        return 0;

        xhci_deconfigure_endpoint ( xhci, slot, endpoint );
 err_configure_endpoint:
        xhci_ring_free ( &endpoint->ring );
 err_ring_alloc:
        slot->endpoint[ctx] = NULL;
        free ( endpoint );
 err_alloc:
        return rc;
}
static void xhci_endpoint_close ( struct usb_endpoint ep) [static]

Close endpoint.

Parameters:
epUSB endpoint

Definition at line 2414 of file xhci.c.

References ctx, xhci_endpoint::ctx, ECANCELED, xhci_slot::endpoint, free, NULL, xhci_endpoint::ring, xhci_endpoint::slot, usb_complete_err(), usb_endpoint_get_hostdata(), xhci_slot::xhci, XHCI_CTX_EP0, xhci_deconfigure_endpoint(), xhci_dequeue_multi(), xhci_ring_fill(), and xhci_ring_free().

                                                            {
        struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
        struct xhci_slot *slot = endpoint->slot;
        struct xhci_device *xhci = slot->xhci;
        struct io_buffer *iobuf;
        unsigned int ctx = endpoint->ctx;

        /* Deconfigure endpoint, if applicable */
        if ( ctx != XHCI_CTX_EP0 )
                xhci_deconfigure_endpoint ( xhci, slot, endpoint );

        /* Cancel any incomplete transfers */
        while ( xhci_ring_fill ( &endpoint->ring ) ) {
                iobuf = xhci_dequeue_multi ( &endpoint->ring );
                usb_complete_err ( ep, iobuf, -ECANCELED );
        }

        /* Free endpoint */
        xhci_ring_free ( &endpoint->ring );
        slot->endpoint[ctx] = NULL;
        free ( endpoint );
}
static int xhci_endpoint_reset ( struct usb_endpoint ep) [static]

Reset endpoint.

Parameters:
epUSB endpoint
Return values:
rcReturn status code

Definition at line 2443 of file xhci.c.

References xhci_endpoint::ctx, DBGC, xhci_slot::id, xhci_device::name, rc, xhci_endpoint::ring, xhci_endpoint::slot, usb_endpoint_get_hostdata(), xhci_slot::xhci, xhci_doorbell(), xhci_reset_endpoint(), and xhci_set_tr_dequeue_pointer().

                                                           {
        struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
        struct xhci_slot *slot = endpoint->slot;
        struct xhci_device *xhci = slot->xhci;
        int rc;

        /* Reset endpoint context */
        if ( ( rc = xhci_reset_endpoint ( xhci, slot, endpoint ) ) != 0 )
                return rc;

        /* Set transfer ring dequeue pointer */
        if ( ( rc = xhci_set_tr_dequeue_pointer ( xhci, slot, endpoint ) ) != 0)
                return rc;

        /* Ring doorbell to resume processing */
        xhci_doorbell ( &endpoint->ring );

        DBGC ( xhci, "XHCI %s slot %d ctx %d reset\n",
               xhci->name, slot->id, endpoint->ctx );
        return 0;
}
static int xhci_endpoint_mtu ( struct usb_endpoint ep) [static]

Update MTU.

Parameters:
epUSB endpoint
Return values:
rcReturn status code

Definition at line 2471 of file xhci.c.

References rc, xhci_endpoint::slot, usb_endpoint_get_hostdata(), xhci_slot::xhci, and xhci_evaluate_context().

                                                         {
        struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
        struct xhci_slot *slot = endpoint->slot;
        struct xhci_device *xhci = slot->xhci;
        int rc;

        /* Evalulate context */
        if ( ( rc = xhci_evaluate_context ( xhci, slot, endpoint ) ) != 0 )
                return rc;

        return 0;
}
static int xhci_endpoint_message ( struct usb_endpoint ep,
struct io_buffer iobuf 
) [static]

Enqueue message transfer.

Parameters:
epUSB endpoint
iobufI/O buffer
Return values:
rcReturn status code

Definition at line 2491 of file xhci.c.

References assert, cpu_to_le16, cpu_to_le32, cpu_to_le64, io_buffer::data, data, xhci_trb_data::data, xhci_trb_setup::direction, xhci_trb_data::direction, xhci_trb_status::direction, xhci_trb_setup::flags, xhci_trb_status::flags, iob_len(), iob_pull, len, xhci_trb_setup::len, xhci_trb_data::len, memcpy(), memset(), xhci_trb_setup::packet, profile_start(), profile_stop(), rc, usb_setup_packet::request, xhci_endpoint::ring, status, xhci_trb_setup::type, xhci_trb_data::type, xhci_trb_status::type, USB_DIR_IN, usb_endpoint_get_hostdata(), virt_to_phys(), XHCI_DATA_IN, XHCI_DATA_OUT, xhci_doorbell(), xhci_enqueue_multi(), XHCI_SETUP_IN, XHCI_SETUP_OUT, XHCI_STATUS_IN, XHCI_STATUS_OUT, XHCI_TRB_DATA, XHCI_TRB_IDT, XHCI_TRB_IOC, XHCI_TRB_SETUP, and XHCI_TRB_STATUS.

                                                             {
        struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
        struct usb_setup_packet *packet;
        unsigned int input;
        size_t len;
        union xhci_trb trbs[ 1 /* setup */ + 1 /* possible data */ +
                             1 /* status */ ];
        union xhci_trb *trb = trbs;
        struct xhci_trb_setup *setup;
        struct xhci_trb_data *data;
        struct xhci_trb_status *status;
        int rc;

        /* Profile message transfers */
        profile_start ( &xhci_message_profiler );

        /* Construct setup stage TRB */
        memset ( trbs, 0, sizeof ( trbs ) );
        assert ( iob_len ( iobuf ) >= sizeof ( *packet ) );
        packet = iobuf->data;
        iob_pull ( iobuf, sizeof ( *packet ) );
        setup = &(trb++)->setup;
        memcpy ( &setup->packet, packet, sizeof ( setup->packet ) );
        setup->len = cpu_to_le32 ( sizeof ( *packet ) );
        setup->flags = XHCI_TRB_IDT;
        setup->type = XHCI_TRB_SETUP;
        len = iob_len ( iobuf );
        input = ( packet->request & cpu_to_le16 ( USB_DIR_IN ) );
        if ( len )
                setup->direction = ( input ? XHCI_SETUP_IN : XHCI_SETUP_OUT );

        /* Construct data stage TRB, if applicable */
        if ( len ) {
                data = &(trb++)->data;
                data->data = cpu_to_le64 ( virt_to_phys ( iobuf->data ) );
                data->len = cpu_to_le32 ( len );
                data->type = XHCI_TRB_DATA;
                data->direction = ( input ? XHCI_DATA_IN : XHCI_DATA_OUT );
        }

        /* Construct status stage TRB */
        status = &(trb++)->status;
        status->flags = XHCI_TRB_IOC;
        status->type = XHCI_TRB_STATUS;
        status->direction =
                ( ( len && input ) ? XHCI_STATUS_OUT : XHCI_STATUS_IN );

        /* Enqueue TRBs */
        if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs,
                                         ( trb - trbs ) ) ) != 0 )
                return rc;

        /* Ring the doorbell */
        xhci_doorbell ( &endpoint->ring );

        profile_stop ( &xhci_message_profiler );
        return 0;
}
static unsigned int xhci_endpoint_count ( size_t  len,
int  zlp 
) [static]

Calculate number of TRBs.

Parameters:
lenLength of data
zlpAppend a zero-length packet
Return values:
countNumber of transfer descriptors

Definition at line 2558 of file xhci.c.

References count, and XHCI_MTU.

Referenced by xhci_endpoint_stream().

                                                                {
        unsigned int count;

        /* Split into 64kB TRBs */
        count = ( ( len + XHCI_MTU - 1 ) / XHCI_MTU );

        /* Append a zero-length TRB if applicable */
        if ( zlp || ( count == 0 ) )
                count++;

        return count;
}
static int xhci_endpoint_stream ( struct usb_endpoint ep,
struct io_buffer iobuf,
int  zlp 
) [static]

Enqueue stream transfer.

Parameters:
epUSB endpoint
iobufI/O buffer
zlpAppend a zero-length packet
Return values:
rcReturn status code

Definition at line 2579 of file xhci.c.

References count, cpu_to_le32, cpu_to_le64, io_buffer::data, data, xhci_trb_normal::data, xhci_trb_normal::flags, iob_len(), len, xhci_trb_normal::len, memset(), normal, xhci_trb::normal, profile_start(), profile_stop(), rc, xhci_endpoint::ring, xhci_trb_normal::type, usb_endpoint_get_hostdata(), virt_to_phys(), xhci_doorbell(), xhci_endpoint_count(), xhci_enqueue_multi(), XHCI_MTU, XHCI_TRB_CH, XHCI_TRB_IOC, and XHCI_TRB_NORMAL.

                                                                     {
        struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
        void *data = iobuf->data;
        size_t len = iob_len ( iobuf );
        unsigned int count = xhci_endpoint_count ( len, zlp );
        union xhci_trb trbs[count];
        union xhci_trb *trb = trbs;
        struct xhci_trb_normal *normal;
        unsigned int i;
        size_t trb_len;
        int rc;

        /* Profile stream transfers */
        profile_start ( &xhci_stream_profiler );

        /* Construct normal TRBs */
        memset ( &trbs, 0, sizeof ( trbs ) );
        for ( i = 0 ; i < count ; i ++ ) {

                /* Calculate TRB length */
                trb_len = XHCI_MTU;
                if ( trb_len > len )
                        trb_len = len;

                /* Construct normal TRB */
                normal = &trb->normal;
                normal->data = cpu_to_le64 ( virt_to_phys ( data ) );
                normal->len = cpu_to_le32 ( trb_len );
                normal->type = XHCI_TRB_NORMAL;
                normal->flags = XHCI_TRB_CH;

                /* Move to next TRB */
                data += trb_len;
                len -= trb_len;
                trb++;
        }

        /* Mark zero-length packet (if present) as a separate transfer */
        if ( zlp && ( count > 1 ) )
                trb[-2].normal.flags = 0;

        /* Generate completion for final TRB */
        trb[-1].normal.flags = XHCI_TRB_IOC;

        /* Enqueue TRBs */
        if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs,
                                         count ) ) != 0 )
                return rc;

        /* Ring the doorbell */
        xhci_doorbell ( &endpoint->ring );

        profile_stop ( &xhci_stream_profiler );
        return 0;
}
static int xhci_device_open ( struct usb_device usb) [static]

Open device.

Parameters:
usbUSB device
Return values:
rcReturn status code

Definition at line 2649 of file xhci.c.

References usb_port::address, assert, usb_hub::bus, xhci_slot::context, cpu_to_le64, DBGC, DBGC2, xhci_device::dcbaa, ENOMEM, free, free_dma(), usb_port::hub, id, xhci_slot::id, len, malloc_dma(), memset(), usb_device::name, xhci_device::name, NULL, usb_device::port, rc, slot, xhci_device::slot, xhci_slot::tt_id, xhci_slot::tt_port, type, usb_hub::usb, xhci_slot::usb, usb_bus_get_hostdata(), usb_get_hostdata(), usb_set_hostdata(), usb_transaction_translator(), virt_to_phys(), xhci_slot::xhci, xhci_align(), XHCI_CTX_END, xhci_device_context_offset(), xhci_disable_slot(), xhci_enable_slot(), xhci_port_slot_type(), and zalloc().

                                                       {
        struct xhci_device *xhci = usb_bus_get_hostdata ( usb->port->hub->bus );
        struct usb_port *tt = usb_transaction_translator ( usb );
        struct xhci_slot *slot;
        struct xhci_slot *tt_slot;
        size_t len;
        int type;
        int id;
        int rc;

        /* Determine applicable slot type */
        type = xhci_port_slot_type ( xhci, usb->port->address );
        if ( type < 0 ) {
                rc = type;
                DBGC ( xhci, "XHCI %s-%d has no slot type\n",
                       xhci->name, usb->port->address );
                goto err_type;
        }

        /* Allocate a device slot number */
        id = xhci_enable_slot ( xhci, type );
        if ( id < 0 ) {
                rc = id;
                goto err_enable_slot;
        }
        assert ( ( id > 0 ) && ( ( unsigned int ) id <= xhci->slots ) );
        assert ( xhci->slot[id] == NULL );

        /* Allocate and initialise structure */
        slot = zalloc ( sizeof ( *slot ) );
        if ( ! slot ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        usb_set_hostdata ( usb, slot );
        xhci->slot[id] = slot;
        slot->xhci = xhci;
        slot->usb = usb;
        slot->id = id;
        if ( tt ) {
                tt_slot = usb_get_hostdata ( tt->hub->usb );
                slot->tt_id = tt_slot->id;
                slot->tt_port = tt->address;
        }

        /* Allocate a device context */
        len = xhci_device_context_offset ( xhci, XHCI_CTX_END );
        slot->context = malloc_dma ( len, xhci_align ( len ) );
        if ( ! slot->context ) {
                rc = -ENOMEM;
                goto err_alloc_context;
        }
        memset ( slot->context, 0, len );

        /* Set device context base address */
        assert ( xhci->dcbaa[id] == 0 );
        xhci->dcbaa[id] = cpu_to_le64 ( virt_to_phys ( slot->context ) );

        DBGC2 ( xhci, "XHCI %s slot %d device context [%08lx,%08lx) for %s\n",
                xhci->name, slot->id, virt_to_phys ( slot->context ),
                ( virt_to_phys ( slot->context ) + len ), usb->name );
        return 0;

        xhci->dcbaa[id] = 0;
        free_dma ( slot->context, len );
 err_alloc_context:
        xhci->slot[id] = NULL;
        free ( slot );
 err_alloc:
        xhci_disable_slot ( xhci, id );
 err_enable_slot:
 err_type:
        return rc;
}
static void xhci_device_close ( struct usb_device usb) [static]

Close device.

Parameters:
usbUSB device

Definition at line 2729 of file xhci.c.

References xhci_slot::context, DBGC, xhci_device::dcbaa, free, free_dma(), id, xhci_slot::id, len, xhci_device::name, NULL, rc, xhci_device::slot, usb_get_hostdata(), xhci_slot::xhci, XHCI_CTX_END, xhci_device_context_offset(), and xhci_disable_slot().

                                                         {
        struct xhci_slot *slot = usb_get_hostdata ( usb );
        struct xhci_device *xhci = slot->xhci;
        size_t len = xhci_device_context_offset ( xhci, XHCI_CTX_END );
        unsigned int id = slot->id;
        int rc;

        /* Disable slot */
        if ( ( rc = xhci_disable_slot ( xhci, id ) ) != 0 ) {
                /* Slot is still enabled.  Leak the slot context,
                 * since the controller may still write to this
                 * memory, and leave the DCBAA entry intact.
                 *
                 * If the controller later reports that this same slot
                 * has been re-enabled, then some assertions will be
                 * triggered.
                 */
                DBGC ( xhci, "XHCI %s slot %d leaking context memory\n",
                       xhci->name, slot->id );
                slot->context = NULL;
        }

        /* Free slot */
        if ( slot->context ) {
                free_dma ( slot->context, len );
                xhci->dcbaa[id] = 0;
        }
        xhci->slot[id] = NULL;
        free ( slot );
}
static int xhci_device_address ( struct usb_device usb) [static]

Assign device address.

Parameters:
usbUSB device
Return values:
rcReturn status code

Definition at line 2766 of file xhci.c.

References usb_port::address, xhci_slot::port, xhci_slot::psiv, rc, xhci_slot::route, usb_device::speed, usb_get_hostdata(), usb_root_hub_port(), usb_route_string(), xhci_slot::xhci, xhci_address_device(), and xhci_port_psiv().

                                                          {
        struct xhci_slot *slot = usb_get_hostdata ( usb );
        struct xhci_device *xhci = slot->xhci;
        struct usb_port *root_port;
        int psiv;
        int rc;

        /* Calculate route string */
        slot->route = usb_route_string ( usb );

        /* Calculate root hub port number */
        root_port = usb_root_hub_port ( usb );
        slot->port = root_port->address;

        /* Calculate protocol speed ID */
        psiv = xhci_port_psiv ( xhci, slot->port, usb->speed );
        if ( psiv < 0 ) {
                rc = psiv;
                return rc;
        }
        slot->psiv = psiv;

        /* Address device */
        if ( ( rc = xhci_address_device ( xhci, slot ) ) != 0 )
                return rc;

        return 0;
}
static int xhci_bus_open ( struct usb_bus bus) [static]

Open USB bus.

Parameters:
busUSB bus
Return values:
rcReturn status code

Definition at line 2808 of file xhci.c.

References ENOMEM, free, rc, xhci_device::slot, xhci_device::slots, usb_bus_get_hostdata(), xhci_command_alloc(), xhci_command_free(), xhci_dcbaa_alloc(), xhci_dcbaa_free(), xhci_event_alloc(), xhci_event_free(), xhci_run(), xhci_scratchpad_alloc(), xhci_scratchpad_free(), xhci_stop(), and zalloc().

                                                 {
        struct xhci_device *xhci = usb_bus_get_hostdata ( bus );
        int rc;

        /* Allocate device slot array */
        xhci->slot = zalloc ( ( xhci->slots + 1 ) * sizeof ( xhci->slot[0] ) );
        if ( ! xhci->slot ) {
                rc = -ENOMEM;
                goto err_slot_alloc;
        }

        /* Allocate device context base address array */
        if ( ( rc = xhci_dcbaa_alloc ( xhci ) ) != 0 )
                goto err_dcbaa_alloc;

        /* Allocate scratchpad buffers */
        if ( ( rc = xhci_scratchpad_alloc ( xhci ) ) != 0 )
                goto err_scratchpad_alloc;

        /* Allocate command ring */
        if ( ( rc = xhci_command_alloc ( xhci ) ) != 0 )
                goto err_command_alloc;

        /* Allocate event ring */
        if ( ( rc = xhci_event_alloc ( xhci ) ) != 0 )
                goto err_event_alloc;

        /* Start controller */
        xhci_run ( xhci );

        return 0;

        xhci_stop ( xhci );
        xhci_event_free ( xhci );
 err_event_alloc:
        xhci_command_free ( xhci );
 err_command_alloc:
        xhci_scratchpad_free ( xhci );
 err_scratchpad_alloc:
        xhci_dcbaa_free ( xhci );
 err_dcbaa_alloc:
        free ( xhci->slot );
 err_slot_alloc:
        return rc;
}
static void xhci_bus_close ( struct usb_bus bus) [static]

Close USB bus.

Parameters:
busUSB bus

Definition at line 2859 of file xhci.c.

References assert, free, NULL, xhci_device::slot, xhci_device::slots, usb_bus_get_hostdata(), xhci_command_free(), xhci_dcbaa_free(), xhci_event_free(), xhci_scratchpad_free(), and xhci_stop().

                                                   {
        struct xhci_device *xhci = usb_bus_get_hostdata ( bus );
        unsigned int i;

        /* Sanity checks */
        assert ( xhci->slot != NULL );
        for ( i = 0 ; i <= xhci->slots ; i++ )
                assert ( xhci->slot[i] == NULL );

        xhci_stop ( xhci );
        xhci_event_free ( xhci );
        xhci_command_free ( xhci );
        xhci_scratchpad_free ( xhci );
        xhci_dcbaa_free ( xhci );
        free ( xhci->slot );
}
static void xhci_bus_poll ( struct usb_bus bus) [static]

Poll USB bus.

Parameters:
busUSB bus

Definition at line 2881 of file xhci.c.

References usb_bus_get_hostdata(), and xhci_event_poll().

                                                  {
        struct xhci_device *xhci = usb_bus_get_hostdata ( bus );

        /* Poll event ring */
        xhci_event_poll ( xhci );
}
static int xhci_hub_open ( struct usb_hub hub) [static]

Open hub.

Parameters:
hubUSB hub
Return values:
rcReturn status code

Definition at line 2901 of file xhci.c.

References usb_hub::ports, xhci_slot::ports, slot, usb_hub::usb, and usb_get_hostdata().

                                                 {
        struct xhci_slot *slot;

        /* Do nothing if this is the root hub */
        if ( ! hub->usb )
                return 0;

        /* Get device slot */
        slot = usb_get_hostdata ( hub->usb );

        /* Update device slot hub parameters.  We don't inform the
         * hardware of this information until the hub's interrupt
         * endpoint is opened, since the only mechanism for so doing
         * provided by the xHCI specification is a Configure Endpoint
         * command, and we can't issue that command until we have a
         * non-EP0 endpoint to configure.
         */
        slot->ports = hub->ports;

        return 0;
}
static void xhci_hub_close ( struct usb_hub *hub  __unused) [static]

Close hub.

Parameters:
hubUSB hub

Definition at line 2928 of file xhci.c.

                                                            {

        /* Nothing to do */
}
static int xhci_root_open ( struct usb_hub hub) [static]

Open root hub.

Parameters:
hubUSB hub
Return values:
rcReturn status code

Definition at line 2946 of file xhci.c.

References bus, usb_hub::bus, mdelay(), xhci_device::op, port, xhci_device::ports, usb_port::protocol, readl(), usb_bus_get_hostdata(), usb_hub_set_drvdata(), usb_port(), USB_PROTO_3_0, writel(), XHCI_LINK_STATE_DELAY_MS, XHCI_OP_PORTSC, XHCI_PORT_POWER_DELAY_MS, XHCI_PORTSC_LWS, XHCI_PORTSC_PLS_DISABLED, XHCI_PORTSC_PLS_MASK, XHCI_PORTSC_PLS_RXDETECT, XHCI_PORTSC_PP, and XHCI_PORTSC_PRESERVE.

                                                  {
        struct usb_bus *bus = hub->bus;
        struct xhci_device *xhci = usb_bus_get_hostdata ( bus );
        struct usb_port *port;
        uint32_t portsc;
        unsigned int i;

        /* Enable power to all ports */
        for ( i = 1 ; i <= xhci->ports ; i++ ) {
                portsc = readl ( xhci->op + XHCI_OP_PORTSC ( i ) );
                portsc &= XHCI_PORTSC_PRESERVE;
                portsc |= XHCI_PORTSC_PP;
                writel ( portsc, xhci->op + XHCI_OP_PORTSC ( i ) );
        }

        /* xHCI spec requires us to potentially wait 20ms after
         * enabling power to a port.
         */
        mdelay ( XHCI_PORT_POWER_DELAY_MS );

        /* USB3 ports may power up as Disabled */
        for ( i = 1 ; i <= xhci->ports ; i++ ) {
                portsc = readl ( xhci->op + XHCI_OP_PORTSC ( i ) );
                port = usb_port ( hub, i );
                if ( ( port->protocol >= USB_PROTO_3_0 ) &&
                     ( ( portsc & XHCI_PORTSC_PLS_MASK ) ==
                       XHCI_PORTSC_PLS_DISABLED ) ) {
                        /* Force link state to RxDetect */
                        portsc &= XHCI_PORTSC_PRESERVE;
                        portsc |= ( XHCI_PORTSC_PLS_RXDETECT | XHCI_PORTSC_LWS);
                        writel ( portsc, xhci->op + XHCI_OP_PORTSC ( i ) );
                }
        }

        /* Some xHCI cards seem to require an additional delay after
         * setting the link state to RxDetect.
         */
        mdelay ( XHCI_LINK_STATE_DELAY_MS );

        /* Record hub driver private data */
        usb_hub_set_drvdata ( hub, xhci );

        return 0;
}
static void xhci_root_close ( struct usb_hub hub) [static]

Close root hub.

Parameters:
hubUSB hub

Definition at line 2996 of file xhci.c.

References NULL, and usb_hub_set_drvdata().

                                                    {

        /* Clear hub driver private data */
        usb_hub_set_drvdata ( hub, NULL );
}
static int xhci_root_enable ( struct usb_hub hub,
struct usb_port port 
) [static]

Enable port.

Parameters:
hubUSB hub
portUSB port
Return values:
rcReturn status code

Definition at line 3009 of file xhci.c.

References usb_port::address, DBGC, ETIMEDOUT, mdelay(), xhci_device::name, xhci_device::op, readl(), usb_hub_get_drvdata(), writel(), XHCI_OP_PORTSC, XHCI_PORT_RESET_MAX_WAIT_MS, XHCI_PORTSC_PED, XHCI_PORTSC_PR, and XHCI_PORTSC_PRESERVE.

                                                                           {
        struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
        uint32_t portsc;
        unsigned int i;

        /* Reset port */
        portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port->address ) );
        portsc &= XHCI_PORTSC_PRESERVE;
        portsc |= XHCI_PORTSC_PR;
        writel ( portsc, xhci->op + XHCI_OP_PORTSC ( port->address ) );

        /* Wait for port to become enabled */
        for ( i = 0 ; i < XHCI_PORT_RESET_MAX_WAIT_MS ; i++ ) {

                /* Check port status */
                portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port->address ) );
                if ( portsc & XHCI_PORTSC_PED )
                        return 0;

                /* Delay */
                mdelay ( 1 );
        }

        DBGC ( xhci, "XHCI %s-%d timed out waiting for port to enable\n",
               xhci->name, port->address );
        return -ETIMEDOUT;
}
static int xhci_root_disable ( struct usb_hub hub,
struct usb_port port 
) [static]

Disable port.

Parameters:
hubUSB hub
portUSB port
Return values:
rcReturn status code

Definition at line 3044 of file xhci.c.

References usb_port::address, xhci_device::op, readl(), usb_hub_get_drvdata(), writel(), XHCI_OP_PORTSC, XHCI_PORTSC_PED, and XHCI_PORTSC_PRESERVE.

                                                                            {
        struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
        uint32_t portsc;

        /* Disable port */
        portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port->address ) );
        portsc &= XHCI_PORTSC_PRESERVE;
        portsc |= XHCI_PORTSC_PED;
        writel ( portsc, xhci->op + XHCI_OP_PORTSC ( port->address ) );

        return 0;
}
static int xhci_root_speed ( struct usb_hub hub,
struct usb_port port 
) [static]

Update root hub port speed.

Parameters:
hubUSB hub
portUSB port
Return values:
rcReturn status code

Definition at line 3064 of file xhci.c.

References usb_port::address, DBGC2, usb_port::disconnected, xhci_device::name, xhci_device::op, usb_port::protocol, rc, readl(), speed, usb_port::speed, usb_hub_get_drvdata(), USB_PROTO_3_0, USB_SPEED_FULL, USB_SPEED_NONE, writel(), XHCI_OP_PORTSC, xhci_port_speed(), XHCI_PORTSC_CCS, XHCI_PORTSC_CHANGE, XHCI_PORTSC_CSC, XHCI_PORTSC_PED, XHCI_PORTSC_PRESERVE, and XHCI_PORTSC_PSIV.

                                                                          {
        struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
        uint32_t portsc;
        unsigned int psiv;
        int ccs;
        int ped;
        int csc;
        int speed;
        int rc;

        /* Read port status */
        portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port->address ) );
        DBGC2 ( xhci, "XHCI %s-%d status is %08x\n",
                xhci->name, port->address, portsc );
        ccs = ( portsc & XHCI_PORTSC_CCS );
        ped = ( portsc & XHCI_PORTSC_PED );
        csc = ( portsc & XHCI_PORTSC_CSC );
        psiv = XHCI_PORTSC_PSIV ( portsc );

        /* Record disconnections and clear changes */
        port->disconnected |= csc;
        portsc &= ( XHCI_PORTSC_PRESERVE | XHCI_PORTSC_CHANGE );
        writel ( portsc, xhci->op + XHCI_OP_PORTSC ( port->address ) );

        /* Port speed is not valid unless port is connected */
        if ( ! ccs ) {
                port->speed = USB_SPEED_NONE;
                return 0;
        }

        /* For USB2 ports, the PSIV field is not valid until the port
         * completes reset and becomes enabled.
         */
        if ( ( port->protocol < USB_PROTO_3_0 ) && ! ped ) {
                port->speed = USB_SPEED_FULL;
                return 0;
        }

        /* Get port speed and map to generic USB speed */
        speed = xhci_port_speed ( xhci, port->address, psiv );
        if ( speed < 0 ) {
                rc = speed;
                return rc;
        }

        port->speed = speed;
        return 0;
}
static int xhci_root_clear_tt ( struct usb_hub hub,
struct usb_port port,
struct usb_endpoint ep 
) [static]

Clear transaction translator buffer.

Parameters:
hubUSB hub
portUSB port
epUSB endpoint
Return values:
rcReturn status code

Definition at line 3121 of file xhci.c.

References usb_port::address, DBGC, ENOTSUP, usb_device::name, xhci_device::name, usb_endpoint::usb, usb_endpoint_name(), and usb_hub_get_drvdata().

                                                          {
        struct xhci_device *xhci = usb_hub_get_drvdata ( hub );

        /* Should never be called; this is a root hub */
        DBGC ( xhci, "XHCI %s-%d nonsensical CLEAR_TT for %s %s\n", xhci->name,
               port->address, ep->usb->name, usb_endpoint_name ( ep ) );

        return -ENOTSUP;
}
static void xhci_pch_fix ( struct xhci_device xhci,
struct pci_device pci 
) [static]

Fix Intel PCH-specific quirks.

Parameters:
xhcixHCI device
pciPCI device

Definition at line 3179 of file xhci.c.

References DBGC, xhci_device::name, xhci_device::pch, pci_read_config_dword(), pci_write_config_dword(), xhci_pch::usb3pssen, XHCI_PCH_USB3PRM, XHCI_PCH_USB3PSSEN, XHCI_PCH_XUSB2PR, XHCI_PCH_XUSB2PRM, and xhci_pch::xusb2pr.

Referenced by xhci_probe().

                                                                              {
        struct xhci_pch *pch = &xhci->pch;
        uint32_t xusb2pr;
        uint32_t xusb2prm;
        uint32_t usb3pssen;
        uint32_t usb3prm;

        /* Enable SuperSpeed capability.  Do this before rerouting
         * USB2 ports, so that USB3 devices connect at SuperSpeed.
         */
        pci_read_config_dword ( pci, XHCI_PCH_USB3PSSEN, &usb3pssen );
        pci_read_config_dword ( pci, XHCI_PCH_USB3PRM, &usb3prm );
        if ( usb3prm & ~usb3pssen ) {
                DBGC ( xhci, "XHCI %s enabling SuperSpeed on ports %08x\n",
                       xhci->name, ( usb3prm & ~usb3pssen ) );
        }
        pch->usb3pssen = usb3pssen;
        usb3pssen |= usb3prm;
        pci_write_config_dword ( pci, XHCI_PCH_USB3PSSEN, usb3pssen );

        /* Route USB2 ports from EHCI to xHCI */
        pci_read_config_dword ( pci, XHCI_PCH_XUSB2PR, &xusb2pr );
        pci_read_config_dword ( pci, XHCI_PCH_XUSB2PRM, &xusb2prm );
        if ( xusb2prm & ~xusb2pr ) {
                DBGC ( xhci, "XHCI %s routing ports %08x from EHCI to xHCI\n",
                       xhci->name, ( xusb2prm & ~xusb2pr ) );
        }
        pch->xusb2pr = xusb2pr;
        xusb2pr |= xusb2prm;
        pci_write_config_dword ( pci, XHCI_PCH_XUSB2PR, xusb2pr );
}
static void xhci_pch_undo ( struct xhci_device xhci,
struct pci_device pci 
) [static]

Undo Intel PCH-specific quirk fixes.

Parameters:
xhcixHCI device
pciPCI device

Definition at line 3217 of file xhci.c.

References xhci_device::pch, pci_write_config_dword(), xhci_pch::usb3pssen, XHCI_PCH_USB3PSSEN, XHCI_PCH_XUSB2PR, and xhci_pch::xusb2pr.

Referenced by xhci_probe(), and xhci_remove().

                                                                               {
        struct xhci_pch *pch = &xhci->pch;

        /* Restore USB2 port routing to original state */
        pci_write_config_dword ( pci, XHCI_PCH_XUSB2PR, pch->xusb2pr );

        /* Restore SuperSpeed capability to original state */
        pci_write_config_dword ( pci, XHCI_PCH_USB3PSSEN, pch->usb3pssen );
}
static int xhci_probe ( struct pci_device pci) [static]

Probe PCI device.

Parameters:
pciPCI device
Return values:
rcReturn status code

Definition at line 3233 of file xhci.c.

References adjust_pci_device(), alloc_usb_bus(), xhci_device::bus, pci_device::dev, pci_device_id::driver_data, ENODEV, ENOMEM, free, free_usb_bus(), usb_bus::hub, pci_device::id, ioremap(), iounmap(), device::name, xhci_device::name, pci_bar_size(), pci_bar_start(), pci_set_drvdata(), port, xhci_device::ports, usb_port::protocol, xhci_device::quirks, rc, register_usb_bus(), xhci_device::regs, unregister_usb_bus(), usb_bus_set_hostdata(), usb_hub_set_drvdata(), usb_port(), XHCI_BAR, xhci_init(), xhci_legacy_claim(), xhci_legacy_init(), xhci_legacy_release(), XHCI_MTU, XHCI_PCH, xhci_pch_fix(), xhci_pch_undo(), xhci_port_protocol(), xhci_reset(), and zalloc().

                                                 {
        struct xhci_device *xhci;
        struct usb_port *port;
        unsigned long bar_start;
        size_t bar_size;
        unsigned int i;
        int rc;

        /* Allocate and initialise structure */
        xhci = zalloc ( sizeof ( *xhci ) );
        if ( ! xhci ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        xhci->name = pci->dev.name;
        xhci->quirks = pci->id->driver_data;

        /* Fix up PCI device */
        adjust_pci_device ( pci );

        /* Map registers */
        bar_start = pci_bar_start ( pci, XHCI_BAR );
        bar_size = pci_bar_size ( pci, XHCI_BAR );
        xhci->regs = ioremap ( bar_start, bar_size );
        if ( ! xhci->regs ) {
                rc = -ENODEV;
                goto err_ioremap;
        }

        /* Initialise xHCI device */
        xhci_init ( xhci, xhci->regs );

        /* Initialise USB legacy support and claim ownership */
        xhci_legacy_init ( xhci );
        xhci_legacy_claim ( xhci );

        /* Fix Intel PCH-specific quirks, if applicable */
        if ( xhci->quirks & XHCI_PCH )
                xhci_pch_fix ( xhci, pci );

        /* Reset device */
        if ( ( rc = xhci_reset ( xhci ) ) != 0 )
                goto err_reset;

        /* Allocate USB bus */
        xhci->bus = alloc_usb_bus ( &pci->dev, xhci->ports, XHCI_MTU,
                                    &xhci_operations );
        if ( ! xhci->bus ) {
                rc = -ENOMEM;
                goto err_alloc_bus;
        }
        usb_bus_set_hostdata ( xhci->bus, xhci );
        usb_hub_set_drvdata ( xhci->bus->hub, xhci );

        /* Set port protocols */
        for ( i = 1 ; i <= xhci->ports ; i++ ) {
                port = usb_port ( xhci->bus->hub, i );
                port->protocol = xhci_port_protocol ( xhci, i );
        }

        /* Register USB bus */
        if ( ( rc = register_usb_bus ( xhci->bus ) ) != 0 )
                goto err_register;

        pci_set_drvdata ( pci, xhci );
        return 0;

        unregister_usb_bus ( xhci->bus );
 err_register:
        free_usb_bus ( xhci->bus );
 err_alloc_bus:
        xhci_reset ( xhci );
 err_reset:
        if ( xhci->quirks & XHCI_PCH )
                xhci_pch_undo ( xhci, pci );
        xhci_legacy_release ( xhci );
        iounmap ( xhci->regs );
 err_ioremap:
        free ( xhci );
 err_alloc:
        return rc;
}
static void xhci_remove ( struct pci_device pci) [static]

Remove PCI device.

Parameters:
pciPCI device

Definition at line 3321 of file xhci.c.

References bus, xhci_device::bus, free, free_usb_bus(), iounmap(), pci_get_drvdata(), xhci_device::quirks, xhci_device::regs, unregister_usb_bus(), xhci_legacy_release(), XHCI_PCH, xhci_pch_undo(), and xhci_reset().

                                                   {
        struct xhci_device *xhci = pci_get_drvdata ( pci );
        struct usb_bus *bus = xhci->bus;

        unregister_usb_bus ( bus );
        free_usb_bus ( bus );
        xhci_reset ( xhci );
        if ( xhci->quirks & XHCI_PCH )
                xhci_pch_undo ( xhci, pci );
        xhci_legacy_release ( xhci );
        iounmap ( xhci->regs );
        free ( xhci );
}
static void xhci_shutdown ( int  booting) [static]

Prepare for exit.

Parameters:
bootingSystem is shutting down for OS boot

Definition at line 3357 of file xhci.c.

                                          {
        /* If we are shutting down to boot an OS, then prevent the
         * release of ownership back to BIOS.
         */
        xhci_legacy_prevent_release = booting;
}
struct startup_fn xhci_startup __startup_fn ( STARTUP_LATE  ) [read]

Startup/shutdown function.


Variable Documentation

struct profiler xhci_transfer_profiler __profiler [static]
Initial value:
        { .name = "xhci.message" }

Message transfer profiler.

Transfer event profiler.

Event ring profiler.

Stream transfer profiler.

Definition at line 48 of file xhci.c.

Prevent the release of ownership back to BIOS.

Definition at line 527 of file xhci.c.

USB host controller operations.

Definition at line 3140 of file xhci.c.

struct pci_device_id xhci_ids[] [static]
Initial value:
 {
        PCI_ROM ( 0x8086, 0x9d2f, "xhci-skylake", "xHCI (Skylake)", ( XHCI_PCH | XHCI_BAD_PSIV ) ),
        PCI_ROM ( 0x8086, 0xffff, "xhci-pch", "xHCI (Intel PCH)", XHCI_PCH ),
        PCI_ROM ( 0xffff, 0xffff, "xhci", "xHCI", 0 ),
}

XHCI PCI device IDs.

Definition at line 3336 of file xhci.c.

struct pci_driver xhci_driver __pci_driver
Initial value:
 {
        .ids = xhci_ids,
        .id_count = ( sizeof ( xhci_ids ) / sizeof ( xhci_ids[0] ) ),
        .class = PCI_CLASS_ID ( PCI_CLASS_SERIAL, PCI_CLASS_SERIAL_USB,
                                PCI_CLASS_SERIAL_USB_XHCI ),
        .probe = xhci_probe,
        .remove = xhci_remove,
}

XHCI PCI driver.

Definition at line 3343 of file xhci.c.