Changeset 4db49344 in mainline for uspace/drv/bus/usb/xhci


Ignore:
Timestamp:
2018-01-23T21:52:28Z (8 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
3dd80f8
Parents:
a6afb4c
git-author:
Ondřej Hlavatý <aearsis@…> (2018-01-23 20:49:35)
git-committer:
Ondřej Hlavatý <aearsis@…> (2018-01-23 21:52:28)
Message:

usb: fix wrong design of transfer aborting

Apparently, we didn't do a good job in thinking through the problem.
In older HCs, it was done just wrong - the UHCI implementation commited
a batch that could have been already aborted, and EHCI+OHCI might miss
an interrupt because they commited the batch sooner than they added it
to their checked list.

This commit takes everything from the other end, which is probably the
only right one. Instead of an endpoint having an extra mutex, it
inherits a mutex from the outside. It never locks it though, it just
checks if the mutex is locked and uses it for waiting on condition
variables.

This mutex is supposed to be the one which the HC driver uses for
locking its structures in scheduling. This way, we avoid the ABBA
deadlock completely, while preserving the synchronization on an
endpoint.

The good thing is that this implementation is much easier to extend with
multiple active batches per endpoint.

Location:
uspace/drv/bus/usb/xhci
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/xhci/device.c

    ra6afb4c r4db49344  
    8181        usb_log_debug("Obtained slot ID: %u.", dev->slot_id);
    8282
    83         /* Create and configure control endpoint. */
    84         endpoint_t *ep0_base = xhci_endpoint_create(&dev->base, &ep0_initial_desc);
    85         if (!ep0_base)
     83        endpoint_t *ep0_base;
     84        if ((err = bus_endpoint_add(&dev->base, &ep0_initial_desc, &ep0_base)))
    8685                goto err_slot;
    87 
    88         /* Bus reference */
    89         endpoint_add_ref(ep0_base);
    90         dev->base.endpoints[0] = ep0_base;
    9186
    9287        usb_log_debug("Looking up new device initial MPS: %s",
  • uspace/drv/bus/usb/xhci/endpoint.c

    ra6afb4c r4db49344  
    6868        endpoint_init(ep, dev, desc);
    6969
     70        fibril_mutex_initialize(&xhci_ep->guard);
     71
    7072        xhci_ep->max_burst = desc->companion.max_burst + 1;
    7173
     
    177179        xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);
    178180
    179         if ((err = hc_add_endpoint(ep)))
     181        if (ep_base->endpoint != 0 && (err = hc_add_endpoint(ep)))
    180182                return err;
    181183
     184        endpoint_set_online(ep_base, &ep->guard);
    182185        return EOK;
    183186}
     
    186189 * Abort a transfer on an endpoint.
    187190 */
    188 static int endpoint_abort(endpoint_t *ep)
     191static void endpoint_abort(endpoint_t *ep)
    189192{
    190193        xhci_device_t *dev = xhci_device_get(ep->device);
    191194        xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
    192195
    193         usb_transfer_batch_t *batch = NULL;
    194         fibril_mutex_lock(&ep->guard);
    195         if (ep->active_batch) {
    196                 if (dev->slot_id) {
    197                         const int err = hc_stop_endpoint(xhci_ep);
    198                         if (err) {
    199                                 usb_log_warning("Failed to stop endpoint %u of device "
    200                                     XHCI_DEV_FMT ": %s", ep->endpoint, XHCI_DEV_ARGS(*dev),
    201                                     str_error(err));
    202                         }
    203 
    204                         endpoint_wait_timeout_locked(ep, 2000);
    205                 }
    206 
    207                 batch = ep->active_batch;
    208                 if (batch) {
    209                         endpoint_deactivate_locked(ep);
    210                 }
    211         }
    212         fibril_mutex_unlock(&ep->guard);
    213 
    214         if (batch) {
    215                 batch->error = EINTR;
    216                 batch->transferred_size = 0;
    217                 usb_transfer_batch_finish(batch);
    218         }
    219         return EOK;
     196        /* This function can only abort endpoints without streams. */
     197        assert(xhci_ep->primary_stream_data_array == NULL);
     198
     199        fibril_mutex_lock(&xhci_ep->guard);
     200
     201        endpoint_set_offline_locked(ep);
     202
     203        if (!ep->active_batch) {
     204                fibril_mutex_unlock(&xhci_ep->guard);
     205                return;
     206        }
     207
     208        /* First, offer the batch a short chance to be finished. */
     209        endpoint_wait_timeout_locked(ep, 10000);
     210
     211        if (!ep->active_batch) {
     212                fibril_mutex_unlock(&xhci_ep->guard);
     213                return;
     214        }
     215
     216        usb_transfer_batch_t * const batch = ep->active_batch;
     217
     218        const int err = hc_stop_endpoint(xhci_ep);
     219        if (err) {
     220                usb_log_error("Failed to stop endpoint %u of device "
     221                    XHCI_DEV_FMT ": %s", ep->endpoint, XHCI_DEV_ARGS(*dev),
     222                    str_error(err));
     223        }
     224
     225        fibril_mutex_unlock(&xhci_ep->guard);
     226
     227        batch->error = EINTR;
     228        batch->transferred_size = 0;
     229        usb_transfer_batch_finish(batch);
     230        return;
    220231}
    221232
     
    235246
    236247        /* If device slot is still available, drop the endpoint. */
    237         if (dev->slot_id) {
     248        if (ep_base->endpoint != 0 && dev->slot_id) {
    238249
    239250                if ((err = hc_drop_endpoint(ep))) {
  • uspace/drv/bus/usb/xhci/endpoint.h

    ra6afb4c r4db49344  
    7070        endpoint_t base;        /**< Inheritance. Keep this first. */
    7171
     72        /** Guarding scheduling of this endpoint. */
     73        fibril_mutex_t guard;
     74
    7275        /** Main transfer ring (unused if streams are enabled) */
    7376        xhci_trb_ring_t ring;
  • uspace/drv/bus/usb/xhci/transfers.c

    ra6afb4c r4db49344  
    300300
    301301        if (TRB_EVENT_DATA(*trb)) {
    302                 assert(ep->base.transfer_type != USB_TRANSFER_ISOCHRONOUS);
     302                /* We schedule those only when streams are involved */
     303                assert(ep->primary_stream_ctx_array != NULL);
     304
    303305                /* We are received transfer pointer instead - work with that */
    304306                transfer = (xhci_transfer_t *) addr;
     
    306308                    transfer->interrupt_trb_phys);
    307309                batch = &transfer->batch;
    308 
    309                 fibril_mutex_lock(&ep->base.guard);
    310                 endpoint_deactivate_locked(&ep->base);
    311                 fibril_mutex_unlock(&ep->base.guard);
    312310        }
    313311        else {
     
    321319                }
    322320
    323                 fibril_mutex_lock(&ep->base.guard);
     321                fibril_mutex_lock(&ep->guard);
    324322                batch = ep->base.active_batch;
     323                endpoint_deactivate_locked(&ep->base);
     324                fibril_mutex_unlock(&ep->guard);
     325
    325326                if (!batch) {
    326                         fibril_mutex_unlock(&ep->base.guard);
    327327                        /* Dropping temporary reference */
    328328                        endpoint_del_ref(&ep->base);
     
    331331
    332332                transfer = xhci_transfer_from_batch(batch);
    333 
    334                 endpoint_deactivate_locked(&ep->base);
    335                 fibril_mutex_unlock(&ep->base.guard);
    336333        }
    337334
     
    482479
    483480
    484         fibril_mutex_lock(&ep->guard);
    485         endpoint_activate_locked(ep, batch);
    486         const int err = transfer_handlers[batch->ep->transfer_type](hc, transfer);
    487 
    488         if (err) {
     481        int err;
     482        fibril_mutex_lock(&xhci_ep->guard);
     483
     484        if ((err = endpoint_activate_locked(ep, batch))) {
     485                fibril_mutex_unlock(&xhci_ep->guard);
     486                return err;
     487        }
     488
     489        if ((err = transfer_handlers[batch->ep->transfer_type](hc, transfer))) {
    489490                endpoint_deactivate_locked(ep);
    490                 fibril_mutex_unlock(&ep->guard);
     491                fibril_mutex_unlock(&xhci_ep->guard);
    491492                return err;
    492493        }
    493494
    494495        hc_ring_ep_doorbell(xhci_ep, batch->target.stream);
    495         fibril_mutex_unlock(&ep->guard);
     496        fibril_mutex_unlock(&xhci_ep->guard);
    496497        return EOK;
    497498}
Note: See TracChangeset for help on using the changeset viewer.