Changeset df6ded8 in mainline for uspace/drv/bus/usb/ehci/ehci_batch.c


Ignore:
Timestamp:
2018-02-28T16:37:50Z (6 years ago)
Author:
Jakub Jermar <jakub@…>
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)
Message:

Merge github.com:helenos-xhci-team/helenos

This commit merges support for USB 3 and generally refactors, fixes,
extends and cleans up the existing USB framework.

Notable additions and features:

  • new host controller driver has been implemented to control various xHC models (among others, NEC Renesas uPD720200)
  • isochronous data transfer mode
  • support for explicit USB device removal
  • USB tablet driver
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/ehci/ehci_batch.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2014 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4243#include <usb/usb.h>
    4344#include <usb/debug.h>
    44 #include <usb/host/utils/malloc32.h>
    4545
    4646#include "ehci_batch.h"
    47 #include "ehci_endpoint.h"
     47#include "ehci_bus.h"
    4848
    4949/* The buffer pointer list in the qTD is long enough to support a maximum
     
    5353#define EHCI_TD_MAX_TRANSFER   (16 * 1024)
    5454
    55 static void (*const batch_setup[])(ehci_transfer_batch_t*, usb_direction_t);
     55static void (*const batch_setup[])(ehci_transfer_batch_t*);
    5656
    5757/** Safely destructs ehci_transfer_batch_t structure
     
    5959 * @param[in] ehci_batch Instance to destroy.
    6060 */
    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);
     61void 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);
    7366        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);
    8867}
    8968
     
    9473 * NULL otherwise.
    9574 *
     75 */
     76ehci_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 *
    9693 * Determines the number of needed transfer descriptors (TDs).
    9794 * Prepares a transport buffer (that is accessible by the hardware).
    9895 * Initializes parameters needed for the transfer and callback.
    9996 */
    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;
     97int 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;
    115113
    116114        /* 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) {
    118116                ehci_batch->td_count += 2;
    119117        }
    120118
    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;
    175151}
    176152
     
    184160 * completes with the last TD.
    185161 */
    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,
     162bool 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,
    196171            ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
    197172            ehci_batch->qh->status, ehci_batch->qh->current,
     
    206181
    207182        /* 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;
    210184
    211185        /* Check all TDs */
    212186        for (size_t i = 0; i < ehci_batch->td_count; ++i) {
    213                 assert(ehci_batch->tds[i] != NULL);
    214187                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) {
    221194                        /* If the TD got all its data through, it will report
    222195                         * 0 bytes remain, the sole exception is INPUT with
     
    231204                         * we leave the very last(unused) TD behind.
    232205                         */
    233                         ehci_batch->usb_batch->transfered_size
    234                             -= td_remain_size(ehci_batch->tds[i]);
     206                        ehci_batch->base.transferred_size
     207                            -= td_remain_size(&ehci_batch->tds[i]);
    235208                } else {
    236209                        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));
    240213                        /* Clear possible ED HALT */
    241214                        qh_clear_halt(ehci_batch->qh);
     
    244217        }
    245218
    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
    248221        /* Clear TD pointers */
    249222        ehci_batch->qh->next = LINK_POINTER_TERM;
    250223        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));
    253226
    254227        return true;
     
    262235{
    263236        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]));
    265239}
    266240
     
    268242 *
    269243 * @param[in] ehci_batch Batch structure to use.
    270  * @param[in] dir Communication direction
    271244 *
    272245 * 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 */
     249static void batch_control(ehci_transfer_batch_t *ehci_batch)
     250{
     251        assert(ehci_batch);
     252
     253        usb_direction_t dir = ehci_batch->base.dir;
    280254        assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
    281255
    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,
    285259            ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
    286260            ehci_batch->qh->status, ehci_batch->qh->current,
     
    292266
    293267        int toggle = 0;
    294         const char* buffer = ehci_batch->device_buffer;
    295268        const usb_direction_t data_dir = dir;
    296269        const usb_direction_t status_dir = reverse_dir[dir];
    297270
    298271        /* 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);
    301276        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);
    307281
    308282        /* 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);
    311287        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);
    314289                toggle = 1 - toggle;
    315290
    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);
    319294                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);
    325300
    326301                buffer += transfer_size;
     
    332307        /* Status stage */
    333308        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);
    341316}
    342317
     
    349324 * EHCI hw in ED.
    350325 */
    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),
     326static 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,
    360333            ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
    361334            ehci_batch->qh->status, ehci_batch->qh->current,
     
    363336
    364337        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);
    367341        while (remain_size > 0) {
    368342                const size_t transfer_size = remain_size > EHCI_TD_MAX_TRANSFER
     
    370344
    371345                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);
    376350
    377351                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);
    383358
    384359                buffer += transfer_size;
     
    390365
    391366/** Transfer setup table. */
    392 static void (*const batch_setup[])(ehci_transfer_batch_t*, usb_direction_t) =
     367static void (*const batch_setup[])(ehci_transfer_batch_t*) =
    393368{
    394369        [USB_TRANSFER_CONTROL] = batch_control,
Note: See TracChangeset for help on using the changeset viewer.