xref: /qemu/tests/qtest/libqos/virtio.h (revision 70556264a89a268efba1d7e8e341adcdd7881eb4)
1311e666aSMarc Marí /*
2311e666aSMarc Marí  * libqos virtio definitions
3311e666aSMarc Marí  *
4311e666aSMarc Marí  * Copyright (c) 2014 Marc Marí
5311e666aSMarc Marí  *
6311e666aSMarc Marí  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7311e666aSMarc Marí  * See the COPYING file in the top-level directory.
8311e666aSMarc Marí  */
9311e666aSMarc Marí 
10311e666aSMarc Marí #ifndef LIBQOS_VIRTIO_H
11311e666aSMarc Marí #define LIBQOS_VIRTIO_H
12311e666aSMarc Marí 
13bf3c63d2SMarc Marí #include "libqos/malloc.h"
14bf3c63d2SMarc Marí 
15311e666aSMarc Marí #define QVIRTIO_VENDOR_ID       0x1AF4
16311e666aSMarc Marí 
1746e0cf76SMarc Marí #define QVIRTIO_RESET           0x0
1846e0cf76SMarc Marí #define QVIRTIO_ACKNOWLEDGE     0x1
1946e0cf76SMarc Marí #define QVIRTIO_DRIVER          0x2
20bf3c63d2SMarc Marí #define QVIRTIO_DRIVER_OK       0x4
2146e0cf76SMarc Marí 
22311e666aSMarc Marí #define QVIRTIO_NET_DEVICE_ID   0x1
23311e666aSMarc Marí #define QVIRTIO_BLK_DEVICE_ID   0x2
24311e666aSMarc Marí 
25f294b029SMarc Marí #define QVIRTIO_F_NOTIFY_ON_EMPTY       0x01000000
26f294b029SMarc Marí #define QVIRTIO_F_ANY_LAYOUT            0x08000000
27f294b029SMarc Marí #define QVIRTIO_F_RING_INDIRECT_DESC    0x10000000
28f294b029SMarc Marí #define QVIRTIO_F_RING_EVENT_IDX        0x20000000
291053587cSMarc Marí #define QVIRTIO_F_BAD_FEATURE           0x40000000
30f294b029SMarc Marí 
31bf3c63d2SMarc Marí #define QVRING_DESC_F_NEXT      0x1
32bf3c63d2SMarc Marí #define QVRING_DESC_F_WRITE     0x2
33bf3c63d2SMarc Marí #define QVRING_DESC_F_INDIRECT  0x4
34bf3c63d2SMarc Marí 
35bf3c63d2SMarc Marí #define QVIRTIO_F_NOTIFY_ON_EMPTY       0x01000000
36bf3c63d2SMarc Marí #define QVIRTIO_F_ANY_LAYOUT            0x08000000
37bf3c63d2SMarc Marí #define QVIRTIO_F_RING_INDIRECT_DESC    0x10000000
38bf3c63d2SMarc Marí #define QVIRTIO_F_RING_EVENT_IDX        0x20000000
39bf3c63d2SMarc Marí #define QVIRTIO_F_BAD_FEATURE           0x40000000
40bf3c63d2SMarc Marí 
41bf3c63d2SMarc Marí #define QVRING_AVAIL_F_NO_INTERRUPT     1
42bf3c63d2SMarc Marí 
43bf3c63d2SMarc Marí #define QVRING_USED_F_NO_NOTIFY     1
44bf3c63d2SMarc Marí 
45311e666aSMarc Marí typedef struct QVirtioDevice {
46311e666aSMarc Marí     /* Device type */
47311e666aSMarc Marí     uint16_t device_type;
48311e666aSMarc Marí } QVirtioDevice;
49311e666aSMarc Marí 
50bf3c63d2SMarc Marí typedef struct QVRingDesc {
51bf3c63d2SMarc Marí     uint64_t addr;
52bf3c63d2SMarc Marí     uint32_t len;
53bf3c63d2SMarc Marí     uint16_t flags;
54bf3c63d2SMarc Marí     uint16_t next;
55bf3c63d2SMarc Marí } QVRingDesc;
56bf3c63d2SMarc Marí 
57bf3c63d2SMarc Marí typedef struct QVRingAvail {
58bf3c63d2SMarc Marí     uint16_t flags;
59bf3c63d2SMarc Marí     uint16_t idx;
60bf3c63d2SMarc Marí     uint16_t ring[0]; /* This is an array of uint16_t */
611053587cSMarc Marí     uint16_t used_event;
62bf3c63d2SMarc Marí } QVRingAvail;
63bf3c63d2SMarc Marí 
64bf3c63d2SMarc Marí typedef struct QVRingUsedElem {
65bf3c63d2SMarc Marí     uint32_t id;
66bf3c63d2SMarc Marí     uint32_t len;
67bf3c63d2SMarc Marí } QVRingUsedElem;
68bf3c63d2SMarc Marí 
69bf3c63d2SMarc Marí typedef struct QVRingUsed {
70bf3c63d2SMarc Marí     uint16_t flags;
71bf3c63d2SMarc Marí     uint16_t idx;
72bf3c63d2SMarc Marí     QVRingUsedElem ring[0]; /* This is an array of QVRingUsedElem structs */
731053587cSMarc Marí     uint16_t avail_event;
74bf3c63d2SMarc Marí } QVRingUsed;
75bf3c63d2SMarc Marí 
76bf3c63d2SMarc Marí typedef struct QVirtQueue {
77bf3c63d2SMarc Marí     uint64_t desc; /* This points to an array of QVRingDesc */
78bf3c63d2SMarc Marí     uint64_t avail; /* This points to a QVRingAvail */
79bf3c63d2SMarc Marí     uint64_t used; /* This points to a QVRingDesc */
80bf3c63d2SMarc Marí     uint16_t index;
81bf3c63d2SMarc Marí     uint32_t size;
82bf3c63d2SMarc Marí     uint32_t free_head;
83bf3c63d2SMarc Marí     uint32_t num_free;
84bf3c63d2SMarc Marí     uint32_t align;
85f294b029SMarc Marí     bool indirect;
861053587cSMarc Marí     bool event;
87bf3c63d2SMarc Marí } QVirtQueue;
88bf3c63d2SMarc Marí 
89f294b029SMarc Marí typedef struct QVRingIndirectDesc {
90f294b029SMarc Marí     uint64_t desc; /* This points to an array fo QVRingDesc */
91f294b029SMarc Marí     uint16_t index;
92f294b029SMarc Marí     uint16_t elem;
93f294b029SMarc Marí } QVRingIndirectDesc;
94f294b029SMarc Marí 
9546e0cf76SMarc Marí typedef struct QVirtioBus {
9646e0cf76SMarc Marí     uint8_t (*config_readb)(QVirtioDevice *d, void *addr);
9746e0cf76SMarc Marí     uint16_t (*config_readw)(QVirtioDevice *d, void *addr);
9846e0cf76SMarc Marí     uint32_t (*config_readl)(QVirtioDevice *d, void *addr);
9946e0cf76SMarc Marí     uint64_t (*config_readq)(QVirtioDevice *d, void *addr);
10046e0cf76SMarc Marí 
101bf3c63d2SMarc Marí     /* Get features of the device */
102bf3c63d2SMarc Marí     uint32_t (*get_features)(QVirtioDevice *d);
103bf3c63d2SMarc Marí 
104f294b029SMarc Marí     /* Set features of the device */
105bf3c63d2SMarc Marí     void (*set_features)(QVirtioDevice *d, uint32_t features);
106bf3c63d2SMarc Marí 
107f294b029SMarc Marí     /* Get features of the guest */
108f294b029SMarc Marí     uint32_t (*get_guest_features)(QVirtioDevice *d);
109f294b029SMarc Marí 
11046e0cf76SMarc Marí     /* Get status of the device */
11146e0cf76SMarc Marí     uint8_t (*get_status)(QVirtioDevice *d);
11246e0cf76SMarc Marí 
11346e0cf76SMarc Marí     /* Set status of the device  */
11446e0cf76SMarc Marí     void (*set_status)(QVirtioDevice *d, uint8_t status);
115bf3c63d2SMarc Marí 
11658368113SMarc Marí     /* Get the queue ISR status of the device */
11758368113SMarc Marí     bool (*get_queue_isr_status)(QVirtioDevice *d, QVirtQueue *vq);
11858368113SMarc Marí 
11958368113SMarc Marí     /* Get the configuration ISR status of the device */
12058368113SMarc Marí     bool (*get_config_isr_status)(QVirtioDevice *d);
121bf3c63d2SMarc Marí 
122bf3c63d2SMarc Marí     /* Select a queue to work on */
123bf3c63d2SMarc Marí     void (*queue_select)(QVirtioDevice *d, uint16_t index);
124bf3c63d2SMarc Marí 
125bf3c63d2SMarc Marí     /* Get the size of the selected queue */
126bf3c63d2SMarc Marí     uint16_t (*get_queue_size)(QVirtioDevice *d);
127bf3c63d2SMarc Marí 
128bf3c63d2SMarc Marí     /* Set the address of the selected queue */
129bf3c63d2SMarc Marí     void (*set_queue_address)(QVirtioDevice *d, uint32_t pfn);
130bf3c63d2SMarc Marí 
131bf3c63d2SMarc Marí     /* Setup the virtqueue specified by index */
132bf3c63d2SMarc Marí     QVirtQueue *(*virtqueue_setup)(QVirtioDevice *d, QGuestAllocator *alloc,
133bf3c63d2SMarc Marí                                                                 uint16_t index);
134bf3c63d2SMarc Marí 
135bf3c63d2SMarc Marí     /* Notify changes in virtqueue */
136bf3c63d2SMarc Marí     void (*virtqueue_kick)(QVirtioDevice *d, QVirtQueue *vq);
13746e0cf76SMarc Marí } QVirtioBus;
13846e0cf76SMarc Marí 
139bf3c63d2SMarc Marí static inline uint32_t qvring_size(uint32_t num, uint32_t align)
140bf3c63d2SMarc Marí {
141bf3c63d2SMarc Marí     return ((sizeof(struct QVRingDesc) * num + sizeof(uint16_t) * (3 + num)
142bf3c63d2SMarc Marí         + align - 1) & ~(align - 1))
143bf3c63d2SMarc Marí         + sizeof(uint16_t) * 3 + sizeof(struct QVRingUsedElem) * num;
144bf3c63d2SMarc Marí }
145bf3c63d2SMarc Marí 
14646e0cf76SMarc Marí uint8_t qvirtio_config_readb(const QVirtioBus *bus, QVirtioDevice *d,
14746e0cf76SMarc Marí                                                                 void *addr);
14846e0cf76SMarc Marí uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d,
14946e0cf76SMarc Marí                                                                 void *addr);
15046e0cf76SMarc Marí uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d,
15146e0cf76SMarc Marí                                                                 void *addr);
15246e0cf76SMarc Marí uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d,
15346e0cf76SMarc Marí                                                                 void *addr);
154bf3c63d2SMarc Marí uint32_t qvirtio_get_features(const QVirtioBus *bus, QVirtioDevice *d);
155bf3c63d2SMarc Marí void qvirtio_set_features(const QVirtioBus *bus, QVirtioDevice *d,
156bf3c63d2SMarc Marí                                                             uint32_t features);
15746e0cf76SMarc Marí 
15846e0cf76SMarc Marí void qvirtio_reset(const QVirtioBus *bus, QVirtioDevice *d);
15946e0cf76SMarc Marí void qvirtio_set_acknowledge(const QVirtioBus *bus, QVirtioDevice *d);
16046e0cf76SMarc Marí void qvirtio_set_driver(const QVirtioBus *bus, QVirtioDevice *d);
161bf3c63d2SMarc Marí void qvirtio_set_driver_ok(const QVirtioBus *bus, QVirtioDevice *d);
162bf3c63d2SMarc Marí 
163*70556264SStefan Hajnoczi void qvirtio_wait_queue_isr(const QVirtioBus *bus, QVirtioDevice *d,
164*70556264SStefan Hajnoczi                             QVirtQueue *vq, gint64 timeout_us);
165e8c81b4dSStefan Hajnoczi uint8_t qvirtio_wait_status_byte_no_isr(const QVirtioBus *bus,
166e8c81b4dSStefan Hajnoczi                                         QVirtioDevice *d,
167e8c81b4dSStefan Hajnoczi                                         QVirtQueue *vq,
168e8c81b4dSStefan Hajnoczi                                         uint64_t addr,
169e8c81b4dSStefan Hajnoczi                                         gint64 timeout_us);
170*70556264SStefan Hajnoczi void qvirtio_wait_config_isr(const QVirtioBus *bus, QVirtioDevice *d,
171*70556264SStefan Hajnoczi                              gint64 timeout_us);
172bf3c63d2SMarc Marí QVirtQueue *qvirtqueue_setup(const QVirtioBus *bus, QVirtioDevice *d,
173bf3c63d2SMarc Marí                                         QGuestAllocator *alloc, uint16_t index);
174bf3c63d2SMarc Marí 
175bf3c63d2SMarc Marí void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr);
176f294b029SMarc Marí QVRingIndirectDesc *qvring_indirect_desc_setup(QVirtioDevice *d,
177f294b029SMarc Marí                                         QGuestAllocator *alloc, uint16_t elem);
178f294b029SMarc Marí void qvring_indirect_desc_add(QVRingIndirectDesc *indirect, uint64_t data,
179f294b029SMarc Marí                                                     uint32_t len, bool write);
180bf3c63d2SMarc Marí uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write,
181bf3c63d2SMarc Marí                                                                     bool next);
182f294b029SMarc Marí uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect);
183bf3c63d2SMarc Marí void qvirtqueue_kick(const QVirtioBus *bus, QVirtioDevice *d, QVirtQueue *vq,
184bf3c63d2SMarc Marí                                                             uint32_t free_head);
18546e0cf76SMarc Marí 
1861053587cSMarc Marí void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx);
187311e666aSMarc Marí #endif
188