On Thu, 2008-11-06 at 17:27 -0600, Hollis Blanchard wrote:
>
> In the patch I sent, they are named VIRTIO_PFN_SHIFT and
> VRING_PAGE_SIZE. In fact, the first could really be named
> VIRTIO_PCI_PFN_SHIFT or even more specific, which hopefully would
> alleviate the confusion.
>
> Anyways, I've been trying to implement your other idea, which was to
> advertise a "virtio page size" from the host to the guest. Since the
> virtio IO space is only 20 bytes long, and it's full, we need to offer a
> feature bit to notify the guest that the IO space has been expanded.
>
> virtio's PCI IO resource
> ------------------------------------
> | 20 bytes | |
> ------------------------------------
> virtio-pci virtio-<device>
> specific specific
> data data
>
> If guests don't acknowledge the feature, the host pretends the
> VIRTIO_PAGE_SIZE register (which would be the new IO offset 20) doesn't
> exist, and reads to offset 20 instead return the device-specific config
> data.
FWIW, here's my current (broken) patch. Aside from being broken, it also
doesn't seem like this approach will scale well should we need to extend
the IO space again in the future.
diff --git a/qemu/hw/virtio.c b/qemu/hw/virtio.c
--- a/qemu/hw/virtio.c
+++ b/qemu/hw/virtio.c
@@ -45,7 +45,11 @@
* a read-and-acknowledge. */
#define VIRTIO_PCI_ISR 19
-#define VIRTIO_PCI_CONFIG 20
+/* A 32-bit r/o register specifying the size of a "page", in bytes, in the
+ * virtio interface. */
+#define VIRTIO_PCI_PAGESIZE 20
+
+#define VIRTIO_PCI_CONFIG 24
/* Virtio ABI version, if we increment this, we break the guest driver. */
#define VIRTIO_PCI_ABI_VERSION 0
@@ -55,6 +59,12 @@
* KVM or if kqemu gets SMP support.
*/
#define wmb() do { } while (0)
+
+#define VIRTIO_PAGE_SHIFT 12
+#define VIRTIO_PAGE_SIZE (1<<VIRTIO_PAGE_SHIFT)
+#define VIRTIO_PAGE_MASK (~(VIRTIO_PAGE_SIZE - 1))
+#define VIRTIO_PAGE_ALIGN(x) (((x) + VIRTIO_PAGE_SIZE - 1) \
+ & VIRTIO_PAGE_MASK)
/* virt queue functions */
@@ -95,7 +105,7 @@ static void *virtio_map_gpa(target_phys_
static size_t virtqueue_size(int num)
{
- return TARGET_PAGE_ALIGN((sizeof(VRingDesc) * num) +
+ return VIRTIO_PAGE_ALIGN((sizeof(VRingDesc) * num) +
(sizeof(VRingAvail) + sizeof(uint16_t) * num)) +
(sizeof(VRingUsed) + sizeof(VRingUsedElem) * num);
}
@@ -104,7 +114,7 @@ static void virtqueue_init(VirtQueue *vq
{
vq->vring.desc = p;
vq->vring.avail = p + vq->vring.num * sizeof(VRingDesc);
- vq->vring.used = (void *)TARGET_PAGE_ALIGN((unsigned
long)&vq->vring.avail->ring[vq->vring.num]);
+ vq->vring.used = (void *)VIRTIO_PAGE_ALIGN((unsigned
long)&vq->vring.avail->ring[vq->vring.num]);
}
static unsigned virtqueue_next_desc(VirtQueue *vq, unsigned int i)
@@ -234,6 +244,9 @@ static uint32_t virtio_config_readb(void
vdev->get_config(vdev, vdev->config);
+ if (!(vdev->features & VIRTIO_F_EXPLICIT_PAGE_SIZE))
+ addr += 4;
+
addr -= vdev->addr + VIRTIO_PCI_CONFIG;
if (addr > (vdev->config_len - sizeof(val)))
return (uint32_t)-1;
@@ -248,6 +261,9 @@ static uint32_t virtio_config_readw(void
uint16_t val;
vdev->get_config(vdev, vdev->config);
+
+ if (!(vdev->features & VIRTIO_F_EXPLICIT_PAGE_SIZE))
+ addr += 4;
addr -= vdev->addr + VIRTIO_PCI_CONFIG;
if (addr > (vdev->config_len - sizeof(val)))
@@ -264,6 +280,9 @@ static uint32_t virtio_config_readl(void
vdev->get_config(vdev, vdev->config);
+ if (!(vdev->features & VIRTIO_F_EXPLICIT_PAGE_SIZE))
+ addr += 4;
+
addr -= vdev->addr + VIRTIO_PCI_CONFIG;
if (addr > (vdev->config_len - sizeof(val)))
return (uint32_t)-1;
@@ -276,6 +295,9 @@ static void virtio_config_writeb(void *o
{
VirtIODevice *vdev = opaque;
uint8_t val = data;
+
+ if (!(vdev->features & VIRTIO_F_EXPLICIT_PAGE_SIZE))
+ addr += 4;
addr -= vdev->addr + VIRTIO_PCI_CONFIG;
if (addr > (vdev->config_len - sizeof(val)))
@@ -292,6 +314,9 @@ static void virtio_config_writew(void *o
VirtIODevice *vdev = opaque;
uint16_t val = data;
+ if (!(vdev->features & VIRTIO_F_EXPLICIT_PAGE_SIZE))
+ addr += 4;
+
addr -= vdev->addr + VIRTIO_PCI_CONFIG;
if (addr > (vdev->config_len - sizeof(val)))
return;
@@ -306,6 +331,9 @@ static void virtio_config_writel(void *o
{
VirtIODevice *vdev = opaque;
uint32_t val = data;
+
+ if (!(vdev->features & VIRTIO_F_EXPLICIT_PAGE_SIZE))
+ addr += 4;
addr -= vdev->addr + VIRTIO_PCI_CONFIG;
if (addr > (vdev->config_len - sizeof(val)))
@@ -329,9 +357,10 @@ static void virtio_ioport_write(void *op
if (vdev->set_features)
vdev->set_features(vdev, val);
vdev->features = val;
+ printf("%s: features 0x%x\n", __func__, val);
break;
case VIRTIO_PCI_QUEUE_PFN:
- pa = (ram_addr_t)val << TARGET_PAGE_BITS;
+ pa = (ram_addr_t)val << VIRTIO_PAGE_SHIFT;
vdev->vq[vdev->queue_sel].pfn = val;
if (pa == 0) {
virtio_reset(vdev);
@@ -368,6 +397,7 @@ static uint32_t virtio_ioport_read(void
case VIRTIO_PCI_HOST_FEATURES:
ret = vdev->get_features(vdev);
ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+ ret |= (1 << VIRTIO_F_EXPLICIT_PAGE_SIZE);
break;
case VIRTIO_PCI_GUEST_FEATURES:
ret = vdev->features;
@@ -390,6 +420,16 @@ static uint32_t virtio_ioport_read(void
vdev->isr = 0;
virtio_update_irq(vdev);
break;
+ case VIRTIO_PCI_PAGESIZE:
+ if (vdev->features & VIRTIO_F_EXPLICIT_PAGE_SIZE) {
+ /* Guest must have acknowledged this feature in order to enable
+ * this IO port. */
+ ret = VIRTIO_PAGE_SIZE;
+ } else {
+ /* If it hasn't, return device config space instead. */
+ ret = virtio_config_readl(vdev, addr);
+ }
+ break;
default:
break;
}
@@ -405,22 +445,24 @@ static void virtio_map(PCIDevice *pci_de
vdev->addr = addr;
for (i = 0; i < 3; i++) {
- register_ioport_write(addr, 20, 1 << i, virtio_ioport_write, vdev);
- register_ioport_read(addr, 20, 1 << i, virtio_ioport_read, vdev);
+ register_ioport_write(addr, VIRTIO_PCI_CONFIG, 1 << i,
+ virtio_ioport_write, vdev);
+ register_ioport_read(addr, VIRTIO_PCI_CONFIG, 1 << i,
+ virtio_ioport_read, vdev);
}
if (vdev->config_len) {
- register_ioport_write(addr + 20, vdev->config_len, 1,
+ register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 1,
virtio_config_writeb, vdev);
- register_ioport_write(addr + 20, vdev->config_len, 2,
+ register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 2,
virtio_config_writew, vdev);
- register_ioport_write(addr + 20, vdev->config_len, 4,
+ register_ioport_write(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 4,
virtio_config_writel, vdev);
- register_ioport_read(addr + 20, vdev->config_len, 1,
+ register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 1,
virtio_config_readb, vdev);
- register_ioport_read(addr + 20, vdev->config_len, 2,
+ register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 2,
virtio_config_readw, vdev);
- register_ioport_read(addr + 20, vdev->config_len, 4,
+ register_ioport_read(addr + VIRTIO_PCI_CONFIG, vdev->config_len, 4,
virtio_config_readl, vdev);
vdev->get_config(vdev, vdev->config);
@@ -519,7 +561,7 @@ void virtio_load(VirtIODevice *vdev, QEM
size_t size;
target_phys_addr_t pa;
- pa = (ram_addr_t)vdev->vq[i].pfn << TARGET_PAGE_BITS;
+ pa = (ram_addr_t)vdev->vq[i].pfn << VIRTIO_PAGE_SHIFT;
size = virtqueue_size(vdev->vq[i].vring.num);
virtqueue_init(&vdev->vq[i], virtio_map_gpa(pa, size));
}
diff --git a/qemu/hw/virtio.h b/qemu/hw/virtio.h
--- a/qemu/hw/virtio.h
+++ b/qemu/hw/virtio.h
@@ -33,6 +33,9 @@
/* We notify when the ring is completely used, even if the guest is supressing
* callbacks */
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
+
+/* Device advertises the size of a "page". */
+#define VIRTIO_F_EXPLICIT_PAGE_SIZE 28
/* from Linux's linux/virtio_ring.h */
--
Hollis Blanchard
IBM Linux Technology Center
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html