Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

Paolo Abeni e7d4c1c5 eade9f57

+156 -54
+26 -17
drivers/virtio/virtio.c
··· 53 53 54 54 /* We actually represent this as a bitstring, as it could be 55 55 * arbitrary length in future. */ 56 - for (i = 0; i < sizeof(dev->features)*8; i++) 56 + for (i = 0; i < VIRTIO_FEATURES_MAX; i++) 57 57 len += sysfs_emit_at(buf, len, "%c", 58 58 __virtio_test_bit(dev, i) ? '1' : '0'); 59 59 len += sysfs_emit_at(buf, len, "\n"); ··· 272 272 int err, i; 273 273 struct virtio_device *dev = dev_to_virtio(_d); 274 274 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]; 277 277 u64 driver_features_legacy; 278 278 279 279 /* We have a driver! */ 280 280 virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER); 281 281 282 282 /* Figure out what features the device supports. */ 283 - device_features = dev->config->get_features(dev); 283 + virtio_get_features(dev, device_features); 284 284 285 285 /* Figure out what features the driver supports. */ 286 - driver_features = 0; 286 + virtio_features_zero(driver_features); 287 287 for (i = 0; i < drv->feature_table_size; i++) { 288 288 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); 291 291 } 292 292 293 293 /* Some drivers have a separate feature table for virtio v1.0 */ ··· 295 295 driver_features_legacy = 0; 296 296 for (i = 0; i < drv->feature_table_size_legacy; i++) { 297 297 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); 300 300 } 301 301 } else { 302 - driver_features_legacy = driver_features; 302 + driver_features_legacy = driver_features[0]; 303 303 } 304 304 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 + } 309 314 310 315 /* When debugging, user may filter some features by hand. */ 311 316 virtio_debug_device_filter_features(dev); 312 317 313 318 /* Transport features always preserved to pass to finalize_features. */ 314 319 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)) 316 321 __virtio_set_bit(dev, i); 317 322 318 323 err = dev->config->finalize_features(dev); ··· 325 320 goto err; 326 321 327 322 if (drv->validate) { 328 - u64 features = dev->features; 323 + u64 features[VIRTIO_FEATURES_DWORDS]; 329 324 325 + virtio_features_copy(features, dev->features_array); 330 326 err = drv->validate(dev); 331 327 if (err) 332 328 goto err; 333 329 334 330 /* Did validation change any features? Then write them again. */ 335 - if (features != dev->features) { 331 + if (!virtio_features_equal(features, dev->features_array)) { 336 332 err = dev->config->finalize_features(dev); 337 333 if (err) 338 334 goto err; ··· 707 701 708 702 static int virtio_init(void) 709 703 { 704 + BUILD_BUG_ON(offsetof(struct virtio_device, features) != 705 + offsetof(struct virtio_device, features_array[0])); 706 + 710 707 if (bus_register(&virtio_bus) != 0) 711 708 panic("virtio bus registration failed"); 712 709 virtio_debug_init();
+15 -12
drivers/virtio/virtio_debug.c
··· 8 8 9 9 static int virtio_debug_device_features_show(struct seq_file *s, void *data) 10 10 { 11 + u64 device_features[VIRTIO_FEATURES_DWORDS]; 11 12 struct virtio_device *dev = s->private; 12 - u64 device_features; 13 13 unsigned int i; 14 14 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)) 18 18 seq_printf(s, "%u\n", i); 19 19 } 20 20 return 0; ··· 26 26 struct virtio_device *dev = s->private; 27 27 unsigned int i; 28 28 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)) 31 31 seq_printf(s, "%u\n", i); 32 32 } 33 33 return 0; ··· 39 39 struct virtio_device *dev = data; 40 40 41 41 if (val == 1) 42 - dev->debugfs_filter_features = 0; 42 + virtio_features_zero(dev->debugfs_filter_features); 43 43 return 0; 44 44 } 45 45 ··· 50 50 { 51 51 struct virtio_device *dev = data; 52 52 53 - if (val >= BITS_PER_LONG_LONG) 53 + if (val >= VIRTIO_FEATURES_MAX) 54 54 return -EINVAL; 55 - dev->debugfs_filter_features |= BIT_ULL_MASK(val); 55 + 56 + virtio_features_set_bit(dev->debugfs_filter_features, val); 56 57 return 0; 57 58 } 58 59 ··· 64 63 { 65 64 struct virtio_device *dev = data; 66 65 67 - if (val >= BITS_PER_LONG_LONG) 66 + if (val >= VIRTIO_FEATURES_MAX) 68 67 return -EINVAL; 69 - dev->debugfs_filter_features &= ~BIT_ULL_MASK(val); 68 + 69 + virtio_features_clear_bit(dev->debugfs_filter_features, val); 70 70 return 0; 71 71 } 72 72 ··· 93 91 94 92 void virtio_debug_device_filter_features(struct virtio_device *dev) 95 93 { 96 - dev->features &= ~dev->debugfs_filter_features; 94 + virtio_features_andnot(dev->features_array, dev->features_array, 95 + dev->debugfs_filter_features); 97 96 } 98 97 EXPORT_SYMBOL_GPL(virtio_debug_device_filter_features); 99 98
+6 -3
include/linux/virtio.h
··· 11 11 #include <linux/gfp.h> 12 12 #include <linux/dma-mapping.h> 13 13 #include <linux/completion.h> 14 + #include <linux/virtio_features.h> 14 15 15 16 /** 16 17 * struct virtqueue - a queue to register buffers for sending or receiving. ··· 142 141 * @config: the configuration ops for this device. 143 142 * @vringh_config: configuration ops for host vrings. 144 143 * @vqs: the list of virtqueues for this device. 145 - * @features: the features supported by both driver and device. 144 + * @features: the 64 lower features supported by both driver and device. 145 + * @features_array: the full features space supported by both driver and 146 + * device. 146 147 * @priv: private pointer for the driver's use. 147 148 * @debugfs_dir: debugfs directory entry. 148 149 * @debugfs_filter_features: features to be filtered set by debugfs. ··· 162 159 const struct virtio_config_ops *config; 163 160 const struct vringh_config_ops *vringh_config; 164 161 struct list_head vqs; 165 - u64 features; 162 + VIRTIO_DECLARE_FEATURES(features); 166 163 void *priv; 167 164 #ifdef CONFIG_VIRTIO_DEBUG 168 165 struct dentry *debugfs_dir; 169 - u64 debugfs_filter_features; 166 + u64 debugfs_filter_features[VIRTIO_FEATURES_DWORDS]; 170 167 #endif 171 168 }; 172 169
+21 -22
include/linux/virtio_config.h
··· 77 77 * vdev: the virtio_device 78 78 * @get_features: get the array of feature bits for this device. 79 79 * 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). 81 85 * @finalize_features: confirm what device features we'll be using. 82 86 * vdev: the virtio_device 83 87 * This sends the driver feature bits to the device: it can change ··· 125 121 void (*del_vqs)(struct virtio_device *); 126 122 void (*synchronize_cbs)(struct virtio_device *); 127 123 u64 (*get_features)(struct virtio_device *vdev); 124 + void (*get_extended_features)(struct virtio_device *vdev, 125 + u64 *features); 128 126 int (*finalize_features)(struct virtio_device *vdev); 129 127 const char *(*bus_name)(struct virtio_device *vdev); 130 128 int (*set_vq_affinity)(struct virtqueue *vq, ··· 153 147 static inline bool __virtio_test_bit(const struct virtio_device *vdev, 154 148 unsigned int fbit) 155 149 { 156 - /* Did you forget to fix assumptions on max features? */ 157 - if (__builtin_constant_p(fbit)) 158 - BUILD_BUG_ON(fbit >= 64); 159 - else 160 - BUG_ON(fbit >= 64); 161 - 162 - return vdev->features & BIT_ULL(fbit); 150 + return virtio_features_test_bit(vdev->features_array, fbit); 163 151 } 164 152 165 153 /** ··· 164 164 static inline void __virtio_set_bit(struct virtio_device *vdev, 165 165 unsigned int fbit) 166 166 { 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); 174 168 } 175 169 176 170 /** ··· 175 181 static inline void __virtio_clear_bit(struct virtio_device *vdev, 176 182 unsigned int fbit) 177 183 { 178 - /* Did you forget to fix assumptions on max features? */ 179 - if (__builtin_constant_p(fbit)) 180 - BUILD_BUG_ON(fbit >= 64); 181 - else 182 - BUG_ON(fbit >= 64); 183 - 184 - vdev->features &= ~BIT_ULL(fbit); 184 + virtio_features_clear_bit(vdev->features_array, fbit); 185 185 } 186 186 187 187 /** ··· 190 202 virtio_check_driver_offered_feature(vdev, fbit); 191 203 192 204 return __virtio_test_bit(vdev, fbit); 205 + } 206 + 207 + static inline void virtio_get_features(struct virtio_device *vdev, 208 + u64 *features) 209 + { 210 + if (vdev->config->get_extended_features) { 211 + vdev->config->get_extended_features(vdev, features); 212 + return; 213 + } 214 + 215 + virtio_features_from_u64(features, vdev->config->get_features(vdev)); 193 216 } 194 217 195 218 /**
+88
include/linux/virtio_features.h
··· 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