diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2014-12-14 09:55:44 -0500 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2014-12-14 11:21:31 -0500 |
commit | d71de9ec6ba806104439d3a669befda84757b5af (patch) | |
tree | 9584862eef22a09b0299a3e5e4a975ddc67e1de9 | |
parent | 0dce3771fdd1db03c6f498594a34bba5a6d1f870 (diff) |
virtio: core support for config generation
virtio 1.0 spec says:
Drivers MUST NOT assume reads from fields greater than 32 bits wide are
atomic, nor are reads from multiple fields: drivers SHOULD read device
configuration space fields like so:
u32 before, after;
do {
before = get_config_generation(device);
// read config entry/entries.
after = get_config_generation(device);
} while (after != before);
Do exactly this, for transports that support it.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r-- | include/linux/virtio_config.h | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index a61cd37f088c..ca3ed78e5ec7 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h | |||
@@ -19,6 +19,9 @@ | |||
19 | * offset: the offset of the configuration field | 19 | * offset: the offset of the configuration field |
20 | * buf: the buffer to read the field value from. | 20 | * buf: the buffer to read the field value from. |
21 | * len: the length of the buffer | 21 | * len: the length of the buffer |
22 | * @generation: config generation counter | ||
23 | * vdev: the virtio_device | ||
24 | * Returns the config generation counter | ||
22 | * @get_status: read the status byte | 25 | * @get_status: read the status byte |
23 | * vdev: the virtio_device | 26 | * vdev: the virtio_device |
24 | * Returns the status byte | 27 | * Returns the status byte |
@@ -60,6 +63,7 @@ struct virtio_config_ops { | |||
60 | void *buf, unsigned len); | 63 | void *buf, unsigned len); |
61 | void (*set)(struct virtio_device *vdev, unsigned offset, | 64 | void (*set)(struct virtio_device *vdev, unsigned offset, |
62 | const void *buf, unsigned len); | 65 | const void *buf, unsigned len); |
66 | u32 (*generation)(struct virtio_device *vdev); | ||
63 | u8 (*get_status)(struct virtio_device *vdev); | 67 | u8 (*get_status)(struct virtio_device *vdev); |
64 | void (*set_status)(struct virtio_device *vdev, u8 status); | 68 | void (*set_status)(struct virtio_device *vdev, u8 status); |
65 | void (*reset)(struct virtio_device *vdev); | 69 | void (*reset)(struct virtio_device *vdev); |
@@ -301,14 +305,33 @@ static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset) | |||
301 | return ret; | 305 | return ret; |
302 | } | 306 | } |
303 | 307 | ||
308 | /* Read @count fields, @bytes each. */ | ||
309 | static inline void __virtio_cread_many(struct virtio_device *vdev, | ||
310 | unsigned int offset, | ||
311 | void *buf, size_t count, size_t bytes) | ||
312 | { | ||
313 | u32 old, gen = vdev->config->generation ? | ||
314 | vdev->config->generation(vdev) : 0; | ||
315 | int i; | ||
316 | |||
317 | do { | ||
318 | old = gen; | ||
319 | |||
320 | for (i = 0; i < count; i++) | ||
321 | vdev->config->get(vdev, offset + bytes * i, | ||
322 | buf + i * bytes, bytes); | ||
323 | |||
324 | gen = vdev->config->generation ? | ||
325 | vdev->config->generation(vdev) : 0; | ||
326 | } while (gen != old); | ||
327 | } | ||
328 | |||
329 | |||
304 | static inline void virtio_cread_bytes(struct virtio_device *vdev, | 330 | static inline void virtio_cread_bytes(struct virtio_device *vdev, |
305 | unsigned int offset, | 331 | unsigned int offset, |
306 | void *buf, size_t len) | 332 | void *buf, size_t len) |
307 | { | 333 | { |
308 | int i; | 334 | __virtio_cread_many(vdev, offset, buf, len, 1); |
309 | |||
310 | for (i = 0; i < len; i++) | ||
311 | vdev->config->get(vdev, offset + i, buf + i, 1); | ||
312 | } | 335 | } |
313 | 336 | ||
314 | static inline void virtio_cwrite8(struct virtio_device *vdev, | 337 | static inline void virtio_cwrite8(struct virtio_device *vdev, |
@@ -352,6 +375,7 @@ static inline u64 virtio_cread64(struct virtio_device *vdev, | |||
352 | { | 375 | { |
353 | u64 ret; | 376 | u64 ret; |
354 | vdev->config->get(vdev, offset, &ret, sizeof(ret)); | 377 | vdev->config->get(vdev, offset, &ret, sizeof(ret)); |
378 | __virtio_cread_many(vdev, offset, &ret, 1, sizeof(ret)); | ||
355 | return virtio64_to_cpu(vdev, (__force __virtio64)ret); | 379 | return virtio64_to_cpu(vdev, (__force __virtio64)ret); |
356 | } | 380 | } |
357 | 381 | ||