Merge branch 'perf/hw_breakpoints' into perf/core
[linux-2.6-block.git] / include / linux / virtio_config.h
index 7f4ef66873ef46f6a963bb64ce0c8ec851cff771..ca3ed78e5ec73b5968ebce4c07e0927373413b93 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/err.h>
 #include <linux/bug.h>
 #include <linux/virtio.h>
+#include <linux/virtio_byteorder.h>
 #include <uapi/linux/virtio_config.h>
 
 /**
@@ -18,6 +19,9 @@
  *     offset: the offset of the configuration field
  *     buf: the buffer to read the field value from.
  *     len: the length of the buffer
+ * @generation: config generation counter
+ *     vdev: the virtio_device
+ *     Returns the config generation counter
  * @get_status: read the status byte
  *     vdev: the virtio_device
  *     Returns the status byte
@@ -46,6 +50,7 @@
  *     vdev: the virtio_device
  *     This gives the final feature bits for the device: it can change
  *     the dev->feature bits if it wants.
+ *     Returns 0 on success or error status
  * @bus_name: return the bus name associated with the device
  *     vdev: the virtio_device
  *      This returns a pointer to the bus name a la pci_name from which
@@ -58,6 +63,7 @@ struct virtio_config_ops {
                    void *buf, unsigned len);
        void (*set)(struct virtio_device *vdev, unsigned offset,
                    const void *buf, unsigned len);
+       u32 (*generation)(struct virtio_device *vdev);
        u8 (*get_status)(struct virtio_device *vdev);
        void (*set_status)(struct virtio_device *vdev, u8 status);
        void (*reset)(struct virtio_device *vdev);
@@ -66,8 +72,8 @@ struct virtio_config_ops {
                        vq_callback_t *callbacks[],
                        const char *names[]);
        void (*del_vqs)(struct virtio_device *);
-       u32 (*get_features)(struct virtio_device *vdev);
-       void (*finalize_features)(struct virtio_device *vdev);
+       u64 (*get_features)(struct virtio_device *vdev);
+       int (*finalize_features)(struct virtio_device *vdev);
        const char *(*bus_name)(struct virtio_device *vdev);
        int (*set_vq_affinity)(struct virtqueue *vq, int cpu);
 };
@@ -77,23 +83,70 @@ void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
                                         unsigned int fbit);
 
 /**
- * virtio_has_feature - helper to determine if this device has this feature.
+ * __virtio_test_bit - helper to test feature bits. For use by transports.
+ *                     Devices should normally use virtio_has_feature,
+ *                     which includes more checks.
  * @vdev: the device
  * @fbit: the feature bit
  */
-static inline bool virtio_has_feature(const struct virtio_device *vdev,
+static inline bool __virtio_test_bit(const struct virtio_device *vdev,
+                                    unsigned int fbit)
+{
+       /* Did you forget to fix assumptions on max features? */
+       if (__builtin_constant_p(fbit))
+               BUILD_BUG_ON(fbit >= 64);
+       else
+               BUG_ON(fbit >= 64);
+
+       return vdev->features & BIT_ULL(fbit);
+}
+
+/**
+ * __virtio_set_bit - helper to set feature bits. For use by transports.
+ * @vdev: the device
+ * @fbit: the feature bit
+ */
+static inline void __virtio_set_bit(struct virtio_device *vdev,
+                                   unsigned int fbit)
+{
+       /* Did you forget to fix assumptions on max features? */
+       if (__builtin_constant_p(fbit))
+               BUILD_BUG_ON(fbit >= 64);
+       else
+               BUG_ON(fbit >= 64);
+
+       vdev->features |= BIT_ULL(fbit);
+}
+
+/**
+ * __virtio_clear_bit - helper to clear feature bits. For use by transports.
+ * @vdev: the device
+ * @fbit: the feature bit
+ */
+static inline void __virtio_clear_bit(struct virtio_device *vdev,
                                      unsigned int fbit)
 {
        /* Did you forget to fix assumptions on max features? */
        if (__builtin_constant_p(fbit))
-               BUILD_BUG_ON(fbit >= 32);
+               BUILD_BUG_ON(fbit >= 64);
        else
-               BUG_ON(fbit >= 32);
+               BUG_ON(fbit >= 64);
+
+       vdev->features &= ~BIT_ULL(fbit);
+}
 
+/**
+ * virtio_has_feature - helper to determine if this device has this feature.
+ * @vdev: the device
+ * @fbit: the feature bit
+ */
+static inline bool virtio_has_feature(const struct virtio_device *vdev,
+                                     unsigned int fbit)
+{
        if (fbit < VIRTIO_TRANSPORT_F_START)
                virtio_check_driver_offered_feature(vdev, fbit);
 
-       return test_bit(fbit, vdev->features);
+       return __virtio_test_bit(vdev, fbit);
 }
 
 static inline
@@ -152,6 +205,37 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu)
        return 0;
 }
 
+/* Memory accessors */
+static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val)
+{
+       return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
+static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val)
+{
+       return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
+static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val)
+{
+       return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
+static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val)
+{
+       return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
+static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val)
+{
+       return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
+static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val)
+{
+       return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
 /* Config space accessors. */
 #define virtio_cread(vdev, structname, member, ptr)                    \
        do {                                                            \
@@ -221,11 +305,33 @@ static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset)
        return ret;
 }
 
+/* Read @count fields, @bytes each. */
+static inline void __virtio_cread_many(struct virtio_device *vdev,
+                                      unsigned int offset,
+                                      void *buf, size_t count, size_t bytes)
+{
+       u32 old, gen = vdev->config->generation ?
+               vdev->config->generation(vdev) : 0;
+       int i;
+
+       do {
+               old = gen;
+
+               for (i = 0; i < count; i++)
+                       vdev->config->get(vdev, offset + bytes * i,
+                                         buf + i * bytes, bytes);
+
+               gen = vdev->config->generation ?
+                       vdev->config->generation(vdev) : 0;
+       } while (gen != old);
+}
+
+
 static inline void virtio_cread_bytes(struct virtio_device *vdev,
                                      unsigned int offset,
                                      void *buf, size_t len)
 {
-       vdev->config->get(vdev, offset, buf, len);
+       __virtio_cread_many(vdev, offset, buf, len, 1);
 }
 
 static inline void virtio_cwrite8(struct virtio_device *vdev,
@@ -239,12 +345,13 @@ static inline u16 virtio_cread16(struct virtio_device *vdev,
 {
        u16 ret;
        vdev->config->get(vdev, offset, &ret, sizeof(ret));
-       return ret;
+       return virtio16_to_cpu(vdev, (__force __virtio16)ret);
 }
 
 static inline void virtio_cwrite16(struct virtio_device *vdev,
                                   unsigned int offset, u16 val)
 {
+       val = (__force u16)cpu_to_virtio16(vdev, val);
        vdev->config->set(vdev, offset, &val, sizeof(val));
 }
 
@@ -253,12 +360,13 @@ static inline u32 virtio_cread32(struct virtio_device *vdev,
 {
        u32 ret;
        vdev->config->get(vdev, offset, &ret, sizeof(ret));
-       return ret;
+       return virtio32_to_cpu(vdev, (__force __virtio32)ret);
 }
 
 static inline void virtio_cwrite32(struct virtio_device *vdev,
                                   unsigned int offset, u32 val)
 {
+       val = (__force u32)cpu_to_virtio32(vdev, val);
        vdev->config->set(vdev, offset, &val, sizeof(val));
 }
 
@@ -267,12 +375,14 @@ static inline u64 virtio_cread64(struct virtio_device *vdev,
 {
        u64 ret;
        vdev->config->get(vdev, offset, &ret, sizeof(ret));
-       return ret;
+       __virtio_cread_many(vdev, offset, &ret, 1, sizeof(ret));
+       return virtio64_to_cpu(vdev, (__force __virtio64)ret);
 }
 
 static inline void virtio_cwrite64(struct virtio_device *vdev,
                                   unsigned int offset, u64 val)
 {
+       val = (__force u64)cpu_to_virtio64(vdev, val);
        vdev->config->set(vdev, offset, &val, sizeof(val));
 }