Changeset e4d7363 in mainline for uspace/drv/bus/usb/xhci/hc.c


Ignore:
Timestamp:
2017-06-22T21:34:39Z (8 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
91ca111
Parents:
cb89430
Message:

usbhost: refactor the initialization

Before that, drivers had to setup MMIO range multiple times, or even parse hw
resources themselves again. The former init method was split in half - init and
start. Init shall allocate and initialize inner structures, start shall start
the HC.

In the XHCI it is demonstrated how to isolate inner HC implementation from the
fact this driver is using libusbhost. It adds some boilerplate code, but
I think it leads to cleaner design.

File:
1 edited

Legend:

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

    rcb89430 re4d7363  
    3737#include <str_error.h>
    3838#include <usb/debug.h>
    39 #include <usb/host/ddf_helpers.h>
    4039#include <usb/host/utils/malloc32.h>
    4140#include "debug.h"
     
    7069};
    7170
     71int hc_init_mmio(xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res)
     72{
     73        int err;
     74
     75        if (hw_res->mem_ranges.count != 1) {
     76                usb_log_error("Unexpected MMIO area, bailing out.");
     77                return EINVAL;
     78        }
     79
     80        hc->mmio_range = hw_res->mem_ranges.ranges[0];
     81
     82        usb_log_debug("MMIO area at %p (size %zu), IRQ %d.\n",
     83            RNGABSPTR(hc->mmio_range), RNGSZ(hc->mmio_range), hw_res->irqs.irqs[0]);
     84
     85        if (RNGSZ(hc->mmio_range) < sizeof(xhci_cap_regs_t))
     86                return EOVERFLOW;
     87
     88        void *base;
     89        if ((err = pio_enable_range(&hc->mmio_range, &base)))
     90                return err;
     91
     92        hc->cap_regs = (xhci_cap_regs_t *)  base;
     93        hc->op_regs  = (xhci_op_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_LENGTH));
     94        hc->rt_regs  = (xhci_rt_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF));
     95        hc->db_arry  = (xhci_doorbell_t *) (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_DBOFF));
     96
     97        usb_log_debug2("Initialized MMIO reg areas:");
     98        usb_log_debug2("\tCapability regs: %p", hc->cap_regs);
     99        usb_log_debug2("\tOperational regs: %p", hc->op_regs);
     100        usb_log_debug2("\tRuntime regs: %p", hc->rt_regs);
     101        usb_log_debug2("\tDoorbell array base: %p", hc->db_arry);
     102
     103        xhci_dump_cap_regs(hc->cap_regs);
     104
     105        hc->ac64 = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_AC64);
     106        hc->max_slots = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_SLOTS);
     107
     108        return EOK;
     109}
     110
     111int hc_init_memory(xhci_hc_t *hc)
     112{
     113        int err;
     114
     115        hc->dcbaa = malloc32((1 + hc->max_slots) * sizeof(xhci_device_ctx_t));
     116        if (!hc->dcbaa)
     117                return ENOMEM;
     118
     119        if ((err = xhci_trb_ring_init(&hc->command_ring, hc)))
     120                goto err_dcbaa;
     121
     122        if ((err = xhci_event_ring_init(&hc->event_ring, hc)))
     123                goto err_cmd_ring;
     124
     125        // TODO: Allocate scratchpad buffers
     126
     127        return EOK;
     128
     129        xhci_event_ring_fini(&hc->event_ring);
     130err_cmd_ring:
     131        xhci_trb_ring_fini(&hc->command_ring);
     132err_dcbaa:
     133        free32(hc->dcbaa);
     134        return err;
     135}
     136
     137
    72138/**
    73139 * Generates code to accept interrupts. The xHCI is designed primarily for
     
    75141 * (except 0) are disabled.
    76142 */
    77 static int hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)
    78 {
    79         int err;
    80 
     143int hc_irq_code_gen(irq_code_t *code, xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res)
     144{
    81145        assert(code);
    82146        assert(hw_res);
    83147
    84         if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1) {
     148        if (hw_res->irqs.count != 1) {
    85149                usb_log_info("Unexpected HW resources to enable interrupts.");
    86150                return EINVAL;
     
    88152
    89153        addr_range_t mmio_range = hw_res->mem_ranges.ranges[0];
    90 
    91         if (RNGSZ(mmio_range) < sizeof(xhci_cap_regs_t))
    92                 return EOVERFLOW;
    93 
    94 
    95         xhci_cap_regs_t *cap_regs = NULL;
    96         if ((err = pio_enable_range(&mmio_range, (void **)&cap_regs)))
    97                 return EIO;
    98154
    99155        code->ranges = malloc(sizeof(irq_pio_range_t));
     
    116172        memcpy(code->cmds, irq_commands, sizeof(irq_commands));
    117173
    118         void *intr0_iman = RNGABSPTR(mmio_range) + XHCI_REG_RD(cap_regs, XHCI_CAP_RTSOFF) + offsetof(xhci_rt_regs_t, ir[0]);
     174        void *intr0_iman = RNGABSPTR(mmio_range) + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF) + offsetof(xhci_rt_regs_t, ir[0]);
    119175        code->cmds[0].addr = intr0_iman;
    120176        code->cmds[3].addr = intr0_iman;
     
    124180}
    125181
    126 static int hc_claim(ddf_dev_t *dev)
    127 {
    128         // TODO: implement handoff: section 4.22.1
     182int hc_claim(xhci_hc_t *hc, ddf_dev_t *dev)
     183{
     184        // TODO: impl
    129185        return EOK;
    130186}
     
    152208 * Initialize the HC: section 4.2
    153209 */
    154 static int hc_start(xhci_hc_t *hc, bool irq)
     210int hc_start(xhci_hc_t *hc, bool irq)
    155211{
    156212        int err;
     
    191247}
    192248
    193 static int hc_init(hcd_t *hcd, const hw_res_list_parsed_t *hw_res, bool irq)
    194 {
    195         int err;
    196 
    197         assert(hcd);
    198         assert(hw_res);
    199         assert(hcd_get_driver_data(hcd) == NULL);
    200 
    201         /* Initialize the MMIO ranges */
    202         if (hw_res->mem_ranges.count != 1) {
    203                 usb_log_error("Unexpected MMIO area, bailing out.");
    204                 return EINVAL;
    205         }
    206 
    207         addr_range_t mmio_range = hw_res->mem_ranges.ranges[0];
    208 
    209         usb_log_debug("MMIO area at %p (size %zu), IRQ %d.\n",
    210             RNGABSPTR(mmio_range), RNGSZ(mmio_range), hw_res->irqs.irqs[0]);
    211 
    212         if (RNGSZ(mmio_range) < sizeof(xhci_cap_regs_t))
    213                 return EOVERFLOW;
    214 
    215         void *base;
    216         if ((err = pio_enable_range(&mmio_range, &base)))
    217                 return err;
    218 
    219         xhci_hc_t *hc = malloc(sizeof(xhci_hc_t));
    220         if (!hc)
    221                 return ENOMEM;
    222 
    223         hc->cap_regs = (xhci_cap_regs_t *)  base;
    224         hc->op_regs  = (xhci_op_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_LENGTH));
    225         hc->rt_regs  = (xhci_rt_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF));
    226         hc->db_arry  = (xhci_doorbell_t *) (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_DBOFF));
    227 
    228         usb_log_debug2("Initialized MMIO reg areas:");
    229         usb_log_debug2("\tCapability regs: %p", hc->cap_regs);
    230         usb_log_debug2("\tOperational regs: %p", hc->op_regs);
    231         usb_log_debug2("\tRuntime regs: %p", hc->rt_regs);
    232         usb_log_debug2("\tDoorbell array base: %p", hc->db_arry);
    233 
    234         xhci_dump_cap_regs(hc->cap_regs);
    235 
    236         hc->ac64 = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_AC64);
    237         hc->max_slots = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_SLOTS);
    238 
    239         hc->dcbaa = malloc32((1 + hc->max_slots) * sizeof(xhci_device_ctx_t));
    240         if (!hc->dcbaa)
    241                 goto err_hc;
    242 
    243         if ((err = xhci_trb_ring_init(&hc->command_ring, hc)))
    244                 goto err_dcbaa;
    245 
    246         if ((err = xhci_event_ring_init(&hc->event_ring, hc)))
    247                 goto err_cmd_ring;
    248 
    249         // TODO: Allocate scratchpad buffers
    250 
    251         hcd_set_implementation(hcd, hc, &xhci_ddf_hc_driver.ops);
    252 
    253         if ((err = hc_start(hc, irq)))
    254                 goto err_event_ring;
    255 
    256         return EOK;
    257 
    258 err_event_ring:
    259         xhci_event_ring_fini(&hc->event_ring);
    260 err_cmd_ring:
    261         xhci_trb_ring_fini(&hc->command_ring);
    262 err_dcbaa:
    263         free32(hc->dcbaa);
    264 err_hc:
    265         free(hc);
    266         hcd_set_implementation(hcd, NULL, NULL);
    267         return err;
    268 }
    269 
    270 static int hc_status(hcd_t *hcd, uint32_t *status)
    271 {
    272         xhci_hc_t *hc = hcd_get_driver_data(hcd);
    273         assert(hc);
    274         assert(status);
    275 
    276         *status = 0;
    277         if (hc->op_regs) {
    278                 *status = XHCI_REG_RD(hc->op_regs, XHCI_OP_STATUS);
    279                 XHCI_REG_WR(hc->op_regs, XHCI_OP_STATUS, *status & XHCI_STATUS_ACK_MASK);
    280         }
     249int hc_status(xhci_hc_t *hc, uint32_t *status)
     250{
     251        *status = XHCI_REG_RD(hc->op_regs, XHCI_OP_STATUS);
     252        XHCI_REG_WR(hc->op_regs, XHCI_OP_STATUS, *status & XHCI_STATUS_ACK_MASK);
     253
    281254        usb_log_debug2("HC(%p): Read status: %x", hc, *status);
    282255        return EOK;
     
    305278}
    306279
    307 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    308 {
    309         xhci_hc_t *hc = hcd_get_driver_data(hcd);
    310         assert(hc);
    311 
     280int hc_schedule(xhci_hc_t *hc, usb_transfer_batch_t *batch)
     281{
    312282        xhci_dump_state(hc);
    313283        send_no_op_command(hc);
     
    346316}
    347317
    348 static void hc_interrupt(hcd_t *hcd, uint32_t status)
    349 {
    350         xhci_hc_t *hc = hcd_get_driver_data(hcd);
    351         assert(hc);
    352 
     318void hc_interrupt(xhci_hc_t *hc, uint32_t status)
     319{
    353320        if (status & XHCI_REG_MASK(XHCI_OP_HSE)) {
    354321                usb_log_error("Host controller error occured. Bad things gonna happen...");
     
    375342}
    376343
    377 static void hc_fini(hcd_t *hcd)
    378 {
    379         xhci_hc_t *hc = hcd_get_driver_data(hcd);
    380         assert(hc);
    381 
    382         usb_log_info("Finishing");
    383 
     344void hc_fini(xhci_hc_t *hc)
     345{
    384346        xhci_trb_ring_fini(&hc->command_ring);
    385347        xhci_event_ring_fini(&hc->event_ring);
    386 
    387         free(hc);
    388         hcd_set_implementation(hcd, NULL, NULL);
    389 }
    390 
    391 const ddf_hc_driver_t xhci_ddf_hc_driver = {
    392         .hc_speed = USB_SPEED_SUPER,
    393         .irq_code_gen = hc_gen_irq_code,
    394         .claim = hc_claim,
    395         .init = hc_init,
    396         .fini = hc_fini,
    397         .name = "XHCI-PCI",
    398         .ops = {
    399                 .schedule       = hc_schedule,
    400                 .irq_hook       = hc_interrupt,
    401                 .status_hook    = hc_status,
    402         }
    403 };
     348        usb_log_info("HC(%p): Finalized.", hc);
     349}
    404350
    405351
Note: See TracChangeset for help on using the changeset viewer.