Skip to content

Commit e7d4c1c

Browse files
author
Paolo Abeni
committed
virtio: introduce extended features
The virtio specifications allows for up to 128 bits for the device features. Soon we are going to use some of the 'extended' bits features (above 64) for the virtio_net driver. Introduce extended features as a fixed size array of u64. To minimize the diffstat allows legacy driver to access the low 64 bits via a transparent union. Introduce an extended get_extended_features configuration callback that devices supporting the extended features range must implement in place of the traditional one. Note that legacy and transport features don't need any change, as they are always in the low 64 bit range. Acked-by: Jason Wang <jasowang@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent eade9f5 commit e7d4c1c

File tree

5 files changed

+156
-54
lines changed

5 files changed

+156
-54
lines changed

drivers/virtio/virtio.c

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ static ssize_t features_show(struct device *_d,
5353

5454
/* We actually represent this as a bitstring, as it could be
5555
* arbitrary length in future. */
56-
for (i = 0; i < sizeof(dev->features)*8; i++)
56+
for (i = 0; i < VIRTIO_FEATURES_MAX; i++)
5757
len += sysfs_emit_at(buf, len, "%c",
5858
__virtio_test_bit(dev, i) ? '1' : '0');
5959
len += sysfs_emit_at(buf, len, "\n");
@@ -272,62 +272,68 @@ static int virtio_dev_probe(struct device *_d)
272272
int err, i;
273273
struct virtio_device *dev = dev_to_virtio(_d);
274274
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
275-
u64 device_features;
276-
u64 driver_features;
275+
u64 device_features[VIRTIO_FEATURES_DWORDS];
276+
u64 driver_features[VIRTIO_FEATURES_DWORDS];
277277
u64 driver_features_legacy;
278278

279279
/* We have a driver! */
280280
virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER);
281281

282282
/* Figure out what features the device supports. */
283-
device_features = dev->config->get_features(dev);
283+
virtio_get_features(dev, device_features);
284284

285285
/* Figure out what features the driver supports. */
286-
driver_features = 0;
286+
virtio_features_zero(driver_features);
287287
for (i = 0; i < drv->feature_table_size; i++) {
288288
unsigned int f = drv->feature_table[i];
289-
BUG_ON(f >= 64);
290-
driver_features |= (1ULL << f);
289+
if (!WARN_ON_ONCE(f >= VIRTIO_FEATURES_MAX))
290+
virtio_features_set_bit(driver_features, f);
291291
}
292292

293293
/* Some drivers have a separate feature table for virtio v1.0 */
294294
if (drv->feature_table_legacy) {
295295
driver_features_legacy = 0;
296296
for (i = 0; i < drv->feature_table_size_legacy; i++) {
297297
unsigned int f = drv->feature_table_legacy[i];
298-
BUG_ON(f >= 64);
299-
driver_features_legacy |= (1ULL << f);
298+
if (!WARN_ON_ONCE(f >= 64))
299+
driver_features_legacy |= (1ULL << f);
300300
}
301301
} else {
302-
driver_features_legacy = driver_features;
302+
driver_features_legacy = driver_features[0];
303303
}
304304

305-
if (device_features & (1ULL << VIRTIO_F_VERSION_1))
306-
dev->features = driver_features & device_features;
307-
else
308-
dev->features = driver_features_legacy & device_features;
305+
if (virtio_features_test_bit(device_features, VIRTIO_F_VERSION_1)) {
306+
for (i = 0; i < VIRTIO_FEATURES_DWORDS; ++i)
307+
dev->features_array[i] = driver_features[i] &
308+
device_features[i];
309+
} else {
310+
virtio_features_from_u64(dev->features_array,
311+
driver_features_legacy &
312+
device_features[0]);
313+
}
309314

310315
/* When debugging, user may filter some features by hand. */
311316
virtio_debug_device_filter_features(dev);
312317

313318
/* Transport features always preserved to pass to finalize_features. */
314319
for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++)
315-
if (device_features & (1ULL << i))
320+
if (virtio_features_test_bit(device_features, i))
316321
__virtio_set_bit(dev, i);
317322

318323
err = dev->config->finalize_features(dev);
319324
if (err)
320325
goto err;
321326

322327
if (drv->validate) {
323-
u64 features = dev->features;
328+
u64 features[VIRTIO_FEATURES_DWORDS];
324329

330+
virtio_features_copy(features, dev->features_array);
325331
err = drv->validate(dev);
326332
if (err)
327333
goto err;
328334

329335
/* Did validation change any features? Then write them again. */
330-
if (features != dev->features) {
336+
if (!virtio_features_equal(features, dev->features_array)) {
331337
err = dev->config->finalize_features(dev);
332338
if (err)
333339
goto err;
@@ -701,6 +707,9 @@ EXPORT_SYMBOL_GPL(virtio_device_reset_done);
701707

702708
static int virtio_init(void)
703709
{
710+
BUILD_BUG_ON(offsetof(struct virtio_device, features) !=
711+
offsetof(struct virtio_device, features_array[0]));
712+
704713
if (bus_register(&virtio_bus) != 0)
705714
panic("virtio bus registration failed");
706715
virtio_debug_init();

drivers/virtio/virtio_debug.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ static struct dentry *virtio_debugfs_dir;
88

99
static int virtio_debug_device_features_show(struct seq_file *s, void *data)
1010
{
11+
u64 device_features[VIRTIO_FEATURES_DWORDS];
1112
struct virtio_device *dev = s->private;
12-
u64 device_features;
1313
unsigned int i;
1414

15-
device_features = dev->config->get_features(dev);
16-
for (i = 0; i < BITS_PER_LONG_LONG; i++) {
17-
if (device_features & (1ULL << i))
15+
virtio_get_features(dev, device_features);
16+
for (i = 0; i < VIRTIO_FEATURES_MAX; i++) {
17+
if (virtio_features_test_bit(device_features, i))
1818
seq_printf(s, "%u\n", i);
1919
}
2020
return 0;
@@ -26,8 +26,8 @@ static int virtio_debug_filter_features_show(struct seq_file *s, void *data)
2626
struct virtio_device *dev = s->private;
2727
unsigned int i;
2828

29-
for (i = 0; i < BITS_PER_LONG_LONG; i++) {
30-
if (dev->debugfs_filter_features & (1ULL << i))
29+
for (i = 0; i < VIRTIO_FEATURES_MAX; i++) {
30+
if (virtio_features_test_bit(dev->debugfs_filter_features, i))
3131
seq_printf(s, "%u\n", i);
3232
}
3333
return 0;
@@ -39,7 +39,7 @@ static int virtio_debug_filter_features_clear(void *data, u64 val)
3939
struct virtio_device *dev = data;
4040

4141
if (val == 1)
42-
dev->debugfs_filter_features = 0;
42+
virtio_features_zero(dev->debugfs_filter_features);
4343
return 0;
4444
}
4545

@@ -50,9 +50,10 @@ static int virtio_debug_filter_feature_add(void *data, u64 val)
5050
{
5151
struct virtio_device *dev = data;
5252

53-
if (val >= BITS_PER_LONG_LONG)
53+
if (val >= VIRTIO_FEATURES_MAX)
5454
return -EINVAL;
55-
dev->debugfs_filter_features |= BIT_ULL_MASK(val);
55+
56+
virtio_features_set_bit(dev->debugfs_filter_features, val);
5657
return 0;
5758
}
5859

@@ -63,9 +64,10 @@ static int virtio_debug_filter_feature_del(void *data, u64 val)
6364
{
6465
struct virtio_device *dev = data;
6566

66-
if (val >= BITS_PER_LONG_LONG)
67+
if (val >= VIRTIO_FEATURES_MAX)
6768
return -EINVAL;
68-
dev->debugfs_filter_features &= ~BIT_ULL_MASK(val);
69+
70+
virtio_features_clear_bit(dev->debugfs_filter_features, val);
6971
return 0;
7072
}
7173

@@ -91,7 +93,8 @@ EXPORT_SYMBOL_GPL(virtio_debug_device_init);
9193

9294
void virtio_debug_device_filter_features(struct virtio_device *dev)
9395
{
94-
dev->features &= ~dev->debugfs_filter_features;
96+
virtio_features_andnot(dev->features_array, dev->features_array,
97+
dev->debugfs_filter_features);
9598
}
9699
EXPORT_SYMBOL_GPL(virtio_debug_device_filter_features);
97100

include/linux/virtio.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/gfp.h>
1212
#include <linux/dma-mapping.h>
1313
#include <linux/completion.h>
14+
#include <linux/virtio_features.h>
1415

1516
/**
1617
* struct virtqueue - a queue to register buffers for sending or receiving.
@@ -141,7 +142,9 @@ struct virtio_admin_cmd {
141142
* @config: the configuration ops for this device.
142143
* @vringh_config: configuration ops for host vrings.
143144
* @vqs: the list of virtqueues for this device.
144-
* @features: the features supported by both driver and device.
145+
* @features: the 64 lower features supported by both driver and device.
146+
* @features_array: the full features space supported by both driver and
147+
* device.
145148
* @priv: private pointer for the driver's use.
146149
* @debugfs_dir: debugfs directory entry.
147150
* @debugfs_filter_features: features to be filtered set by debugfs.
@@ -159,11 +162,11 @@ struct virtio_device {
159162
const struct virtio_config_ops *config;
160163
const struct vringh_config_ops *vringh_config;
161164
struct list_head vqs;
162-
u64 features;
165+
VIRTIO_DECLARE_FEATURES(features);
163166
void *priv;
164167
#ifdef CONFIG_VIRTIO_DEBUG
165168
struct dentry *debugfs_dir;
166-
u64 debugfs_filter_features;
169+
u64 debugfs_filter_features[VIRTIO_FEATURES_DWORDS];
167170
#endif
168171
};
169172

include/linux/virtio_config.h

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,11 @@ struct virtqueue_info {
7777
* vdev: the virtio_device
7878
* @get_features: get the array of feature bits for this device.
7979
* vdev: the virtio_device
80-
* Returns the first 64 feature bits (all we currently need).
80+
* Returns the first 64 feature bits.
81+
* @get_extended_features:
82+
* vdev: the virtio_device
83+
* Returns the first VIRTIO_FEATURES_MAX feature bits (all we currently
84+
* need).
8185
* @finalize_features: confirm what device features we'll be using.
8286
* vdev: the virtio_device
8387
* This sends the driver feature bits to the device: it can change
@@ -121,6 +125,8 @@ struct virtio_config_ops {
121125
void (*del_vqs)(struct virtio_device *);
122126
void (*synchronize_cbs)(struct virtio_device *);
123127
u64 (*get_features)(struct virtio_device *vdev);
128+
void (*get_extended_features)(struct virtio_device *vdev,
129+
u64 *features);
124130
int (*finalize_features)(struct virtio_device *vdev);
125131
const char *(*bus_name)(struct virtio_device *vdev);
126132
int (*set_vq_affinity)(struct virtqueue *vq,
@@ -147,13 +153,7 @@ void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
147153
static inline bool __virtio_test_bit(const struct virtio_device *vdev,
148154
unsigned int fbit)
149155
{
150-
/* Did you forget to fix assumptions on max features? */
151-
if (__builtin_constant_p(fbit))
152-
BUILD_BUG_ON(fbit >= 64);
153-
else
154-
BUG_ON(fbit >= 64);
155-
156-
return vdev->features & BIT_ULL(fbit);
156+
return virtio_features_test_bit(vdev->features_array, fbit);
157157
}
158158

159159
/**
@@ -164,13 +164,7 @@ static inline bool __virtio_test_bit(const struct virtio_device *vdev,
164164
static inline void __virtio_set_bit(struct virtio_device *vdev,
165165
unsigned int fbit)
166166
{
167-
/* Did you forget to fix assumptions on max features? */
168-
if (__builtin_constant_p(fbit))
169-
BUILD_BUG_ON(fbit >= 64);
170-
else
171-
BUG_ON(fbit >= 64);
172-
173-
vdev->features |= BIT_ULL(fbit);
167+
virtio_features_set_bit(vdev->features_array, fbit);
174168
}
175169

176170
/**
@@ -181,13 +175,7 @@ static inline void __virtio_set_bit(struct virtio_device *vdev,
181175
static inline void __virtio_clear_bit(struct virtio_device *vdev,
182176
unsigned int fbit)
183177
{
184-
/* Did you forget to fix assumptions on max features? */
185-
if (__builtin_constant_p(fbit))
186-
BUILD_BUG_ON(fbit >= 64);
187-
else
188-
BUG_ON(fbit >= 64);
189-
190-
vdev->features &= ~BIT_ULL(fbit);
178+
virtio_features_clear_bit(vdev->features_array, fbit);
191179
}
192180

193181
/**
@@ -204,6 +192,17 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev,
204192
return __virtio_test_bit(vdev, fbit);
205193
}
206194

195+
static inline void virtio_get_features(struct virtio_device *vdev,
196+
u64 *features)
197+
{
198+
if (vdev->config->get_extended_features) {
199+
vdev->config->get_extended_features(vdev, features);
200+
return;
201+
}
202+
203+
virtio_features_from_u64(features, vdev->config->get_features(vdev));
204+
}
205+
207206
/**
208207
* virtio_has_dma_quirk - determine whether this device has the DMA quirk
209208
* @vdev: the device

include/linux/virtio_features.h

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _LINUX_VIRTIO_FEATURES_H
3+
#define _LINUX_VIRTIO_FEATURES_H
4+
5+
#include <linux/bits.h>
6+
7+
#define VIRTIO_FEATURES_DWORDS 2
8+
#define VIRTIO_FEATURES_MAX (VIRTIO_FEATURES_DWORDS * 64)
9+
#define VIRTIO_FEATURES_WORDS (VIRTIO_FEATURES_DWORDS * 2)
10+
#define VIRTIO_BIT(b) BIT_ULL((b) & 0x3f)
11+
#define VIRTIO_DWORD(b) ((b) >> 6)
12+
#define VIRTIO_DECLARE_FEATURES(name) \
13+
union { \
14+
u64 name; \
15+
u64 name##_array[VIRTIO_FEATURES_DWORDS];\
16+
}
17+
18+
static inline bool virtio_features_chk_bit(unsigned int bit)
19+
{
20+
if (__builtin_constant_p(bit)) {
21+
/*
22+
* Don't care returning the correct value: the build
23+
* will fail before any bad features access
24+
*/
25+
BUILD_BUG_ON(bit >= VIRTIO_FEATURES_MAX);
26+
} else {
27+
if (WARN_ON_ONCE(bit >= VIRTIO_FEATURES_MAX))
28+
return false;
29+
}
30+
return true;
31+
}
32+
33+
static inline bool virtio_features_test_bit(const u64 *features,
34+
unsigned int bit)
35+
{
36+
return virtio_features_chk_bit(bit) &&
37+
!!(features[VIRTIO_DWORD(bit)] & VIRTIO_BIT(bit));
38+
}
39+
40+
static inline void virtio_features_set_bit(u64 *features,
41+
unsigned int bit)
42+
{
43+
if (virtio_features_chk_bit(bit))
44+
features[VIRTIO_DWORD(bit)] |= VIRTIO_BIT(bit);
45+
}
46+
47+
static inline void virtio_features_clear_bit(u64 *features,
48+
unsigned int bit)
49+
{
50+
if (virtio_features_chk_bit(bit))
51+
features[VIRTIO_DWORD(bit)] &= ~VIRTIO_BIT(bit);
52+
}
53+
54+
static inline void virtio_features_zero(u64 *features)
55+
{
56+
memset(features, 0, sizeof(features[0]) * VIRTIO_FEATURES_DWORDS);
57+
}
58+
59+
static inline void virtio_features_from_u64(u64 *features, u64 from)
60+
{
61+
virtio_features_zero(features);
62+
features[0] = from;
63+
}
64+
65+
static inline bool virtio_features_equal(const u64 *f1, const u64 *f2)
66+
{
67+
int i;
68+
69+
for (i = 0; i < VIRTIO_FEATURES_DWORDS; ++i)
70+
if (f1[i] != f2[i])
71+
return false;
72+
return true;
73+
}
74+
75+
static inline void virtio_features_copy(u64 *to, const u64 *from)
76+
{
77+
memcpy(to, from, sizeof(to[0]) * VIRTIO_FEATURES_DWORDS);
78+
}
79+
80+
static inline void virtio_features_andnot(u64 *to, const u64 *f1, const u64 *f2)
81+
{
82+
int i;
83+
84+
for (i = 0; i < VIRTIO_FEATURES_DWORDS; i++)
85+
to[i] = f1[i] & ~f2[i];
86+
}
87+
88+
#endif

0 commit comments

Comments
 (0)