1 /*- 2 * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Apple T2 BCE Virtual USB Host Controller Interface (VHCI). 7 * Translates USB operations into BCE firmware messages over DMA queues. 8 */ 9 10 #ifndef _APPLE_BCE_VHCI_H_ 11 #define _APPLE_BCE_VHCI_H_ 12 13 #include <sys/param.h> 14 #include <sys/bus.h> 15 #include <sys/lock.h> 16 #include <sys/mutex.h> 17 #include <sys/sx.h> 18 #include <sys/sema.h> 19 #include <sys/taskqueue.h> 20 21 #include "apple_bce.h" 22 23 /* Forward declaration -- full USB headers included only in .c file */ 24 struct usb_bus; 25 struct usb_device; 26 struct usb_xfer; 27 28 /* 29 * VHCI limits. 30 */ 31 #define BCE_VHCI_MAX_PORTS 16 32 #define BCE_VHCI_MAX_DEVICES 32 33 #define BCE_VHCI_MAX_ENDPOINTS 32 34 35 /* Queue element counts */ 36 #define BCE_VHCI_MSG_QUEUE_EL 32 37 #define BCE_VHCI_EVT_QUEUE_EL 256 38 #define BCE_VHCI_EVT_PENDING 32 39 #define BCE_VHCI_TQ_EL 32 /* Transfer queue elements */ 40 #define BCE_VHCI_XFER_BUFSZ 4096 /* DMA buffer per transfer queue */ 41 42 /* 43 * VHCI message format (16 bytes, matches firmware protocol). 44 */ 45 struct bce_vhci_message { 46 uint16_t cmd; 47 uint16_t status; 48 uint32_t param1; 49 uint64_t param2; 50 } __packed; 51 52 /* 53 * VHCI command IDs. 54 */ 55 enum bce_vhci_cmd_id { 56 /* Controller commands */ 57 BCE_VHCI_CMD_CONTROLLER_ENABLE = 0x0001, 58 BCE_VHCI_CMD_CONTROLLER_DISABLE = 0x0002, 59 BCE_VHCI_CMD_CONTROLLER_START = 0x0003, 60 BCE_VHCI_CMD_CONTROLLER_PAUSE = 0x0004, 61 62 /* Port commands */ 63 BCE_VHCI_CMD_PORT_POWER_ON = 0x0010, 64 BCE_VHCI_CMD_PORT_POWER_OFF = 0x0011, 65 BCE_VHCI_CMD_PORT_RESUME = 0x0012, 66 BCE_VHCI_CMD_PORT_SUSPEND = 0x0013, 67 BCE_VHCI_CMD_PORT_RESET = 0x0014, 68 BCE_VHCI_CMD_PORT_DISABLE = 0x0015, 69 BCE_VHCI_CMD_PORT_STATUS = 0x0016, 70 BCE_VHCI_CMD_PORT_STATUS_CHANGE = 0x0018, 71 72 /* Device commands */ 73 BCE_VHCI_CMD_DEVICE_CREATE = 0x0030, 74 BCE_VHCI_CMD_DEVICE_DESTROY = 0x0031, 75 76 /* Endpoint commands */ 77 BCE_VHCI_CMD_ENDPOINT_CREATE = 0x0040, 78 BCE_VHCI_CMD_ENDPOINT_DESTROY = 0x0041, 79 BCE_VHCI_CMD_ENDPOINT_SET_STATE = 0x0042, 80 BCE_VHCI_CMD_ENDPOINT_REQ_STATE = 0x0043, 81 BCE_VHCI_CMD_ENDPOINT_RESET = 0x0044, 82 83 /* Transfer commands */ 84 BCE_VHCI_CMD_TRANSFER_REQUEST = 0x1000, 85 BCE_VHCI_CMD_CTRL_TRANSFER_STATUS = 0x1005, 86 87 /* Reply flag -- firmware replies have cmd | 0x8000 */ 88 BCE_VHCI_CMD_REPLY_FLAG = 0x8000, 89 90 /* Cancel flag -- timeout sends cmd | 0x4000 */ 91 BCE_VHCI_CMD_CANCEL_FLAG = 0x4000, 92 }; 93 94 /* 95 * VHCI message status codes. 96 */ 97 enum bce_vhci_msg_status { 98 BCE_VHCI_SUCCESS = 1, 99 BCE_VHCI_ERROR = 2, 100 BCE_VHCI_PIPE_STALL = 3, 101 BCE_VHCI_ABORT = 4, 102 BCE_VHCI_BAD_ARGUMENT = 5, 103 BCE_VHCI_OVERRUN = 6, 104 BCE_VHCI_INTERNAL_ERROR = 7, 105 BCE_VHCI_NO_POWER = 8, 106 BCE_VHCI_UNSUPPORTED = 9, 107 }; 108 109 /* 110 * Endpoint states. 111 */ 112 enum bce_vhci_endpoint_state { 113 BCE_VHCI_ENDP_ACTIVE = 0, 114 BCE_VHCI_ENDP_PAUSED = 1, 115 BCE_VHCI_ENDP_STALLED = 2, 116 }; 117 118 /* 119 * Control transfer state machine. 120 */ 121 enum bce_vhci_ctrl_state { 122 BCE_VHCI_CTRL_IDLE = 0, 123 BCE_VHCI_CTRL_SETUP = 1, /* Awaiting setup XFER_REQ */ 124 BCE_VHCI_CTRL_DATA = 2, /* Awaiting data XFER_REQ */ 125 BCE_VHCI_CTRL_STATUS = 3, /* Awaiting CTRL_XFER_STATUS */ 126 }; 127 128 /* 129 * Pause sources (bitmask). 130 */ 131 #define BCE_VHCI_PAUSE_INTERNAL 0x01 132 #define BCE_VHCI_PAUSE_FIRMWARE 0x02 133 #define BCE_VHCI_PAUSE_SUSPEND 0x04 134 #define BCE_VHCI_PAUSE_SHUTDOWN 0x08 135 136 /* 137 * Port status bit mapping (firmware -> USB). 138 * Firmware uses its own bit encoding; we translate in roothub_exec. 139 */ 140 #define BCE_VHCI_PORT_CONNECTED 0x0004 141 #define BCE_VHCI_PORT_ENABLED 0x0010 142 #define BCE_VHCI_PORT_SUSPENDED 0x0060 143 #define BCE_VHCI_PORT_OVERCURRENT 0x0002 144 #define BCE_VHCI_PORT_RESET 0x0008 145 #define BCE_VHCI_PORT_C_CONNECTION 0x40000 146 147 /* 148 * VHCI message queue (host -> device). 149 */ 150 struct bce_vhci_msg_queue { 151 struct bce_queue_cq *cq; 152 struct bce_queue_sq *sq; 153 bus_dma_tag_t dma_tag; 154 bus_dmamap_t dma_map; 155 bus_addr_t dma_addr; 156 struct bce_vhci_message *data; 157 uint32_t el_count; 158 }; 159 160 /* 161 * VHCI event queue (device -> host). 162 * Single contiguous DMA buffer for all receive slots. 163 */ 164 struct bce_vhci_evt_queue { 165 struct bce_queue_sq *sq; 166 bus_dma_tag_t dma_tag; 167 bus_dmamap_t dma_map; 168 bus_addr_t dma_addr; 169 struct bce_vhci_message *data; 170 uint32_t el_count; 171 void *userdata; 172 }; 173 174 /* 175 * VHCI command queue (synchronous command execution). 176 */ 177 struct bce_vhci_cmd_queue { 178 struct bce_vhci_msg_queue *msg; 179 struct sx exec_lock; /* Serialize callers */ 180 struct mtx lock; 181 struct sema completion; 182 struct bce_vhci_message response; 183 volatile int pending; 184 uint16_t expected_cmd; /* Filter late replies */ 185 }; 186 187 /* 188 * VHCI transfer queue (per endpoint). 189 * 190 * Each endpoint gets a CQ + IN SQ + OUT SQ triplet registered with 191 * firmware as named DMA queues. The DMA buffer is used to shuttle 192 * USB payloads between the USB stack's frame buffers and firmware. 193 */ 194 struct bce_vhci_transfer_queue { 195 struct bce_vhci_softc *vhci; 196 uint8_t dev_addr; /* firmware device id */ 197 uint8_t endp_addr; /* USB endpoint address */ 198 struct mtx lock; /* Protects SQ submission */ 199 struct bce_queue_cq *cq; 200 struct bce_queue_sq *sq_in; /* Device -> host */ 201 struct bce_queue_sq *sq_out; /* Host -> device */ 202 struct usb_xfer *active_xfer; 203 uint32_t paused_by; 204 int active; /* Queues created with FW */ 205 int stalled; 206 int dma_inflight; /* DMA pending */ 207 int create_pending; /* Deferred ep create */ 208 struct usb_endpoint_descriptor *create_edesc; 209 struct usb_xfer *create_xfer; /* Deferred xfer */ 210 211 /* DMA buffer for data transfer */ 212 bus_dma_tag_t dma_tag; 213 bus_dmamap_t dma_map; 214 bus_addr_t dma_addr; 215 void *dma_buf; 216 217 /* Control transfer state machine */ 218 enum bce_vhci_ctrl_state ctrl_state; 219 uint8_t ctrl_dir; /* UE_DIR_IN or UE_DIR_OUT */ 220 uint32_t ctrl_data_len; /* Expected data phase length */ 221 uint32_t ctrl_actual; /* Actual bytes transferred */ 222 int ctrl_data_done; /* IN DMA completion seen */ 223 int ctrl_status_pending; /* Deferred STATUS msg */ 224 struct bce_vhci_message ctrl_status_msg; /* Saved STATUS for defer */ 225 226 /* Queued transfer waiting for active_xfer to finish */ 227 struct usb_xfer *pending_xfer; 228 229 /* Deferred firmware event (TRANSFER_REQUEST arrives before xfer) */ 230 int evt_pending; 231 struct bce_vhci_message evt_saved; 232 }; 233 234 /* 235 * VHCI per-device state. 236 */ 237 struct bce_vhci_device { 238 int allocated; /* Device created with FW */ 239 uint8_t fw_dev_id; /* Firmware device ID */ 240 uint8_t port; /* Port number */ 241 struct bce_vhci_transfer_queue tq[BCE_VHCI_MAX_ENDPOINTS]; 242 }; 243 244 /* VHCI softc is defined in apple_bce_vhci.c (depends on USB headers) */ 245 struct bce_vhci_softc; 246 247 /* VHCI driver interface */ 248 int bce_vhci_attach(struct apple_bce_softc *sc); 249 int bce_vhci_detach(struct apple_bce_softc *sc); 250 251 #endif /* _APPLE_BCE_VHCI_H_ */ 252