Skip to content

Commit e63d07d

Browse files
Dan Mileaarnopo
Dan Milea
authored andcommitted
virtio: virtio-mmio framework
VIRTIO MMIO transport for OpenAMP. Signed-off-by: Dan Milea <[email protected]>
1 parent 5891cb4 commit e63d07d

File tree

9 files changed

+710
-10
lines changed

9 files changed

+710
-10
lines changed

cmake/options.cmake

+6
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ if (NOT WITH_VIRTIO_DEVICE AND NOT WITH_VIRTIO_SLAVE)
7878
add_definitions(-DVIRTIO_DRIVER_ONLY)
7979
endif (NOT WITH_VIRTIO_DEVICE AND NOT WITH_VIRTIO_SLAVE)
8080

81+
option (WITH_VIRTIO_MMIO_DRV "Build with virtio mmio driver support enabled" OFF)
82+
83+
if (WITH_VIRTIO_MMIO_DRV)
84+
add_definitions(-DWITH_VIRTIO_MMIO_DRV)
85+
endif (WITH_VIRTIO_MMIO_DRV)
86+
8187
option (WITH_DCACHE_VRINGS "Build with vrings cache operations enabled" OFF)
8288

8389
if (WITH_DCACHE_VRINGS)

lib/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ collect (PROJECT_LIB_SOURCES version.c)
1010
add_subdirectory (virtio)
1111
add_subdirectory (rpmsg)
1212
add_subdirectory (remoteproc)
13+
if (WITH_VIRTIO_MMIO_DRV)
14+
add_subdirectory (virtio_mmio)
15+
endif (WITH_VIRTIO_MMIO_DRV)
1316

1417
if (WITH_PROXY)
1518
add_subdirectory (proxy)

lib/include/openamp/rpmsg_virtio.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev,
142142
vq_callback *callbacks)
143143
{
144144
return virtio_create_virtqueues(rvdev->vdev, flags, nvqs, names,
145-
callbacks);
145+
callbacks, NULL);
146146
}
147147

148148
/**

lib/include/openamp/virtio.h

+63-7
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ __deprecated static inline int deprecated_virtio_dev_slave(void)
9898
struct virtio_device_id {
9999
uint32_t device;
100100
uint32_t vendor;
101+
uint32_t version;
101102
};
102103

103104
/*
@@ -120,6 +121,45 @@ struct virtio_device_id {
120121
#define VIRTIO_TRANSPORT_F_START 28
121122
#define VIRTIO_TRANSPORT_F_END 32
122123

124+
#ifdef VIRTIO_DEBUG
125+
#include <metal/log.h>
126+
127+
#define VIRTIO_ASSERT(_exp, _msg) do { \
128+
int exp = (_exp); \
129+
if (!(exp)) { \
130+
metal_log(METAL_LOG_EMERGENCY, \
131+
"FATAL: %s - " _msg, __func__); \
132+
metal_assert(exp); \
133+
} \
134+
} while (0)
135+
#else
136+
#define VIRTIO_ASSERT(_exp, _msg) metal_assert(_exp)
137+
#endif /* VIRTIO_DEBUG */
138+
139+
#define VRING_ALIGNMENT 4096
140+
141+
#define VIRTIO_RING_SIZE(n, align) \
142+
(( \
143+
( \
144+
sizeof(struct vring_desc) * n + \
145+
sizeof(struct vring_avail) + \
146+
sizeof(uint16_t) * (n + 1) + \
147+
align - 1 \
148+
) \
149+
& ~(align - 1) \
150+
) + \
151+
sizeof(struct vring_used) + \
152+
sizeof(struct vring_used_elem) * n + sizeof(uint16_t))
153+
154+
#define VRING_DECLARE(name, n, align) \
155+
static char __vrbuf_##name[VIRTIO_RING_SIZE(n, align)] __aligned(VRING_ALIGNMENT); \
156+
static struct vring __vring_##name = { \
157+
.desc = (void *)__vrbuf_##name, \
158+
.avail = (void *)((unsigned long)__vrbuf_##name + n * sizeof(struct vring_desc)), \
159+
.used = (void *)((unsigned long)__vrbuf_##name + ((n * sizeof(struct vring_desc) + \
160+
(n + 1) * sizeof(uint16_t) + align - 1) & ~(align - 1))), \
161+
}
162+
123163
typedef void (*virtio_dev_reset_cb)(struct virtio_device *vdev);
124164

125165
struct virtio_dispatch;
@@ -180,7 +220,8 @@ struct virtio_dispatch {
180220
int (*create_virtqueues)(struct virtio_device *vdev,
181221
unsigned int flags,
182222
unsigned int nvqs, const char *names[],
183-
vq_callback callbacks[]);
223+
vq_callback callbacks[],
224+
void *callback_args[]);
184225
void (*delete_virtqueues)(struct virtio_device *vdev);
185226
uint8_t (*get_status)(struct virtio_device *dev);
186227
void (*set_status)(struct virtio_device *dev, uint8_t status);
@@ -205,17 +246,18 @@ struct virtio_dispatch {
205246
/**
206247
* @brief Create the virtio device virtqueue.
207248
*
208-
* @param vdev Pointer to virtio device structure.
209-
* @param flags Create flag.
210-
* @param nvqs The virtqueue number.
211-
* @param names Virtqueue names.
212-
* @param callbacks Virtqueue callback functions.
249+
* @param vdev Pointer to virtio device structure.
250+
* @param flags Create flag.
251+
* @param nvqs The virtqueue number.
252+
* @param names Virtqueue names.
253+
* @param callbacks Virtqueue callback functions.
254+
* @param callback_args Virtqueue callback function arguments.
213255
*
214256
* @return 0 on success, otherwise error code.
215257
*/
216258
int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags,
217259
unsigned int nvqs, const char *names[],
218-
vq_callback callbacks[]);
260+
vq_callback callbacks[], void *callback_args[]);
219261

220262
/**
221263
* @brief Delete the virtio device virtqueue.
@@ -236,6 +278,20 @@ static inline int virtio_delete_virtqueues(struct virtio_device *vdev)
236278
return 0;
237279
}
238280

281+
/**
282+
* @brief Get device ID.
283+
*
284+
* @param dev Pointer to device structure.
285+
*
286+
* @return Device ID value.
287+
*/
288+
static inline uint32_t virtio_get_devid(const struct virtio_device *vdev)
289+
{
290+
if (!vdev)
291+
return 0;
292+
return vdev->id.device;
293+
}
294+
239295
/**
240296
* @brief Retrieve device status.
241297
*

lib/include/openamp/virtio_mmio.h

+216
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/*
2+
* Copyright (c) 2022 Wind River Systems, Inc.
3+
* Based on Virtio PCI driver by Anthony Liguori, copyright IBM Corp. 2007
4+
*
5+
* SPDX-License-Identifier: BSD-3-Clause
6+
*/
7+
8+
#ifndef OPENAMP_VIRTIO_MMIO_H
9+
#define OPENAMP_VIRTIO_MMIO_H
10+
11+
#include <metal/device.h>
12+
#include <openamp/virtio.h>
13+
#include <openamp/virtqueue.h>
14+
15+
#ifdef __cplusplus
16+
extern "C" {
17+
#endif
18+
19+
/* Enable support for legacy devices */
20+
#define VIRTIO_MMIO_LEGACY
21+
22+
/* Control registers */
23+
24+
/* Magic value ("virt" string) - Read Only */
25+
#define VIRTIO_MMIO_MAGIC_VALUE 0x000
26+
27+
#define VIRTIO_MMIO_MAGIC_VALUE_STRING ('v' | ('i' << 8) | ('r' << 16) | ('t' << 24))
28+
29+
/* Virtio device version - Read Only */
30+
#define VIRTIO_MMIO_VERSION 0x004
31+
32+
/* Virtio device ID - Read Only */
33+
#define VIRTIO_MMIO_DEVICE_ID 0x008
34+
35+
/* Virtio vendor ID - Read Only */
36+
#define VIRTIO_MMIO_VENDOR_ID 0x00c
37+
38+
/*
39+
* Bitmask of the features supported by the device (host)
40+
* (32 bits per set) - Read Only
41+
*/
42+
#define VIRTIO_MMIO_DEVICE_FEATURES 0x010
43+
44+
/* Device (host) features set selector - Write Only */
45+
#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014
46+
47+
/*
48+
* Bitmask of features activated by the driver (guest)
49+
* (32 bits per set) - Write Only
50+
*/
51+
#define VIRTIO_MMIO_DRIVER_FEATURES 0x020
52+
53+
/* Activated features set selector - Write Only */
54+
#define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024
55+
56+
#ifndef VIRTIO_MMIO_NO_LEGACY /* LEGACY DEVICES ONLY! */
57+
/* Guest's memory page size in bytes - Write Only */
58+
#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028
59+
#endif
60+
61+
/* Queue selector - Write Only */
62+
#define VIRTIO_MMIO_QUEUE_SEL 0x030
63+
64+
/* Maximum size of the currently selected queue - Read Only */
65+
#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034
66+
67+
/* Queue size for the currently selected queue - Write Only */
68+
#define VIRTIO_MMIO_QUEUE_NUM 0x038
69+
70+
#ifdef VIRTIO_MMIO_LEGACY
71+
/* Used Ring alignment for the currently selected queue - Write Only */
72+
#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c
73+
/* Guest's PFN for the currently selected queue - Read Write */
74+
#define VIRTIO_MMIO_QUEUE_PFN 0x040
75+
#endif
76+
77+
/* Ready bit for the currently selected queue - Read Write */
78+
#define VIRTIO_MMIO_QUEUE_READY 0x044
79+
80+
/* Queue notifier - Write Only */
81+
#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050
82+
83+
/* Interrupt status - Read Only */
84+
#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060
85+
86+
/* Interrupt acknowledge - Write Only */
87+
#define VIRTIO_MMIO_INTERRUPT_ACK 0x064
88+
89+
/* Device status register - Read Write */
90+
#define VIRTIO_MMIO_STATUS 0x070
91+
92+
/* Selected queue's Descriptor Table address, 64 bits in two halves */
93+
#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080
94+
#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084
95+
96+
/* Selected queue's Available Ring address, 64 bits in two halves */
97+
#define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090
98+
#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094
99+
100+
/* Selected queue's Used Ring address, 64 bits in two halves */
101+
#define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0
102+
#define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4
103+
104+
/* Shared memory region id */
105+
#define VIRTIO_MMIO_SHM_SEL 0x0ac
106+
107+
/* Shared memory region length, 64 bits in two halves */
108+
#define VIRTIO_MMIO_SHM_LEN_LOW 0x0b0
109+
#define VIRTIO_MMIO_SHM_LEN_HIGH 0x0b4
110+
111+
/* Shared memory region base address, 64 bits in two halves */
112+
#define VIRTIO_MMIO_SHM_BASE_LOW 0x0b8
113+
#define VIRTIO_MMIO_SHM_BASE_HIGH 0x0bc
114+
115+
/* Configuration atomicity value */
116+
#define VIRTIO_MMIO_CONFIG_GENERATION 0x0fc
117+
118+
/*
119+
* The config space is defined by each driver as
120+
* the per-driver configuration space - Read Write
121+
*/
122+
#define VIRTIO_MMIO_CONFIG 0x100
123+
124+
/* Interrupt flags (re: interrupt status & acknowledge registers) */
125+
#define VIRTIO_MMIO_INT_VRING (1 << 0)
126+
#define VIRTIO_MMIO_INT_CONFIG (1 << 1)
127+
128+
/* Data buffer size for preallocated buffers before vring */
129+
#define VIRTIO_MMIO_MAX_DATA_SIZE 128
130+
131+
/**
132+
* struct virtio_mmio_dev_mem: VIRTIO MMIO memory area
133+
* @base memory region physical address
134+
* @size memory region size
135+
*/
136+
struct virtio_mmio_dev_mem {
137+
void *base;
138+
size_t size;
139+
};
140+
141+
/**
142+
* struct virtio_mmio_device: representation of a VIRTIO MMIO device
143+
* @vdev base virtio device struct
144+
* @cfg_io device configuration space metal_io_region
145+
* @shm_io pre-shared memory space metal_io_region
146+
* @shm_device shared memory device
147+
* @cfg_mem VIRTIO device configuration space
148+
* @shm_mem VIRTIO device pre-shared memory
149+
* @device_mode VIRTIO_DEV_DRIVER or VIRTIO_DEV_DEVICE
150+
* @irq interrupt number
151+
* @user_data custom user data
152+
*/
153+
struct virtio_mmio_device {
154+
struct virtio_device vdev;
155+
struct metal_io_region *cfg_io;
156+
struct metal_io_region *shm_io;
157+
struct metal_device shm_device;
158+
struct virtio_mmio_dev_mem cfg_mem;
159+
struct virtio_mmio_dev_mem shm_mem;
160+
unsigned int device_mode;
161+
unsigned int irq;
162+
void *user_data;
163+
};
164+
165+
/**
166+
* @brief Register a VIRTIO device with the VIRTIO stack.
167+
*
168+
* @param dev Pointer to device structure.
169+
* @param vq_num Number of virtqueues the device uses.
170+
* @param vqs Array of pointers to vthe virtqueues used by the device.
171+
*/
172+
void virtio_mmio_register_device(struct virtio_device *vdev, int vq_num, struct virtqueue **vqs);
173+
174+
/**
175+
* @brief Setup a virtqueue structure.
176+
*
177+
* @param dev Pointer to device structure.
178+
* @param idx Index of the virtqueue.
179+
* @param vq Pointer to virtqueue structure.
180+
* @param cb Pointer to virtqueue callback. Can be NULL.
181+
* @param cb_arg Argument for the virtqueue callback.
182+
*
183+
* @return pointer to virtqueue structure.
184+
*/
185+
struct virtqueue *virtio_mmio_setup_virtqueue(struct virtio_device *vdev,
186+
unsigned int idx,
187+
struct virtqueue *vq,
188+
void (*cb)(void *),
189+
void *cb_arg,
190+
const char *vq_name);
191+
192+
/**
193+
* @brief VIRTIO MMIO device initialization.
194+
*
195+
* @param vmdev Pointer to virtio_mmio_device structure.
196+
* @param virt_mem_ptr Guest virtio (shared) memory base address (virtual).
197+
* @param cfg_mem_ptr Virtio device configuration memory base address (virtual).
198+
* @param user_data Pointer to custom user data.
199+
*
200+
* @return int 0 for success.
201+
*/
202+
int virtio_mmio_device_init(struct virtio_mmio_device *vmdev, uintptr_t virt_mem_ptr,
203+
uintptr_t cfg_mem_ptr, void *user_data);
204+
205+
/**
206+
* @brief VIRTIO MMIO interrupt service routine.
207+
*
208+
* @param vdev Pointer to virtio_device structure.
209+
*/
210+
void virtio_mmio_isr(struct virtio_device *vdev);
211+
212+
#ifdef __cplusplus
213+
}
214+
#endif
215+
216+
#endif /* OPENAMP_VIRTIO_MMIO_H */

lib/include/openamp/virtqueue.h

+25
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ struct virtqueue {
6363
uint16_t vq_queue_index;
6464
uint16_t vq_nentries;
6565
void (*callback)(struct virtqueue *vq);
66+
void *priv;
6667
void (*notify)(struct virtqueue *vq);
6768
struct vring vq_ring;
6869
uint16_t vq_free_cnt;
@@ -334,6 +335,30 @@ uint32_t virtqueue_get_desc_size(struct virtqueue *vq);
334335
uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx);
335336
void *virtqueue_get_buffer_addr(struct virtqueue *vq, uint16_t idx);
336337

338+
/**
339+
* @brief Test if virtqueue is empty
340+
*
341+
* @param vq Pointer to VirtIO queue control block
342+
*
343+
* @return 1 if virtqueue is empty, 0 otherwise
344+
*/
345+
static inline int virtqueue_empty(struct virtqueue *vq)
346+
{
347+
return (vq->vq_nentries == vq->vq_free_cnt);
348+
}
349+
350+
/**
351+
* @brief Test if virtqueue is full
352+
*
353+
* @param vq Pointer to VirtIO queue control block
354+
*
355+
* @return 1 if virtqueue is full, 0 otherwise
356+
*/
357+
static inline int virtqueue_full(struct virtqueue *vq)
358+
{
359+
return (vq->vq_free_cnt == 0);
360+
}
361+
337362
#if defined __cplusplus
338363
}
339364
#endif

0 commit comments

Comments
 (0)