Ignore:
File:
1 edited

Legend:

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

    r933b0d7 r26858040  
    4141
    4242#include "hc.h"
    43 #include "uhci_batch.h"
    4443
    4544#define UHCI_INTR_ALLOW_INTERRUPTS \
     
    4746#define UHCI_STATUS_USED_INTERRUPTS \
    4847    (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)
    49 
    5048
    5149static const irq_cmd_t uhci_irq_commands[] =
     
    5957};
    6058
    61 static void hc_init_hw(const hc_t *instance);
     59static int hc_init_transfer_lists(hc_t *instance);
    6260static int hc_init_mem_structures(hc_t *instance);
    63 static int hc_init_transfer_lists(hc_t *instance);
    64 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
     61static void hc_init_hw(hc_t *instance);
    6562
    6663static int hc_interrupt_emulator(void *arg);
     
    9895        cmds[3].addr = (void*)&registers->usbsts;
    9996        return EOK;
    100 }
    101 /*----------------------------------------------------------------------------*/
    102 /** Take action based on the interrupt cause.
    103  *
    104  * @param[in] instance UHCI structure to use.
    105  * @param[in] status Value of the status register at the time of interrupt.
    106  *
    107  * Interrupt might indicate:
    108  * - transaction completed, either by triggering IOC, SPD, or an error
    109  * - some kind of device error
    110  * - resume from suspend state (not implemented)
    111  */
    112 void hc_interrupt(hc_t *instance, uint16_t status)
    113 {
    114         assert(instance);
    115         /* Lower 2 bits are transaction error and transaction complete */
    116         if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
    117                 LIST_INITIALIZE(done);
    118                 transfer_list_remove_finished(
    119                     &instance->transfers_interrupt, &done);
    120                 transfer_list_remove_finished(
    121                     &instance->transfers_control_slow, &done);
    122                 transfer_list_remove_finished(
    123                     &instance->transfers_control_full, &done);
    124                 transfer_list_remove_finished(
    125                     &instance->transfers_bulk_full, &done);
    126 
    127                 while (!list_empty(&done)) {
    128                         link_t *item = list_first(&done);
    129                         list_remove(item);
    130                         uhci_transfer_batch_t *batch =
    131                             uhci_transfer_batch_from_link(item);
    132                         uhci_transfer_batch_call_dispose(batch);
    133                 }
    134         }
    135         /* Resume interrupts are not supported */
    136         if (status & UHCI_STATUS_RESUME) {
    137                 usb_log_error("Resume interrupt!\n");
    138         }
    139 
    140         /* Bits 4 and 5 indicate hc error */
    141         if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
    142                 usb_log_error("UHCI hardware failure!.\n");
    143                 ++instance->hw_failures;
    144                 transfer_list_abort_all(&instance->transfers_interrupt);
    145                 transfer_list_abort_all(&instance->transfers_control_slow);
    146                 transfer_list_abort_all(&instance->transfers_control_full);
    147                 transfer_list_abort_all(&instance->transfers_bulk_full);
    148 
    149                 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) {
    150                         /* reinitialize hw, this triggers virtual disconnect*/
    151                         hc_init_hw(instance);
    152                 } else {
    153                         usb_log_fatal("Too many UHCI hardware failures!.\n");
    154                         hc_fini(instance);
    155                 }
    156         }
    15797}
    15898/*----------------------------------------------------------------------------*/
     
    192132            "Device registers at %p (%zuB) accessible.\n", io, reg_size);
    193133
    194         ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
    195             bandwidth_count_usb11);
    196         CHECK_RET_RETURN(ret, "Failed to initialize HCD generic driver: %s.\n",
     134        ret = hc_init_mem_structures(instance);
     135        CHECK_RET_RETURN(ret,
     136            "Failed to initialize UHCI memory structures: %s.\n",
    197137            str_error(ret));
    198 
    199         instance->generic.private_data = instance;
    200         instance->generic.schedule = hc_schedule;
    201         instance->generic.ep_add_hook = NULL;
    202 
    203 #undef CHECK_RET_DEST_FUN_RETURN
    204 
    205         ret = hc_init_mem_structures(instance);
    206         if (ret != EOK) {
    207                 usb_log_error(
    208                     "Failed to initialize UHCI memory structures: %s.\n",
    209                     str_error(ret));
    210                 hcd_destroy(&instance->generic);
    211                 return ret;
    212         }
    213138
    214139        hc_init_hw(instance);
     
    221146
    222147        return EOK;
     148#undef CHECK_RET_DEST_FUN_RETURN
    223149}
    224150/*----------------------------------------------------------------------------*/
     
    228154 * For magic values see UHCI Design Guide
    229155 */
    230 void hc_init_hw(const hc_t *instance)
     156void hc_init_hw(hc_t *instance)
    231157{
    232158        assert(instance);
     
    272198 *
    273199 * Structures:
     200 *  - interrupt code (I/O addressses are customized per instance)
    274201 *  - transfer lists (queue heads need to be accessible by the hw)
    275202 *  - frame list page (needs to be one UHCI hw accessible 4K page)
     
    278205{
    279206        assert(instance);
    280 
    281         /* 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*/
    282228        instance->frame_list = get_page();
    283229        if (!instance->frame_list) {
     230                usb_log_error("Failed to get frame list page.\n");
     231                usb_endpoint_manager_destroy(&instance->ep_manager);
    284232                return ENOMEM;
    285233        }
    286234        usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
    287 
    288         /* Init transfer lists */
    289         int ret = hc_init_transfer_lists(instance);
    290         if (ret != EOK) {
    291                 usb_log_error("Failed to initialize transfer lists.\n");
    292                 return_page(instance->frame_list);
    293                 return ENOMEM;
    294         }
    295         usb_log_debug("Initialized transfer lists.\n");
    296 
    297235
    298236        /* Set all frames to point to the first queue head */
     
    305243
    306244        return EOK;
     245#undef CHECK_RET_RETURN
    307246}
    308247/*----------------------------------------------------------------------------*/
     
    377316 * Checks for bandwidth availability and appends the batch to the proper queue.
    378317 */
    379 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    380 {
    381         assert(hcd);
    382         hc_t *instance = hcd->private_data;
     318int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
     319{
    383320        assert(instance);
    384321        assert(batch);
    385         uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
    386         if (!uhci_batch) {
    387                 usb_log_error("Failed to create UHCI transfer structures.\n");
    388                 return ENOMEM;
    389         }
    390322
    391323        transfer_list_t *list =
    392324            instance->transfers[batch->ep->speed][batch->ep->transfer_type];
    393325        assert(list);
    394         transfer_list_add_batch(list, uhci_batch);
    395 
    396         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        }
    397386}
    398387/*----------------------------------------------------------------------------*/
     
    414403                if (status != 0)
    415404                        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;
    416409                hc_interrupt(instance, status);
    417410                async_usleep(UHCI_INT_EMULATOR_TIMEOUT);
     
    419412        return EOK;
    420413}
    421 /*----------------------------------------------------------------------------*/
     414/*---------------------------------------------------------------------------*/
    422415/** Debug function, checks consistency of memory structures.
    423416 *
Note: See TracChangeset for help on using the changeset viewer.