Adding RPMsg Extension layer implementing zero-copy send and receive.
[processor-sdk/open-amp.git] / lib / include / openamp / virtqueue.h
1 #ifndef VIRTQUEUE_H_
2 #define VIRTQUEUE_H_
4 /*-
5  * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice unmodified, this list of conditions, and the following
13  *    disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
32 #include <stdint.h>
33 typedef uint8_t boolean;
35 #include "openamp/virtio_ring.h"
36 #include "openamp/env.h"
37 #include "metal/dma.h"
38 #include "metal/io.h"
40 /*Error Codes*/
41 #define VQ_ERROR_BASE                                 -3000
42 #define ERROR_VRING_FULL                              (VQ_ERROR_BASE - 1)
43 #define ERROR_INVLD_DESC_IDX                          (VQ_ERROR_BASE - 2)
44 #define ERROR_EMPTY_RING                              (VQ_ERROR_BASE - 3)
45 #define ERROR_NO_MEM                                  (VQ_ERROR_BASE - 4)
46 #define ERROR_VRING_MAX_DESC                          (VQ_ERROR_BASE - 5)
47 #define ERROR_VRING_ALIGN                             (VQ_ERROR_BASE - 6)
48 #define ERROR_VRING_NO_BUFF                           (VQ_ERROR_BASE - 7)
49 #define ERROR_VQUEUE_INVLD_PARAM                      (VQ_ERROR_BASE - 8)
51 #define true                                          1
52 #define false                                         0
53 #define VQUEUE_SUCCESS                                0
54 #define VQUEUE_DEBUG                                  false
56 //TODO:
57 /* This is temporary macro to replace C NULL support.
58  * At the moment all the RTL specific functions are present in env.
59  * */
60 #define VQ_NULL                                       0
62 /* The maximum virtqueue size is 2^15. Use that value as the end of
63  * descriptor chain terminator since it will never be a valid index
64  * in the descriptor table. This is used to verify we are correctly
65  * handling vq_free_cnt.
66  */
67 #define VQ_RING_DESC_CHAIN_END                         32768
68 #define VIRTQUEUE_FLAG_INDIRECT                        0x0001
69 #define VIRTQUEUE_FLAG_EVENT_IDX                       0x0002
70 #define VIRTQUEUE_MAX_NAME_SZ                          32
72 /* Support for indirect buffer descriptors. */
73 #define VIRTIO_RING_F_INDIRECT_DESC    (1 << 28)
75 /* Support to suppress interrupt until specific index is reached. */
76 #define VIRTIO_RING_F_EVENT_IDX        (1 << 29)
78 /*
79  * Hint on how long the next interrupt should be postponed. This is
80  * only used when the EVENT_IDX feature is negotiated.
81  */
82 typedef enum {
83         VQ_POSTPONE_SHORT,
84         VQ_POSTPONE_LONG,
85         VQ_POSTPONE_EMPTIED     /* Until all available desc are used. */
86 } vq_postpone_t;
88 struct virtqueue {
89         //TODO: Need to define proper structure for
90         //        virtio device with RPmsg and paravirtualization.
92         struct virtio_device *vq_dev;
93         char vq_name[VIRTQUEUE_MAX_NAME_SZ];
94         uint16_t vq_queue_index;
95         uint16_t vq_nentries;
96         uint32_t vq_flags;
97         int vq_alignment;
98         int vq_ring_size;
99         boolean vq_inuse;
100         void *vq_ring_mem;
101         void (*callback) (struct virtqueue * vq);
102         void (*notify) (struct virtqueue * vq);
103         int vq_max_indirect_size;
104         int vq_indirect_mem_size;
105         struct vring vq_ring;
106         uint16_t vq_free_cnt;
107         uint16_t vq_queued_cnt;
108         /** Shared memory I/O region */
109         struct metal_io_region *shm_io;
111         /*
112          * Head of the free chain in the descriptor table. If
113          * there are no free descriptors, this will be set to
114          * VQ_RING_DESC_CHAIN_END.
115          */
116         uint16_t vq_desc_head_idx;
118         /*
119          * Last consumed descriptor in the used table,
120          * trails vq_ring.used->idx.
121          */
122         uint16_t vq_used_cons_idx;
124         /*
125          * Last consumed descriptor in the available table -
126          * used by the consumer side.
127          */
128         uint16_t vq_available_idx;
130         uint8_t padd;
132         /*
133          * Used by the host side during callback. Cookie
134          * holds the address of buffer received from other side.
135          * Other fields in this structure are not used currently.
136          */
138         struct vq_desc_extra {
139                 void *cookie;
140                 struct vring_desc *indirect;
141                 uint32_t indirect_paddr;
142                 uint16_t ndescs;
143         } vq_descx[0];
144 };
146 /* struct to hold vring specific information */
147 struct vring_alloc_info {
148         void *vaddr;
149         uint32_t align;
150         uint16_t num_descs;
151         uint16_t pad;
152 };
154 typedef void vq_callback(struct virtqueue *);
155 typedef void vq_notify(struct virtqueue *);
157 #if (VQUEUE_DEBUG == true)
159 #define VQASSERT(_vq, _exp, _msg) do{ \
160     if (!(_exp)){ openamp_print("%s: %s - "_msg, __func__, (_vq)->vq_name); while(1);} \
161     } while(0)
163 #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)            \
164     VQASSERT((_vq), (_idx) < (_vq)->vq_nentries,        \
165     "invalid ring index")
167 #define VQ_RING_ASSERT_CHAIN_TERM(_vq)                \
168     VQASSERT((_vq), (_vq)->vq_desc_head_idx ==            \
169     VQ_RING_DESC_CHAIN_END,    "full ring terminated incorrectly: invalid head")
171 #define VQ_PARAM_CHK(condition, status_var, status_err)                 \
172                        if ((status_var == 0) && (condition))            \
173                        {                                                \
174                            status_var = status_err;                     \
175                        }
177 #define VQUEUE_BUSY(vq)         if ((vq)->vq_inuse == false)                 \
178                                     (vq)->vq_inuse = true;                   \
179                                 else                                         \
180                                     VQASSERT(vq, (vq)->vq_inuse == false,    \
181                                         "VirtQueue already in use")
183 #define VQUEUE_IDLE(vq)            ((vq)->vq_inuse = false)
185 #else
187 #define KASSERT(cond, str)
188 #define VQASSERT(_vq, _exp, _msg)
189 #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)
190 #define VQ_RING_ASSERT_CHAIN_TERM(_vq)
191 #define VQ_PARAM_CHK(condition, status_var, status_err)
192 #define VQUEUE_BUSY(vq)
193 #define VQUEUE_IDLE(vq)
195 #endif
197 int virtqueue_create(struct virtio_device *device, unsigned short id,
198                      char *name, struct vring_alloc_info *ring,
199                      void (*callback) (struct virtqueue * vq),
200                      void (*notify) (struct virtqueue * vq),
201                      struct metal_io_region *shm_io,
202                      struct virtqueue **v_queue);
204 int virtqueue_add_buffer(struct virtqueue *vq, struct metal_sg *sg,
205                          int readable, int writable, void *cookie);
207 int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie,
208                                 struct metal_sg *sg, int writable,
209                                 boolean has_next);
211 void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len, uint16_t *idx);
213 void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t * avail_idx,
214                                      uint32_t * len);
216 int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
217                                   uint32_t len);
219 void virtqueue_disable_cb(struct virtqueue *vq);
221 int virtqueue_enable_cb(struct virtqueue *vq);
223 void virtqueue_kick(struct virtqueue *vq);
225 void virtqueue_free(struct virtqueue *vq);
227 void virtqueue_dump(struct virtqueue *vq);
229 void virtqueue_notification(struct virtqueue *vq);
231 uint32_t virtqueue_get_desc_size(struct virtqueue *vq);
233 uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx);
235 #endif                          /* VIRTQUEUE_H_ */