XenevaOS
Loading...
Searching...
No Matches
virtio_config.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _LINUX_VIRTIO_CONFIG_H
3#define _LINUX_VIRTIO_CONFIG_H
4
5/*
6 * DCL <linux/virtio_config.h> -- a router, and four helpers mainline puts
7 * here that <linux/virtio.h> does not.
8 *
9 * ### Why this is not mainline's 699-line header
10 *
11 * mainline's <linux/virtio_config.h> carries its own copies of the three
12 * types DCL's <linux/virtio.h> already defines: `struct virtqueue_info`
13 * (:29), `struct virtio_config_ops` (:112) and, through the helpers, an
14 * opinion about `struct virtio_device` -- it reads `vdev->features_array`
15 * (:228, :239, :250) and declares `virtio_find_vqs()` with an
16 * `struct irq_affinity *` parameter (:293) that disagrees with the one in
17 * virtio.h. Two definitions of one struct in one translation unit is a hard
18 * redefinition error, and DCL's version is the one that is authoritative:
19 * it is the layout the native AuVirtIO layer fills in and the layout the
20 * module loader indexes, and `features_array` is not a member of it and
21 * cannot be added without deciding where in `_linux_prefix[0x328]` the
22 * feature bitmap mainline keeps there is supposed to live.
23 *
24 * So the header includes <linux/virtio.h> and stops. Everything mainline
25 * defines below the type declarations that DCL does not need is not needed
26 * here either: virtio_cread8/16/32/64, virtio_get_status/set_status,
27 * virtio_device_ready, virtio_find_vqs, the endian wrappers -- all of those
28 * are already in virtio.h, which is the file this one routes to.
29 *
30 * ### The four helpers that are actually missing
31 *
32 * __virtio_test_bit / virtio_has_feature / virtio_cread_feature are what a
33 * mainline driver tests a feature bit with; virtio_device_for_each_vq is the
34 * list walk. They cannot come from virtio.h because mainline does not put
35 * them there, and a ported source is written against mainline's *layout of
36 * the headers*, not against where DCL happens to prefer things.
37 */
38
39#include <linux/virtio.h>
40#include <linux/virtio_byteorder.h> /* the uapi endian wrappers */
41#include <uapi/linux/virtio_config.h> /* VIRTIO_F_* and the status bits */
42
43/*
44 * __virtio_test_bit(vdev, fbit) -- is feature `fbit` agreed with this device?
45 *
46 * mainline reads `vdev->features_array[fbit]`: a bitmap of the features that
47 * survived negotiation, filled once by virtio_finalise_features(). DCL has no
48 * negotiation to have survived -- see shim_finalize_features() in
49 * DCL/virtio_shim.c, which writes the device's whole feature set back
50 * unfiltered and sets FEATURES_OK (it reports failure only if the device
51 * itself rejects). The guest accepts everything the device offers, so
52 * "offered" and "agreed" name the same bits, and the bitmap mainline caches
53 * is here a query instead:
54 *
55 * vdev->config->get_features(vdev)
56 *
57 * which is shim_get_features() -- two reads of the device's DevFeature
58 * registers, select 0 then select 1, reassembled lo||hi. Two MMIO-ish reads
59 * per feature test, where mainline does one load from memory, on paths that
60 * run a handful of times at probe and once per config change: not worth a
61 * cache, and a cache would have to be invalidated by something that does not
62 * exist yet.
63 *
64 * The NULL guard is not defensive padding. use_multiport() calls this at
65 * virtio_console.c:343 during probe, and probe runs for a device whose config
66 * ops were installed by virtio_device_register() -- but a ported source that
67 * builds its own virtio_device would not have gone through that path, and a
68 * NULL call there faults with no register to point at. FALSE is the answer
69 * that keeps the caller on the single-port path, which is the safe one.
70 */
71static inline bool __virtio_test_bit(const struct virtio_device* vdev,
72 unsigned int fbit)
73{
74 u64 features;
75
76 if (!vdev || !vdev->config || !vdev->config->get_features)
77 return false;
78
79 features = vdev->config->get_features((struct virtio_device*)vdev);
80 return (features >> fbit) & 1ULL;
81}
82
83/*
84 * virtio_has_feature() -- the spelling drivers reach for. mainline wraps
85 * __virtio_test_bit() with a debug check that the feature is one the driver
86 * actually offered (typecheck() against the driver's feature_table, via
87 * virtio_check_driver_offered_feature()); that check is a CONFIG that DCL
88 * does not set, and reproducing its *expression* would mean reproducing
89 * typecheck() for a branch that is compiled out. The answer is the same.
90 */
91static inline bool virtio_has_feature(const struct virtio_device* vdev,
92 unsigned int fbit)
93{
94 return __virtio_test_bit(vdev, fbit);
95}
96
97/*
98 * virtio_has_dma_quirk() -- mainline's reverse-polarity ACCESS_PLATFORM test
99 * (linux/virtio_config.h:714 in linux-7.2). A device without the feature has
100 * not announced that it takes bus DMA addresses, so drivers fall back to
101 * their non-DMA-API branch -- sg_phys() addresses instead of
102 * sg_dma_address().
103 *
104 * That fallback is the branch this port wants, not merely tolerates: the
105 * shim never offers VIRTIO_F_ACCESS_PLATFORM, and DCL's scatterlist is
106 * {buf, len} with no page for an IOMMU to translate (see that header).
107 * virtgpu_object.c:166 is the reader that made this a must-have.
108 */
109static inline bool virtio_has_dma_quirk(const struct virtio_device* vdev)
110{
111 return !virtio_has_feature(vdev, VIRTIO_F_ACCESS_PLATFORM);
112}
113
114/*
115 * struct virtio_shm_region -- a shared-memory window as reported through the
116 * config ops' get_shm_region (linux/virtio.h:135). mainline keeps the struct
117 * in this header; the members are mainline's.
118 */
123
124/*
125 * virtio_get_shm_region() -- checked routing to config->get_shm_region.
126 * mainline calls the op unconditionally, on the contract that a device
127 * advertising the region installed it. DCL's shim installs no op at all
128 * (none of its devices has a window), and a NULL call would fault in the
129 * middle of virtio_gpu_init(); answering false is the same "no region" that
130 * mainline's has_host_visible=false arm gets, and it keeps virtio-gpu's
131 * non-blob resource paths working.
132 */
133static inline bool virtio_get_shm_region(struct virtio_device* vdev,
134 struct virtio_shm_region* region_out,
135 u8 id)
136{
137 if (!vdev || !vdev->config || !vdev->config->get_shm_region)
138 return false;
139 return vdev->config->get_shm_region(vdev, region_out, id);
140}
141
142/*
143 * virtio_cread_le() / virtio_cwrite() / virtio_cwrite_le() -- mainline's
144 * endian-converting config accessors, reduced to what LE-on-LE makes them.
145 *
146 * virtio_cread_le() is DCL's virtio_cread() (<linux/virtio.h>) byte for
147 * byte: on a little-endian target the conversion mainline performs is the
148 * identity, and the copy already lands in the caller's member-typed object.
149 *
150 * The write stages the member-typed value from *ptr before handing
151 * config->set() the span -- set's DCL contract is (offset, buf, length) of
152 * raw bytes, and staging through the struct member is what guarantees the
153 * width written is the config field's, not whatever type the caller happened
154 * to hold. The one writer today is virtgpu_kms.c:59's virtio_cwrite_le() of
155 * events_clear.
156 */
157#define virtio_cread_le(vdev, structname, member, ptr) \
158 virtio_cread((vdev), structname, member, ptr)
159
160#define virtio_cwrite(vdev, structname, member, ptr) \
161 do { \
162 typeof(((structname*)0)->member) _dcl_cw = \
163 (typeof(((structname*)0)->member))(*(ptr)); \
164 (vdev)->config->set((vdev), offsetof(structname, member), \
165 &_dcl_cw, sizeof(_dcl_cw)); \
166 } while (0)
167
168#define virtio_cwrite_le(vdev, structname, member, ptr) \
169 virtio_cwrite((vdev), structname, member, ptr)
170
171/*
172 * virtio_cread_feature(vdev, fbit, structname, member, ptr) -- read a config
173 * field, but only if feature `fbit` is agreed; otherwise report -ENOENT.
174 *
175 * mainline's is a statement expression (linux/virtio_config.h:678) with the
176 * same three-part shape, and this is that expression verbatim. The caller at
177 * virtio_console.c:1999 compares the result against 0, so the two arms have
178 * to be 0 and a *negative* errno -- 0 on the read, -ENOENT when the feature
179 * is not there. virtio_cread() comes from <linux/virtio.h>.
180 *
181 * `-ENOENT` needs <linux/err.h>'s errno, which reaches <linux/kernel.h>,
182 * which includes <linux/virtio.h> before this file: the chain is already
183 * closed by the time this macro is expanded, and a macro expands where it is
184 * used, not where it is written.
185 */
186#define virtio_cread_feature(vdev, fbit, structname, member, ptr) \
187 ({ \
188 int _r = 0; \
189 if (!virtio_has_feature(vdev, fbit)) \
190 _r = -ENOENT; \
191 else \
192 virtio_cread((vdev), structname, member, ptr); \
193 _r; \
194 })
195
196/*
197 * virtio_device_for_each_vq(vdev, vq) -- walk every queue on a device.
198 *
199 * mainline's is one line (linux/virtio.h:221):
200 *
201 * list_for_each_entry(vq, &(vdev)->vqs, list)
202 *
203 * and this is the same line. It needs `vdev->vqs` (a list head, appended to
204 * DCL's struct virtio_device) and `vq->list` (appended to struct virtqueue);
205 * both were added for this macro, because the only caller -- remove_vqs(),
206 * virtio_console.c:1895 -- is the loop that flushes and frees every in-flight
207 * receive buffer, and a macro that quietly walked nothing would leave that
208 * loop silently empty rather than obviously wrong.
209 *
210 * The head is initialised by virtio_device_register() and the queues are
211 * linked in by shim_find_vqs(); _virtio_devices[]'s snapshot copy gets its
212 * own empty head so that walking *it* terminates instead of treating the
213 * original's head as if it were a struct virtqueue.
214 */
215#define virtio_device_for_each_vq(vdev, vq) \
216 list_for_each_entry(vq, &(vdev)->vqs, list)
217
218/*
219 * virtio_is_little_endian(vdev) -- byte order of this device's config fields
220 * and vring entries.
221 *
222 * mainline (linux/virtio_config.h:399) forwards to
223 * virtio_legacy_is_little_endian(), which is in <linux/virtio_byteorder.h>
224 * -- the header included above, and DCL's copy answers it with
225 * `#ifdef __LITTLE_ENDIAN` (line 9), which is true because types.h defines
226 * __LITTLE_ENDIAN as 1234 and clang predefines no such macro for
227 * aarch64-unknown-windows. The `vdev` parameter is accepted for mainline's
228 * signature and ignored: the legacy/modern split it exists to query has no
229 * second arm in a tree with one byte order.
230 */
231static inline bool virtio_is_little_endian(struct virtio_device* vdev)
232{
233 (void)vdev;
234 return virtio_legacy_is_little_endian();
235}
236
237/*
238 * The four converters a ported source names, in mainline's order and with
239 * mainline's parameter types -- `struct virtio_device *`, non-const, because
240 * mainline's is and a const mismatch would be a diagnostic on a call site
241 * that has nothing to do with endianness.
242 *
243 * virtio_console.c:553/:554 use cpu_to_virtio32/16 to write a control
244 * message into the out-queue; :1534/:1536/:1543 read the device's own
245 * control word back. They route through virtio_is_little_endian() above, so
246 * all four are the identity on this target -- which is the correct answer,
247 * not a shortcut: QEMU's virtio-serial and the aarch64 ports are both
248 * little-endian, and the bswap that would not happen here is the one that
249 * must not.
250 */
251static inline u16 virtio16_to_cpu(struct virtio_device* vdev, __virtio16 val)
252{
253 return __virtio16_to_cpu(virtio_is_little_endian(vdev), val);
254}
255
256static inline __virtio16 cpu_to_virtio16(struct virtio_device* vdev, u16 val)
257{
258 return __cpu_to_virtio16(virtio_is_little_endian(vdev), val);
259}
260
261static inline u32 virtio32_to_cpu(struct virtio_device* vdev, __virtio32 val)
262{
263 return __virtio32_to_cpu(virtio_is_little_endian(vdev), val);
264}
265
266static inline __virtio32 cpu_to_virtio32(struct virtio_device* vdev, u32 val)
267{
268 return __cpu_to_virtio32(virtio_is_little_endian(vdev), val);
269}
270
271#endif /* _LINUX_VIRTIO_CONFIG_H */
uint64_t u64
Definition kernel.h:17
uint8_t u8
Definition kernel.h:14
uint16_t u16
Definition kernel.h:15
uint32_t u32
Definition kernel.h:16
__u32 __bitwise __virtio32
Definition virtio_types.h:43
__u16 __bitwise __virtio16
Definition virtio_types.h:42
u64(* get_features)(struct virtio_device *vdev)
Definition virtio.h:129
bool(* get_shm_region)(struct virtio_device *vdev, void *region, u8 id)
Definition virtio.h:135
Definition virtio.h:157
struct virtio_config_ops * config
Definition virtio.h:161
Definition virtio_config.h:119
u64 len
Definition virtio_config.h:121
u64 addr
Definition virtio_config.h:120
#define VIRTIO_F_ACCESS_PLATFORM
Definition virtio_config.h:76