blob: d92bd0686258ed661d22a2f7c9ede7286ece6872 [file] [log] [blame]
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright (c) 2018, Joyent, Inc.
*/
#ifndef _SYS_USB_XHCI_XHCI_H
#define _SYS_USB_XHCI_XHCI_H
/*
* Extensible Host Controller Interface (xHCI) USB Driver
*/
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/taskq_impl.h>
#include <sys/sysmacros.h>
#include <sys/usb/hcd/xhci/xhcireg.h>
#include <sys/usb/usba.h>
#include <sys/usb/usba/hcdi.h>
#include <sys/usb/hubd/hub.h>
#include <sys/usb/usba/hubdi.h>
#include <sys/usb/hubd/hubdvar.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* The base segment for DMA attributes was determined to be 4k based on xHCI 1.1
* / table 54: Data Structure Max Size, Boundary, and Alignment Requirement
* Summary. This indicates that the required alignment for most things is
* PAGESIZE, which in our current implementation is required to be 4K. We
* provide the ring segment value below for the things which need 64K alignment
*
* Similarly, in the same table, the maximum required alignment is 64 bytes,
* hence we use that for everything.
*
* Next is the scatter/gather lengths. For most of the data structures, we only
* want to have a single SGL entry, e.g. just a simple flat mapping. For many of
* our transfers, we use the same logic to simplify the implementation of the
* driver. However, for bulk transfers, which are the largest by far, we want to
* be able to leverage SGLs to give us more DMA flexibility.
*
* We can transfer up to 64K in one transfer request block (TRB) which
* corresponds to a single SGL entry. Each ring we create is a single page in
* size and will support at most 256 TRBs. To try and give the operating system
* flexibility when allocating DMA transfers, we've opted to allow up to 63
* SGLs. Because there isn't a good way to support DMA windows with the xHCI
* controller design, if this number is too small then DMA allocations and
* binding might fail. If the DMA binding fails, the transfer will fail.
*
* The reason that we use 63 SGLs and not the expected 64 is that we always need
* to allocate an additional TRB for the event data. This leaves us with a
* nicely divisible number of entries.
*
* The final piece of this is the maximum sized transfer that the driver
* advertises to the broader framework. This is currently sized at 512 KiB. For
* reference the ehci driver sized this value at 640 KiB. It's important to
* understand that this isn't reflected in the DMA attribute limitation, because
* it's not an attribute of the hardware. Experimentally, this has proven to be
* sufficient for most of the drivers that we support today. When considering
* increasing this number, please note the impact that might have on the
* required number of DMA SGL entries required to satisfy the allocation.
*
* The value of 512 KiB was originally based on the number of SGLs we supported
* multiplied by the maximum transfer size. The original number of
* XHCI_TRANSFER_DMA_SGL was 8. The 512 KiB value was based upon taking the
* number of SGLs and assuming that each TRB used its maximum transfer size of
* 64 KiB.
*/
#define XHCI_TRB_MAX_TRANSFER 65536 /* 64 KiB */
#define XHCI_DMA_ALIGN 64
#define XHCI_DEF_DMA_SGL 1
#define XHCI_TRANSFER_DMA_SGL 63
#define XHCI_MAX_TRANSFER 524288 /* 512 KiB */
/*
* Properties and values for rerouting ehci ports to xhci.
*/
#define XHCI_PROP_REROUTE_DISABLE 0
#define XHCI_PROP_REROUTE_DEFAULT 1
/*
* This number is a bit made up. Truthfully, the API here isn't the most useful
* for what we need to define as it should really be based on the endpoint that
* we're interested in rather than the device as a whole.
*
* We're basically being asked how many TRBs we're willing to schedule in one
* go. There's no great way to come up with this number, so we basically are
* making up something such that we use up a good portion of a ring, but not too
* much of it.
*/
#define XHCI_ISOC_MAX_TRB 64
#ifdef DEBUG
#define XHCI_DMA_SYNC(dma, flag) VERIFY0(ddi_dma_sync( \
(dma).xdb_dma_handle, 0, 0, \
(flag)))
#else
#define XHCI_DMA_SYNC(dma, flag) ((void) ddi_dma_sync( \
(dma).xdb_dma_handle, 0, 0, \
(flag)))
#endif
/*
* TRBs need to indicate the number of remaining USB packets in the overall
* transfer. This is a 5-bit value, which means that the maximum value we can
* store in that TRD field is 31.
*/
#define XHCI_MAX_TDSIZE 31
/*
* This defines a time in 2-ms ticks that is required to wait for the controller
* to be ready to go. Section 5.4.8 of the XHCI specification in the description
* of the PORTSC register indicates that the upper bound is 20 ms. Therefore the
* number of ticks is 10.
*/
#define XHCI_POWER_GOOD 10
/*
* Definitions to determine the default number of interrupts. Note that we only
* bother with a single interrupt at this time, though we've arranged the driver
* to make it possible to request more if, for some unlikely reason, it becomes
* necessary.
*/
#define XHCI_NINTR 1
/*
* Default interrupt modulation value. This enables us to have 4000 interrupts /
* second. This is supposed to be the default value of the controller. See xHCI
* 1.1 / 4.17.2 for more information.
*/
#define XHCI_IMOD_DEFAULT 0x000003F8U
/*
* Definitions that surround the default values used in various contexts. These
* come from various parts of the xHCI specification. In general, see xHCI 1.1 /
* 4.8.2. Note that the MPS_MASK is used for ISOCH and INTR endpoints which have
* different sizes.
*
* The burst member is a bit more complicated. By default for USB 2 devices, it
* only matters for ISOCH and INTR endpoints and so we use the macros below to
* pull it out of the endpoint description's max packet field. For USB 3, it
* matters for non-control endpoints. However, it comes out of a companion
* description.
*
* By default the mult member is zero for all cases except for super speed
* ISOCH endpoints, where it comes from the companion descriptor.
*/
#define XHCI_CONTEXT_DEF_CERR 3
#define XHCI_CONTEXT_ISOCH_CERR 0
#define XHCI_CONTEXT_MPS_MASK 0x07ff
#define XHCI_CONTEXT_BURST_MASK 0x1800
#define XHCI_CONTEXT_BURST_SHIFT 11
#define XHCI_CONTEXT_DEF_MULT 0
#define XHCI_CONTEXT_DEF_MAX_ESIT 0
#define XHCI_CONTEXT_DEF_CTRL_ATL 8
/*
* This number represents the number of transfers that we'll set up for a given
* interrupt transfer. Note that the idea here is that we'll want to allocate a
* certain number of transfers to basically ensure that we'll always be able to
* have a transfer available, even if the system is a bit caught up in trying to
* process it and for some reason we can't fire the interrupt. As such, we
* basically want to have enough available that at the fastest interval (125 us)
* that we have enough. So in this case we choose 8, with the assumption that we
* should be able to process at least one in a given millisecond. Note that this
* is not based in fact and is really just as much a guess and a hope.
*
* While we could then use less resources for other interrupt transfers that are
* slower, starting with uniform resource usage will make things a bit easier.
*/
#define XHCI_INTR_IN_NTRANSFERS 8
/*
* This number represents the number of xhci_transfer_t structures that we'll
* set up for a given isochronous transfer polling request. A given isochronous
* transfer may actually have multiple units of time associated with it. As
* such, we basically want to treat this like a case of classic double
* buffering. We have one ready to go while the other is being filled up. This
* will compensate for additional latency in the system. This is smaller than
* the Interrupt IN transfer case above as many callers may ask for multiple
* intervals in a single request.
*/
#define XHCI_ISOC_IN_NTRANSFERS 2
#define XHCI_PERIODIC_IN_NTRANSFERS \
MAX(XHCI_ISOC_IN_NTRANSFERS, XHCI_INTR_IN_NTRANSFERS)
/*
* Mask for a route string which is a 20-bit value.
*/
#define XHCI_ROUTE_MASK(x) ((x) & 0xfffff)
/*
* This is the default tick that we use for timeouts while endpoints have
* outstanding, active, non-periodic transfers. We choose one second as the USBA
* specifies timeouts in units of seconds. Note that this is in microseconds, so
* it can be fed into drv_usectohz().
*/
#define XHCI_TICK_TIMEOUT_US (MICROSEC)
/*
* Set of bits that we need one of to indicate that this port has something
* interesting on it.
*/
#define XHCI_HUB_INTR_CHANGE_MASK (XHCI_PS_CSC | XHCI_PS_PEC | \
XHCI_PS_WRC | XHCI_PS_OCC | XHCI_PS_PRC | XHCI_PS_PLC | XHCI_PS_CEC)
/*
* These represent known issues with various xHCI controllers.
*
* XHCI_QUIRK_NO_MSI MSI support on this controller is known to be
* broken.
*
* XHCI_QUIRK_32_ONLY Only use 32-bit DMA addreses with this
* controller.
*
* XHCI_QUIRK_INTC_EHCI This is an Intel platform which supports
* rerouting ports between EHCI and xHCI
* controllers on the platform.
*/
typedef enum xhci_quirk {
XHCI_QUIRK_NO_MSI = 0x01,
XHCI_QUIRK_32_ONLY = 0x02,
XHCI_QUIRK_INTC_EHCI = 0x04
} xhci_quirk_t;
/*
* xHCI capability parameter flags. These are documented in xHCI 1.1 / 5.3.6.
*/
typedef enum xhci_cap_flags {
XCAP_AC64 = 0x001,
XCAP_BNC = 0x002,
XCAP_CSZ = 0x004,
XCAP_PPC = 0x008,
XCAP_PIND = 0x010,
XCAP_LHRC = 0x020,
XCAP_LTC = 0x040,
XCAP_NSS = 0x080,
XCAP_PAE = 0x100,
XCAP_SPC = 0x200,
XCAP_SEC = 0x400,
XCAP_CFC = 0x800
} xchi_cap_flags_t;
/*
* Second set of capabilities, these are documented in xHCI 1.1 / 5.3.9.
*/
typedef enum xhci_cap2_flags {
XCAP2_U3C = 0x01,
XCAP2_CMC = 0x02,
XCAP2_FMC = 0x04,
XCAP2_CTC = 0x08,
XCAP2_LEC = 0x10,
XCAP2_CIC = 0x20
} xhci_cap2_flags_t;
/*
* These represent and store the various capability registers that we'll need to
* use. In addition, we stash a few other versioning related bits here. Note
* that we cache more information than we might need so that we have it for
* debugging purposes.
*/
typedef struct xhci_capability {
uint8_t xcap_usb_vers;
uint16_t xcap_hci_vers;
uint32_t xcap_pagesize;
uint8_t xcap_max_slots;
uint16_t xcap_max_intrs;
uint8_t xcap_max_ports;
boolean_t xcap_ist_micro;
uint8_t xcap_ist;
uint16_t xcap_max_esrt;
boolean_t xcap_scratch_restore;
uint16_t xcap_max_scratch;
uint8_t xcap_u1_lat;
uint16_t xcap_u2_lat;
xchi_cap_flags_t xcap_flags;
uint8_t xcap_max_psa;
uint16_t xcap_xecp_off;
xhci_cap2_flags_t xcap_flags2;
int xcap_intr_types;
} xhci_capability_t;
/*
* This represents a single logical DMA allocation. For the vast majority of
* non-transfer cases, it only represents a single DMA buffer and not a
* scatter-gather list.
*/
typedef struct xhci_dma_buffer {
caddr_t xdb_va; /* Buffer VA */
size_t xdb_len; /* Buffer logical len */
ddi_acc_handle_t xdb_acc_handle; /* Access handle */
ddi_dma_handle_t xdb_dma_handle; /* DMA handle */
int xdb_ncookies; /* Number of actual cookies */
ddi_dma_cookie_t xdb_cookies[XHCI_TRANSFER_DMA_SGL];
} xhci_dma_buffer_t;
/*
* This is a single transfer descriptor. It's packed to match the hardware
* layout.
*/
#pragma pack(1)
typedef struct xhci_trb {
uint64_t trb_addr;
uint32_t trb_status;
uint32_t trb_flags;
} xhci_trb_t;
#pragma pack()
/*
* This represents a single transfer that we want to allocate and perform.
*/
typedef struct xhci_transfer {
list_node_t xt_link;
hrtime_t xt_sched_time;
xhci_dma_buffer_t xt_buffer;
uint_t xt_ntrbs;
uint_t xt_short;
uint_t xt_timeout;
usb_cr_t xt_cr;
boolean_t xt_data_tohost;
xhci_trb_t *xt_trbs;
uint64_t *xt_trbs_pa;
usb_isoc_pkt_descr_t *xt_isoc;
usb_opaque_t xt_usba_req;
} xhci_transfer_t;
/*
* This represents a ring in xHCI, upon which event, transfer, and command TRBs
* are scheduled.
*/
typedef struct xhci_ring {
xhci_dma_buffer_t xr_dma;
uint_t xr_ntrb;
xhci_trb_t *xr_trb;
uint_t xr_head;
uint_t xr_tail;
uint8_t xr_cycle;
} xhci_ring_t;
/*
* This structure is used to represent the xHCI Device Context Base Address
* Array. It's defined in section 6.1 of the specification and is required for
* the controller to start.
*
* The maximum number of slots supported is always 256, therefore we size this
* structure at its maximum.
*/
#define XHCI_MAX_SLOTS 256
#define XHCI_DCBAA_SCRATCHPAD_INDEX 0
typedef struct xhci_dcbaa {
uint64_t *xdc_base_addrs;
xhci_dma_buffer_t xdc_dma;
} xhci_dcbaa_t;
typedef struct xhci_scratchpad {
uint64_t *xsp_addrs;
xhci_dma_buffer_t xsp_addr_dma;
xhci_dma_buffer_t *xsp_scratch_dma;
} xhci_scratchpad_t;
/*
* Contexts. These structures are inserted into the DCBAA above and are used for
* describing the state of the system. Note, that while many of these are
* 32-bytes in size, the xHCI specification defines that they'll be extended to
* 64-bytes with all the extra bytes as zeros if the CSZ flag is set in the
* HCCPARAMS1 register, e.g. we have the flag XCAP_CSZ set.
*
* The device context covers the slot context and 31 endpoints.
*/
#define XHCI_DEVICE_CONTEXT_32 1024
#define XHCI_DEVICE_CONTEXT_64 2048
#define XHCI_NUM_ENDPOINTS 31
#define XHCI_DEFAULT_ENDPOINT 0
#pragma pack(1)
typedef struct xhci_slot_context {
uint32_t xsc_info;
uint32_t xsc_info2;
uint32_t xsc_tt;
uint32_t xsc_state;
uint32_t xsc_reserved[4];
} xhci_slot_context_t;
typedef struct xhci_endpoint_context {
uint32_t xec_info;
uint32_t xec_info2;
uint64_t xec_dequeue;
uint32_t xec_txinfo;
uint32_t xec_reserved[3];
} xhci_endpoint_context_t;
typedef struct xhci_input_context {
uint32_t xic_drop_flags;
uint32_t xic_add_flags;
uint32_t xic_reserved[6];
} xhci_input_context_t;
#pragma pack()
/*
* Definitions and structures for maintaining the event ring.
*/
#define XHCI_EVENT_NSEGS 1
#pragma pack(1)
typedef struct xhci_event_segment {
uint64_t xes_addr;
uint16_t xes_size;
uint16_t xes_rsvd0;
uint32_t xes_rsvd1;
} xhci_event_segment_t;
#pragma pack()
typedef struct xhci_event_ring {
xhci_event_segment_t *xev_segs;
xhci_dma_buffer_t xev_dma;
xhci_ring_t xev_ring;
} xhci_event_ring_t;
typedef enum xhci_command_ring_state {
XHCI_COMMAND_RING_IDLE = 0x00,
XHCI_COMMAND_RING_RUNNING = 0x01,
XHCI_COMMAND_RING_ABORTING = 0x02,
XHCI_COMMAND_RING_ABORT_DONE = 0x03
} xhci_command_ring_state_t;
typedef struct xhci_command_ring {
xhci_ring_t xcr_ring;
kmutex_t xcr_lock;
kcondvar_t xcr_cv;
list_t xcr_commands;
timeout_id_t xcr_timeout;
xhci_command_ring_state_t xcr_state;
} xhci_command_ring_t;
/*
* Individual command states.
*
* XHCI_COMMAND_S_INIT The command has yet to be inserted into the
* command ring.
*
* XHCI_COMMAND_S_QUEUED The command is queued in the command ring.
*
* XHCI_COMMAND_S_RECEIVED A command completion for this was received.
*
* XHCI_COMMAND_S_DONE The command has been executed. Note that it may
* have been aborted.
*
* XHCI_COMMAND_S_RESET The ring is being reset due to a fatal error and
* this command has been removed from the ring.
* This means it has been aborted, but it was not
* the cause of the abort.
*
* Note, when adding states, anything after XHCI_COMMAND_S_DONE implies that
* upon reaching this state, it is no longer in the ring.
*/
typedef enum xhci_command_state {
XHCI_COMMAND_S_INIT = 0x00,
XHCI_COMMAND_S_QUEUED = 0x01,
XHCI_COMMAND_S_RECEIVED = 0x02,
XHCI_COMMAND_S_DONE = 0x03,
XHCI_COMMAND_S_RESET = 0x04
} xhci_command_state_t;
/*
* The TRB contents here are always kept in host byte order and are transformed
* to little endian when actually scheduled on the ring.
*/
typedef struct xhci_command {
list_node_t xco_link;
kcondvar_t xco_cv;
xhci_trb_t xco_req;
xhci_trb_t xco_res;
xhci_command_state_t xco_state;
} xhci_command_t;
typedef enum xhci_endpoint_state {
XHCI_ENDPOINT_PERIODIC = 0x01,
XHCI_ENDPOINT_HALTED = 0x02,
XHCI_ENDPOINT_QUIESCE = 0x04,
XHCI_ENDPOINT_TIMED_OUT = 0x08,
/*
* This is a composite of states that we need to watch for. We don't
* want to allow ourselves to set one of these flags while one of them
* is currently active.
*/
XHCI_ENDPOINT_SERIALIZE = 0x0c,
/*
* This is a composite of states that we need to make sure that if set,
* we do not schedule activity on the ring.
*/
XHCI_ENDPOINT_DONT_SCHEDULE = 0x0e,
/*
* This enpdoint is being torn down and should make sure it de-schedules
* itself.
*/
XHCI_ENDPOINT_TEARDOWN = 0x10
} xhci_endpoint_state_t;
/*
* Forwards required for the endpoint
*/
struct xhci_device;
struct xhci;
typedef struct xhci_endpoint {
struct xhci *xep_xhci;
struct xhci_device *xep_xd;
uint_t xep_num;
uint_t xep_type;
xhci_endpoint_state_t xep_state;
kcondvar_t xep_state_cv;
timeout_id_t xep_timeout;
list_t xep_transfers;
usba_pipe_handle_data_t *xep_pipe;
xhci_ring_t xep_ring;
} xhci_endpoint_t;
typedef struct xhci_device {
list_node_t xd_link;
usb_port_t xd_port;
uint8_t xd_slot;
boolean_t xd_addressed;
usba_device_t *xd_usbdev;
xhci_dma_buffer_t xd_ictx;
kmutex_t xd_imtx; /* Protects input contexts */
xhci_input_context_t *xd_input;
xhci_slot_context_t *xd_slotin;
xhci_endpoint_context_t *xd_endin[XHCI_NUM_ENDPOINTS];
xhci_dma_buffer_t xd_octx;
xhci_slot_context_t *xd_slotout;
xhci_endpoint_context_t *xd_endout[XHCI_NUM_ENDPOINTS];
xhci_endpoint_t *xd_endpoints[XHCI_NUM_ENDPOINTS];
} xhci_device_t;
typedef enum xhci_periodic_state {
XHCI_PERIODIC_POLL_IDLE = 0x0,
XHCI_PERIODIC_POLL_ACTIVE,
XHCI_PERIODIC_POLL_NOMEM,
XHCI_PERIODIC_POLL_STOPPING
} xhci_periodic_state_t;
typedef struct xhci_periodic_pipe {
xhci_periodic_state_t xpp_poll_state;
usb_opaque_t xpp_usb_req;
size_t xpp_tsize;
uint_t xpp_ntransfers;
xhci_transfer_t *xpp_transfers[XHCI_PERIODIC_IN_NTRANSFERS];
} xhci_periodic_pipe_t;
typedef struct xhci_pipe {
list_node_t xp_link;
hrtime_t xp_opentime;
usba_pipe_handle_data_t *xp_pipe;
xhci_endpoint_t *xp_ep;
xhci_periodic_pipe_t xp_periodic;
} xhci_pipe_t;
typedef struct xhci_usba {
usba_hcdi_ops_t *xa_ops;
ddi_dma_attr_t xa_dma_attr;
usb_dev_descr_t xa_dev_descr;
usb_ss_hub_descr_t xa_hub_descr;
usba_pipe_handle_data_t *xa_intr_cb_ph;
usb_intr_req_t *xa_intr_cb_req;
list_t xa_devices;
list_t xa_pipes;
} xhci_usba_t;
typedef enum xhci_attach_seq {
XHCI_ATTACH_FM = 0x1 << 0,
XHCI_ATTACH_PCI_CONFIG = 0x1 << 1,
XHCI_ATTACH_REGS_MAP = 0x1 << 2,
XHCI_ATTACH_INTR_ALLOC = 0x1 << 3,
XHCI_ATTACH_INTR_ADD = 0x1 << 4,
XHCI_ATTACH_SYNCH = 0x1 << 5,
XHCI_ATTACH_INTR_ENABLE = 0x1 << 6,
XHCI_ATTACH_STARTED = 0x1 << 7,
XHCI_ATTACH_USBA = 0x1 << 8,
XHCI_ATTACH_ROOT_HUB = 0x1 << 9
} xhci_attach_seq_t;
typedef enum xhci_state_flags {
XHCI_S_ERROR = 0x1 << 0
} xhci_state_flags_t;
typedef struct xhci {
dev_info_t *xhci_dip;
xhci_attach_seq_t xhci_seq;
int xhci_fm_caps;
ddi_acc_handle_t xhci_cfg_handle;
uint16_t xhci_vendor_id;
uint16_t xhci_device_id;
caddr_t xhci_regs_base;
ddi_acc_handle_t xhci_regs_handle;
uint_t xhci_regs_capoff;
uint_t xhci_regs_operoff;
uint_t xhci_regs_runoff;
uint_t xhci_regs_dooroff;
xhci_capability_t xhci_caps;
xhci_quirk_t xhci_quirks;
ddi_intr_handle_t xhci_intr_hdl;
int xhci_intr_num;
int xhci_intr_type;
uint_t xhci_intr_pri;
int xhci_intr_caps;
xhci_dcbaa_t xhci_dcbaa;
xhci_scratchpad_t xhci_scratchpad;
xhci_command_ring_t xhci_command;
xhci_event_ring_t xhci_event;
taskq_ent_t xhci_tqe;
kmutex_t xhci_lock;
kcondvar_t xhci_statecv;
xhci_state_flags_t xhci_state;
xhci_usba_t xhci_usba;
} xhci_t;
/*
* The xHCI memory mapped registers come in four different categories. The
* offset to them is variable. These represent the given register set that we're
* after.
*/
typedef enum xhci_reg_type {
XHCI_R_CAP,
XHCI_R_OPER,
XHCI_R_RUN,
XHCI_R_DOOR
} xhci_reg_type_t;
/*
* Quirks related functions
*/
extern void xhci_quirks_populate(xhci_t *);
extern void xhci_reroute_intel(xhci_t *);
/*
* Interrupt related functions
*/
extern uint_t xhci_intr(caddr_t, caddr_t);
extern boolean_t xhci_ddi_intr_disable(xhci_t *);
extern boolean_t xhci_ddi_intr_enable(xhci_t *);
extern int xhci_intr_conf(xhci_t *);
/*
* DMA related functions
*/
extern int xhci_check_dma_handle(xhci_t *, xhci_dma_buffer_t *);
extern void xhci_dma_acc_attr(xhci_t *, ddi_device_acc_attr_t *);
extern void xhci_dma_dma_attr(xhci_t *, ddi_dma_attr_t *);
extern void xhci_dma_scratchpad_attr(xhci_t *, ddi_dma_attr_t *);
extern void xhci_dma_transfer_attr(xhci_t *, ddi_dma_attr_t *, uint_t);
extern void xhci_dma_free(xhci_dma_buffer_t *);
extern boolean_t xhci_dma_alloc(xhci_t *, xhci_dma_buffer_t *, ddi_dma_attr_t *,
ddi_device_acc_attr_t *, boolean_t, size_t, boolean_t);
extern uint64_t xhci_dma_pa(xhci_dma_buffer_t *);
/*
* DMA Transfer Ring functions
*/
extern xhci_transfer_t *xhci_transfer_alloc(xhci_t *, xhci_endpoint_t *, size_t,
uint_t, int);
extern void xhci_transfer_free(xhci_t *, xhci_transfer_t *);
extern void xhci_transfer_copy(xhci_transfer_t *, void *, size_t, boolean_t);
extern int xhci_transfer_sync(xhci_t *, xhci_transfer_t *, uint_t);
extern void xhci_transfer_trb_fill_data(xhci_endpoint_t *, xhci_transfer_t *,
int, boolean_t);
extern void xhci_transfer_calculate_isoc(xhci_device_t *, xhci_endpoint_t *,
uint_t, uint_t *, uint_t *);
/*
* Context (DCBAA, Scratchpad, Slot) functions
*/
extern int xhci_context_init(xhci_t *);
extern void xhci_context_fini(xhci_t *);
extern boolean_t xhci_context_slot_output_init(xhci_t *, xhci_device_t *);
extern void xhci_context_slot_output_fini(xhci_t *, xhci_device_t *);
/*
* Command Ring Functions
*/
extern int xhci_command_ring_init(xhci_t *);
extern void xhci_command_ring_fini(xhci_t *);
extern boolean_t xhci_command_event_callback(xhci_t *, xhci_trb_t *trb);
extern void xhci_command_init(xhci_command_t *);
extern void xhci_command_fini(xhci_command_t *);
extern int xhci_command_enable_slot(xhci_t *, uint8_t *);
extern int xhci_command_disable_slot(xhci_t *, uint8_t);
extern int xhci_command_set_address(xhci_t *, xhci_device_t *, boolean_t);
extern int xhci_command_configure_endpoint(xhci_t *, xhci_device_t *);
extern int xhci_command_evaluate_context(xhci_t *, xhci_device_t *);
extern int xhci_command_reset_endpoint(xhci_t *, xhci_device_t *,
xhci_endpoint_t *);
extern int xhci_command_set_tr_dequeue(xhci_t *, xhci_device_t *,
xhci_endpoint_t *);
extern int xhci_command_stop_endpoint(xhci_t *, xhci_device_t *,
xhci_endpoint_t *);
/*
* Event Ring Functions
*/
extern int xhci_event_init(xhci_t *);
extern void xhci_event_fini(xhci_t *);
extern boolean_t xhci_event_process(xhci_t *);
/*
* General Ring functions
*/
extern void xhci_ring_free(xhci_ring_t *);
extern int xhci_ring_reset(xhci_t *, xhci_ring_t *);
extern int xhci_ring_alloc(xhci_t *, xhci_ring_t *);
/*
* Event Ring (Consumer) oriented functions.
*/
extern xhci_trb_t *xhci_ring_event_advance(xhci_ring_t *);
/*
* Command and Transfer Ring (Producer) oriented functions.
*/
extern boolean_t xhci_ring_trb_tail_valid(xhci_ring_t *, uint64_t);
extern int xhci_ring_trb_valid_range(xhci_ring_t *, uint64_t, uint_t);
extern boolean_t xhci_ring_trb_space(xhci_ring_t *, uint_t);
extern void xhci_ring_trb_fill(xhci_ring_t *, uint_t, xhci_trb_t *, uint64_t *,
boolean_t);
extern void xhci_ring_trb_produce(xhci_ring_t *, uint_t);
extern boolean_t xhci_ring_trb_consumed(xhci_ring_t *, uint64_t);
extern void xhci_ring_trb_put(xhci_ring_t *, xhci_trb_t *);
extern void xhci_ring_skip(xhci_ring_t *);
extern void xhci_ring_skip_transfer(xhci_ring_t *, xhci_transfer_t *);
/*
* MMIO related functions. Note callers are responsible for checking with FM
* after accessing registers.
*/
extern int xhci_check_regs_acc(xhci_t *);
extern uint8_t xhci_get8(xhci_t *, xhci_reg_type_t, uintptr_t);
extern uint16_t xhci_get16(xhci_t *, xhci_reg_type_t, uintptr_t);
extern uint32_t xhci_get32(xhci_t *, xhci_reg_type_t, uintptr_t);
extern uint64_t xhci_get64(xhci_t *, xhci_reg_type_t, uintptr_t);
extern void xhci_put8(xhci_t *, xhci_reg_type_t, uintptr_t, uint8_t);
extern void xhci_put16(xhci_t *, xhci_reg_type_t, uintptr_t, uint16_t);
extern void xhci_put32(xhci_t *, xhci_reg_type_t, uintptr_t, uint32_t);
extern void xhci_put64(xhci_t *, xhci_reg_type_t, uintptr_t, uint64_t);
/*
* Runtime FM related functions
*/
extern void xhci_fm_runtime_reset(xhci_t *);
/*
* Endpoint related functions
*/
extern int xhci_endpoint_init(xhci_t *, xhci_device_t *,
usba_pipe_handle_data_t *);
extern void xhci_endpoint_fini(xhci_device_t *, int);
extern int xhci_endpoint_update_default(xhci_t *, xhci_device_t *,
xhci_endpoint_t *);
extern int xhci_endpoint_setup_default_context(xhci_t *, xhci_device_t *,
xhci_endpoint_t *);
extern uint_t xhci_endpoint_pipe_to_epid(usba_pipe_handle_data_t *);
extern boolean_t xhci_endpoint_is_periodic_in(xhci_endpoint_t *);
extern int xhci_endpoint_quiesce(xhci_t *, xhci_device_t *, xhci_endpoint_t *);
extern int xhci_endpoint_schedule(xhci_t *, xhci_device_t *, xhci_endpoint_t *,
xhci_transfer_t *, boolean_t);
extern int xhci_endpoint_ring(xhci_t *, xhci_device_t *, xhci_endpoint_t *);
extern boolean_t xhci_endpoint_transfer_callback(xhci_t *, xhci_trb_t *);
/*
* USB Framework related functions
*/
extern int xhci_hcd_init(xhci_t *);
extern void xhci_hcd_fini(xhci_t *);
/*
* Root hub related functions
*/
extern int xhci_root_hub_init(xhci_t *);
extern int xhci_root_hub_fini(xhci_t *);
extern int xhci_root_hub_ctrl_req(xhci_t *, usba_pipe_handle_data_t *,
usb_ctrl_req_t *);
extern void xhci_root_hub_psc_callback(xhci_t *);
extern int xhci_root_hub_intr_root_enable(xhci_t *, usba_pipe_handle_data_t *,
usb_intr_req_t *);
extern void xhci_root_hub_intr_root_disable(xhci_t *);
/*
* Logging functions
*/
extern void xhci_log(xhci_t *xhcip, const char *fmt, ...) __KPRINTFLIKE(2);
extern void xhci_error(xhci_t *xhcip, const char *fmt, ...) __KPRINTFLIKE(2);
/*
* Misc. data
*/
extern void *xhci_soft_state;
#ifdef __cplusplus
}
#endif
#endif /* _SYS_USB_XHCI_XHCI_H */