1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#pragma once
6
7#include <ddk/io-buffer.h>
8#include <zircon/listnode.h>
9
10#include "xhci-hw.h"
11
12// used for both command ring and transfer rings
13typedef struct xhci_transfer_ring {
14    io_buffer_t buffer;
15    xhci_trb_t* start;
16    xhci_trb_t* current;        // next to be filled by producer
17    uint8_t pcs;                // producer cycle status
18    xhci_trb_t* dequeue_ptr;    // next to be processed by consumer
19                                // (not used for command ring)
20    size_t size;                // number of TRBs in ring
21    bool full;                  // true if there are no available TRBs,
22                                // this is needed to differentiate between
23                                // an empty and full ring state
24} xhci_transfer_ring_t;
25
26typedef struct xhci_event_ring {
27    io_buffer_t buffer;
28    xhci_trb_t* start;
29    xhci_trb_t* current;
30    xhci_trb_t* end;
31    uint8_t ccs; // consumer cycle status
32} xhci_event_ring_t;
33
34typedef struct xhci xhci_t;
35
36zx_status_t xhci_transfer_ring_init(xhci_transfer_ring_t* tr, zx_handle_t bti_handle, int count);
37void xhci_transfer_ring_free(xhci_transfer_ring_t* ring);
38size_t xhci_transfer_ring_free_trbs(xhci_transfer_ring_t* ring);
39zx_status_t xhci_event_ring_init(xhci_event_ring_t*, zx_handle_t bti_handle,
40                                 erst_entry_t* erst_array, int count);
41void xhci_event_ring_free(xhci_event_ring_t* ring);
42void xhci_clear_trb(xhci_trb_t* trb);
43// Converts a transfer trb into a NO-OP transfer TRB, does nothing if it is the LINK TRB.
44void xhci_set_transfer_noop_trb(xhci_trb_t* trb);
45void* xhci_read_trb_ptr(xhci_transfer_ring_t* ring, xhci_trb_t* trb);
46xhci_trb_t* xhci_get_next_trb(xhci_transfer_ring_t* ring, xhci_trb_t* trb);
47void xhci_increment_ring(xhci_transfer_ring_t* ring);
48void xhci_set_dequeue_ptr(xhci_transfer_ring_t* ring, xhci_trb_t* new_ptr);
49
50// Returns the TRB corresponding to the given physical address, or NULL if the address is invalid.
51xhci_trb_t* xhci_transfer_ring_phys_to_trb(xhci_transfer_ring_t* ring, zx_paddr_t phys);
52
53static inline zx_paddr_t xhci_transfer_ring_start_phys(xhci_transfer_ring_t* ring) {
54    return io_buffer_phys(&ring->buffer);
55}
56
57static inline zx_paddr_t xhci_transfer_ring_current_phys(xhci_transfer_ring_t* ring) {
58    return io_buffer_phys(&ring->buffer) + ((ring->current - ring->start) * sizeof(xhci_trb_t));
59}
60
61static inline zx_paddr_t xhci_event_ring_start_phys(xhci_event_ring_t* ring) {
62    return io_buffer_phys(&ring->buffer);
63}
64
65static inline zx_paddr_t xhci_event_ring_current_phys(xhci_event_ring_t* ring) {
66    return io_buffer_phys(&ring->buffer) + ((ring->current - ring->start) * sizeof(xhci_trb_t));
67}
68