Message ID | 1473260545-9737-1-git-send-email-marcel@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, Sep 07, 2016 at 06:02:25PM +0300, Marcel Apfelbaum wrote: > Currently each VQ Notification Virtio Capability is allocated > on a different page. The idea is to enable split drivers within > guests, however there are no known plans to do that. > The allocation will result in a 8MB BAR, more than various > guest firmwares pre-allocates for PCI Bridges hotplug process. > > Reserve 4 bytes per VQ by default and add a new parameter > "page-per-vq" to be used with split drivers. > > Signed-off-by: Marcel Apfelbaum <marcel@redhat.com> Looks good to me, I'll queue it up. > --- > Hi, > > v1 -> v2: > - Use inline function instead of a new proxy field (Michael) > - Add comment explaining PCI BAR regions must be powers of 2 (Michael) > > To be applied on top of: > [PATCH v5 1/2] pc: Add 2.8 machine (http://patchwork.ozlabs.org/patch/666812/) > > Thanks, > Marcel > > > hw/virtio/virtio-pci.c | 22 +++++++++++++++------- > hw/virtio/virtio-pci.h | 5 +++++ > include/hw/compat.h | 6 +++++- > 3 files changed, 25 insertions(+), 8 deletions(-) > > diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c > index 755f921..c7610ea 100644 > --- a/hw/virtio/virtio-pci.c > +++ b/hw/virtio/virtio-pci.c > @@ -294,6 +294,12 @@ static void virtio_pci_ioeventfd_set_disabled(DeviceState *d, bool disabled) > > #define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000 > > +static inline int virtio_pci_queue_mem_mult(struct VirtIOPCIProxy *proxy) > +{ > + return (proxy->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ) ? > + QEMU_VIRTIO_PCI_QUEUE_MEM_MULT : 4; > +} > + > static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, > int n, bool assign) > { > @@ -307,7 +313,7 @@ static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, > MemoryRegion *modern_mr = &proxy->notify.mr; > MemoryRegion *modern_notify_mr = &proxy->notify_pio.mr; > MemoryRegion *legacy_mr = &proxy->bar; > - hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * > + hwaddr modern_addr = virtio_pci_queue_mem_mult(proxy) * > virtio_get_queue_index(vq); > hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY; > > @@ -1370,7 +1376,8 @@ static void virtio_pci_notify_write(void *opaque, hwaddr addr, > uint64_t val, unsigned size) > { > VirtIODevice *vdev = opaque; > - unsigned queue = addr / QEMU_VIRTIO_PCI_QUEUE_MEM_MULT; > + VirtIOPCIProxy *proxy = VIRTIO_PCI(DEVICE(vdev)->parent_bus->parent); > + unsigned queue = addr / virtio_pci_queue_mem_mult(proxy); > > if (queue < VIRTIO_QUEUE_MAX) { > virtio_queue_notify(vdev, queue); > @@ -1609,7 +1616,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) > struct virtio_pci_notify_cap notify = { > .cap.cap_len = sizeof notify, > .notify_off_multiplier = > - cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT), > + cpu_to_le32(virtio_pci_queue_mem_mult(proxy)), > }; > struct virtio_pci_cfg_cap cfg = { > .cap.cap_len = sizeof cfg, > @@ -1744,8 +1751,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) > proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG; > > proxy->notify.offset = 0x3000; > - proxy->notify.size = > - QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX; > + proxy->notify.size = virtio_pci_queue_mem_mult(proxy) * VIRTIO_QUEUE_MAX; > proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG; > > proxy->notify_pio.offset = 0x0; > @@ -1754,8 +1760,8 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) > > /* subclasses can enforce modern, so do this unconditionally */ > memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci", > - 2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * > - VIRTIO_QUEUE_MAX); > + /* PCI BAR regions must be powers of 2 */ > + pow2ceil(proxy->notify.offset + proxy->notify.size)); > > memory_region_init_alias(&proxy->modern_cfg, > OBJECT(proxy), > @@ -1833,6 +1839,8 @@ static Property virtio_pci_properties[] = { > VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, false), > DEFINE_PROP_BIT("x-disable-pcie", VirtIOPCIProxy, flags, > VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, false), > + DEFINE_PROP_BIT("page-per-vq", VirtIOPCIProxy, flags, > + VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, false), > DEFINE_PROP_END_OF_LIST(), > }; > > diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h > index 25fbf8a..a745512 100644 > --- a/hw/virtio/virtio-pci.h > +++ b/hw/virtio/virtio-pci.h > @@ -64,6 +64,7 @@ enum { > VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, > VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, > VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, > + VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, > }; > > /* Need to activate work-arounds for buggy guests at vmstate load. */ > @@ -84,6 +85,10 @@ enum { > #define VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY \ > (1 << VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT) > > +/* page per vq flag to be used by split drivers within guests */ > +#define VIRTIO_PCI_FLAG_PAGE_PER_VQ \ > + (1 << VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT) > + > typedef struct { > MSIMessage msg; > int virq; > diff --git a/include/hw/compat.h b/include/hw/compat.h > index 08dd4fb..a1d6694 100644 > --- a/include/hw/compat.h > +++ b/include/hw/compat.h > @@ -2,7 +2,11 @@ > #define HW_COMPAT_H > > #define HW_COMPAT_2_7 \ > - /* empty */ > + {\ > + .driver = "virtio-pci",\ > + .property = "page-per-vq",\ > + .value = "on",\ > + }, > > #define HW_COMPAT_2_6 \ > {\ > -- > 2.5.5
On 09/07/2016 06:05 PM, Michael S. Tsirkin wrote: > On Wed, Sep 07, 2016 at 06:02:25PM +0300, Marcel Apfelbaum wrote: >> Currently each VQ Notification Virtio Capability is allocated >> on a different page. The idea is to enable split drivers within >> guests, however there are no known plans to do that. >> The allocation will result in a 8MB BAR, more than various >> guest firmwares pre-allocates for PCI Bridges hotplug process. >> >> Reserve 4 bytes per VQ by default and add a new parameter >> "page-per-vq" to be used with split drivers. >> >> Signed-off-by: Marcel Apfelbaum <marcel@redhat.com> > > Looks good to me, I'll queue it up. > > Thanks! BTW, RE - question about the division added to virtio_pci_notify_write, if is actually translated by gcc as a shift: The answer is no: 00000000000038c1 <virtio_pci_notify_write>: ... 393b: e8 74 d5 ff ff callq eb4 <virtio_pci_queue_mem_mult> 3940: 48 63 c8 movslq %eax,%rcx 3943: 48 8b 45 d0 mov -0x30(%rbp),%rax 3947: ba 00 00 00 00 mov $0x0,%edx 394c: 48 f7 f1 div %rcx ^^^^^^^^ 394f: 89 45 ec mov %eax,-0x14(%rbp) 3952: 81 7d ec ff 03 00 00 cmpl $0x3ff,-0x14(%rbp ... Should we do something about it? Thanks, Marcel > >> --- >> Hi, >> >> v1 -> v2: >> - Use inline function instead of a new proxy field (Michael) >> - Add comment explaining PCI BAR regions must be powers of 2 (Michael) >> >> To be applied on top of: >> [PATCH v5 1/2] pc: Add 2.8 machine (http://patchwork.ozlabs.org/patch/666812/) >> >> Thanks, >> Marcel >> >> >> hw/virtio/virtio-pci.c | 22 +++++++++++++++------- >> hw/virtio/virtio-pci.h | 5 +++++ >> include/hw/compat.h | 6 +++++- >> 3 files changed, 25 insertions(+), 8 deletions(-) >> >> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c >> index 755f921..c7610ea 100644 >> --- a/hw/virtio/virtio-pci.c >> +++ b/hw/virtio/virtio-pci.c >> @@ -294,6 +294,12 @@ static void virtio_pci_ioeventfd_set_disabled(DeviceState *d, bool disabled) >> >> #define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000 >> >> +static inline int virtio_pci_queue_mem_mult(struct VirtIOPCIProxy *proxy) >> +{ >> + return (proxy->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ) ? >> + QEMU_VIRTIO_PCI_QUEUE_MEM_MULT : 4; >> +} >> + >> static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, >> int n, bool assign) >> { >> @@ -307,7 +313,7 @@ static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, >> MemoryRegion *modern_mr = &proxy->notify.mr; >> MemoryRegion *modern_notify_mr = &proxy->notify_pio.mr; >> MemoryRegion *legacy_mr = &proxy->bar; >> - hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * >> + hwaddr modern_addr = virtio_pci_queue_mem_mult(proxy) * >> virtio_get_queue_index(vq); >> hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY; >> >> @@ -1370,7 +1376,8 @@ static void virtio_pci_notify_write(void *opaque, hwaddr addr, >> uint64_t val, unsigned size) >> { >> VirtIODevice *vdev = opaque; >> - unsigned queue = addr / QEMU_VIRTIO_PCI_QUEUE_MEM_MULT; >> + VirtIOPCIProxy *proxy = VIRTIO_PCI(DEVICE(vdev)->parent_bus->parent); >> + unsigned queue = addr / virtio_pci_queue_mem_mult(proxy); >> >> if (queue < VIRTIO_QUEUE_MAX) { >> virtio_queue_notify(vdev, queue); >> @@ -1609,7 +1616,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) >> struct virtio_pci_notify_cap notify = { >> .cap.cap_len = sizeof notify, >> .notify_off_multiplier = >> - cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT), >> + cpu_to_le32(virtio_pci_queue_mem_mult(proxy)), >> }; >> struct virtio_pci_cfg_cap cfg = { >> .cap.cap_len = sizeof cfg, >> @@ -1744,8 +1751,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) >> proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG; >> >> proxy->notify.offset = 0x3000; >> - proxy->notify.size = >> - QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX; >> + proxy->notify.size = virtio_pci_queue_mem_mult(proxy) * VIRTIO_QUEUE_MAX; >> proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG; >> >> proxy->notify_pio.offset = 0x0; >> @@ -1754,8 +1760,8 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) >> >> /* subclasses can enforce modern, so do this unconditionally */ >> memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci", >> - 2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * >> - VIRTIO_QUEUE_MAX); >> + /* PCI BAR regions must be powers of 2 */ >> + pow2ceil(proxy->notify.offset + proxy->notify.size)); >> >> memory_region_init_alias(&proxy->modern_cfg, >> OBJECT(proxy), >> @@ -1833,6 +1839,8 @@ static Property virtio_pci_properties[] = { >> VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, false), >> DEFINE_PROP_BIT("x-disable-pcie", VirtIOPCIProxy, flags, >> VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, false), >> + DEFINE_PROP_BIT("page-per-vq", VirtIOPCIProxy, flags, >> + VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, false), >> DEFINE_PROP_END_OF_LIST(), >> }; >> >> diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h >> index 25fbf8a..a745512 100644 >> --- a/hw/virtio/virtio-pci.h >> +++ b/hw/virtio/virtio-pci.h >> @@ -64,6 +64,7 @@ enum { >> VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, >> VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, >> VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, >> + VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, >> }; >> >> /* Need to activate work-arounds for buggy guests at vmstate load. */ >> @@ -84,6 +85,10 @@ enum { >> #define VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY \ >> (1 << VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT) >> >> +/* page per vq flag to be used by split drivers within guests */ >> +#define VIRTIO_PCI_FLAG_PAGE_PER_VQ \ >> + (1 << VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT) >> + >> typedef struct { >> MSIMessage msg; >> int virq; >> diff --git a/include/hw/compat.h b/include/hw/compat.h >> index 08dd4fb..a1d6694 100644 >> --- a/include/hw/compat.h >> +++ b/include/hw/compat.h >> @@ -2,7 +2,11 @@ >> #define HW_COMPAT_H >> >> #define HW_COMPAT_2_7 \ >> - /* empty */ >> + {\ >> + .driver = "virtio-pci",\ >> + .property = "page-per-vq",\ >> + .value = "on",\ >> + }, >> >> #define HW_COMPAT_2_6 \ >> {\ >> -- >> 2.5.5
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 755f921..c7610ea 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -294,6 +294,12 @@ static void virtio_pci_ioeventfd_set_disabled(DeviceState *d, bool disabled) #define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000 +static inline int virtio_pci_queue_mem_mult(struct VirtIOPCIProxy *proxy) +{ + return (proxy->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ) ? + QEMU_VIRTIO_PCI_QUEUE_MEM_MULT : 4; +} + static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, int n, bool assign) { @@ -307,7 +313,7 @@ static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, MemoryRegion *modern_mr = &proxy->notify.mr; MemoryRegion *modern_notify_mr = &proxy->notify_pio.mr; MemoryRegion *legacy_mr = &proxy->bar; - hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * + hwaddr modern_addr = virtio_pci_queue_mem_mult(proxy) * virtio_get_queue_index(vq); hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY; @@ -1370,7 +1376,8 @@ static void virtio_pci_notify_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { VirtIODevice *vdev = opaque; - unsigned queue = addr / QEMU_VIRTIO_PCI_QUEUE_MEM_MULT; + VirtIOPCIProxy *proxy = VIRTIO_PCI(DEVICE(vdev)->parent_bus->parent); + unsigned queue = addr / virtio_pci_queue_mem_mult(proxy); if (queue < VIRTIO_QUEUE_MAX) { virtio_queue_notify(vdev, queue); @@ -1609,7 +1616,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) struct virtio_pci_notify_cap notify = { .cap.cap_len = sizeof notify, .notify_off_multiplier = - cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT), + cpu_to_le32(virtio_pci_queue_mem_mult(proxy)), }; struct virtio_pci_cfg_cap cfg = { .cap.cap_len = sizeof cfg, @@ -1744,8 +1751,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG; proxy->notify.offset = 0x3000; - proxy->notify.size = - QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX; + proxy->notify.size = virtio_pci_queue_mem_mult(proxy) * VIRTIO_QUEUE_MAX; proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG; proxy->notify_pio.offset = 0x0; @@ -1754,8 +1760,8 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) /* subclasses can enforce modern, so do this unconditionally */ memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci", - 2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * - VIRTIO_QUEUE_MAX); + /* PCI BAR regions must be powers of 2 */ + pow2ceil(proxy->notify.offset + proxy->notify.size)); memory_region_init_alias(&proxy->modern_cfg, OBJECT(proxy), @@ -1833,6 +1839,8 @@ static Property virtio_pci_properties[] = { VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, false), DEFINE_PROP_BIT("x-disable-pcie", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, false), + DEFINE_PROP_BIT("page-per-vq", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 25fbf8a..a745512 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -64,6 +64,7 @@ enum { VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, + VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, }; /* Need to activate work-arounds for buggy guests at vmstate load. */ @@ -84,6 +85,10 @@ enum { #define VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY \ (1 << VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT) +/* page per vq flag to be used by split drivers within guests */ +#define VIRTIO_PCI_FLAG_PAGE_PER_VQ \ + (1 << VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT) + typedef struct { MSIMessage msg; int virq; diff --git a/include/hw/compat.h b/include/hw/compat.h index 08dd4fb..a1d6694 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -2,7 +2,11 @@ #define HW_COMPAT_H #define HW_COMPAT_2_7 \ - /* empty */ + {\ + .driver = "virtio-pci",\ + .property = "page-per-vq",\ + .value = "on",\ + }, #define HW_COMPAT_2_6 \ {\
Currently each VQ Notification Virtio Capability is allocated on a different page. The idea is to enable split drivers within guests, however there are no known plans to do that. The allocation will result in a 8MB BAR, more than various guest firmwares pre-allocates for PCI Bridges hotplug process. Reserve 4 bytes per VQ by default and add a new parameter "page-per-vq" to be used with split drivers. Signed-off-by: Marcel Apfelbaum <marcel@redhat.com> --- Hi, v1 -> v2: - Use inline function instead of a new proxy field (Michael) - Add comment explaining PCI BAR regions must be powers of 2 (Michael) To be applied on top of: [PATCH v5 1/2] pc: Add 2.8 machine (http://patchwork.ozlabs.org/patch/666812/) Thanks, Marcel hw/virtio/virtio-pci.c | 22 +++++++++++++++------- hw/virtio/virtio-pci.h | 5 +++++ include/hw/compat.h | 6 +++++- 3 files changed, 25 insertions(+), 8 deletions(-)