Skip to content

xHCI

include/drivers/usb/xhci.h View source View on GitHub
struct xhci_cap_regs {
    uint8_t   cap_length;
    uint8_t   reserved;
    uint16_t  hci_version;
    uint32_t  hcs_params1;
    uint32_t  hcs_params2;
    uint32_t  hcs_params3;
    uint32_t  hcc_params1;
    uint32_t  dboff;
    uint32_t  rtsoff;
    uint32_t  hcc_params2;
};
struct xhci_port_regs {
    uint32_t  portsc;
    uint32_t  portpmsc;
    uint32_t  portli;
    uint32_t  portct;
};
struct xhci_usbcmd {
    union {
        uint32_t  raw;
        struct {
            uint32_t  run_stop : 1;
            uint32_t  host_controller_reset : 1;
            uint32_t  interrupter_enable : 1;
            uint32_t  host_system_error_en : 1;
            uint32_t  reserved0 : 3;
            uint32_t  light_host_controller_reset : 1;
            uint32_t  controller_save_state : 1;
            uint32_t  controller_restore_state : 1;
            uint32_t  enable_wrap_event : 1;
            uint32_t  enable_u3_mf_index : 1;
            uint32_t  reserved1 : 1;
            uint32_t  cem_enable : 1;
            uint32_t  extended_tbc_enable : 1;
            uint32_t  extended_tbc_trb_status_enable : 1;
            uint32_t  vtio_enable : 1;
            uint32_t  reserved2 : 15;
        };
    };
};
struct xhci_slot_ctx {
    uint32_t  route_string : 20;
    uint32_t  speed : 4;
    uint32_t  reserved0 : 1;
    uint32_t  mtt : 1;
    uint32_t  hub : 1;
    uint32_t  context_entries : 5;
    uint32_t  max_exit_latency : 16;
    uint32_t  root_hub_port : 8;
    uint32_t  num_ports : 8;
    uint32_t  parent_hub_slot_id : 8;
    uint32_t  parent_port_number : 8;
    uint32_t  parent_think_time : 2;
    uint32_t  reserved1 : 4;
    uint32_t  interrupter_target : 10;
    uint32_t  usb_device_address : 8;
    uint32_t  reserved2 : 19;
    uint32_t  slot_state : 5;
    uint32_t  reserved3[4];
};
struct xhci_ep_ctx {
    uint32_t  ep_state : 3;
    uint32_t  reserved1 : 5;
    uint32_t  mult : 2;
    uint32_t  max_pstreams : 5;
    uint32_t  lsa : 1;
    uint32_t  interval : 8;
    uint32_t  max_esit_payload_hi : 8;
    uint32_t  reserved2 : 1;
    uint32_t  error_count : 2;
    uint32_t  ep_type : 3;
    uint32_t  reserved3 : 1;
    uint32_t  host_initiate_disable : 1;
    uint32_t  max_burst_size : 8;
    uint32_t  max_packet_size : 16;
    union {
        uint64_t  dequeue_ptr_raw;
        struct {
            uint32_t  dcs : 1;
            uint32_t  reserved4 : 3;
            uint64_t  dequeue_ptr : 60;
        };
    };
    uint32_t  average_trb_length : 16;
    uint32_t  max_esit_payload_lo : 16;
    uint32_t  reserved5[3];
};
struct xhci_input_ctrl_ctx {
    uint32_t  drop_flags;
    uint32_t  add_flags;
    uint32_t  reserved[5];
    uint32_t  config : 8;
    uint32_t  interface_num : 8;
    uint32_t  alternate_setting : 8;
    uint32_t  reserved1 : 8;
};
struct xhci_input_ctx {
    struct xhci_input_ctrl_ctx  ctrl_ctx;
    struct xhci_slot_ctx        slot_ctx;
    struct xhci_ep_ctx          ep_ctx[31];
};
struct xhci_device_ctx {
    struct xhci_slot_ctx  slot_ctx;
    struct xhci_ep_ctx    ep_ctx[32];
};
struct xhci_op_regs {
    struct xhci_usbcmd     usbcmd;
    uint32_t               usbsts;
    uint32_t               pagesize;
    uint32_t               reserved[2];
    uint32_t               dnctrl;
    uint64_t               crcr;
    uint32_t               reserved2[4];
    uint64_t               dcbaap;
    uint32_t               config;
    uint32_t               reserved3[241];
    struct xhci_port_regs  regs[];
};
struct xhci_trb {
    uint64_t  parameter;
    uint32_t  status;
    uint32_t  control;
};
struct xhci_ring {
    struct xhci_trb  *trbs;
    uint64_t         phys;
    uint32_t         enqueue_index;
    uint32_t         dequeue_index;
    uint8_t          cycle;
    uint32_t         size;
    size_t           outgoing;
};
struct xhci_erst_entry {
    uint64_t  ring_segment_base;
    uint32_t  ring_segment_size;
    uint32_t  reserved;
};
struct xhci_interrupter_regs {
    uint32_t  iman;
    uint32_t  imod;
    uint32_t  erstsz;
    uint32_t  reserved;
    uint64_t  erstba;
    uint64_t  erdp;
};
struct xhci_dcbaa {
    uint64_t  ptrs[256];
};
struct xhci_ext_cap {
    uint8_t   cap_id;
    uint8_t   next;
    uint16_t  cap_specific;
};
struct xhci_slot {
    _Atomic enum xhci_slot_state  state;
    struct xhci_device            *dev;
    struct xhci_ring              *ep_rings[32];
    uint8_t                       slot_id;
    refcount_t                    refcount;
    struct xhci_port              *port;
    struct usb_device             *udev;
};
struct xhci_port {
    struct spinlock       update_lock;
    uint8_t               port_id;
    struct xhci_slot      *slot;
    uint8_t               speed;
    bool                  usb3;
    uint64_t              generation;
    enum xhci_port_state  state;
    struct xhci_device    *dev;
};
struct xhci_device {
    irq_t                         irq;
    struct pci_device             *pci;
    struct xhci_input_ctx         *input_ctx;
    struct xhci_cap_regs          *cap_regs;
    struct xhci_op_regs           *op_regs;
    struct xhci_interrupter_regs  *intr_regs;
    struct xhci_dcbaa             *dcbaa;
    struct xhci_ring              *event_ring;
    struct xhci_ring              *cmd_ring;
    struct xhci_erst_entry        *erst;
    struct xhci_port_regs         *port_regs;
    uint64_t                      ports;
    struct xhci_slot              slots[XHCI_SLOT_COUNT];
    struct xhci_port              port_info[XHCI_PORT_COUNT];
    struct list_head              requests[XHCI_REQ_LIST_MAX];
    size_t                        num_devices;
    struct list_head              devices;
    struct spinlock               lock;
    struct semaphore              sem;
    struct semaphore              port_disconnect;
    struct semaphore              port_connect;
    struct usb_controller         *controller;
    atomic_bool                   worker_waiting;
};
struct xhci_command {
    struct xhci_ring     *ring;
    struct xhci_slot     *slot;
    uint32_t             ep_id;
    size_t               num_trbs;
    void                 (*emit)(struct xhci_command *cmd, struct xhci_ring *ring);
    struct xhci_request  *request;
    void                 *private;
};
struct xhci_request {
    enum xhci_request_command_type     type;
    enum xhci_request_list             list_owner;
    struct usb_request                 *urb;
    struct xhci_command                *command;
    struct xhci_trb                    *last_trb;
    uint64_t                           trb_phys;
    uint8_t                            port;
    volatile uint8_t                   completion_code;
    volatile uint64_t                  return_parameter;
    volatile uint32_t                  return_status;
    volatile uint32_t                  return_control;
    uint64_t                           generation;
    volatile enum xhci_request_status  status;
    struct list_head                   list;
    void                               (*callback)(struct xhci_device *, struct xhci_request *);
    void                               *private;
};
struct xhci_return {
    uint32_t  control;
    uint32_t  status;
};
enum xhci_slot_state {
    XHCI_SLOT_STATE_UNDEF,
    XHCI_SLOT_STATE_ENABLED,
    XHCI_SLOT_STATE_DISCONNECTING,
    XHCI_SLOT_STATE_DISCONNECTED,
};
enum xhci_port_state {
    XHCI_PORT_STATE_UNDEF,
    XHCI_PORT_STATE_CONNECTING,
    XHCI_PORT_STATE_CONNECTED,
    XHCI_PORT_STATE_DISCONNECTING,
    XHCI_PORT_STATE_DISCONNECTED,
};
enum xhci_request_status {
    XHCI_REQUEST_SENDING,
    XHCI_REQUEST_OK,
    XHCI_REQUEST_CANCELLED,
    XHCI_REQUEST_DISCONNECT,
    XHCI_REQUEST_ERR,
};
enum xhci_request_list {
    XHCI_REQ_LIST_NONE,
    XHCI_REQ_LIST_OUTGOING,
    XHCI_REQ_LIST_WAITING,
    XHCI_REQ_LIST_PROCESSED,
    XHCI_REQ_LIST_MAX,
};
enum xhci_request_command_type {
    XHCI_CMD_TYPE_NONE,
    XHCI_CMD_TYPE_ENABLE_SLOT,
    XHCI_CMD_TYPE_DISABLE_SLOT,
    XHCI_CMD_TYPE_ADDRESS_DEVICE,
    XHCI_CMD_TYPE_CONFIGURE_ENDPOINT,
    XHCI_CMD_TYPE_EVALUATE_CONTEXT,
    XHCI_CMD_TYPE_RESET_ENDPOINT,
    XHCI_CMD_TYPE_STOP_ENDPOINT,
    XHCI_CMD_TYPE_SET_TR_DEQUEUE_POINTER,
    XHCI_CMD_TYPE_RESET_DEVICE,
    XHCI_CMD_TYPE_FORCE_EVENT,
    XHCI_CMD_TYPE_INTERRUPT_TRANSFER,
    XHCI_CMD_TYPE_CONTROL_TRANSFER,
    XHCI_CMD_TYPE_NO_OP,
    XHCI_CMD_TYPE_NORMAL,
};
char xhci_slot_state_str(enum xhci_slot_state s);
char xhci_port_state_str(enum xhci_port_state s);
char xhci_request_command_type_str(enum xhci_request_command_type t);
void xhci_init(uint8_t bus, uint8_t slot, uint8_t func, struct pci_device *dev);
#define XHCI_DEVICE_TIMEOUT 1000
#define TRB_RING_SIZE 256
#define XHCI_PORT_COUNT 64
#define XHCI_SLOT_COUNT 255
#define XHCI_INPUT_CTX_ADD_FLAGS ((1 << 0) | (1 << 1))
#define XHCI_SETUP_TRANSFER_TYPE_NONE 0
#define XHCI_SETUP_TRANSFER_TYPE_OUT 2
#define XHCI_SETUP_TRANSFER_TYPE_IN 3
#define XHCI_USBSTS_HCH 1        /* HC halted */
#define XHCI_USBSTS_HSE (1 << 2) /* host system error */
#define XHCI_USBSTS_EI (1 << 3)  /* event interrupt */
#define XHCI_USBSTS_PCD (1 << 4) /* port change detect */
#define XHCI_IMAN_MASK 0x2
#define XHCI_IMAN_INT_PENDING 0x1
#define XHCI_IMAN_INT_ENABLE 0x2
#define XHCI_ENDPOINT_TYPE_INVAL 0
#define XHCI_ENDPOINT_TYPE_ISOCH_OUT 1
#define XHCI_ENDPOINT_TYPE_BULK_OUT 2
#define XHCI_ENDPOINT_TYPE_INTERRUPT_OUT 3
#define XHCI_ENDPOINT_TYPE_CONTROL_BI 4
#define XHCI_ENDPOINT_TYPE_ISOCH_IN 5
#define XHCI_ENDPOINT_TYPE_BULK_IN 6
#define XHCI_ENDPOINT_TYPE_INTERRUPT_IN 7
#define XHCI_EXT_CAP_ID_LEGACY_SUPPORT 1
#define XHCI_EXT_CAP_ID_USB 2
#define TRB_TYPE_RESERVED 0x00
#define TRB_TYPE_NORMAL 0x01
#define TRB_TYPE_SETUP_STAGE 0x02
#define TRB_TYPE_DATA_STAGE 0x03
#define TRB_TYPE_STATUS_STAGE 0x04
#define TRB_TYPE_ISOCH 0x05
#define TRB_TYPE_LINK 0x06
#define TRB_TYPE_EVENT_DATA 0x07
#define TRB_TYPE_NO_OP 0x08
#define TRB_TYPE_NO_OP_COMMAND 0x8
#define TRB_TYPE_ENABLE_SLOT 0x09
#define TRB_TYPE_DISABLE_SLOT 0x0A
#define TRB_TYPE_ADDRESS_DEVICE 0x0B
#define TRB_TYPE_CONFIGURE_ENDPOINT 0x0C
#define TRB_TYPE_EVALUATE_CONTEXT 0x0D
#define TRB_TYPE_RESET_ENDPOINT 0x0E
#define TRB_TYPE_STOP_ENDPOINT 0x0F
#define TRB_TYPE_SET_TR_DEQUEUE_POINTER 0x10
#define TRB_TYPE_RESET_DEVICE 0x11
#define TRB_TYPE_FORCE_EVENT 0x12
#define TRB_TYPE_NEGOTIATE_BW 0x13
#define TRB_TYPE_SET_LATENCY_TOLERANCE 0x14
#define TRB_TYPE_GET_PORT_BANDWIDTH 0x15
#define TRB_TYPE_FORCE_HEADER 0x16
#define TRB_TYPE_NO_OP_2_COMMAND 0x17
#define TRB_TYPE_TRANSFER_EVENT 0x20
#define TRB_TYPE_COMMAND_COMPLETION 0x21
#define TRB_TYPE_PORT_STATUS_CHANGE 0x22
#define TRB_TYPE_BANDWIDTH_REQUEST 0x23
#define TRB_TYPE_DOORBELL_EVENT 0x24
#define TRB_TYPE_HOST_CONTROLLER_EVENT 0x25
#define TRB_TYPE_DEVICE_NOTIFICATION 0x26
#define TRB_TYPE_MFINDEX_WRAP 0x27
#define TRB_FIELD(val, lo, hi) BIT_RANGE(val, lo, hi)
#define TRB_TYPE(ctrl) TRB_FIELD(ctrl, 10, 15)
#define TRB_SLOT(ctrl) TRB_FIELD(ctrl, 24, 31)
#define TRB_EP(ctrl) TRB_FIELD(ctrl, 16, 23)
#define TRB_CC(status) TRB_FIELD(status, 24, 31)
#define TRB_PORT(parameter) TRB_FIELD(parameter, 24, 31)
#define TRB_SET_TYPE(val) (((val) & 0x3F) << 10)
#define TRB_SET_CYCLE(val) (((val) & 1))
#define TRB_SET_INTERRUPTER_TARGET(target) ((target) >> 21)
#define TRB_CYCLE_BIT (1 << 0)
#define TRB_ENT_BIT (1 << 1) // Evaluate Next TRB
#define TRB_ISP_BIT (1 << 2) // Interrupt on Short Packet
#define TRB_NS_BIT (1 << 3)  // No Snoop
#define TRB_CH_BIT (1 << 4)  // Chain
#define TRB_IOC_BIT (1 << 5) // Interrupt On Completion
#define TRB_IDT_BIT (1 << 6) // Immediate Data
#define TRB_BEI_BIT (1 << 9) // Block Event Interrupt (ISO)
#define TRB_TOGGLE_CYCLE_BIT (1 << 1)
#define TRB_TYPE_SHIFT 10
#define TRB_SET_SLOT_ID(id) (((id) & 0xFF) << 24)
#define PORTSC_CCS (1 << 0)           // Current Connect Status
#define PORTSC_PED (1 << 1)           // Port Enabled/Disabled
#define PORTSC_OCA (1 << 3)           // Over-Current Active
#define PORTSC_RESET (1 << 4)         // Port Reset
#define PORTSC_PR (1 << 4)            // Port Reset
#define PORTSC_PLSE (1 << 5)          // Port Link State Enable
#define PORTSC_PRES (1 << 6)          // Port Resume
#define PORTSC_PP (1 << 9)            // Port Power
#define PORTSC_SPEED_MASK (0xF << 10) // Bits 10–13: Port Speed
#define PORTSC_SPEED_SHIFT 10
#define PORTSC_PLS_SHIFT 5
#define PORTSC_PLS_MASK (0xF << 5)
#define PORTSC_LWS (1 << 16) // Link Write Strobe
#define PORTSC_CSC (1 << 17) // Connect Status Change
#define PORTSC_PEC (1 << 18) // Port Enable/Disable Change
#define PORTSC_WRC (1 << 19) // Warm Port Reset Change
#define PORTSC_OCC (1 << 20) // Over-current Change
#define PORTSC_PRC (1 << 21) // Port Reset Change
#define PORTSC_PLC (1 << 22) // Port Link State Change
#define PORTSC_CEC (1 << 23) // Port Config Error Change
#define PORTSC_PLS_POLLING 7
#define PORTSC_PLS_U0 0
#define PORTSC_PLS_U2 2
#define PORTSC_PLS_U3 3
#define PORTSC_PLS_RXDETECT 5
#define PORTSC_IND (1 << 24)     // Port Indicator Control
#define PORTSC_LWS_BIT (1 << 16) // Link Write Strobe
#define PORTSC_DR (1 << 30)      // Device Removable
#define PORTSC_WPR (1u << 31)    // Warm Port Reset
#define PORT_SPEED_FULL 1       // USB 1.1 Full Speed
#define PORT_SPEED_LOW 2        // USB 1.1 Low Speed
#define PORT_SPEED_HIGH 3       // USB 2.0 High Speed
#define PORT_SPEED_SUPER 4      // USB 3.0 SuperSpeed
#define PORT_SPEED_SUPER_PLUS 5 // USB 3.1 Gen2 (SuperSpeed+)
#define CC_SUCCESS 1
#define CC_DATA_BUFFER_ERROR 2
#define CC_BABBLE_DETECTED 3
#define CC_USB_TRANSACTION_ERROR 4
#define CC_TRB_ERROR 5
#define CC_STALL_ERROR 6
#define CC_RESOURCE_ERROR 7
#define CC_BANDWIDTH_ERROR 8
#define CC_NO_SLOTS_AVAILABLE 9
#define CC_INVALID_STREAM_TYPE 10
#define CC_SLOT_NOT_ENABLED_ERROR 11
#define CC_ENDPOINT_NOT_ENABLED 12
#define CC_SHORT_PACKET 13
#define CC_RING_UNDERRUN 14
#define CC_RING_OVERRUN 15
#define CC_VF_EVENT_RING_FULL_ERROR 16
#define CC_PARAMETER_ERROR 17
#define CC_BANDWIDTH_OVERRUN_ERROR 18
#define CC_CONTEXT_STATE_ERROR 19
#define CC_NO_PING_RESPONSE_ERROR 20
#define CC_EVENT_RING_FULL 21
#define CC_INCOMPATIBLE_DEVICE 22
#define CC_MISSED_SERVICE 23
#define CC_COMMAND_RING_STOPPED 24
#define CC_COMMAND_ABORTED 25
#define CC_STOPPED 26
#define CC_STOPPED_LEN_INVALID 27
#define CC_STOPPED_SHORT_PACKET 28
#define CC_MAX_EXIT_LATENCY_TOO_LARGE 29
#define xhci_log(log_level, fmt, ...) \
    log(LOG_SITE(xhci), LOG_HANDLE(xhci), log_level, fmt, ##__VA_ARGS__)
#define xhci_warn(fmt, ...) xhci_log(LOG_WARN, fmt, ##__VA_ARGS__)
#define xhci_error(fmt, ...) xhci_log(LOG_ERROR, fmt, ##__VA_ARGS__)
#define xhci_info(fmt, ...) xhci_log(LOG_INFO, fmt, ##__VA_ARGS__)
#define xhci_debug(fmt, ...) xhci_log(LOG_DEBUG, fmt, ##__VA_ARGS__)
#define xhci_trace(fmt, ...) xhci_log(LOG_TRACE, fmt, ##__VA_ARGS__)
#define XHCI_ERDP_EHB_BIT (1 << 3)