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


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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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))) {
Note: See TracChangeset for help on using the changeset viewer.