aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2014-12-14 09:55:44 -0500
committerMichael S. Tsirkin <mst@redhat.com>2014-12-14 11:21:31 -0500
commitd71de9ec6ba806104439d3a669befda84757b5af (patch)
tree9584862eef22a09b0299a3e5e4a975ddc67e1de9
parent0dce3771fdd1db03c6f498594a34bba5a6d1f870 (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.h32
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. */
309static 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
304static inline void virtio_cread_bytes(struct virtio_device *vdev, 330static 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
314static inline void virtio_cwrite8(struct virtio_device *vdev, 337static 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