HelenOS sources

root/uspace/drv/bus/usb/xhci/trb_ring.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. xhci_trb_ring_update_dequeue

/*
 * Copyright (c) 2018 Ondrej Hlavaty, Jan Hrach
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** @addtogroup drvusbxhci
 * @{
 */
/** @file
 * TRB Ring is a data structure for communication between HC and software.
 *
 * Despite this description, it is not used as an hardware structure - all but
 * the Event ring is used as buffer of the TRBs itself, linked by Link TRB to
 * form a (possibly multi-segment) circular buffer.
 *
 * This data structure abstracts this behavior.
 */

#ifndef XHCI_TRB_RING_H
#define XHCI_TRB_RING_H

#include <adt/list.h>
#include <fibril_synch.h>
#include <libarch/config.h>
#include <usb/dma_buffer.h>

typedef struct trb_segment trb_segment_t;
typedef struct xhci_hc xhci_hc_t;
typedef struct xhci_trb xhci_trb_t;
typedef struct xhci_erst_entry xhci_erst_entry_t;

/**
 * A TRB ring of which the software is a producer - command / transfer.
 */
typedef struct xhci_trb_ring {
        list_t segments;                /**< List of assigned segments */
        int segment_count;              /**< Number of segments assigned */

        /**
         * As the link TRBs connect physical addresses, we need to keep track
         * of active segment in virtual memory. The enqueue ptr should always
         * belong to the enqueue segment.
         */
        trb_segment_t *enqueue_segment;
        xhci_trb_t *enqueue_trb;

        uintptr_t dequeue; /**< Last reported position of the dequeue pointer */
        bool pcs;          /**< Producer Cycle State: section 4.9.2 */

        fibril_mutex_t guard;
} xhci_trb_ring_t;

extern errno_t xhci_trb_ring_init(xhci_trb_ring_t *, size_t);
extern void xhci_trb_ring_fini(xhci_trb_ring_t *);
extern errno_t xhci_trb_ring_enqueue(xhci_trb_ring_t *, xhci_trb_t *,
    uintptr_t *);
extern errno_t xhci_trb_ring_enqueue_multiple(xhci_trb_ring_t *, xhci_trb_t *,
    size_t, uintptr_t *);
extern size_t xhci_trb_ring_size(xhci_trb_ring_t *);

extern void xhci_trb_ring_reset_dequeue_state(xhci_trb_ring_t *, uintptr_t *);

/**
 * When an event is received by the upper layer, it needs to update the dequeue
 * pointer inside the ring. Otherwise, the ring will soon show up as full.
 */
static inline void xhci_trb_ring_update_dequeue(xhci_trb_ring_t *ring,
    uintptr_t phys)
{
        ring->dequeue = phys;
}

/**
 * A TRB ring of which the software is a consumer (event rings).
 */
typedef struct xhci_event_ring {
        list_t segments;                /**< List of assigned segments */
        int segment_count;              /**< Number of segments assigned */

        trb_segment_t *dequeue_segment; /**< Current segment */
        xhci_trb_t *dequeue_trb;        /**< Next TRB to be processed */
        uintptr_t dequeue_ptr;  /**< Physical ERDP to be reported to the HC */

        dma_buffer_t erst;      /**< ERST given to the HC */

        bool ccs;               /**< Consumer Cycle State: section 4.9.2 */

        fibril_mutex_t guard;
} xhci_event_ring_t;

extern errno_t xhci_event_ring_init(xhci_event_ring_t *, size_t);
extern void xhci_event_ring_fini(xhci_event_ring_t *);
extern void xhci_event_ring_reset(xhci_event_ring_t *);
extern errno_t xhci_event_ring_dequeue(xhci_event_ring_t *, xhci_trb_t *);

/**
 * A TRB ring of which the software is both consumer and provider.
 */
typedef struct xhci_sw_ring {
        xhci_trb_t *begin, *end;
        xhci_trb_t *enqueue, *dequeue;

        fibril_mutex_t guard;
        fibril_condvar_t enqueued_cv, dequeued_cv;

        bool running;
} xhci_sw_ring_t;

extern void xhci_sw_ring_init(xhci_sw_ring_t *, size_t);

/* Both may block if the ring is full/empty. */
extern errno_t xhci_sw_ring_enqueue(xhci_sw_ring_t *, xhci_trb_t *);
extern errno_t xhci_sw_ring_dequeue(xhci_sw_ring_t *, xhci_trb_t *);

extern void xhci_sw_ring_restart(xhci_sw_ring_t *);
extern void xhci_sw_ring_stop(xhci_sw_ring_t *);
extern void xhci_sw_ring_fini(xhci_sw_ring_t *);

#endif

/**
 * @}
 */

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub