Changeset df6ded8 in mainline for uspace/drv/bus/usb/uhci/hc.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/uhci/hc.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    34 * All rights reserved.
    45 *
     
    5051#include <usb/usb.h>
    5152#include <usb/host/utils/malloc32.h>
     53#include <usb/host/bandwidth.h>
     54#include <usb/host/utility.h>
    5255
    5356#include "uhci_batch.h"
     57#include "transfer_list.h"
    5458#include "hc.h"
    5559
     
    107111 * @return Error code.
    108112 */
    109 errno_t uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
     113errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
    110114{
    111115        assert(code);
     
    140144        code->cmds[3].addr = (void*)&registers->usbsts;
    141145
    142         usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n",
     146        usb_log_debug("I/O regs at %p (size %zu), IRQ %d.",
    143147            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    144148
     
    157161 * - resume from suspend state (not implemented)
    158162 */
    159 void uhci_hc_interrupt(hcd_t *hcd, uint32_t status)
    160 {
    161         assert(hcd);
    162         hc_t *instance = hcd_get_driver_data(hcd);
    163         assert(instance);
     163static void hc_interrupt(bus_t *bus, uint32_t status)
     164{
     165        hc_t *instance = bus_to_hc(bus);
     166
    164167        /* Lower 2 bits are transaction error and transaction complete */
    165168        if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
    166                 LIST_INITIALIZE(done);
    167                 transfer_list_remove_finished(
    168                     &instance->transfers_interrupt, &done);
    169                 transfer_list_remove_finished(
    170                     &instance->transfers_control_slow, &done);
    171                 transfer_list_remove_finished(
    172                     &instance->transfers_control_full, &done);
    173                 transfer_list_remove_finished(
    174                     &instance->transfers_bulk_full, &done);
    175 
    176                 list_foreach_safe(done, current, next) {
    177                         list_remove(current);
    178                         uhci_transfer_batch_t *batch =
    179                             uhci_transfer_batch_from_link(current);
    180                         uhci_transfer_batch_finish_dispose(batch);
    181                 }
    182         }
     169                transfer_list_check_finished(&instance->transfers_interrupt);
     170                transfer_list_check_finished(&instance->transfers_control_slow);
     171                transfer_list_check_finished(&instance->transfers_control_full);
     172                transfer_list_check_finished(&instance->transfers_bulk_full);
     173        }
     174
    183175        /* Resume interrupts are not supported */
    184176        if (status & UHCI_STATUS_RESUME) {
    185                 usb_log_error("Resume interrupt!\n");
     177                usb_log_error("Resume interrupt!");
    186178        }
    187179
    188180        /* Bits 4 and 5 indicate hc error */
    189181        if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
    190                 usb_log_error("UHCI hardware failure!.\n");
     182                usb_log_error("UHCI hardware failure!.");
    191183                ++instance->hw_failures;
    192184                transfer_list_abort_all(&instance->transfers_interrupt);
     
    199191                        hc_init_hw(instance);
    200192                } else {
    201                         usb_log_fatal("Too many UHCI hardware failures!.\n");
    202                         hc_fini(instance);
     193                        usb_log_fatal("Too many UHCI hardware failures!.");
     194                        hc_gone(&instance->base);
    203195                }
    204196        }
     
    216208 * interrupt fibrils.
    217209 */
    218 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    219 {
    220         assert(instance);
     210errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
     211{
     212        hc_t *instance = hcd_to_hc(hcd);
    221213        assert(hw_res);
    222214        if (hw_res->io_ranges.count != 1 ||
     
    224216            return EINVAL;
    225217
    226         instance->hw_interrupts = interrupts;
    227218        instance->hw_failures = 0;
    228219
     
    231222            (void **) &instance->registers);
    232223        if (ret != EOK) {
    233                 usb_log_error("Failed to gain access to registers: %s.\n",
     224                usb_log_error("Failed to gain access to registers: %s.",
    234225                    str_error(ret));
    235226                return ret;
    236227        }
    237228
    238         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
     229        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
    239230            hw_res->io_ranges.ranges[0].address.absolute,
    240231            hw_res->io_ranges.ranges[0].size);
     
    242233        ret = hc_init_mem_structures(instance);
    243234        if (ret != EOK) {
    244                 usb_log_error("Failed to init UHCI memory structures: %s.\n",
     235                usb_log_error("Failed to init UHCI memory structures: %s.",
    245236                    str_error(ret));
    246237                // TODO: we should disable pio here
     
    248239        }
    249240
     241        return EOK;
     242}
     243
     244int hc_start(hc_device_t *hcd)
     245{
     246        hc_t *instance = hcd_to_hc(hcd);
    250247        hc_init_hw(instance);
    251248        (void)hc_debug_checker;
    252249
    253         uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
    254 
    255         return EOK;
     250        return uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
     251}
     252
     253int hc_setup_roothub(hc_device_t *hcd)
     254{
     255        return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
    256256}
    257257
     
    260260 * @param[in] instance Host controller structure to use.
    261261 */
    262 void hc_fini(hc_t *instance)
     262int hc_gone(hc_device_t *instance)
    263263{
    264264        assert(instance);
    265265        //TODO Implement
     266        return ENOTSUP;
    266267}
    267268
     
    293294        pio_write_32(&registers->flbaseadd, pa);
    294295
    295         if (instance->hw_interrupts) {
     296        if (instance->base.irq_cap >= 0) {
    296297                /* Enable all interrupts, but resume interrupt */
    297298                pio_write_16(&instance->registers->usbintr,
     
    301302        const uint16_t cmd = pio_read_16(&registers->usbcmd);
    302303        if (cmd != 0)
    303                 usb_log_warning("Previous command value: %x.\n", cmd);
     304                usb_log_warning("Previous command value: %x.", cmd);
    304305
    305306        /* Start the hc with large(64B) packet FSBR */
     
    308309}
    309310
     311static usb_transfer_batch_t *create_transfer_batch(endpoint_t *ep)
     312{
     313        uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep);
     314        return &batch->base;
     315}
     316
     317static void destroy_transfer_batch(usb_transfer_batch_t *batch)
     318{
     319        uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch));
     320}
     321
     322static endpoint_t *endpoint_create(device_t *device, const usb_endpoint_descriptors_t *desc)
     323{
     324        endpoint_t *ep = calloc(1, sizeof(uhci_endpoint_t));
     325        if (ep)
     326                endpoint_init(ep, device, desc);
     327        return ep;
     328}
     329
     330static errno_t endpoint_register(endpoint_t *ep)
     331{
     332        hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));
     333
     334        const errno_t err = usb2_bus_endpoint_register(&hc->bus_helper, ep);
     335        if (err)
     336                return err;
     337
     338        transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type];
     339        if (!list)
     340                /*
     341                 * We don't support this combination (e.g. isochronous). Do not
     342                 * fail early, because that would block any device with these
     343                 * endpoints from connecting. Instead, make sure these transfers
     344                 * are denied soon enough with ENOTSUP not to fail on asserts.
     345                 */
     346                return EOK;
     347
     348        endpoint_set_online(ep, &list->guard);
     349        return EOK;
     350}
     351
     352static void endpoint_unregister(endpoint_t *ep)
     353{
     354        hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));
     355        usb2_bus_endpoint_unregister(&hc->bus_helper, ep);
     356
     357        // Check for the roothub, as it does not schedule into lists
     358        if (ep->device->address == uhci_rh_get_address(&hc->rh)) {
     359                // FIXME: We shall check the roothub for active transfer. But
     360                // as it is polling, there is no way to make it stop doing so.
     361                // Return after rewriting uhci rh.
     362                return;
     363        }
     364
     365        transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type];
     366        if (!list)
     367                /*
     368                 * We don't support this combination (e.g. isochronous),
     369                 * so no transfer can be active.
     370                 */
     371                return;
     372
     373        fibril_mutex_lock(&list->guard);
     374
     375        endpoint_set_offline_locked(ep);
     376        /* From now on, no other transfer will be scheduled. */
     377
     378        if (!ep->active_batch) {
     379                fibril_mutex_unlock(&list->guard);
     380                return;
     381        }
     382
     383        /* First, offer the batch a short chance to be finished. */
     384        endpoint_wait_timeout_locked(ep, 10000);
     385
     386        if (!ep->active_batch) {
     387                fibril_mutex_unlock(&list->guard);
     388                return;
     389        }
     390
     391        uhci_transfer_batch_t * const batch =
     392                uhci_transfer_batch_get(ep->active_batch);
     393
     394        /* Remove the batch from the schedule to stop it from being finished. */
     395        endpoint_deactivate_locked(ep);
     396        transfer_list_remove_batch(list, batch);
     397
     398        fibril_mutex_unlock(&list->guard);
     399
     400        /*
     401         * We removed the batch from software schedule only, it's still possible
     402         * that HC has it in its caches. Better wait a while before we release
     403         * the buffers.
     404         */
     405        async_usleep(20000);
     406        batch->base.error = EINTR;
     407        batch->base.transferred_size = 0;
     408        usb_transfer_batch_finish(&batch->base);
     409}
     410
     411static int device_enumerate(device_t *dev)
     412{
     413        hc_t * const hc = bus_to_hc(dev->bus);
     414        return usb2_bus_device_enumerate(&hc->bus_helper, dev);
     415}
     416
     417static void device_gone(device_t *dev)
     418{
     419        hc_t * const hc = bus_to_hc(dev->bus);
     420        usb2_bus_device_gone(&hc->bus_helper, dev);
     421}
     422
     423static int hc_status(bus_t *, uint32_t *);
     424static int hc_schedule(usb_transfer_batch_t *);
     425
     426static const bus_ops_t uhci_bus_ops = {
     427        .interrupt = hc_interrupt,
     428        .status = hc_status,
     429
     430        .device_enumerate = device_enumerate,
     431        .device_gone = device_gone,
     432
     433        .endpoint_create = endpoint_create,
     434        .endpoint_register = endpoint_register,
     435        .endpoint_unregister = endpoint_unregister,
     436
     437        .batch_create = create_transfer_batch,
     438        .batch_schedule = hc_schedule,
     439        .batch_destroy = destroy_transfer_batch,
     440};
     441
    310442/** Initialize UHCI hc memory structures.
    311443 *
     
    321453{
    322454        assert(instance);
     455
     456        usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11);
     457
     458        bus_init(&instance->bus, sizeof(device_t));
     459        instance->bus.ops = &uhci_bus_ops;
     460
     461        hc_device_setup(&instance->base, &instance->bus);
    323462
    324463        /* Init USB frame list page */
     
    327466                return ENOMEM;
    328467        }
    329         usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
     468        usb_log_debug("Initialized frame list at %p.", instance->frame_list);
    330469
    331470        /* Init transfer lists */
    332471        errno_t ret = hc_init_transfer_lists(instance);
    333472        if (ret != EOK) {
    334                 usb_log_error("Failed to initialize transfer lists.\n");
     473                usb_log_error("Failed to initialize transfer lists.");
    335474                return_page(instance->frame_list);
    336475                return ENOMEM;
    337476        }
    338         usb_log_debug("Initialized transfer lists.\n");
     477        list_initialize(&instance->pending_endpoints);
     478        usb_log_debug("Initialized transfer lists.");
    339479
    340480
     
    366506        errno_t ret = transfer_list_init(&instance->transfers_##type, name); \
    367507        if (ret != EOK) { \
    368                 usb_log_error("Failed to setup %s transfer list: %s.\n", \
     508                usb_log_error("Failed to setup %s transfer list: %s.", \
    369509                    name, str_error(ret)); \
    370510                transfer_list_fini(&instance->transfers_bulk_full); \
     
    411551}
    412552
    413 errno_t uhci_hc_status(hcd_t *hcd, uint32_t *status)
    414 {
    415         assert(hcd);
     553static errno_t hc_status(bus_t *bus, uint32_t *status)
     554{
     555        hc_t *instance = bus_to_hc(bus);
    416556        assert(status);
    417         hc_t *instance = hcd_get_driver_data(hcd);
    418         assert(instance);
    419557
    420558        *status = 0;
     
    427565}
    428566
    429 /** Schedule batch for execution.
     567/**
     568 * Schedule batch for execution.
    430569 *
    431570 * @param[in] instance UHCI structure to use.
    432571 * @param[in] batch Transfer batch to schedule.
    433572 * @return Error code
    434  *
    435  * Checks for bandwidth availability and appends the batch to the proper queue.
    436  */
    437 errno_t uhci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    438 {
    439         assert(hcd);
    440         hc_t *instance = hcd_get_driver_data(hcd);
    441         assert(instance);
    442         assert(batch);
    443 
    444         if (batch->ep->address == uhci_rh_get_address(&instance->rh))
    445                 return uhci_rh_schedule(&instance->rh, batch);
    446 
     573 */
     574static errno_t hc_schedule(usb_transfer_batch_t *batch)
     575{
    447576        uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
    448         if (!uhci_batch) {
    449                 usb_log_error("Failed to create UHCI transfer structures.\n");
    450                 return ENOMEM;
    451         }
    452 
    453         transfer_list_t *list =
    454             instance->transfers[batch->ep->speed][batch->ep->transfer_type];
    455         assert(list);
    456         transfer_list_add_batch(list, uhci_batch);
    457 
    458         return EOK;
     577        endpoint_t *ep = batch->ep;
     578        hc_t *hc = bus_to_hc(endpoint_get_bus(ep));
     579
     580        if (batch->target.address == uhci_rh_get_address(&hc->rh))
     581                return uhci_rh_schedule(&hc->rh, batch);
     582
     583        transfer_list_t * const list =
     584            hc->transfers[ep->device->speed][ep->transfer_type];
     585
     586        if (!list)
     587                return ENOTSUP;
     588
     589        errno_t err;
     590        if ((err = uhci_transfer_batch_prepare(uhci_batch)))
     591                return err;
     592
     593        return transfer_list_add_batch(list, uhci_batch);
    459594}
    460595
     
    479614
    480615                if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
    481                         usb_log_debug2("Command: %X Status: %X Intr: %x\n",
     616                        usb_log_debug2("Command: %X Status: %X Intr: %x",
    482617                            cmd, sts, intr);
    483618                }
     
    486621                    pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
    487622                if (frame_list != addr_to_phys(instance->frame_list)) {
    488                         usb_log_debug("Framelist address: %p vs. %p.\n",
     623                        usb_log_debug("Framelist address: %p vs. %p.",
    489624                            (void *) frame_list,
    490625                            (void *) addr_to_phys(instance->frame_list));
     
    497632                uintptr_t real_pa = addr_to_phys(QH(interrupt));
    498633                if (expected_pa != real_pa) {
    499                         usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.\n",
     634                        usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.",
    500635                            (void *) expected_pa, frnum, (void *) real_pa);
    501636                }
     
    504639                real_pa = addr_to_phys(QH(control_slow));
    505640                if (expected_pa != real_pa) {
    506                         usb_log_debug("Control Slow QH: %p vs. %p.\n",
     641                        usb_log_debug("Control Slow QH: %p vs. %p.",
    507642                            (void *) expected_pa, (void *) real_pa);
    508643                }
     
    511646                real_pa = addr_to_phys(QH(control_full));
    512647                if (expected_pa != real_pa) {
    513                         usb_log_debug("Control Full QH: %p vs. %p.\n",
     648                        usb_log_debug("Control Full QH: %p vs. %p.",
    514649                            (void *) expected_pa, (void *) real_pa);
    515650                }
     
    518653                real_pa = addr_to_phys(QH(bulk_full));
    519654                if (expected_pa != real_pa ) {
    520                         usb_log_debug("Bulk QH: %p vs. %p.\n",
     655                        usb_log_debug("Bulk QH: %p vs. %p.",
    521656                            (void *) expected_pa, (void *) real_pa);
    522657                }
Note: See TracChangeset for help on using the changeset viewer.