Changeset 0892663a in mainline for uspace/drv/bus/usb/uhci


Ignore:
Timestamp:
2018-01-11T04:14:37Z (8 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
9848c77
Parents:
bad4a05
git-author:
Ondřej Hlavatý <aearsis@…> (2018-01-11 03:59:03)
git-committer:
Ondřej Hlavatý <aearsis@…> (2018-01-11 04:14:37)
Message:

usbhost: device removal and off/onlining moved into the library

Also, it is just not possible to make generic transfer abortion. So the
current semantics of endpoint unregistering is also aborting the pending
transfer. As it is not yet implemented in XHCI, and the stub in UHCI is
missing the magic, it breaks offlining interrupt devices, such as mouse.

When finishing this commit, I came across the fact we need some more
synchronization above device. Guard can protect internal structures, but
it cannot synchronize multiple calls to offline, or offline & removal
between each other - they both need to allow driver to unregister
endpoints, and as such must release the guard.

Location:
uspace/drv/bus/usb/uhci
Files:
5 edited

Legend:

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

    rbad4a05 r0892663a  
    321321}
    322322
    323 static int device_online(device_t *device)
    324 {
    325         int err;
    326         hc_t *instance = bus_to_hc(device->bus);
    327         assert(instance);
    328 
    329         /* Allow creation of new endpoints and transfers. */
    330         usb_log_info("Device(%d): Going online.", device->address);
    331         fibril_mutex_lock(&device->guard);
    332         device->online = true;
    333         fibril_mutex_unlock(&device->guard);
    334 
    335         if ((err = ddf_fun_online(device->fun))) {
    336                 return err;
    337         }
    338 
    339         return EOK;
    340 }
    341 
    342 static int device_offline(device_t *device)
    343 {
    344         int err;
    345         hc_t *instance = bus_to_hc(device->bus);
    346         assert(instance);
    347 
    348         /* Tear down all drivers working with the device. */
    349         if ((err = ddf_fun_offline(device->fun))) {
    350                 return err;
    351         }
    352 
    353         /* At this point, all drivers are assumed to have already terminated
    354          * in a consistent way. The following code just cleans up hanging
    355          * transfers if there are any. */
    356 
    357         /* Block creation of new endpoints and transfers. */
    358         usb_log_info("Device(%d): Going offline.", device->address);
    359         fibril_mutex_lock(&device->guard);
    360         device->online = false;
    361         fibril_mutex_unlock(&device->guard);
    362 
    363         /* Abort all transfers to all endpoints. */
    364         transfer_list_abort_device(&instance->transfers_interrupt, device->address);
    365         transfer_list_abort_device(&instance->transfers_control_slow, device->address);
    366         transfer_list_abort_device(&instance->transfers_control_full, device->address);
    367         transfer_list_abort_device(&instance->transfers_bulk_full, device->address);
    368 
    369         return EOK;
     323static void endpoint_unregister(endpoint_t *ep)
     324{
     325        usb2_bus_ops.endpoint_unregister(ep);
     326
     327        fibril_mutex_lock(&ep->guard);
     328        if (ep->active_batch) {
     329                uhci_transfer_batch_t *ub = uhci_transfer_batch_get(ep->active_batch);
     330                uhci_transfer_batch_abort(ub);
     331
     332                assert(ep->active_batch == NULL);
     333        }
     334        fibril_mutex_unlock(&ep->guard);
    370335}
    371336
     
    379344        .status = hc_status,
    380345
     346        .endpoint_unregister = endpoint_unregister,
    381347        .endpoint_count_bw = bandwidth_count_usb11,
     348
    382349        .batch_create = create_transfer_batch,
    383350        .batch_schedule = hc_schedule,
    384351        .batch_destroy = destroy_transfer_batch,
    385 
    386         .device_online = device_online,
    387         .device_offline = device_offline,
    388352};
    389353
     
    522486static int hc_schedule(usb_transfer_batch_t *batch)
    523487{
     488        assert(batch);
    524489        hc_t *instance = bus_to_hc(endpoint_get_bus(batch->ep));
    525         assert(batch);
    526490
    527491        if (batch->target.address == uhci_rh_get_address(&instance->rh))
  • uspace/drv/bus/usb/uhci/transfer_list.c

    rbad4a05 r0892663a  
    194194        while (!list_empty(&instance->batch_list)) {
    195195                link_t * const current = list_first(&instance->batch_list);
    196                 uhci_transfer_batch_t *batch =
    197                     uhci_transfer_batch_from_link(current);
     196                uhci_transfer_batch_t *batch = uhci_transfer_batch_from_link(current);
    198197                transfer_list_remove_batch(instance, batch);
    199                 endpoint_abort(batch->base.ep);
    200         }
    201         fibril_mutex_unlock(&instance->guard);
    202 }
    203 
    204 /** Walk the list and finish all batches of a specified device with EINTR.
    205  *
    206  * @param[in] instance List to use.
    207  * @param[in] address Address of the specified device. Other addresses are skipped.
    208  */
    209 void transfer_list_abort_device(transfer_list_t *instance, usb_address_t address)
    210 {
    211         fibril_mutex_lock(&instance->guard);
    212         link_t *current = list_first(&instance->batch_list);
    213         while (current && current != &instance->batch_list.head && !list_empty(&instance->batch_list)) {
    214                 link_t * const next = current->next;
    215                 uhci_transfer_batch_t *batch =
    216                     uhci_transfer_batch_from_link(current);
    217 
    218                 if (batch->base.target.address == address) {
    219                         transfer_list_remove_batch(instance, batch);
    220                         endpoint_abort(batch->base.ep);
    221                 }
    222 
    223                 current = next;
    224198        }
    225199        fibril_mutex_unlock(&instance->guard);
  • uspace/drv/bus/usb/uhci/transfer_list.h

    rbad4a05 r0892663a  
    6363void transfer_list_remove_finished(transfer_list_t *instance, list_t *done);
    6464void transfer_list_abort_all(transfer_list_t *instance);
    65 void transfer_list_abort_device(transfer_list_t *instance, usb_address_t address);
    6665
    6766#endif
  • uspace/drv/bus/usb/uhci/uhci_batch.c

    rbad4a05 r0892663a  
    6464}
    6565
     66/**
     67 * Abort a transfer that is currently running.
     68 * Call with endpoint guard locked.
     69 */
     70void uhci_transfer_batch_abort(uhci_transfer_batch_t *batch)
     71{
     72        assert(batch);
     73
     74        endpoint_t *ep = batch->base.ep;
     75        assert(ep);
     76        assert(fibril_mutex_is_locked(&ep->guard));
     77        assert(ep->active_batch == &batch->base);
     78
     79        /*
     80         * TODO: Do some magic here to remove the batch from schedule.
     81         */
     82
     83        /*
     84         * Wait for 2 frames. If the transfer was being processed,
     85         * it shall be marked as finished already after 1ms.
     86         */
     87        endpoint_wait_timeout_locked(ep, 2000);
     88        if (ep->active_batch != &batch->base)
     89                return;
     90
     91        /*
     92         * Now, we can be sure the transfer is not scheduled,
     93         * and as such will not be completed. We now own the batch.
     94         */
     95        endpoint_deactivate_locked(ep);
     96
     97        /* Leave the critical section for finishing the batch. */
     98        fibril_mutex_unlock(&ep->guard);
     99
     100        batch->base.error = EINTR;
     101        batch->base.transfered_size = 0;
     102        usb_transfer_batch_finish(&batch->base);
     103
     104        fibril_mutex_lock(&ep->guard);
     105}
     106
    66107/** Allocate memory and initialize internal data structure.
    67108 *
  • uspace/drv/bus/usb/uhci/uhci_batch.h

    rbad4a05 r0892663a  
    7070int uhci_transfer_batch_prepare(uhci_transfer_batch_t *);
    7171bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *);
    72 void uhci_transfer_batch_finish(uhci_transfer_batch_t *);
     72void uhci_transfer_batch_abort(uhci_transfer_batch_t *);
    7373void uhci_transfer_batch_destroy(uhci_transfer_batch_t *);
    7474
Note: See TracChangeset for help on using the changeset viewer.