Changeset cb89430 in mainline for uspace/drv/bus/usb/xhci/trb_ring.c


Ignore:
Timestamp:
2017-06-22T13:59:15Z (8 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
e4d7363
Parents:
62ba2cbe
Message:

xhci: event rings && hc initialization (WIP)

File:
1 edited

Legend:

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

    r62ba2cbe rcb89430  
    3232#include <as.h>
    3333#include <align.h>
     34#include <usb/debug.h>
     35#include <usb/host/utils/malloc32.h>
     36#include "hw_struct/trb.h"
    3437#include "trb_ring.h"
    3538
     
    4245
    4346struct trb_segment {
    44         xhci_trb_t trb_storage [SEGMENT_TRB_COUNT] __attribute__((packed));
     47        xhci_trb_t trb_storage [SEGMENT_TRB_COUNT];
    4548
    4649        link_t segments_link;
     
    5962}
    6063
     64/**
     65 * Allocate and initialize new segment.
     66 *
     67 * TODO: When the HC supports 64-bit addressing, there's no need to restrict
     68 * to DMAMEM_4GiB.
     69 */
    6170static int trb_segment_allocate(trb_segment_t **segment)
    6271{
     
    7281                memset(*segment, 0, PAGE_SIZE);
    7382                (*segment)->phys = phys;
     83
     84                usb_log_debug2("Allocated new ring segment.");
    7485        }
    7586
     
    7788}
    7889
    79 int trb_ring_init(xhci_trb_ring_t *ring)
     90/**
     91 * Initializes the ring with one segment.
     92 * Event when it fails, the structure needs to be finalized.
     93 */
     94int xhci_trb_ring_init(xhci_trb_ring_t *ring, xhci_hc_t *hc)
    8095{
    8196        struct trb_segment *segment;
    8297        int err;
    8398
     99        list_initialize(&ring->segments);
     100
    84101        if ((err = trb_segment_allocate(&segment)) != EOK)
    85102                return err;
    86103
    87         list_initialize(&ring->segments);
    88104        list_append(&segment->segments_link, &ring->segments);
     105        ring->segment_count = 1;
    89106
    90107        xhci_trb_t *last = segment_end(segment) - 1;
     
    97114        ring->pcs = 1;
    98115
    99         return EOK;
    100 }
    101 
    102 int trb_ring_fini(xhci_trb_ring_t *ring)
    103 {
     116        usb_log_debug("Initialized new TRB ring.");
     117
     118        return EOK;
     119}
     120
     121int xhci_trb_ring_fini(xhci_trb_ring_t *ring)
     122{
     123        list_foreach(ring->segments, segments_link, trb_segment_t, segment)
     124                dmamem_unmap_anonymous(segment);
    104125        return EOK;
    105126}
     
    123144}
    124145
    125 static uintptr_t xhci_trb_ring_enqueue_phys(xhci_trb_ring_t *ring)
     146static uintptr_t trb_ring_enqueue_phys(xhci_trb_ring_t *ring)
    126147{
    127148        uintptr_t trb_id = ring->enqueue_trb - segment_begin(ring->enqueue_segment);
     
    129150}
    130151
    131 int trb_ring_enqueue(xhci_trb_ring_t *ring, xhci_trb_t *td)
     152/**
     153 * Enqueue a TD composed of TRBs.
     154 *
     155 * This will copy all TRBs chained together into the ring. The cycle flag in
     156 * TRBs may be changed.
     157 *
     158 * The chained TRBs must be contiguous in memory, and must not contain Link TRBs.
     159 *
     160 * We cannot avoid the copying, because the TRB in ring should be updated atomically.
     161 *
     162 * @param td the first TRB of TD
     163 * @return EOK on success,
     164 *         EAGAIN when the ring is too full to fit all TRBs (temporary)
     165 */
     166int xhci_trb_ring_enqueue(xhci_trb_ring_t *ring, xhci_trb_t *td)
    132167{
    133168        xhci_trb_t * const saved_enqueue_trb = ring->enqueue_trb;
     
    145180                        trb_ring_resolve_link(ring);
    146181
    147                 if (xhci_trb_ring_enqueue_phys(ring) == ring->dequeue)
     182                if (trb_ring_enqueue_phys(ring) == ring->dequeue)
    148183                        goto err_again;
    149184        } while (xhci_trb_is_chained(trb++));
     
    160195                xhci_trb_copy(ring->enqueue_trb, trb);
    161196
     197                usb_log_debug2("TRB ring(%p): Enqueued TRB %p", ring, trb);
    162198                ring->enqueue_trb++;
    163199
     
    166202                        xhci_trb_set_cycle(ring->enqueue_trb, ring->pcs);
    167203
    168                         if (TRB_LINK_TC(*ring->enqueue_trb))
     204                        if (TRB_LINK_TC(*ring->enqueue_trb)) {
    169205                                ring->pcs = !ring->pcs;
     206                                usb_log_debug2("TRB ring(%p): PCS toggled", ring);
     207                        }
    170208
    171209                        trb_ring_resolve_link(ring);
     
    180218        return EAGAIN;
    181219}
     220
     221/**
     222 * Initializes an event ring.
     223 * Even when it fails, the structure needs to be finalized.
     224 */
     225int xhci_event_ring_init(xhci_event_ring_t *ring, xhci_hc_t *hc)
     226{
     227        struct trb_segment *segment;
     228        int err;
     229
     230        list_initialize(&ring->segments);
     231
     232        if ((err = trb_segment_allocate(&segment)) != EOK)
     233                return err;
     234
     235        list_append(&segment->segments_link, &ring->segments);
     236        ring->segment_count = 1;
     237
     238        ring->dequeue_segment = segment;
     239        ring->dequeue_trb = segment_begin(segment);
     240        ring->dequeue_ptr = segment->phys;
     241
     242        ring->erst = malloc32(PAGE_SIZE);
     243        if (ring->erst == NULL)
     244                return ENOMEM;
     245
     246        xhci_fill_erst_entry(&ring->erst[0], segment->phys, SEGMENT_TRB_COUNT);
     247
     248        ring->ccs = 1;
     249
     250        usb_log_debug("Initialized event ring.");
     251
     252        return EOK;
     253}
     254
     255int xhci_event_ring_fini(xhci_event_ring_t *ring)
     256{
     257        list_foreach(ring->segments, segments_link, trb_segment_t, segment)
     258                dmamem_unmap_anonymous(segment);
     259
     260        if (ring->erst)
     261                free32(ring->erst);
     262
     263        return EOK;
     264}
     265
     266static uintptr_t event_ring_dequeue_phys(xhci_event_ring_t *ring)
     267{
     268        uintptr_t trb_id = ring->dequeue_trb - segment_begin(ring->dequeue_segment);
     269        return ring->dequeue_segment->phys + trb_id * sizeof(xhci_trb_t);
     270}
     271
     272/**
     273 * Fill the event with next valid event from the ring.
     274 *
     275 * @param event pointer to event to be overwritten
     276 * @return EOK on success,
     277 *         ENOENT when the ring is empty
     278 */
     279int xhci_event_ring_dequeue(xhci_event_ring_t *ring, xhci_trb_t *event)
     280{
     281        /**
     282         * The ERDP reported to the HC is a half-phase off the one we need to
     283         * maintain. Therefore, we keep it extra.
     284         */
     285        ring->dequeue_ptr = event_ring_dequeue_phys(ring);
     286
     287        if (TRB_CYCLE(*ring->dequeue_trb) != ring->ccs)
     288                return ENOENT; /* The ring is empty. */
     289
     290        memcpy(event, ring->dequeue_trb, sizeof(xhci_trb_t));
     291
     292        ring->dequeue_trb++;
     293        const unsigned index = ring->dequeue_trb - segment_begin(ring->dequeue_segment);
     294
     295        /* Wrapping around segment boundary */
     296        if (index >= SEGMENT_TRB_COUNT) {
     297                link_t *next_segment = list_next(&ring->dequeue_segment->segments_link, &ring->segments);
     298
     299                /* Wrapping around table boundary */
     300                if (!next_segment) {
     301                        next_segment = list_first(&ring->segments);
     302                        ring->ccs = !ring->ccs;
     303                }
     304
     305                ring->dequeue_segment = list_get_instance(next_segment, trb_segment_t, segments_link);
     306                ring->dequeue_trb = segment_begin(ring->dequeue_segment);
     307        }
     308       
     309
     310        return EOK;
     311}
Note: See TracChangeset for help on using the changeset viewer.