Changeset 17873ac7 in mainline


Ignore:
Timestamp:
2017-10-31T19:06:57Z (6 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
479e32d
Parents:
a312d8f
Message:

usbhost endpoint: endpoint→active replaced by tracking active batch

The mechanism is optional, synchronization over endpoint is now not forced. It will be used by xhci to utilize streams.

Location:
uspace
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/uhci/hc.c

    ra312d8f r17873ac7  
    177177                        uhci_transfer_batch_t *batch =
    178178                            uhci_transfer_batch_from_link(current);
    179                         uhci_transfer_batch_finish(batch);
     179                        usb_transfer_batch_finish(&batch->base);
    180180                }
    181181        }
  • uspace/drv/bus/usb/uhci/transfer_list.c

    ra312d8f r17873ac7  
    115115        assert(instance);
    116116        assert(uhci_batch);
     117
     118        endpoint_t *ep = uhci_batch->base.ep;
     119
     120        /* First, wait until the endpoint is free to use */
     121        fibril_mutex_lock(&ep->guard);
     122        endpoint_activate_locked(ep, &uhci_batch->base);
     123        fibril_mutex_unlock(&ep->guard);
     124
    117125        usb_log_debug2("Batch %p adding to queue %s.\n",
    118126            uhci_batch, instance->name);
     
    189197                    uhci_transfer_batch_from_link(current);
    190198                transfer_list_remove_batch(instance, batch);
    191                 uhci_transfer_batch_abort(batch);
     199                endpoint_abort(batch->base.ep);
    192200        }
    193201        fibril_mutex_unlock(&instance->guard);
  • uspace/drv/bus/usb/uhci/uhci_batch.c

    ra312d8f r17873ac7  
    6464}
    6565
    66 void uhci_transfer_batch_finish(uhci_transfer_batch_t *batch)
    67 {
    68         if (batch->base.dir == USB_DIRECTION_IN) {
    69                 assert(batch->base.transfered_size <= batch->base.buffer_size);
    70                 memcpy(batch->base.buffer, uhci_transfer_batch_data_buffer(batch), batch->base.transfered_size);
    71         }
    72         usb_transfer_batch_finish(&batch->base);
    73 }
    74 
    7566/** Allocate memory and initialize internal data structure.
    7667 *
     
    113104        }
    114105
    115         const size_t setup_size = (uhci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
     106        const size_t setup_size = (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL)
    116107                ? USB_SETUP_PACKET_SIZE
    117108                : 0;
     
    165156{
    166157        assert(uhci_batch);
     158        usb_transfer_batch_t *batch = &uhci_batch->base;
    167159
    168160        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
    169161            " checking %zu transfer(s) for completion.\n",
    170             uhci_batch, USB_TRANSFER_BATCH_ARGS(uhci_batch->base),
     162            uhci_batch, USB_TRANSFER_BATCH_ARGS(*batch),
    171163            uhci_batch->td_count);
    172         uhci_batch->base.transfered_size = 0;
     164        batch->transfered_size = 0;
    173165
    174166        for (size_t i = 0;i < uhci_batch->td_count; ++i) {
     
    177169                }
    178170
    179                 uhci_batch->base.error = td_status(&uhci_batch->tds[i]);
    180                 if (uhci_batch->base.error != EOK) {
    181                         assert(uhci_batch->base.ep != NULL);
     171                batch->error = td_status(&uhci_batch->tds[i]);
     172                if (batch->error != EOK) {
     173                        assert(batch->ep != NULL);
    182174
    183175                        usb_log_debug("Batch %p found error TD(%zu->%p):%"
     
    186178                        td_print_status(&uhci_batch->tds[i]);
    187179
    188                         endpoint_toggle_set(uhci_batch->base.ep,
     180                        endpoint_toggle_set(batch->ep,
    189181                            td_toggle(&uhci_batch->tds[i]));
    190182                        if (i > 0)
     
    193185                }
    194186
    195                 uhci_batch->base.transfered_size
     187                batch->transfered_size
    196188                    += td_act_size(&uhci_batch->tds[i]);
    197189                if (td_is_short(&uhci_batch->tds[i]))
     
    199191        }
    200192substract_ret:
    201         if (uhci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
    202                 uhci_batch->base.transfered_size -= USB_SETUP_PACKET_SIZE;
     193        if (batch->ep->transfer_type == USB_TRANSFER_CONTROL)
     194                batch->transfered_size -= USB_SETUP_PACKET_SIZE;
     195
     196        fibril_mutex_lock(&batch->ep->guard);
     197        usb_transfer_batch_reset_toggle(batch);
     198        endpoint_deactivate_locked(batch->ep);
     199        fibril_mutex_unlock(&batch->ep->guard);
     200
     201        if (batch->dir == USB_DIRECTION_IN) {
     202                assert(batch->transfered_size <= batch->buffer_size);
     203                memcpy(batch->buffer,
     204                    uhci_transfer_batch_data_buffer(uhci_batch),
     205                    batch->transfered_size);
     206        }
     207
    203208        return true;
    204209}
  • uspace/drv/bus/usb/uhci/uhci_batch.h

    ra312d8f r17873ac7  
    9898}
    9999
    100 /** Aborts the batch.
    101  * Sets error to EINTR and size off transferd data to 0, before finishing the
    102  * batch.
    103  * @param uhci_batch Batch to abort.
    104  */
    105 static inline void uhci_transfer_batch_abort(uhci_transfer_batch_t *uhci_batch)
    106 {
    107         assert(uhci_batch);
    108         uhci_batch->base.error = EINTR;
    109         uhci_batch->base.transfered_size = 0;
    110         usb_transfer_batch_finish(&uhci_batch->base);
    111 }
    112 
    113100/** Linked list conversion wrapper.
    114101 * @param l Linked list link.
  • uspace/drv/bus/usb/xhci/bus.c

    ra312d8f r17873ac7  
    198198        for (size_t i = 0; i < ARRAY_SIZE(xhci_dev->endpoints); ++i) {
    199199                xhci_endpoint_t *ep = xhci_dev->endpoints[i];
    200                 if (!ep || !ep->base.active)
     200                if (!ep)
    201201                        continue;
    202202
    203                 /* FIXME: This is racy. */
    204                 if ((err = xhci_transfer_abort(&ep->active_transfer))) {
    205                         usb_log_warning("Failed to abort active transfer to "
    206                             " endpoint " XHCI_EP_FMT ": %s", XHCI_EP_ARGS(*ep),
    207                             str_error(err));
    208                 }
     203                endpoint_abort(&ep->base);
    209204        }
    210205
     
    454449}
    455450
    456 static int reset_toggle(bus_t *bus_base, usb_target_t target, bool all)
     451static int reset_toggle(bus_t *bus_base, usb_target_t target, toggle_reset_mode_t mode)
    457452{
    458453        // TODO: Implement me!
  • uspace/drv/bus/usb/xhci/endpoint.h

    ra312d8f r17873ac7  
    6868        /** Main transfer ring (unused if streams are enabled) */
    6969        xhci_trb_ring_t ring;
    70 
    71         /** There shall be only one transfer active on an endpoint. The
    72          * synchronization is performed using the active flag in base
    73          * endpoint_t */
    74         xhci_transfer_t active_transfer;
    7570
    7671        /** Primary stream context array (or NULL if endpoint doesn't use streams). */
  • uspace/drv/bus/usb/xhci/transfers.c

    ra312d8f r17873ac7  
    101101xhci_transfer_t* xhci_transfer_create(endpoint_t* ep)
    102102{
    103         xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
    104         xhci_transfer_t *transfer = &xhci_ep->active_transfer;
    105 
    106         /* Do not access the transfer yet, it may be still in use. */
     103        xhci_transfer_t *transfer = calloc(1, sizeof(xhci_transfer_t));
     104        if (!transfer)
     105                return NULL;
    107106
    108107        usb_transfer_batch_init(&transfer->batch, ep);
    109         assert(ep->active);
    110 
    111         /* Clean just our data. */
    112         memset(((void *) transfer) + sizeof(usb_transfer_batch_t), 0,
    113             sizeof(xhci_transfer_t) - sizeof(usb_transfer_batch_t));
    114 
    115108        return transfer;
    116109}
     
    246239        usb_log_error("Isochronous transfers are not yet implemented!");
    247240        return ENOTSUP;
    248 }
    249 
    250 int xhci_transfer_abort(xhci_transfer_t *transfer)
    251 {
    252         usb_transfer_batch_t *batch = &transfer->batch;
    253         batch->error = EAGAIN;
    254         batch->transfered_size = 0;
    255         usb_transfer_batch_finish(batch);
    256         return EOK;
    257241}
    258242
     
    277261        }
    278262
    279         xhci_transfer_t *transfer = &ep->active_transfer;
    280 
    281         /** FIXME: This is racy. Do we care? */
     263        /* FIXME: This is racy. Do we care? */
    282264        ep->ring.dequeue = addr;
    283265
    284         usb_transfer_batch_t *batch = &transfer->batch;
     266        fibril_mutex_lock(&ep->base.guard);
     267        usb_transfer_batch_t *batch = ep->base.active_batch;
     268        if (!batch) {
     269                fibril_mutex_unlock(&ep->base.guard);
     270                return ENOENT;
     271        }
    285272
    286273        batch->error = (TRB_COMPLETION_CODE(*trb) == XHCI_TRBC_SUCCESS) ? EOK : ENAK;
    287274        batch->transfered_size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb);
     275        usb_transfer_batch_reset_toggle(batch);
     276        endpoint_deactivate_locked(&ep->base);
     277        fibril_mutex_unlock(&ep->base.guard);
     278
     279        xhci_transfer_t *transfer = xhci_transfer_from_batch(batch);
    288280
    289281        if (batch->dir == USB_DIRECTION_IN) {
     
    309301{
    310302        assert(hc);
     303        endpoint_t *ep = batch->ep;
    311304
    312305        xhci_transfer_t *transfer = xhci_transfer_from_batch(batch);
    313         xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep);
    314         assert(xhci_ep);
    315 
     306        xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
    316307        xhci_device_t *xhci_dev = xhci_ep_to_dev(xhci_ep);
    317308
    318309        /* Offline devices don't schedule transfers other than on EP0. */
    319         if (!xhci_dev->online && xhci_ep->base.endpoint) {
     310        if (!xhci_dev->online && ep->endpoint > 0) {
    320311                return EAGAIN;
    321312        }
     
    334325        if (batch->buffer_size > 0) {
    335326                transfer->hc_buffer = malloc32(batch->buffer_size);
    336         }
    337 
     327                if (!transfer->hc_buffer)
     328                        return ENOMEM;
     329        }
    338330
    339331        if (batch->dir != USB_DIRECTION_IN) {
     
    342334        }
    343335
     336        fibril_mutex_lock(&ep->guard);
     337        endpoint_activate_locked(ep, batch);
    344338        const int err = transfer_handlers[batch->ep->transfer_type](hc, transfer);
    345         if (err)
     339
     340        if (err) {
     341                endpoint_deactivate_locked(ep);
     342                fibril_mutex_unlock(&ep->guard);
    346343                return err;
     344        }
     345
     346        /* After the critical section, the transfer can already be finished or aborted. */
     347        transfer = NULL; batch = NULL;
     348        fibril_mutex_unlock(&ep->guard);
    347349
    348350        const uint8_t slot_id = xhci_dev->slot_id;
  • uspace/drv/bus/usb/xhci/transfers.h

    ra312d8f r17873ac7  
    5858xhci_transfer_t* xhci_transfer_create(endpoint_t *);
    5959int xhci_transfer_schedule(xhci_hc_t *, usb_transfer_batch_t *);
    60 int xhci_transfer_abort(xhci_transfer_t *);
    6160int xhci_handle_transfer_event(xhci_hc_t *, xhci_trb_t *);
    6261void xhci_transfer_destroy(xhci_transfer_t *);
  • uspace/lib/usb/include/usb/request.h

    ra312d8f r17873ac7  
    109109int assert[(sizeof(usb_device_request_setup_packet_t) == 8) ? 1: -1];
    110110
    111 /** How much toggles needs to be reset */
     111/** How many toggles need to be reset */
    112112typedef enum {
    113113        RESET_NONE,
  • uspace/lib/usbhost/include/usb/host/bus.h

    ra312d8f r17873ac7  
    4444
    4545#include <usb/usb.h>
     46#include <usb/request.h>
    4647
    4748#include <assert.h>
     
    9798        int (*release_address)(bus_t *, usb_address_t);
    9899
    99         int (*reset_toggle)(bus_t *, usb_target_t, bool);
     100        int (*reset_toggle)(bus_t *, usb_target_t, toggle_reset_mode_t);
    100101
    101102        size_t (*count_bw) (endpoint_t *, size_t);
  • uspace/lib/usbhost/include/usb/host/endpoint.h

    ra312d8f r17873ac7  
    5252/** Host controller side endpoint structure. */
    5353typedef struct endpoint {
     54        /** Part of linked list. */
     55        link_t link;
    5456        /** Managing bus */
    5557        bus_t *bus;
    5658        /** Reference count. */
    5759        atomic_t refcnt;
    58         /** Part of linked list. */
    59         link_t link;
    6060        /** USB device */
    6161        device_t *device;
     
    7676        /** Value of the toggle bit. */
    7777        unsigned toggle:1;
    78         /** True if there is a batch using this scheduled for this endpoint. */
    79         bool active;
     78        /** The currently active transfer batch. Write using methods, read under guard. */
     79        usb_transfer_batch_t *active_batch;
    8080        /** Protects resources and active status changes. */
    8181        fibril_mutex_t guard;
     
    9191extern void endpoint_del_ref(endpoint_t *);
    9292
    93 extern void endpoint_use(endpoint_t *);
    94 extern void endpoint_release(endpoint_t *);
     93/* Pay atention to synchronization of batch access wrt to aborting & finishing from another fibril. */
     94
     95/* Set currently active batch. The common case is to activate in the same
     96 * critical section as scheduling to HW.
     97 */
     98extern void endpoint_activate_locked(endpoint_t *, usb_transfer_batch_t *);
     99
     100/* Deactivate the endpoint, allowing others to activate it again. Batch shall
     101 * already have an error set. */
     102extern void endpoint_deactivate_locked(endpoint_t *);
     103
     104/* Abort the currenty active batch. */
     105void endpoint_abort(endpoint_t *);
    95106
    96107extern int endpoint_toggle_get(endpoint_t *);
    97 extern void endpoint_toggle_set(endpoint_t *, unsigned);
     108extern void endpoint_toggle_set(endpoint_t *, bool);
    98109
    99110/** list_get_instance wrapper.
  • uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h

    ra312d8f r17873ac7  
    4040#include <usb/request.h>
    4141
     42#include <atomic.h>
    4243#include <stddef.h>
     44#include <errno.h>
    4345#include <stdint.h>
    4446#include <usbhc_iface.h>
     
    8688        /** Size of memory pointed to by buffer member */
    8789        size_t buffer_size;
    88 
    8990        /** Actually used portion of the buffer */
    9091        size_t transfered_size;
     92
    9193        /** Indicates success/failure of the communication */
    9294        int error;
     
    106108        (batch).buffer_size, (batch).ep->max_packet_size
    107109
     110/** Wrapper for bus operation. */
     111usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *);
     112
     113/** Batch initializer. */
    108114void usb_transfer_batch_init(usb_transfer_batch_t *, endpoint_t *);
     115
     116/** Call after status is known, but before releasing endpoint */
     117int usb_transfer_batch_reset_toggle(usb_transfer_batch_t *);
     118
     119/** Batch finalization. */
     120void usb_transfer_batch_abort(usb_transfer_batch_t *);
    109121void usb_transfer_batch_finish(usb_transfer_batch_t *);
    110122
    111 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *);
     123/** To be called from outside only when the transfer is not going to be finished
     124 * (i.o.w. until successfuly scheduling)
     125 */
    112126void usb_transfer_batch_destroy(usb_transfer_batch_t *);
    113127
  • uspace/lib/usbhost/src/endpoint.c

    ra312d8f r17873ac7  
    3636
    3737#include <usb/host/endpoint.h>
     38#include <usb/host/usb_transfer_batch.h>
    3839#include <usb/host/bus.h>
    3940
     
    6869                }
    6970                else {
    70                         assert(!ep->active);
     71                        assert(ep->active_batch == NULL);
    7172
    7273                        /* Assume mostly the eps will be allocated by malloc. */
     
    7980 * @param ep endpoint_t structure.
    8081 */
    81 void endpoint_use(endpoint_t *ep)
     82void endpoint_activate_locked(endpoint_t *ep, usb_transfer_batch_t *batch)
    8283{
    8384        assert(ep);
    84         /* Add reference for active endpoint. */
    85         endpoint_add_ref(ep);
    86         fibril_mutex_lock(&ep->guard);
    87         while (ep->active)
     85        assert(batch);
     86        assert(batch->ep == ep);
     87        assert(fibril_mutex_is_locked(&ep->guard));
     88
     89        while (ep->active_batch != NULL)
    8890                fibril_condvar_wait(&ep->avail, &ep->guard);
    89         ep->active = true;
    90         fibril_mutex_unlock(&ep->guard);
     91        ep->active_batch = batch;
    9192}
    9293
     
    9495 * @param ep endpoint_t structure.
    9596 */
    96 void endpoint_release(endpoint_t *ep)
     97void endpoint_deactivate_locked(endpoint_t *ep)
    9798{
    9899        assert(ep);
     100        assert(fibril_mutex_is_locked(&ep->guard));
     101
     102        if (ep->active_batch && ep->active_batch->error == EOK)
     103                usb_transfer_batch_reset_toggle(ep->active_batch);
     104
     105        ep->active_batch = NULL;
     106        fibril_condvar_signal(&ep->avail);
     107}
     108
     109/** Abort an active batch on endpoint, if any.
     110 *
     111 * @param[in] ep endpoint_t structure.
     112 */
     113void endpoint_abort(endpoint_t *ep)
     114{
     115        assert(ep);
     116
    99117        fibril_mutex_lock(&ep->guard);
    100         ep->active = false;
     118        usb_transfer_batch_t *batch = ep->active_batch;
     119        endpoint_deactivate_locked(ep);
    101120        fibril_mutex_unlock(&ep->guard);
    102         fibril_condvar_signal(&ep->avail);
    103         /* Drop reference for active endpoint. */
    104         endpoint_del_ref(ep);
     121
     122        if (batch)
     123                usb_transfer_batch_abort(batch);
    105124}
    106125
     
    112131{
    113132        assert(ep);
    114         fibril_mutex_lock(&ep->guard);
    115         const int ret = ep->bus->ops.endpoint_get_toggle
     133
     134        return ep->bus->ops.endpoint_get_toggle
    116135            ? ep->bus->ops.endpoint_get_toggle(ep)
    117136            : ep->toggle;
    118         fibril_mutex_unlock(&ep->guard);
    119         return ret;
    120137}
    121138
     
    124141 * @param ep endpoint_t structure.
    125142 */
    126 void endpoint_toggle_set(endpoint_t *ep, unsigned toggle)
     143void endpoint_toggle_set(endpoint_t *ep, bool toggle)
    127144{
    128145        assert(ep);
    129         assert(toggle == 0 || toggle == 1);
    130         fibril_mutex_lock(&ep->guard);
     146
    131147        if (ep->bus->ops.endpoint_set_toggle) {
    132148                ep->bus->ops.endpoint_set_toggle(ep, toggle);
     
    135151                ep->toggle = toggle;
    136152        }
    137         fibril_mutex_unlock(&ep->guard);
    138153}
    139154
  • uspace/lib/usbhost/src/usb2_bus.c

    ra312d8f r17873ac7  
    367367}
    368368
    369 static int usb2_bus_reset_toggle(bus_t *bus_base, usb_target_t target, bool all)
     369static int usb2_bus_reset_toggle(bus_t *bus_base, usb_target_t target, toggle_reset_mode_t mode)
    370370{
    371371        usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
     
    374374                return EINVAL;
    375375
     376        if (mode == RESET_NONE)
     377                return EOK;
     378
    376379        int ret = ENOENT;
    377380
     
    379382                assert(ep->device->address == target.address);
    380383
    381                 if (all || ep->endpoint == target.endpoint) {
     384                if (mode == RESET_ALL || ep->endpoint == target.endpoint) {
    382385                        endpoint_toggle_set(ep, 0);
    383386                        ret = EOK;
  • uspace/lib/usbhost/src/usb_transfer_batch.c

    ra312d8f r17873ac7  
    6363void usb_transfer_batch_init(usb_transfer_batch_t *batch, endpoint_t *ep)
    6464{
    65         endpoint_use(ep);
    66 
    6765        memset(batch, 0, sizeof(*batch));
    6866        batch->ep = ep;
    6967}
    7068
    71 /** Call the handler of the batch.
     69/** Resolve resetting toggle.
    7270 *
    7371 * @param[in] batch Batch structure to use.
    7472 */
    75 static int batch_complete(usb_transfer_batch_t *batch)
     73int usb_transfer_batch_reset_toggle(usb_transfer_batch_t *batch)
    7674{
    7775        assert(batch);
    7876
    79         usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed.\n",
    80             batch, USB_TRANSFER_BATCH_ARGS(*batch));
     77        if (batch->error != EOK || batch->toggle_reset_mode == RESET_NONE)
     78                return EOK;
    8179
    82         if (batch->error == EOK && batch->toggle_reset_mode != RESET_NONE) {
    83                 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " resets %s",
    84                     batch, USB_TRANSFER_BATCH_ARGS(*batch),
    85                     batch->toggle_reset_mode == RESET_ALL ? "all EPs toggle" : "EP toggle");
    86                 bus_reset_toggle(batch->ep->bus,
    87                     batch->target, batch->toggle_reset_mode == RESET_ALL);
    88         }
     80        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " resets %s",
     81            batch, USB_TRANSFER_BATCH_ARGS(*batch),
     82            batch->toggle_reset_mode == RESET_ALL ? "all EPs toggle" : "EP toggle");
    8983
    90         return batch->on_complete
    91                 ? batch->on_complete(batch)
    92                 : EOK;
     84        return bus_reset_toggle(batch->ep->bus, batch->target, batch->toggle_reset_mode);
    9385}
    9486
     
    114106                free(batch);
    115107        }
    116 
    117         endpoint_release(batch->ep);
    118108}
    119109
     
    126116void usb_transfer_batch_finish(usb_transfer_batch_t *batch)
    127117{
    128         const int err = batch_complete(batch);
    129         if (err)
    130                 usb_log_warning("batch %p failed to complete: %s", batch, str_error(err));
     118        assert(batch);
     119        assert(batch->ep);
     120
     121        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n",
     122            batch, USB_TRANSFER_BATCH_ARGS(*batch));
     123
     124        if (batch->on_complete) {
     125                const int err = batch->on_complete(batch);
     126                if (err)
     127                        usb_log_warning("batch %p failed to complete: %s",
     128                            batch, str_error(err));
     129        }
    131130
    132131        usb_transfer_batch_destroy(batch);
     132}
     133
     134/** Finish a transfer batch as an aborted one.
     135 *
     136 * @param[in] batch Batch structure to use.
     137 */
     138void usb_transfer_batch_abort(usb_transfer_batch_t *batch)
     139{
     140        assert(batch);
     141        assert(batch->ep);
     142
     143        batch->error = EAGAIN;
     144        usb_transfer_batch_finish(batch);
    133145}
    134146
Note: See TracChangeset for help on using the changeset viewer.