/* * 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 /** * @} */