[RFC PATCH 2/3] virtio: mmio: endian *fixes* *HACK*
Daniel Palmer
daniel at thingy.jp
Tue Mar 10 14:59:39 CET 2026
From: Daniel Palmer <daniel at 0x0f.com>
This is an attempt to *fix* virtio mmio on the QEMU m68k virt machine.
As far as I can tell all of the registers in the virtio mmio regions
should be little endian so after reading them they need to be converted
to big endian for the code to work on them? other parts of the code
are also doing endian conversion so I'm not sure.
Or QEMU is incorrectly giving big endian register values?
---
drivers/virtio/virtio_mmio.c | 114 +++++++++++++++++++++--------------
1 file changed, 68 insertions(+), 46 deletions(-)
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index 28b46ab66238..2cf85fdab4ed 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -19,6 +19,27 @@
#include <linux/io.h>
#include "virtio_mmio.h"
+static inline u32 virtio_mmio_readl(void *addr)
+{
+ return in_le32(addr);
+}
+
+static inline u16 virtio_mmio_readw(void *addr)
+{
+ return in_le16(addr);
+}
+
+static inline void virtio_mmio_writel(u32 val, void *addr)
+{
+ out_le32(addr, val);
+}
+
+static inline void virtio_mmio_writew(u32 val, void *addr)
+{
+ out_le16(addr, val);
+}
+
+
static int virtio_mmio_get_config(struct udevice *udev, unsigned int offset,
void *buf, unsigned int len)
{
@@ -44,17 +65,17 @@ static int virtio_mmio_get_config(struct udevice *udev, unsigned int offset,
memcpy(buf, &b, sizeof(b));
break;
case 2:
- w = cpu_to_le16(readw(base + offset));
+ w = cpu_to_le16(virtio_mmio_readw(base + offset));
memcpy(buf, &w, sizeof(w));
break;
case 4:
- l = cpu_to_le32(readl(base + offset));
+ l = cpu_to_le32(virtio_mmio_readl(base + offset));
memcpy(buf, &l, sizeof(l));
break;
case 8:
- l = cpu_to_le32(readl(base + offset));
+ l = cpu_to_le32(virtio_mmio_readl(base + offset));
memcpy(buf, &l, sizeof(l));
- l = cpu_to_le32(readl(base + offset + sizeof(l)));
+ l = cpu_to_le32(virtio_mmio_readl(base + offset + sizeof(l)));
memcpy(buf + sizeof(l), &l, sizeof(l));
break;
default:
@@ -90,17 +111,17 @@ static int virtio_mmio_set_config(struct udevice *udev, unsigned int offset,
break;
case 2:
memcpy(&w, buf, sizeof(w));
- writew(le16_to_cpu(w), base + offset);
+ virtio_mmio_writew(le16_to_cpu(w), base + offset);
break;
case 4:
memcpy(&l, buf, sizeof(l));
- writel(le32_to_cpu(l), base + offset);
+ virtio_mmio_writel(le32_to_cpu(l), base + offset);
break;
case 8:
memcpy(&l, buf, sizeof(l));
- writel(le32_to_cpu(l), base + offset);
+ virtio_mmio_writel(le32_to_cpu(l), base + offset);
memcpy(&l, buf + sizeof(l), sizeof(l));
- writel(le32_to_cpu(l), base + offset + sizeof(l));
+ virtio_mmio_writel(le32_to_cpu(l), base + offset + sizeof(l));
break;
default:
WARN_ON(true);
@@ -116,7 +137,7 @@ static int virtio_mmio_generation(struct udevice *udev, u32 *counter)
if (priv->version == 1)
*counter = 0;
else
- *counter = readl(priv->base + VIRTIO_MMIO_CONFIG_GENERATION);
+ *counter = virtio_mmio_readl(priv->base + VIRTIO_MMIO_CONFIG_GENERATION);
return 0;
}
@@ -125,7 +146,7 @@ static int virtio_mmio_get_status(struct udevice *udev, u8 *status)
{
struct virtio_mmio_priv *priv = dev_get_priv(udev);
- *status = readl(priv->base + VIRTIO_MMIO_STATUS) & 0xff;
+ *status = virtio_mmio_readl(priv->base + VIRTIO_MMIO_STATUS) & 0xff;
return 0;
}
@@ -137,7 +158,7 @@ static int virtio_mmio_set_status(struct udevice *udev, u8 status)
/* We should never be setting status to 0 */
WARN_ON(status == 0);
- writel(status, priv->base + VIRTIO_MMIO_STATUS);
+ virtio_mmio_writel(status, priv->base + VIRTIO_MMIO_STATUS);
return 0;
}
@@ -147,7 +168,7 @@ static int virtio_mmio_reset(struct udevice *udev)
struct virtio_mmio_priv *priv = dev_get_priv(udev);
/* 0 status means a reset */
- writel(0, priv->base + VIRTIO_MMIO_STATUS);
+ virtio_mmio_writel(0, priv->base + VIRTIO_MMIO_STATUS);
return 0;
}
@@ -156,12 +177,12 @@ static int virtio_mmio_get_features(struct udevice *udev, u64 *features)
{
struct virtio_mmio_priv *priv = dev_get_priv(udev);
- writel(1, priv->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
- *features = readl(priv->base + VIRTIO_MMIO_DEVICE_FEATURES);
+ virtio_mmio_writel(1, priv->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
+ *features = virtio_mmio_readl(priv->base + VIRTIO_MMIO_DEVICE_FEATURES);
*features <<= 32;
- writel(0, priv->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
- *features |= readl(priv->base + VIRTIO_MMIO_DEVICE_FEATURES);
+ virtio_mmio_writel(0, priv->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
+ *features |= virtio_mmio_readl(priv->base + VIRTIO_MMIO_DEVICE_FEATURES);
return 0;
}
@@ -177,12 +198,12 @@ static int virtio_mmio_set_features(struct udevice *udev)
return -EINVAL;
}
- writel(1, priv->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
- writel((u32)(uc_priv->features >> 32),
+ virtio_mmio_writel(1, priv->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
+ virtio_mmio_writel((u32)(uc_priv->features >> 32),
priv->base + VIRTIO_MMIO_DRIVER_FEATURES);
- writel(0, priv->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
- writel((u32)uc_priv->features,
+ virtio_mmio_writel(0, priv->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
+ virtio_mmio_writel((u32)uc_priv->features,
priv->base + VIRTIO_MMIO_DRIVER_FEATURES);
return 0;
@@ -197,16 +218,16 @@ static struct virtqueue *virtio_mmio_setup_vq(struct udevice *udev,
int err;
/* Select the queue we're interested in */
- writel(index, priv->base + VIRTIO_MMIO_QUEUE_SEL);
+ virtio_mmio_writel(index, priv->base + VIRTIO_MMIO_QUEUE_SEL);
/* Queue shouldn't already be set up */
- if (readl(priv->base + (priv->version == 1 ?
+ if (virtio_mmio_readl(priv->base + (priv->version == 1 ?
VIRTIO_MMIO_QUEUE_PFN : VIRTIO_MMIO_QUEUE_READY))) {
err = -ENOENT;
goto error_available;
}
- num = readl(priv->base + VIRTIO_MMIO_QUEUE_NUM_MAX);
+ num = virtio_mmio_readl(priv->base + VIRTIO_MMIO_QUEUE_NUM_MAX);
if (num == 0) {
err = -ENOENT;
goto error_new_virtqueue;
@@ -220,7 +241,7 @@ static struct virtqueue *virtio_mmio_setup_vq(struct udevice *udev,
}
/* Activate the queue */
- writel(virtqueue_get_vring_size(vq),
+ virtio_mmio_writel(virtqueue_get_vring_size(vq),
priv->base + VIRTIO_MMIO_QUEUE_NUM);
if (priv->version == 1) {
u64 q_pfn = virtqueue_get_desc_addr(vq) >> PAGE_SHIFT;
@@ -237,27 +258,27 @@ static struct virtqueue *virtio_mmio_setup_vq(struct udevice *udev,
goto error_bad_pfn;
}
- writel(PAGE_SIZE, priv->base + VIRTIO_MMIO_QUEUE_ALIGN);
- writel(q_pfn, priv->base + VIRTIO_MMIO_QUEUE_PFN);
+ virtio_mmio_writel(PAGE_SIZE, priv->base + VIRTIO_MMIO_QUEUE_ALIGN);
+ virtio_mmio_writel(q_pfn, priv->base + VIRTIO_MMIO_QUEUE_PFN);
} else {
u64 addr;
addr = virtqueue_get_desc_addr(vq);
- writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_DESC_LOW);
- writel((u32)(addr >> 32),
+ virtio_mmio_writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_DESC_LOW);
+ virtio_mmio_writel((u32)(addr >> 32),
priv->base + VIRTIO_MMIO_QUEUE_DESC_HIGH);
addr = virtqueue_get_avail_addr(vq);
- writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW);
- writel((u32)(addr >> 32),
+ virtio_mmio_writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW);
+ virtio_mmio_writel((u32)(addr >> 32),
priv->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH);
addr = virtqueue_get_used_addr(vq);
- writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_USED_LOW);
- writel((u32)(addr >> 32),
+ virtio_mmio_writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_USED_LOW);
+ virtio_mmio_writel((u32)(addr >> 32),
priv->base + VIRTIO_MMIO_QUEUE_USED_HIGH);
- writel(1, priv->base + VIRTIO_MMIO_QUEUE_READY);
+ virtio_mmio_writel(1, priv->base + VIRTIO_MMIO_QUEUE_READY);
}
return vq;
@@ -267,10 +288,10 @@ error_bad_pfn:
error_new_virtqueue:
if (priv->version == 1) {
- writel(0, priv->base + VIRTIO_MMIO_QUEUE_PFN);
+ virtio_mmio_writel(0, priv->base + VIRTIO_MMIO_QUEUE_PFN);
} else {
- writel(0, priv->base + VIRTIO_MMIO_QUEUE_READY);
- WARN_ON(readl(priv->base + VIRTIO_MMIO_QUEUE_READY));
+ virtio_mmio_writel(0, priv->base + VIRTIO_MMIO_QUEUE_READY);
+ WARN_ON(virtio_mmio_readl(priv->base + VIRTIO_MMIO_QUEUE_READY));
}
error_available:
@@ -283,12 +304,12 @@ static void virtio_mmio_del_vq(struct virtqueue *vq)
unsigned int index = vq->index;
/* Select and deactivate the queue */
- writel(index, priv->base + VIRTIO_MMIO_QUEUE_SEL);
+ virtio_mmio_writel(index, priv->base + VIRTIO_MMIO_QUEUE_SEL);
if (priv->version == 1) {
- writel(0, priv->base + VIRTIO_MMIO_QUEUE_PFN);
+ virtio_mmio_writel(0, priv->base + VIRTIO_MMIO_QUEUE_PFN);
} else {
- writel(0, priv->base + VIRTIO_MMIO_QUEUE_READY);
- WARN_ON(readl(priv->base + VIRTIO_MMIO_QUEUE_READY));
+ virtio_mmio_writel(0, priv->base + VIRTIO_MMIO_QUEUE_READY);
+ WARN_ON(virtio_mmio_readl(priv->base + VIRTIO_MMIO_QUEUE_READY));
}
vring_del_virtqueue(vq);
@@ -329,7 +350,7 @@ static int virtio_mmio_notify(struct udevice *udev, struct virtqueue *vq)
* We write the queue's selector into the notification register
* to signal the other end
*/
- writel(vq->index, priv->base + VIRTIO_MMIO_QUEUE_NOTIFY);
+ virtio_mmio_writel(vq->index, priv->base + VIRTIO_MMIO_QUEUE_NOTIFY);
return 0;
}
@@ -359,14 +380,14 @@ static int virtio_mmio_probe(struct udevice *udev)
priv->base = (void __iomem *)plat->base;
/* Check magic value */
- magic = readl(priv->base + VIRTIO_MMIO_MAGIC_VALUE);
+ magic = virtio_mmio_readl(priv->base + VIRTIO_MMIO_MAGIC_VALUE);
if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
debug("(%s): wrong magic value 0x%08x!\n", udev->name, magic);
return 0;
}
/* Check device version */
- priv->version = readl(priv->base + VIRTIO_MMIO_VERSION);
+ priv->version = virtio_mmio_readl(priv->base + VIRTIO_MMIO_VERSION);
if (priv->version < 1 || priv->version > 2) {
debug("(%s): version %d not supported!\n",
udev->name, priv->version);
@@ -374,7 +395,7 @@ static int virtio_mmio_probe(struct udevice *udev)
}
/* Check device ID */
- uc_priv->device = readl(priv->base + VIRTIO_MMIO_DEVICE_ID);
+ uc_priv->device = virtio_mmio_readl(priv->base + VIRTIO_MMIO_DEVICE_ID);
if (uc_priv->device == 0) {
/*
* virtio-mmio device with an ID 0 is a (dummy) placeholder
@@ -382,10 +403,11 @@ static int virtio_mmio_probe(struct udevice *udev)
*/
return 0;
}
- uc_priv->vendor = readl(priv->base + VIRTIO_MMIO_VENDOR_ID);
+ /* This is actually used as little endian locally? noice */
+ uc_priv->vendor = cpu_to_le32(virtio_mmio_readl(priv->base + VIRTIO_MMIO_VENDOR_ID));
if (priv->version == 1)
- writel(PAGE_SIZE, priv->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
+ virtio_mmio_writel(PAGE_SIZE, priv->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
debug("(%s): device (%d) vendor (%08x) version (%d)\n", udev->name,
uc_priv->device, uc_priv->vendor, priv->version);
--
2.51.0
More information about the U-Boot
mailing list