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 #pragma once
5 
6 #include <ddk/io-buffer.h>
7 #include <virtio/virtio_ring.h>
8 #include <zircon/types.h>
9 
10 #include "trace.h"
11 
12 namespace virtio {
13 
14 class Device;
15 
16 class Ring {
17 public:
18     Ring(Device* device);
19     ~Ring();
20 
21     // Initialize ring |index| with default (device-offered) size.
22     zx_status_t Init(uint16_t index);
23     zx_status_t Init(uint16_t index, uint16_t count);
24 
25     void FreeDesc(uint16_t desc_index);
26     struct vring_desc* AllocDescChain(uint16_t count, uint16_t* start_index);
27     void SubmitChain(uint16_t desc_index);
28     void Kick();
29 
DescFromIndex(uint16_t index)30     struct vring_desc* DescFromIndex(uint16_t index) {
31         return &ring_.desc[index];
32     }
33 
34     template <typename T>
35     void IrqRingUpdate(T free_chain);
36 
37 private:
38     Device* device_ = nullptr;
39 
40     io_buffer_t ring_buf_;
41 
42     uint16_t index_ = 0;
43 
44     vring ring_ = {};
45 };
46 
47 // perform the main loop of finding free descriptor chains and passing it to a passed in function
48 template <typename T>
IrqRingUpdate(T free_chain)49 inline void Ring::IrqRingUpdate(T free_chain) {
50     // TRACEF("used flags %#x idx %#x last_used %u\n",
51     //         ring_.used->flags, ring_.used->idx, ring_.last_used);
52 
53     // find a new free chain of descriptors
54     uint16_t cur_idx = ring_.used->idx;
55     uint16_t i = ring_.last_used;
56     for (; i != cur_idx; ++i) {
57         // TRACEF("looking at idx %u\n", i);
58 
59         struct vring_used_elem* used_elem = &ring_.used->ring[i & ring_.num_mask];
60         // TRACEF("used chain id %u, len %u\n", used_elem->id, used_elem->len);
61 
62         // free the chain
63         free_chain(used_elem);
64     }
65     ring_.last_used = i;
66 }
67 
68 void virtio_dump_desc(const struct vring_desc* desc);
69 
70 } // namespace virtio
71