Changeset 159100a in mainline for uspace/drv/bus/usb/ohci/hc.c


Ignore:
Timestamp:
2011-07-13T22:19:26Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ef9460b
Parents:
3e5c48c9 (diff), 5d36062 (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.
Message:

Merge OHCI improvements and fixes.

File:
1 edited

Legend:

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

    r3e5c48c9 r159100a  
    4646#define OHCI_USED_INTERRUPTS \
    4747    (I_SO | I_WDH | I_UE | I_RHSC)
    48 static int interrupt_emulator(hc_t *instance);
     48
     49static const irq_cmd_t ohci_irq_commands[] =
     50{
     51        { .cmd = CMD_MEM_READ_32, .dstarg = 1, .addr = NULL /*filled later*/ },
     52        { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, .value = OHCI_USED_INTERRUPTS },
     53        { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 },
     54        { .cmd = CMD_MEM_WRITE_A_32, .srcarg = 1, .addr = NULL /*filled later*/ },
     55        { .cmd = CMD_ACCEPT },
     56};
     57
    4958static void hc_gain_control(hc_t *instance);
     59static void hc_start(hc_t *instance);
    5060static int hc_init_transfer_lists(hc_t *instance);
    5161static int hc_init_memory(hc_t *instance);
     62static int interrupt_emulator(hc_t *instance);
     63
     64/*----------------------------------------------------------------------------*/
     65/** Get number of commands used in IRQ code.
     66 * @return Number of commands.
     67 */
     68size_t hc_irq_cmd_count(void)
     69{
     70        return sizeof(ohci_irq_commands) / sizeof(irq_cmd_t);
     71}
     72/*----------------------------------------------------------------------------*/
     73/** Generate IRQ code commands.
     74 * @param[out] cmds Place to store the commands.
     75 * @param[in] cmd_size Size of the place (bytes).
     76 * @param[in] regs Physical address of device's registers.
     77 * @param[in] reg_size Size of the register area (bytes).
     78 *
     79 * @return Error code.
     80 */
     81int hc_get_irq_commands(
     82    irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size)
     83{
     84        if (cmd_size < sizeof(ohci_irq_commands)
     85            || reg_size < sizeof(ohci_regs_t))
     86                return EOVERFLOW;
     87
     88        /* Create register mapping to use in IRQ handler.
     89         * This mapping should be present in kernel only.
     90         * Remove it from here when kernel knows how to create mappings
     91         * and accepts physical addresses in IRQ code.
     92         * TODO: remove */
     93        ohci_regs_t *registers;
     94        const int ret = pio_enable((void*)regs, reg_size, (void**)&registers);
     95        if (ret != EOK)
     96                return ret;
     97
     98        /* Some bogus access to force create mapping. DO NOT remove,
     99         * unless whole virtual addresses in irq is replaced
     100         * NOTE: Compiler won't remove this as ohci_regs_t members
     101         * are declared volatile.
     102         *
     103         * Introducing CMD_MEM set of IRQ code commands broke
     104         * assumption that IRQ code does not cause page faults.
     105         * If this happens during idling (THREAD == NULL)
     106         * it causes kernel panic.
     107         */
     108        registers->revision;
     109
     110        memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
     111
     112        void *address = (void*)&registers->interrupt_status;
     113        cmds[0].addr = address;
     114        cmds[3].addr = address;
     115        return EOK;
     116}
    52117/*----------------------------------------------------------------------------*/
    53118/** Announce OHCI root hub to the DDF
     
    83148        int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
    84149            USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
    85         CHECK_RET_RELEASE(ret, "Failed(%d) to add OHCI rh endpoint 0.\n", ret);
     150        CHECK_RET_RELEASE(ret,
     151            "Failed to add OHCI root hub endpoint 0: %s.\n", str_error(ret));
    86152
    87153        char *match_str = NULL;
    88         /* DDF needs heap allocated string */
     154        /* DDF needs heap allocated string. */
    89155        ret = asprintf(&match_str, "usb&class=hub");
    90156        ret = ret > 0 ? 0 : ret;
    91         CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret);
     157        CHECK_RET_RELEASE(ret,
     158            "Failed to create match-id string: %s.\n", str_error(ret));
    92159
    93160        ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
    94         CHECK_RET_RELEASE(ret, "Failed(%d) add root hub match-id.\n", ret);
     161        CHECK_RET_RELEASE(ret,
     162            "Failed to add root hub match-id: %s.\n", str_error(ret));
    95163
    96164        ret = ddf_fun_bind(hub_fun);
    97         CHECK_RET_RELEASE(ret, "Failed(%d) to bind root hub function.\n", ret);
     165        CHECK_RET_RELEASE(ret,
     166            "Failed to bind root hub function: %s.\n", str_error(ret));
    98167
    99168        return EOK;
     
    112181{
    113182        assert(instance);
    114         int ret = EOK;
     183
    115184#define CHECK_RET_RETURN(ret, message...) \
    116185if (ret != EOK) { \
     
    119188} else (void)0
    120189
    121         ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers);
     190        int ret =
     191            pio_enable((void*)regs, reg_size, (void**)&instance->registers);
    122192        CHECK_RET_RETURN(ret,
    123             "Failed(%d) to gain access to device registers: %s.\n",
    124             ret, str_error(ret));
     193            "Failed to gain access to device registers: %s.\n", str_error(ret));
    125194
    126195        list_initialize(&instance->pending_batches);
    127196        usb_device_keeper_init(&instance->manager);
     197
    128198        ret = usb_endpoint_manager_init(&instance->ep_manager,
    129199            BANDWIDTH_AVAILABLE_USB11);
     
    137207
    138208        fibril_mutex_initialize(&instance->guard);
     209
    139210        hc_gain_control(instance);
    140 
    141         rh_init(&instance->rh, instance->registers);
    142211
    143212        if (!interrupts) {
     
    147216        }
    148217
    149         return EOK;
    150 }
    151 /*----------------------------------------------------------------------------*/
    152 /** Create end register endpoint structures
     218        rh_init(&instance->rh, instance->registers);
     219        hc_start(instance);
     220
     221        return EOK;
     222}
     223/*----------------------------------------------------------------------------*/
     224/** Create and register endpoint structures.
    153225 *
    154226 * @param[in] instance OHCI driver structure.
     
    168240    size_t mps, size_t size, unsigned interval)
    169241{
    170         endpoint_t *ep = malloc(sizeof(endpoint_t));
     242        endpoint_t *ep =
     243            endpoint_get(address, endpoint, direction, type, speed, mps);
    171244        if (ep == NULL)
    172245                return ENOMEM;
    173         int ret =
    174             endpoint_init(ep, address, endpoint, direction, type, speed, mps);
    175         if (ret != EOK) {
    176                 free(ep);
    177                 return ret;
    178         }
    179246
    180247        hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
     
    184251        }
    185252
    186         ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
     253        int ret =
     254            usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
    187255        if (ret != EOK) {
    188256                hcd_endpoint_clear(ep);
     
    212280                    &instance->lists[ep->transfer_type], hcd_ep);
    213281                instance->registers->control |= C_PLE | C_IE;
    214                 break;
    215         default:
    216282                break;
    217283        }
     
    312378        /* Check for root hub communication */
    313379        if (batch->ep->address == instance->rh.address) {
    314                 return rh_request(&instance->rh, batch);
     380                rh_request(&instance->rh, batch);
     381                return EOK;
    315382        }
    316383
     
    374441
    375442        if (status & I_UE) {
    376                 hc_start_hw(instance);
     443                hc_start(instance);
    377444        }
    378445
     
    399466/** Turn off any (BIOS)driver that might be in control of the device.
    400467 *
     468 * This function implements routines described in chapter 5.1.1.3 of the OHCI
     469 * specification (page 40, pdf page 54).
     470 *
    401471 * @param[in] instance OHCI hc driver structure.
    402472 */
     
    404474{
    405475        assert(instance);
     476
    406477        usb_log_debug("Requesting OHCI control.\n");
    407         /* Turn off legacy emulation */
    408         volatile uint32_t *ohci_emulation_reg =
    409             (uint32_t*)((char*)instance->registers + 0x100);
    410         usb_log_debug("OHCI legacy register %p: %x.\n",
    411             ohci_emulation_reg, *ohci_emulation_reg);
    412         /* Do not change A20 state */
    413         *ohci_emulation_reg &= 0x100;
    414         usb_log_debug("OHCI legacy register %p: %x.\n",
    415             ohci_emulation_reg, *ohci_emulation_reg);
     478        if (instance->registers->revision & R_LEGACY_FLAG) {
     479                /* Turn off legacy emulation, it should be enough to zero
     480                 * the lowest bit, but it caused problems. Thus clear all
     481                 * except GateA20 (causes restart on some hw).
     482                 * See page 145 of the specs for details.
     483                 */
     484                volatile uint32_t *ohci_emulation_reg =
     485                (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
     486                usb_log_debug("OHCI legacy register %p: %x.\n",
     487                    ohci_emulation_reg, *ohci_emulation_reg);
     488                /* Zero everything but A20State */
     489                *ohci_emulation_reg &= 0x100;
     490                usb_log_debug(
     491                    "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
     492                    ohci_emulation_reg, *ohci_emulation_reg);
     493        }
    416494
    417495        /* Interrupt routing enabled => smm driver is active */
     
    419497                usb_log_debug("SMM driver: request ownership change.\n");
    420498                instance->registers->command_status |= CS_OCR;
     499                /* Hope that SMM actually knows its stuff or we can hang here */
    421500                while (instance->registers->control & C_IR) {
    422501                        async_usleep(1000);
    423502                }
    424503                usb_log_info("SMM driver: Ownership taken.\n");
    425                 instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
     504                C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
    426505                async_usleep(50000);
    427506                return;
    428507        }
    429508
    430         const unsigned hc_status =
    431             (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK;
     509        const unsigned hc_status = C_HCFS_GET(instance->registers->control);
    432510        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    433511        if (hc_status != C_HCFS_RESET) {
     
    437515                        return;
    438516                }
    439                 /* HC is suspended assert resume for 20ms */
    440                 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
     517                /* HC is suspended assert resume for 20ms, */
     518                C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
    441519                async_usleep(20000);
    442520                usb_log_info("BIOS driver: HC resumed.\n");
     
    454532 * @param[in] instance OHCI hc driver structure.
    455533 */
    456 void hc_start_hw(hc_t *instance)
     534void hc_start(hc_t *instance)
    457535{
    458536        /* OHCI guide page 42 */
     
    516594            instance->registers->periodic_start, frame_length);
    517595
    518         instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
     596        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
    519597        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
    520598            instance->registers->control);
     
    534612        int ret = endpoint_list_init(&instance->lists[type], name); \
    535613        if (ret != EOK) { \
    536                 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
    537                     ret, name); \
     614                usb_log_error("Failed to setup %s endpoint list: %s.\n", \
     615                    name, str_error(ret)); \
    538616                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
    539617                endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
     
    587665            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    588666
    589         /* Init interrupt code */
    590         instance->interrupt_code.cmds = instance->interrupt_commands;
    591         instance->interrupt_code.cmdcount = OHCI_NEEDED_IRQ_COMMANDS;
    592         {
    593                 /* Read status register */
    594                 instance->interrupt_commands[0].cmd = CMD_MEM_READ_32;
    595                 instance->interrupt_commands[0].dstarg = 1;
    596                 instance->interrupt_commands[0].addr =
    597                     (void*)&instance->registers->interrupt_status;
    598 
    599                 /* Test whether we are the interrupt cause */
    600                 instance->interrupt_commands[1].cmd = CMD_BTEST;
    601                 instance->interrupt_commands[1].value =
    602                     OHCI_USED_INTERRUPTS;
    603                 instance->interrupt_commands[1].srcarg = 1;
    604                 instance->interrupt_commands[1].dstarg = 2;
    605 
    606                 /* Predicate cleaning and accepting */
    607                 instance->interrupt_commands[2].cmd = CMD_PREDICATE;
    608                 instance->interrupt_commands[2].value = 2;
    609                 instance->interrupt_commands[2].srcarg = 2;
    610 
    611                 /* Write-clean status register */
    612                 instance->interrupt_commands[3].cmd = CMD_MEM_WRITE_A_32;
    613                 instance->interrupt_commands[3].srcarg = 1;
    614                 instance->interrupt_commands[3].addr =
    615                     (void*)&instance->registers->interrupt_status;
    616 
    617                 /* Accept interrupt */
    618                 instance->interrupt_commands[4].cmd = CMD_ACCEPT;
    619         }
    620 
    621         return EOK;
    622 }
     667        return EOK;
     668}
     669
    623670/**
    624671 * @}
Note: See TracChangeset for help on using the changeset viewer.