]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - lib/include/openamp/virtqueue.h
83d2fb54f551797b4a38c43df23d76c319d4930b
[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 "openamp/llist.h"
39 /*Error Codes*/
40 #define VQ_ERROR_BASE                                 -3000
41 #define ERROR_VRING_FULL                              (VQ_ERROR_BASE - 1)
42 #define ERROR_INVLD_DESC_IDX                          (VQ_ERROR_BASE - 2)
43 #define ERROR_EMPTY_RING                              (VQ_ERROR_BASE - 3)
44 #define ERROR_NO_MEM                                  (VQ_ERROR_BASE - 4)
45 #define ERROR_VRING_MAX_DESC                          (VQ_ERROR_BASE - 5)
46 #define ERROR_VRING_ALIGN                             (VQ_ERROR_BASE - 6)
47 #define ERROR_VRING_NO_BUFF                           (VQ_ERROR_BASE - 7)
48 #define ERROR_VQUEUE_INVLD_PARAM                      (VQ_ERROR_BASE - 8)
50 #define true                                          1
51 #define false                                         0
52 #define VQUEUE_SUCCESS                                0
53 #define VQUEUE_DEBUG                                  false
55 //TODO:
56 /* This is temporary macro to replace C NULL support.
57  * At the moment all the RTL specific functions are present in env.
58  * */
59 #define VQ_NULL                                       0
61 /* The maximum virtqueue size is 2^15. Use that value as the end of
62  * descriptor chain terminator since it will never be a valid index
63  * in the descriptor table. This is used to verify we are correctly
64  * handling vq_free_cnt.
65  */
66 #define VQ_RING_DESC_CHAIN_END                         32768
67 #define VIRTQUEUE_FLAG_INDIRECT                        0x0001
68 #define VIRTQUEUE_FLAG_EVENT_IDX                       0x0002
69 #define VIRTQUEUE_MAX_NAME_SZ                          32
71 /* Support for indirect buffer descriptors. */
72 #define VIRTIO_RING_F_INDIRECT_DESC    (1 << 28)
74 /* Support to suppress interrupt until specific index is reached. */
75 #define VIRTIO_RING_F_EVENT_IDX        (1 << 29)
77 /*
78  * Hint on how long the next interrupt should be postponed. This is
79  * only used when the EVENT_IDX feature is negotiated.
80  */
81 typedef enum {
82         VQ_POSTPONE_SHORT,
83         VQ_POSTPONE_LONG,
84         VQ_POSTPONE_EMPTIED     /* Until all available desc are used. */
85 } vq_postpone_t;
87 struct virtqueue {
88         //TODO: Need to define proper structure for
89         //        virtio device with RPmsg and paravirtualization.
91         struct virtio_device *vq_dev;
92         char vq_name[VIRTQUEUE_MAX_NAME_SZ];
93         uint16_t vq_queue_index;
94         uint16_t vq_nentries;
95         uint32_t vq_flags;
96         int vq_alignment;
97         int vq_ring_size;
98         boolean vq_inuse;
99         void *vq_ring_mem;
100         void (*callback) (struct virtqueue * vq);
101         void (*notify) (struct virtqueue * vq);
102         int vq_max_indirect_size;
103         int vq_indirect_mem_size;
104         struct vring vq_ring;
105         uint16_t vq_free_cnt;
106         uint16_t vq_queued_cnt;
108         /*
109          * Head of the free chain in the descriptor table. If
110          * there are no free descriptors, this will be set to
111          * VQ_RING_DESC_CHAIN_END.
112          */
113         uint16_t vq_desc_head_idx;
115         /*
116          * Last consumed descriptor in the used table,
117          * trails vq_ring.used->idx.
118          */
119         uint16_t vq_used_cons_idx;
121         /*
122          * Last consumed descriptor in the available table -
123          * used by the consumer side.
124          */
125         uint16_t vq_available_idx;
127         uint8_t padd;
129         /*
130          * Used by the host side during callback. Cookie
131          * holds the address of buffer received from other side.
132          * Other fields in this structure are not used currently.
133          */
135         struct vq_desc_extra {
136                 void *cookie;
137                 struct vring_desc *indirect;
138                 uint32_t indirect_paddr;
139                 uint16_t ndescs;
140         } vq_descx[0];
141 };
143 /* struct to hold vring specific information */
144 struct vring_alloc_info {
145         void *vaddr;
146         uint32_t align;
147         uint16_t num_descs;
148         uint16_t pad;
149 };
151 typedef void vq_callback(struct virtqueue *);
152 typedef void vq_notify(struct virtqueue *);
154 #if (VQUEUE_DEBUG == true)
156 #define VQASSERT(_vq, _exp, _msg) do{ \
157     if (!(_exp)){ printf("%s: %s - "_msg, __func__, (_vq)->vq_name); while(1);} \
158     } while(0)
160 #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)            \
161     VQASSERT((_vq), (_idx) < (_vq)->vq_nentries,        \
162     "invalid ring index")
164 #define VQ_RING_ASSERT_CHAIN_TERM(_vq)                \
165     VQASSERT((_vq), (_vq)->vq_desc_head_idx ==            \
166     VQ_RING_DESC_CHAIN_END,    "full ring terminated incorrectly: invalid head")
168 #define VQ_PARAM_CHK(condition, status_var, status_err)                 \
169                        if ((status_var == 0) && (condition))            \
170                        {                                                \
171                            status_var = status_err;                     \
172                        }
174 #define VQUEUE_BUSY(vq)         if ((vq)->vq_inuse == false)                 \
175                                     (vq)->vq_inuse = true;                   \
176                                 else                                         \
177                                     VQASSERT(vq, (vq)->vq_inuse == false,    \
178                                         "VirtQueue already in use")
180 #define VQUEUE_IDLE(vq)            ((vq)->vq_inuse = false)
182 #else
184 #define KASSERT(cond, str)
185 #define VQASSERT(_vq, _exp, _msg)
186 #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)
187 #define VQ_RING_ASSERT_CHAIN_TERM(_vq)
188 #define VQ_PARAM_CHK(condition, status_var, status_err)
189 #define VQUEUE_BUSY(vq)
190 #define VQUEUE_IDLE(vq)
192 #endif
194 int virtqueue_create(struct virtio_device *device, unsigned short id,
195                      char *name, struct vring_alloc_info *ring,
196                      void (*callback) (struct virtqueue * vq),
197                      void (*notify) (struct virtqueue * vq),
198                      struct virtqueue **v_queue);
200 int virtqueue_add_buffer(struct virtqueue *vq, struct llist *buffer,
201                          int readable, int writable, void *cookie);
203 int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie,
204                                 void *buffer_addr, uint32_t len, int writable,
205                                 boolean has_next);
207 void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len);
209 void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t * avail_idx,
210                                      uint32_t * len);
212 int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
213                                   uint32_t len);
215 void virtqueue_disable_cb(struct virtqueue *vq);
217 int virtqueue_enable_cb(struct virtqueue *vq);
219 void virtqueue_kick(struct virtqueue *vq);
221 void virtqueue_free(struct virtqueue *vq);
223 void virtqueue_dump(struct virtqueue *vq);
225 void virtqueue_notification(struct virtqueue *vq);
227 uint32_t virtqueue_get_desc_size(struct virtqueue *vq);
229 #endif                          /* VIRTQUEUE_H_ */