Ignore:
File:
1 edited

Legend:

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

    rd57122c r26858040  
    4141
    4242#include "hc.h"
    43 #include "uhci_batch.h"
    4443
    4544#define UHCI_INTR_ALLOW_INTERRUPTS \
     
    4847    (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)
    4948
    50 static const irq_pio_range_t uhci_irq_pio_ranges[] = {
    51         {
    52                 .base = 0,      /* filled later */
    53                 .size = sizeof(uhci_regs_t)
    54         }
    55 };
    56 
    57 static const irq_cmd_t uhci_irq_commands[] = {
     49static const irq_cmd_t uhci_irq_commands[] =
     50{
    5851        { .cmd = CMD_PIO_READ_16, .dstarg = 1, .addr = NULL/*filled later*/},
    5952        { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2,
     
    6457};
    6558
    66 static void hc_init_hw(const hc_t *instance);
     59static int hc_init_transfer_lists(hc_t *instance);
    6760static int hc_init_mem_structures(hc_t *instance);
    68 static int hc_init_transfer_lists(hc_t *instance);
    69 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
     61static void hc_init_hw(hc_t *instance);
    7062
    7163static int hc_interrupt_emulator(void *arg);
     
    7365
    7466/*----------------------------------------------------------------------------*/
    75 /** Get number of PIO ranges used in IRQ code.
    76  * @return Number of ranges.
    77  */
    78 size_t hc_irq_pio_range_count(void)
    79 {
    80         return sizeof(uhci_irq_pio_ranges) / sizeof(irq_pio_range_t);
    81 }
    82 /*----------------------------------------------------------------------------*/
    8367/** Get number of commands used in IRQ code.
    8468 * @return Number of commands.
     
    8973}
    9074/*----------------------------------------------------------------------------*/
    91 /** Generate IRQ code.
    92  * @param[out] ranges PIO ranges buffer.
    93  * @param[in] ranges_size Size of the ranges buffer (bytes).
    94  * @param[out] cmds Commands buffer.
    95  * @param[in] cmds_size Size of the commands buffer (bytes).
     75/** Generate IRQ code commands.
     76 * @param[out] cmds Place to store the commands.
     77 * @param[in] cmd_size Size of the place (bytes).
    9678 * @param[in] regs Physical address of device's registers.
    9779 * @param[in] reg_size Size of the register area (bytes).
     
    9981 * @return Error code.
    10082 */
    101 int
    102 hc_get_irq_code(irq_pio_range_t ranges[], size_t ranges_size, irq_cmd_t cmds[],
    103     size_t cmds_size, uintptr_t regs, size_t reg_size)
    104 {
    105         if ((ranges_size < sizeof(uhci_irq_pio_ranges)) ||
    106             (cmds_size < sizeof(uhci_irq_commands)) ||
    107             (reg_size < sizeof(uhci_regs_t)))
     83int hc_get_irq_commands(
     84    irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size)
     85{
     86        if (cmd_size < sizeof(uhci_irq_commands)
     87            || reg_size < sizeof(uhci_regs_t))
    10888                return EOVERFLOW;
    10989
    110         memcpy(ranges, uhci_irq_pio_ranges, sizeof(uhci_irq_pio_ranges));
    111         ranges[0].base = regs;
     90        uhci_regs_t *registers = (uhci_regs_t*)regs;
    11291
    11392        memcpy(cmds, uhci_irq_commands, sizeof(uhci_irq_commands));
    114         uhci_regs_t *registers = (uhci_regs_t *) regs;
    115         cmds[0].addr = &registers->usbsts;
    116         cmds[3].addr = &registers->usbsts;
    117 
    118         return EOK;
    119 }
    120 /*----------------------------------------------------------------------------*/
    121 /** Take action based on the interrupt cause.
    122  *
    123  * @param[in] instance UHCI structure to use.
    124  * @param[in] status Value of the status register at the time of interrupt.
    125  *
    126  * Interrupt might indicate:
    127  * - transaction completed, either by triggering IOC, SPD, or an error
    128  * - some kind of device error
    129  * - resume from suspend state (not implemented)
    130  */
    131 void hc_interrupt(hc_t *instance, uint16_t status)
    132 {
    133         assert(instance);
    134         /* Lower 2 bits are transaction error and transaction complete */
    135         if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
    136                 LIST_INITIALIZE(done);
    137                 transfer_list_remove_finished(
    138                     &instance->transfers_interrupt, &done);
    139                 transfer_list_remove_finished(
    140                     &instance->transfers_control_slow, &done);
    141                 transfer_list_remove_finished(
    142                     &instance->transfers_control_full, &done);
    143                 transfer_list_remove_finished(
    144                     &instance->transfers_bulk_full, &done);
    145 
    146                 while (!list_empty(&done)) {
    147                         link_t *item = list_first(&done);
    148                         list_remove(item);
    149                         uhci_transfer_batch_t *batch =
    150                             uhci_transfer_batch_from_link(item);
    151                         uhci_transfer_batch_finish_dispose(batch);
    152                 }
    153         }
    154         /* Resume interrupts are not supported */
    155         if (status & UHCI_STATUS_RESUME) {
    156                 usb_log_error("Resume interrupt!\n");
    157         }
    158 
    159         /* Bits 4 and 5 indicate hc error */
    160         if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
    161                 usb_log_error("UHCI hardware failure!.\n");
    162                 ++instance->hw_failures;
    163                 transfer_list_abort_all(&instance->transfers_interrupt);
    164                 transfer_list_abort_all(&instance->transfers_control_slow);
    165                 transfer_list_abort_all(&instance->transfers_control_full);
    166                 transfer_list_abort_all(&instance->transfers_bulk_full);
    167 
    168                 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) {
    169                         /* reinitialize hw, this triggers virtual disconnect*/
    170                         hc_init_hw(instance);
    171                 } else {
    172                         usb_log_fatal("Too many UHCI hardware failures!.\n");
    173                         hc_fini(instance);
    174                 }
    175         }
     93
     94        cmds[0].addr = (void*)&registers->usbsts;
     95        cmds[3].addr = (void*)&registers->usbsts;
     96        return EOK;
    17697}
    17798/*----------------------------------------------------------------------------*/
     
    216137            str_error(ret));
    217138
    218 #undef CHECK_RET_RETURN
    219 
    220         hcd_init(&instance->generic, USB_SPEED_FULL,
    221             BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
    222 
    223         instance->generic.private_data = instance;
    224         instance->generic.schedule = hc_schedule;
    225         instance->generic.ep_add_hook = NULL;
    226 
    227139        hc_init_hw(instance);
    228140        if (!interrupts) {
     
    234146
    235147        return EOK;
     148#undef CHECK_RET_DEST_FUN_RETURN
    236149}
    237150/*----------------------------------------------------------------------------*/
     
    241154 * For magic values see UHCI Design Guide
    242155 */
    243 void hc_init_hw(const hc_t *instance)
     156void hc_init_hw(hc_t *instance)
    244157{
    245158        assert(instance);
     
    285198 *
    286199 * Structures:
     200 *  - interrupt code (I/O addressses are customized per instance)
    287201 *  - transfer lists (queue heads need to be accessible by the hw)
    288202 *  - frame list page (needs to be one UHCI hw accessible 4K page)
     
    291205{
    292206        assert(instance);
    293 
    294         /* Init USB frame list page */
     207#define CHECK_RET_RETURN(ret, message...) \
     208        if (ret != EOK) { \
     209                usb_log_error(message); \
     210                return ret; \
     211        } else (void) 0
     212
     213        /* Init transfer lists */
     214        int ret = hc_init_transfer_lists(instance);
     215        CHECK_RET_RETURN(ret, "Failed to initialize transfer lists.\n");
     216        usb_log_debug("Initialized transfer lists.\n");
     217
     218        /* Init device keeper */
     219        usb_device_keeper_init(&instance->manager);
     220        usb_log_debug("Initialized device keeper.\n");
     221
     222        ret = usb_endpoint_manager_init(&instance->ep_manager,
     223            BANDWIDTH_AVAILABLE_USB11);
     224        CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
     225            str_error(ret));
     226
     227        /* Init USB frame list page*/
    295228        instance->frame_list = get_page();
    296229        if (!instance->frame_list) {
     230                usb_log_error("Failed to get frame list page.\n");
     231                usb_endpoint_manager_destroy(&instance->ep_manager);
    297232                return ENOMEM;
    298233        }
    299234        usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
    300 
    301         /* Init transfer lists */
    302         int ret = hc_init_transfer_lists(instance);
    303         if (ret != EOK) {
    304                 usb_log_error("Failed to initialize transfer lists.\n");
    305                 return_page(instance->frame_list);
    306                 return ENOMEM;
    307         }
    308         usb_log_debug("Initialized transfer lists.\n");
    309 
    310235
    311236        /* Set all frames to point to the first queue head */
    312237        const uint32_t queue = LINK_POINTER_QH(
    313238                addr_to_phys(instance->transfers_interrupt.queue_head));
    314 
    315         for (unsigned i = 0; i < UHCI_FRAME_LIST_COUNT; ++i) {
     239        unsigned i = 0;
     240        for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
    316241                instance->frame_list[i] = queue;
    317242        }
    318243
    319244        return EOK;
     245#undef CHECK_RET_RETURN
    320246}
    321247/*----------------------------------------------------------------------------*/
     
    390316 * Checks for bandwidth availability and appends the batch to the proper queue.
    391317 */
    392 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    393 {
    394         assert(hcd);
    395         hc_t *instance = hcd->private_data;
     318int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
     319{
    396320        assert(instance);
    397321        assert(batch);
    398         uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
    399         if (!uhci_batch) {
    400                 usb_log_error("Failed to create UHCI transfer structures.\n");
    401                 return ENOMEM;
    402         }
    403322
    404323        transfer_list_t *list =
    405324            instance->transfers[batch->ep->speed][batch->ep->transfer_type];
    406325        assert(list);
    407         transfer_list_add_batch(list, uhci_batch);
    408 
    409         return EOK;
     326        transfer_list_add_batch(list, batch);
     327
     328        return EOK;
     329}
     330/*----------------------------------------------------------------------------*/
     331/** Take action based on the interrupt cause.
     332 *
     333 * @param[in] instance UHCI structure to use.
     334 * @param[in] status Value of the status register at the time of interrupt.
     335 *
     336 * Interrupt might indicate:
     337 * - transaction completed, either by triggering IOC, SPD, or an error
     338 * - some kind of device error
     339 * - resume from suspend state (not implemented)
     340 */
     341void hc_interrupt(hc_t *instance, uint16_t status)
     342{
     343        assert(instance);
     344        /* Lower 2 bits are transaction error and transaction complete */
     345        if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
     346                LIST_INITIALIZE(done);
     347                transfer_list_remove_finished(
     348                    &instance->transfers_interrupt, &done);
     349                transfer_list_remove_finished(
     350                    &instance->transfers_control_slow, &done);
     351                transfer_list_remove_finished(
     352                    &instance->transfers_control_full, &done);
     353                transfer_list_remove_finished(
     354                    &instance->transfers_bulk_full, &done);
     355
     356                while (!list_empty(&done)) {
     357                        link_t *item = list_first(&done);
     358                        list_remove(item);
     359                        usb_transfer_batch_t *batch =
     360                            list_get_instance(item, usb_transfer_batch_t, link);
     361                        usb_transfer_batch_finish(batch);
     362                }
     363        }
     364        /* Resume interrupts are not supported */
     365        if (status & UHCI_STATUS_RESUME) {
     366                usb_log_error("Resume interrupt!\n");
     367        }
     368
     369        /* Bits 4 and 5 indicate hc error */
     370        if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
     371                usb_log_error("UHCI hardware failure!.\n");
     372                ++instance->hw_failures;
     373                transfer_list_abort_all(&instance->transfers_interrupt);
     374                transfer_list_abort_all(&instance->transfers_control_slow);
     375                transfer_list_abort_all(&instance->transfers_control_full);
     376                transfer_list_abort_all(&instance->transfers_bulk_full);
     377
     378                if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) {
     379                        /* reinitialize hw, this triggers virtual disconnect*/
     380                        hc_init_hw(instance);
     381                } else {
     382                        usb_log_fatal("Too many UHCI hardware failures!.\n");
     383                        hc_fini(instance);
     384                }
     385        }
    410386}
    411387/*----------------------------------------------------------------------------*/
     
    427403                if (status != 0)
    428404                        usb_log_debug2("UHCI status: %x.\n", status);
     405// Qemu fails to report stalled communication
     406// see https://bugs.launchpad.net/qemu/+bug/757654
     407// This is a simple workaround to force queue processing every time
     408        //      status |= 1;
    429409                hc_interrupt(instance, status);
    430410                async_usleep(UHCI_INT_EMULATOR_TIMEOUT);
     
    432412        return EOK;
    433413}
    434 /*----------------------------------------------------------------------------*/
     414/*---------------------------------------------------------------------------*/
    435415/** Debug function, checks consistency of memory structures.
    436416 *
Note: See TracChangeset for help on using the changeset viewer.