Changeset 5fe3f954 in mainline
- Timestamp:
- 2018-02-12T10:28:14Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- ee820ff
- Parents:
- 1d758fc
- git-author:
- Ondřej Hlavatý <aearsis@…> (2018-02-12 10:23:51)
- git-committer:
- Ondřej Hlavatý <aearsis@…> (2018-02-12 10:28:14)
- Location:
- uspace
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/xhci/transfers.c
r1d758fc r5fe3f954 48 48 } stage_dir_flag_t; 49 49 50 #define REQUEST_TYPE_DTD (0x80)51 #define REQUEST_TYPE_IS_DEVICE_TO_HOST(rq) ((rq) & REQUEST_TYPE_DTD)52 53 54 50 /** Get direction flag of data stage. 55 51 * See Table 7 of xHCI specification. … … 59 55 { 60 56 /* See Table 7 of xHCI specification */ 61 return REQUEST_TYPE_IS_DEVICE_TO_HOST(bmRequestType) && (wLength > 0)57 return SETUP_REQUEST_TYPE_IS_DEVICE_TO_HOST(bmRequestType) && (wLength > 0) 62 58 ? STAGE_OUT 63 59 : STAGE_IN; … … 80 76 81 77 /* See Table 7 of xHCI specification */ 82 return REQUEST_TYPE_IS_DEVICE_TO_HOST(bmRequestType)78 return SETUP_REQUEST_TYPE_IS_DEVICE_TO_HOST(bmRequestType) 83 79 ? DATA_STAGE_IN 84 80 : DATA_STAGE_NO; … … 124 120 } 125 121 126 static int calculate_trb_count(xhci_transfer_t *transfer) 127 { 128 const size_t size = transfer->batch.size; 129 return (size + PAGE_SIZE - 1 )/ PAGE_SIZE; 130 } 131 132 static void trb_set_buffer(xhci_transfer_t *transfer, xhci_trb_t *trb, 133 size_t i, size_t total, size_t *remaining) 134 { 135 const uintptr_t ptr = dma_buffer_phys(&transfer->batch.dma_buffer, 136 transfer->batch.dma_buffer.virt + i * PAGE_SIZE); 137 138 trb->parameter = host2xhci(64, ptr); 139 TRB_CTRL_SET_TD_SIZE(*trb, max(31, total - i - 1)); 140 if (*remaining > PAGE_SIZE) { 141 TRB_CTRL_SET_XFER_LEN(*trb, PAGE_SIZE); 142 *remaining -= PAGE_SIZE; 143 } 144 else { 145 TRB_CTRL_SET_XFER_LEN(*trb, *remaining); 146 *remaining = 0; 147 } 122 #define MAX_CHUNK_SIZE (1 << 16) 123 124 typedef struct { 125 /* Input parameters */ 126 dma_buffer_t buf; 127 size_t chunk_size, packet_count, mps, max_trb_count; 128 129 /* Changing at runtime */ 130 size_t transferred, remaining; 131 void *pos; 132 } trb_splitter_t; 133 134 static void trb_splitter_init(trb_splitter_t *ts, xhci_transfer_t *transfer) 135 { 136 ts->buf = transfer->batch.dma_buffer; 137 138 const size_t chunk_mask = dma_policy_chunk_mask(ts->buf.policy); 139 ts->chunk_size = (chunk_mask > MAX_CHUNK_SIZE + 1) 140 ? MAX_CHUNK_SIZE : (chunk_mask + 1); 141 142 ts->remaining = transfer->batch.size; 143 ts->max_trb_count = (ts->remaining + ts->chunk_size - 1) / ts->chunk_size + 1; 144 ts->mps = transfer->batch.ep->max_packet_size; 145 ts->packet_count = (ts->remaining + ts->mps - 1) / ts->mps; 146 147 ts->transferred = 0; 148 ts->pos = ts->buf.virt + transfer->batch.offset; 149 } 150 151 static void trb_split_next(xhci_trb_t *trb, trb_splitter_t *ts) 152 { 153 xhci_trb_clean(trb); 154 155 size_t size = min(ts->remaining, ts->chunk_size); 156 157 /* First TRB might be misaligned */ 158 if (ts->transferred == 0) { 159 const size_t offset = (ts->pos - ts->buf.virt) % ts->chunk_size; 160 size = min(size, ts->chunk_size - offset); 161 } 162 163 ts->transferred += size; 164 ts->remaining -= size; 165 166 const size_t tx_packets = (ts->transferred + ts->mps - 1) / ts->mps; 167 const unsigned td_size = min(31, ts->packet_count - tx_packets); 168 169 /* Last TRB must have TD Size = 0 */ 170 assert(ts->remaining > 0 || td_size == 0); 171 172 uintptr_t phys = dma_buffer_phys(&ts->buf, ts->pos); 173 174 trb->parameter = host2xhci(64, phys); 175 TRB_CTRL_SET_TD_SIZE(*trb, td_size); 176 TRB_CTRL_SET_XFER_LEN(*trb, size); 177 TRB_CTRL_SET_TRB_TYPE(*trb, XHCI_TRB_TYPE_NORMAL); 178 179 if (ts->remaining) 180 TRB_CTRL_SET_CHAIN(*trb, 1); 181 182 ts->pos += size; 148 183 } 149 184 … … 155 190 usb_device_request_setup_packet_t* setup = &batch->setup.packet; 156 191 157 size_t buffer_count = 0; 158 if (setup->length > 0) { 159 buffer_count = calculate_trb_count(transfer); 160 } 161 162 xhci_trb_t trbs[buffer_count + 2]; 163 164 xhci_trb_t *trb_setup = trbs; 192 trb_splitter_t splitter; 193 trb_splitter_init(&splitter, transfer); 194 195 xhci_trb_t trbs[splitter.max_trb_count + 2]; 196 size_t trbs_used = 0; 197 198 xhci_trb_t *trb_setup = &trbs[trbs_used++]; 165 199 xhci_trb_clean(trb_setup); 166 200 167 TRB_CTRL_SET_SETUP_WVALUE(*trb_setup, setup->value); 168 TRB_CTRL_SET_SETUP_WLENGTH(*trb_setup, setup->length); 169 TRB_CTRL_SET_SETUP_WINDEX(*trb_setup, setup->index); 170 TRB_CTRL_SET_SETUP_BREQ(*trb_setup, setup->request); 171 TRB_CTRL_SET_SETUP_BMREQTYPE(*trb_setup, setup->request_type); 201 trb_setup->parameter = batch->setup.packed; 172 202 173 203 /* Size of the setup packet is always 8 */ … … 180 210 get_transfer_type(trb_setup, setup->request_type, setup->length)); 181 211 182 /* Data stage */ 183 if (setup->length > 0) { 184 int stage_dir = REQUEST_TYPE_IS_DEVICE_TO_HOST(setup->request_type) 185 ? STAGE_IN : STAGE_OUT; 186 size_t remaining = transfer->batch.size; 187 188 for (size_t i = 0; i < buffer_count; ++i) { 189 xhci_trb_clean(&trbs[i + 1]); 190 trb_set_buffer(transfer, &trbs[i + 1], i, buffer_count, &remaining); 191 192 TRB_CTRL_SET_DIR(trbs[i + 1], stage_dir); 193 TRB_CTRL_SET_TRB_TYPE(trbs[i + 1], XHCI_TRB_TYPE_DATA_STAGE); 194 195 if (i == buffer_count - 1) break; 196 197 /* Set the chain bit as this is not the last TRB */ 198 TRB_CTRL_SET_CHAIN(trbs[i], 1); 199 } 200 } 212 stage_dir_flag_t stage_dir = (transfer->batch.dir == USB_DIRECTION_IN) 213 ? STAGE_IN : STAGE_OUT; 214 215 /* Data stage - first TRB is special */ 216 if (splitter.remaining > 0) { 217 xhci_trb_t *trb = &trbs[trbs_used++]; 218 trb_split_next(trb, &splitter); 219 TRB_CTRL_SET_TRB_TYPE(*trb, XHCI_TRB_TYPE_DATA_STAGE); 220 TRB_CTRL_SET_DIR(*trb, stage_dir); 221 } 222 while (splitter.remaining > 0) 223 trb_split_next(&trbs[trbs_used++], &splitter); 201 224 202 225 /* Status stage */ 203 xhci_trb_t *trb_status = trbs + buffer_count + 1;226 xhci_trb_t *trb_status = &trbs[trbs_used++]; 204 227 xhci_trb_clean(trb_status); 205 228 … … 217 240 218 241 return xhci_trb_ring_enqueue_multiple(get_ring(transfer), trbs, 219 buffer_count + 2, &transfer->interrupt_trb_phys); 220 } 221 222 static errno_t schedule_bulk(xhci_hc_t* hc, xhci_transfer_t *transfer) 223 { 242 trbs_used, &transfer->interrupt_trb_phys); 243 } 244 245 static errno_t schedule_bulk_intr(xhci_hc_t* hc, xhci_transfer_t *transfer) 246 { 247 xhci_trb_ring_t * const ring = get_ring(transfer); 248 if (!ring) 249 return EINVAL; 250 224 251 /* The stream-enabled endpoints need to chain ED trb */ 225 252 xhci_endpoint_t *ep = xhci_endpoint_get(transfer->batch.ep); 226 if (!ep->primary_stream_data_size) { 227 const size_t buffer_count = calculate_trb_count(transfer); 228 xhci_trb_t trbs[buffer_count]; 229 size_t remaining = transfer->batch.size; 230 231 for (size_t i = 0; i < buffer_count; ++i) { 232 xhci_trb_clean(&trbs[i]); 233 trb_set_buffer(transfer, &trbs[i], i, buffer_count, &remaining); 234 TRB_CTRL_SET_TRB_TYPE(trbs[i], XHCI_TRB_TYPE_NORMAL); 235 236 if (i == buffer_count - 1) break; 237 238 /* Set the chain bit as this is not the last TRB */ 239 TRB_CTRL_SET_CHAIN(trbs[i], 1); 240 } 253 const bool use_streams = !!ep->primary_stream_data_size; 254 255 trb_splitter_t splitter; 256 trb_splitter_init(&splitter, transfer); 257 258 const size_t trb_count = splitter.max_trb_count + use_streams; 259 xhci_trb_t trbs[trb_count]; 260 size_t trbs_used = 0; 261 262 while (splitter.remaining > 0) 263 trb_split_next(&trbs[trbs_used++], &splitter); 264 265 if (!use_streams) { 241 266 /* Set the interrupt bit for last TRB */ 242 TRB_CTRL_SET_IOC(trbs[buffer_count - 1], 1); 243 244 xhci_trb_ring_t* ring = get_ring(transfer); 245 return xhci_trb_ring_enqueue_multiple(ring, &trbs[0], buffer_count, 246 &transfer->interrupt_trb_phys); 267 TRB_CTRL_SET_IOC(trbs[trbs_used - 1], 1); 247 268 } 248 269 else { 249 xhci_trb_ring_t* ring = get_ring(transfer); 250 if (!ring) { 251 return EINVAL; 252 } 253 254 const size_t buffer_count = calculate_trb_count(transfer); 255 xhci_trb_t trbs[buffer_count + 1]; 256 size_t remaining = transfer->batch.size; 257 258 for (size_t i = 0; i < buffer_count; ++i) { 259 xhci_trb_clean(&trbs[i]); 260 trb_set_buffer(transfer, &trbs[i], i, buffer_count + 1, &remaining); 261 TRB_CTRL_SET_TRB_TYPE(trbs[i], XHCI_TRB_TYPE_NORMAL); 262 TRB_CTRL_SET_CHAIN(trbs[i], 1); 263 } 264 TRB_CTRL_SET_ENT(trbs[buffer_count - 1], 1); 265 266 xhci_trb_clean(&trbs[buffer_count]); 267 trbs[buffer_count].parameter = host2xhci(64, (uintptr_t) transfer); 268 TRB_CTRL_SET_TRB_TYPE(trbs[buffer_count], XHCI_TRB_TYPE_EVENT_DATA); 269 TRB_CTRL_SET_IOC(trbs[buffer_count], 1); 270 271 return xhci_trb_ring_enqueue_multiple(ring, &trbs[0], buffer_count + 1, 272 &transfer->interrupt_trb_phys); 273 } 274 } 275 276 static errno_t schedule_interrupt(xhci_hc_t* hc, xhci_transfer_t* transfer) 277 { 278 const size_t buffer_count = calculate_trb_count(transfer); 279 xhci_trb_t trbs[buffer_count]; 280 size_t remaining = transfer->batch.size; 281 282 for (size_t i = 0; i < buffer_count; ++i) { 283 xhci_trb_clean(&trbs[i]); 284 trb_set_buffer(transfer, &trbs[i], i, buffer_count, &remaining); 285 TRB_CTRL_SET_TRB_TYPE(trbs[i], XHCI_TRB_TYPE_NORMAL); 286 287 if (i == buffer_count - 1) break; 288 289 /* Set the chain bit as this is not the last TRB */ 290 TRB_CTRL_SET_CHAIN(trbs[i], 1); 291 } 292 /* Set the interrupt bit for last TRB */ 293 TRB_CTRL_SET_IOC(trbs[buffer_count - 1], 1); 294 295 xhci_trb_ring_t* ring = get_ring(transfer); 296 return xhci_trb_ring_enqueue_multiple(ring, &trbs[0], buffer_count, 270 /* Clear the chain bit on the last TRB */ 271 TRB_CTRL_SET_CHAIN(trbs[trbs_used - 1], 1); 272 TRB_CTRL_SET_ENT(trbs[trbs_used - 1], 1); 273 274 xhci_trb_t *ed = &trbs[trbs_used++]; 275 xhci_trb_clean(ed); 276 ed->parameter = host2xhci(64, (uintptr_t) transfer); 277 TRB_CTRL_SET_TRB_TYPE(*ed, XHCI_TRB_TYPE_EVENT_DATA); 278 TRB_CTRL_SET_IOC(*ed, 1); 279 } 280 281 return xhci_trb_ring_enqueue_multiple(ring, trbs, trbs_used, 297 282 &transfer->interrupt_trb_phys); 298 283 } … … 429 414 [USB_TRANSFER_CONTROL] = schedule_control, 430 415 [USB_TRANSFER_ISOCHRONOUS] = NULL, 431 [USB_TRANSFER_BULK] = schedule_bulk ,432 [USB_TRANSFER_INTERRUPT] = schedule_ interrupt,416 [USB_TRANSFER_BULK] = schedule_bulk_intr, 417 [USB_TRANSFER_INTERRUPT] = schedule_bulk_intr, 433 418 }; 434 419 -
uspace/lib/usb/include/usb/request.h
r1d758fc r5fe3f954 85 85 #define SETUP_REQUEST_TYPE_DEVICE_TO_HOST (1 << 7) 86 86 #define SETUP_REQUEST_TYPE_HOST_TO_DEVICE (0 << 7) 87 #define SETUP_REQUEST_TYPE_IS_DEVICE_TO_HOST(rt) ((rt) & (1 << 7)) 87 88 #define SETUP_REQUEST_TYPE_GET_TYPE(rt) ((rt >> 5) & 0x3) 88 89 #define SETUP_REQUEST_TYPE_GET_RECIPIENT(rec) (rec & 0x1f)
Note:
See TracChangeset
for help on using the changeset viewer.