Changeset df6ded8 in mainline for uspace/drv/bus/usb/ehci/ehci_batch.c
- Timestamp:
- 2018-02-28T16:37:50Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 1b20da0
- Parents:
- f5e5f73 (diff), b2dca8de (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - git-author:
- Jakub Jermar <jakub@…> (2018-02-28 16:06:42)
- git-committer:
- Jakub Jermar <jakub@…> (2018-02-28 16:37:50)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ehci/ehci_batch.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2014 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 42 43 #include <usb/usb.h> 43 44 #include <usb/debug.h> 44 #include <usb/host/utils/malloc32.h>45 45 46 46 #include "ehci_batch.h" 47 #include "ehci_ endpoint.h"47 #include "ehci_bus.h" 48 48 49 49 /* The buffer pointer list in the qTD is long enough to support a maximum … … 53 53 #define EHCI_TD_MAX_TRANSFER (16 * 1024) 54 54 55 static void (*const batch_setup[])(ehci_transfer_batch_t* , usb_direction_t);55 static void (*const batch_setup[])(ehci_transfer_batch_t*); 56 56 57 57 /** Safely destructs ehci_transfer_batch_t structure … … 59 59 * @param[in] ehci_batch Instance to destroy. 60 60 */ 61 static void ehci_transfer_batch_dispose(ehci_transfer_batch_t *ehci_batch) 62 { 63 if (!ehci_batch) 64 return; 65 if (ehci_batch->tds) { 66 for (size_t i = 0; i < ehci_batch->td_count; ++i) { 67 free32(ehci_batch->tds[i]); 68 } 69 free(ehci_batch->tds); 70 } 71 usb_transfer_batch_destroy(ehci_batch->usb_batch); 72 free32(ehci_batch->device_buffer); 61 void ehci_transfer_batch_destroy(ehci_transfer_batch_t *ehci_batch) 62 { 63 assert(ehci_batch); 64 dma_buffer_free(&ehci_batch->ehci_dma_buffer); 65 usb_log_debug2("Batch(%p): disposed", ehci_batch); 73 66 free(ehci_batch); 74 usb_log_debug2("Batch(%p): disposed", ehci_batch);75 }76 77 /** Finishes usb_transfer_batch and destroys the structure.78 *79 * @param[in] uhci_batch Instance to finish and destroy.80 */81 void ehci_transfer_batch_finish_dispose(ehci_transfer_batch_t *ehci_batch)82 {83 assert(ehci_batch);84 assert(ehci_batch->usb_batch);85 usb_transfer_batch_finish(ehci_batch->usb_batch,86 ehci_batch->device_buffer + ehci_batch->usb_batch->setup_size);87 ehci_transfer_batch_dispose(ehci_batch);88 67 } 89 68 … … 94 73 * NULL otherwise. 95 74 * 75 */ 76 ehci_transfer_batch_t * ehci_transfer_batch_create(endpoint_t *ep) 77 { 78 assert(ep); 79 80 ehci_transfer_batch_t *ehci_batch = calloc(1, sizeof(ehci_transfer_batch_t)); 81 if (!ehci_batch) { 82 usb_log_error("Failed to allocate EHCI batch data."); 83 return NULL; 84 } 85 86 usb_transfer_batch_init(&ehci_batch->base, ep); 87 88 return ehci_batch; 89 } 90 91 /** Prepares a batch to be sent. 92 * 96 93 * Determines the number of needed transfer descriptors (TDs). 97 94 * Prepares a transport buffer (that is accessible by the hardware). 98 95 * Initializes parameters needed for the transfer and callback. 99 96 */ 100 ehci_transfer_batch_t * ehci_transfer_batch_get(usb_transfer_batch_t *usb_batch) 101 { 102 assert(usb_batch); 103 104 ehci_transfer_batch_t *ehci_batch = 105 calloc(1, sizeof(ehci_transfer_batch_t)); 106 if (!ehci_batch) { 107 usb_log_error("Batch %p: Failed to allocate EHCI batch data.", 108 usb_batch); 109 goto dispose; 110 } 111 link_initialize(&ehci_batch->link); 112 ehci_batch->td_count = 113 (usb_batch->buffer_size + EHCI_TD_MAX_TRANSFER - 1) 114 / EHCI_TD_MAX_TRANSFER; 97 int ehci_transfer_batch_prepare(ehci_transfer_batch_t *ehci_batch) 98 { 99 assert(ehci_batch); 100 101 const size_t setup_size = (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) 102 ? USB_SETUP_PACKET_SIZE 103 : 0; 104 105 const size_t size = ehci_batch->base.size; 106 107 /* Add TD left over by the previous transfer */ 108 ehci_batch->qh = ehci_endpoint_get(ehci_batch->base.ep)->qh; 109 110 /* Determine number of TDs needed */ 111 ehci_batch->td_count = (size + EHCI_TD_MAX_TRANSFER - 1) 112 / EHCI_TD_MAX_TRANSFER; 115 113 116 114 /* Control transfer need Setup and Status stage */ 117 if ( usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) {115 if (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) { 118 116 ehci_batch->td_count += 2; 119 117 } 120 118 121 ehci_batch->tds = calloc(ehci_batch->td_count, sizeof(td_t*)); 122 if (!ehci_batch->tds) { 123 usb_log_error("Batch %p: Failed to allocate EHCI transfer " 124 "descriptors.", usb_batch); 125 goto dispose; 126 } 127 128 /* Add TD left over by the previous transfer */ 129 ehci_batch->qh = ehci_endpoint_get(usb_batch->ep)->qh; 130 131 for (unsigned i = 0; i < ehci_batch->td_count; ++i) { 132 ehci_batch->tds[i] = malloc32(sizeof(td_t)); 133 if (!ehci_batch->tds[i]) { 134 usb_log_error("Batch %p: Failed to allocate TD %d.", 135 usb_batch, i); 136 goto dispose; 137 } 138 memset(ehci_batch->tds[i], 0, sizeof(td_t)); 139 } 140 141 142 /* Mix setup stage and data together, we have enough space */ 143 if (usb_batch->setup_size + usb_batch->buffer_size > 0) { 144 /* Use one buffer for setup and data stage */ 145 ehci_batch->device_buffer = 146 malloc32(usb_batch->setup_size + usb_batch->buffer_size); 147 if (!ehci_batch->device_buffer) { 148 usb_log_error("Batch %p: Failed to allocate device " 149 "buffer", usb_batch); 150 goto dispose; 151 } 152 /* Copy setup data */ 153 memcpy(ehci_batch->device_buffer, usb_batch->setup_buffer, 154 usb_batch->setup_size); 155 /* Copy generic data */ 156 if (usb_batch->ep->direction != USB_DIRECTION_IN) 157 memcpy( 158 ehci_batch->device_buffer + usb_batch->setup_size, 159 usb_batch->buffer, usb_batch->buffer_size); 160 } 161 ehci_batch->usb_batch = usb_batch; 162 163 const usb_direction_t dir = usb_transfer_batch_direction(usb_batch); 164 assert(batch_setup[usb_batch->ep->transfer_type]); 165 batch_setup[usb_batch->ep->transfer_type](ehci_batch, dir); 166 167 usb_log_debug("Batch %p %s " USB_TRANSFER_BATCH_FMT " initialized.\n", 168 usb_batch, usb_str_direction(dir), 169 USB_TRANSFER_BATCH_ARGS(*usb_batch)); 170 171 return ehci_batch; 172 dispose: 173 ehci_transfer_batch_dispose(ehci_batch); 174 return NULL; 119 assert(ehci_batch->td_count > 0); 120 121 const size_t tds_size = ehci_batch->td_count * sizeof(td_t); 122 123 /* Mix setup stage and TDs together, we have enough space */ 124 if (dma_buffer_alloc(&ehci_batch->ehci_dma_buffer, tds_size + setup_size)) { 125 usb_log_error("Batch %p: Failed to allocate device buffer", 126 ehci_batch); 127 return ENOMEM; 128 } 129 130 /* Clean TDs */ 131 ehci_batch->tds = ehci_batch->ehci_dma_buffer.virt; 132 memset(ehci_batch->tds, 0, tds_size); 133 134 /* Copy setup data */ 135 ehci_batch->setup_buffer = ehci_batch->ehci_dma_buffer.virt + tds_size; 136 memcpy(ehci_batch->setup_buffer, ehci_batch->base.setup.buffer, setup_size); 137 138 /* Generic data already prepared*/ 139 ehci_batch->data_buffer = ehci_batch->base.dma_buffer.virt; 140 141 if (!batch_setup[ehci_batch->base.ep->transfer_type]) 142 return ENOTSUP; 143 144 batch_setup[ehci_batch->base.ep->transfer_type](ehci_batch); 145 146 usb_log_debug("Batch %p %s " USB_TRANSFER_BATCH_FMT " initialized.", 147 ehci_batch, usb_str_direction(ehci_batch->base.dir), 148 USB_TRANSFER_BATCH_ARGS(ehci_batch->base)); 149 150 return EOK; 175 151 } 176 152 … … 184 160 * completes with the last TD. 185 161 */ 186 bool ehci_transfer_batch_is_complete(const ehci_transfer_batch_t *ehci_batch) 187 { 188 assert(ehci_batch); 189 assert(ehci_batch->usb_batch); 190 191 usb_log_debug("Batch %p: checking %zu td(s) for completion.\n", 192 ehci_batch->usb_batch, ehci_batch->td_count); 193 194 usb_log_debug2("Batch %p: QH: %08x:%08x:%08x:%08x:%08x:%08x.\n", 195 ehci_batch->usb_batch, 162 bool ehci_transfer_batch_check_completed(ehci_transfer_batch_t *ehci_batch) 163 { 164 assert(ehci_batch); 165 166 usb_log_debug("Batch %p: checking %zu td(s) for completion.", 167 ehci_batch, ehci_batch->td_count); 168 169 usb_log_debug2("Batch %p: QH: %08x:%08x:%08x:%08x:%08x:%08x.", 170 ehci_batch, 196 171 ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap, 197 172 ehci_batch->qh->status, ehci_batch->qh->current, … … 206 181 207 182 /* Assume all data got through */ 208 ehci_batch->usb_batch->transfered_size = 209 ehci_batch->usb_batch->buffer_size; 183 ehci_batch->base.transferred_size = ehci_batch->base.size; 210 184 211 185 /* Check all TDs */ 212 186 for (size_t i = 0; i < ehci_batch->td_count; ++i) { 213 assert(ehci_batch->tds[i] != NULL);214 187 usb_log_debug("Batch %p: TD %zu: %08x:%08x:%08x.", 215 ehci_batch ->usb_batch, i,216 ehci_batch->tds[i] ->status, ehci_batch->tds[i]->next,217 ehci_batch->tds[i] ->alternate);218 219 ehci_batch-> usb_batch->error = td_error(ehci_batch->tds[i]);220 if (ehci_batch-> usb_batch->error == EOK) {188 ehci_batch, i, 189 ehci_batch->tds[i].status, ehci_batch->tds[i].next, 190 ehci_batch->tds[i].alternate); 191 192 ehci_batch->base.error = td_error(&ehci_batch->tds[i]); 193 if (ehci_batch->base.error == EOK) { 221 194 /* If the TD got all its data through, it will report 222 195 * 0 bytes remain, the sole exception is INPUT with … … 231 204 * we leave the very last(unused) TD behind. 232 205 */ 233 ehci_batch-> usb_batch->transfered_size234 -= td_remain_size( ehci_batch->tds[i]);206 ehci_batch->base.transferred_size 207 -= td_remain_size(&ehci_batch->tds[i]); 235 208 } else { 236 209 usb_log_debug("Batch %p found error TD(%zu):%08x: %s.", 237 ehci_batch ->usb_batch, i,238 ehci_batch->tds[i] ->status,239 str_error_name(ehci_batch-> usb_batch->error));210 ehci_batch, i, 211 ehci_batch->tds[i].status, 212 str_error_name(ehci_batch->base.error)); 240 213 /* Clear possible ED HALT */ 241 214 qh_clear_halt(ehci_batch->qh); … … 244 217 } 245 218 246 assert(ehci_batch-> usb_batch->transfered_size <=247 ehci_batch->usb_batch->buffer_size); 219 assert(ehci_batch->base.transferred_size <= ehci_batch->base.size); 220 248 221 /* Clear TD pointers */ 249 222 ehci_batch->qh->next = LINK_POINTER_TERM; 250 223 ehci_batch->qh->current = LINK_POINTER_TERM; 251 usb_log_debug("Batch %p complete: %s", ehci_batch ->usb_batch,252 str_error(ehci_batch-> usb_batch->error));224 usb_log_debug("Batch %p complete: %s", ehci_batch, 225 str_error(ehci_batch->base.error)); 253 226 254 227 return true; … … 262 235 { 263 236 assert(ehci_batch); 264 qh_set_next_td(ehci_batch->qh, ehci_batch->tds[0]); 237 qh_set_next_td(ehci_batch->qh, 238 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[0])); 265 239 } 266 240 … … 268 242 * 269 243 * @param[in] ehci_batch Batch structure to use. 270 * @param[in] dir Communication direction271 244 * 272 245 * Setup stage with toggle 0 and direction BOTH(SETUP_PID) 273 * Data stage with alternating toggle and direction supplied by parameter. 274 * Status stage with toggle 1 and direction supplied by parameter. 275 */ 276 static void batch_control(ehci_transfer_batch_t *ehci_batch, usb_direction_t dir) 277 { 278 assert(ehci_batch); 279 assert(ehci_batch->usb_batch); 246 * Data stage with alternating toggle and direction 247 * Status stage with toggle 1 and direction 248 */ 249 static void batch_control(ehci_transfer_batch_t *ehci_batch) 250 { 251 assert(ehci_batch); 252 253 usb_direction_t dir = ehci_batch->base.dir; 280 254 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 281 255 282 usb_log_debug2("Batch %p: Control QH(% "PRIxn"): "283 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch ->usb_batch,284 addr_to_phys(ehci_batch->qh),256 usb_log_debug2("Batch %p: Control QH(%p): " 257 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch, 258 ehci_batch->qh, 285 259 ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap, 286 260 ehci_batch->qh->status, ehci_batch->qh->current, … … 292 266 293 267 int toggle = 0; 294 const char* buffer = ehci_batch->device_buffer;295 268 const usb_direction_t data_dir = dir; 296 269 const usb_direction_t status_dir = reverse_dir[dir]; 297 270 298 271 /* Setup stage */ 299 td_init(ehci_batch->tds[0], ehci_batch->tds[1], USB_DIRECTION_BOTH, 300 buffer, ehci_batch->usb_batch->setup_size, toggle, false); 272 td_init(&ehci_batch->tds[0], 273 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[1]), 274 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, ehci_batch->setup_buffer), 275 USB_DIRECTION_BOTH, USB_SETUP_PACKET_SIZE, toggle, false); 301 276 usb_log_debug2("Batch %p: Created CONTROL SETUP TD(%"PRIxn"): " 302 "%08x:%08x:%08x", ehci_batch->usb_batch, 303 addr_to_phys(ehci_batch->tds[0]), 304 ehci_batch->tds[0]->status, ehci_batch->tds[0]->next, 305 ehci_batch->tds[0]->alternate); 306 buffer += ehci_batch->usb_batch->setup_size; 277 "%08x:%08x:%08x", ehci_batch, 278 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[0]), 279 ehci_batch->tds[0].status, ehci_batch->tds[0].next, 280 ehci_batch->tds[0].alternate); 307 281 308 282 /* Data stage */ 309 size_t td_current = 1; 310 size_t remain_size = ehci_batch->usb_batch->buffer_size; 283 unsigned td_current = 1; 284 size_t remain_size = ehci_batch->base.size; 285 uintptr_t buffer = dma_buffer_phys(&ehci_batch->base.dma_buffer, 286 ehci_batch->data_buffer); 311 287 while (remain_size > 0) { 312 const size_t transfer_size = 313 min(remain_size, EHCI_TD_MAX_TRANSFER); 288 const size_t transfer_size = min(remain_size, EHCI_TD_MAX_TRANSFER); 314 289 toggle = 1 - toggle; 315 290 316 td_init( ehci_batch->tds[td_current],317 ehci_batch->tds[td_current + 1], data_dir, buffer,318 transfer_size, toggle, false);291 td_init(&ehci_batch->tds[td_current], 292 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[td_current + 1]), 293 buffer, data_dir, transfer_size, toggle, false); 319 294 usb_log_debug2("Batch %p: Created CONTROL DATA TD(%"PRIxn"): " 320 "%08x:%08x:%08x", ehci_batch ->usb_batch,321 addr_to_phys(ehci_batch->tds[td_current]),322 ehci_batch->tds[td_current] ->status,323 ehci_batch->tds[td_current] ->next,324 ehci_batch->tds[td_current] ->alternate);295 "%08x:%08x:%08x", ehci_batch, 296 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[td_current]), 297 ehci_batch->tds[td_current].status, 298 ehci_batch->tds[td_current].next, 299 ehci_batch->tds[td_current].alternate); 325 300 326 301 buffer += transfer_size; … … 332 307 /* Status stage */ 333 308 assert(td_current == ehci_batch->td_count - 1); 334 td_init( ehci_batch->tds[td_current], NULL, status_dir, NULL, 0, 1, true);335 usb_log_debug2("Batch %p: Created CONTROL STATUS TD (%"PRIxn"): "336 "%08x:%08x:%08x", ehci_batch ->usb_batch,337 addr_to_phys(ehci_batch->tds[td_current]),338 ehci_batch->tds[td_current] ->status,339 ehci_batch->tds[td_current] ->next,340 ehci_batch->tds[td_current] ->alternate);309 td_init(&ehci_batch->tds[td_current], 0, 0, status_dir, 0, 1, true); 310 usb_log_debug2("Batch %p: Created CONTROL STATUS TD %d(%"PRIxn"): " 311 "%08x:%08x:%08x", ehci_batch, td_current, 312 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[td_current]), 313 ehci_batch->tds[td_current].status, 314 ehci_batch->tds[td_current].next, 315 ehci_batch->tds[td_current].alternate); 341 316 } 342 317 … … 349 324 * EHCI hw in ED. 350 325 */ 351 static void batch_data(ehci_transfer_batch_t *ehci_batch, usb_direction_t dir) 352 { 353 assert(ehci_batch); 354 assert(ehci_batch->usb_batch); 355 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 356 357 usb_log_debug2("Batch %p: Data QH(%"PRIxn"): " 358 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch->usb_batch, 359 addr_to_phys(ehci_batch->qh), 326 static void batch_data(ehci_transfer_batch_t *ehci_batch) 327 { 328 assert(ehci_batch); 329 330 usb_log_debug2("Batch %p: Data QH(%p): " 331 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch, 332 ehci_batch->qh, 360 333 ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap, 361 334 ehci_batch->qh->status, ehci_batch->qh->current, … … 363 336 364 337 size_t td_current = 0; 365 size_t remain_size = ehci_batch->usb_batch->buffer_size; 366 char *buffer = ehci_batch->device_buffer; 338 size_t remain_size = ehci_batch->base.size; 339 uintptr_t buffer = dma_buffer_phys(&ehci_batch->base.dma_buffer, 340 ehci_batch->data_buffer); 367 341 while (remain_size > 0) { 368 342 const size_t transfer_size = remain_size > EHCI_TD_MAX_TRANSFER … … 370 344 371 345 const bool last = (remain_size == transfer_size); 372 td_init( 373 ehci_batch->tds[td_current],374 last ? NULL : ehci_batch->tds[td_current + 1],375 dir, buffer, transfer_size, -1, last);346 td_init(&ehci_batch->tds[td_current], 347 last ? 0 : dma_buffer_phys(&ehci_batch->ehci_dma_buffer, 348 &ehci_batch->tds[td_current + 1]), 349 buffer, ehci_batch->base.dir, transfer_size, -1, last); 376 350 377 351 usb_log_debug2("Batch %p: DATA TD(%"PRIxn": %08x:%08x:%08x", 378 ehci_batch->usb_batch, 379 addr_to_phys(ehci_batch->tds[td_current]), 380 ehci_batch->tds[td_current]->status, 381 ehci_batch->tds[td_current]->next, 382 ehci_batch->tds[td_current]->alternate); 352 ehci_batch, 353 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, 354 &ehci_batch->tds[td_current]), 355 ehci_batch->tds[td_current].status, 356 ehci_batch->tds[td_current].next, 357 ehci_batch->tds[td_current].alternate); 383 358 384 359 buffer += transfer_size; … … 390 365 391 366 /** Transfer setup table. */ 392 static void (*const batch_setup[])(ehci_transfer_batch_t* , usb_direction_t) =367 static void (*const batch_setup[])(ehci_transfer_batch_t*) = 393 368 { 394 369 [USB_TRANSFER_CONTROL] = batch_control,
Note:
See TracChangeset
for help on using the changeset viewer.