* [Qemu-devel] [RFC 0/2] platform device passthrough
@ 2014-02-26 2:37 Kim Phillips
2014-02-26 2:37 ` [Qemu-devel] [RFC 1/2] hw/arm/virt: add a Calxeda XGMAC device Kim Phillips
2014-02-26 2:37 ` [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support Kim Phillips
0 siblings, 2 replies; 12+ messages in thread
From: Kim Phillips @ 2014-02-26 2:37 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, kim.phillips, eric.auger, kim.phillips, agraf,
stuart.yoder, alex.williamson, Antonios Motakis, kvmarm,
christoffer.dall
This is an RFC for the first step of many to enable platform device
passthrough, where a guest OS is able to directly access platform
device MMIO, DMA regions, and receive interrupts from platform devices.
The first RFC patch works around the limitation of QEMU not being able
to create platform devices from the command line, and should only
be used for testing the second patch. A discussion of how to address
the limitation is encouraged, however, in the context of the first patch.
Whilst the second RFC patch achieves MMIO direct access to the device,
it lacks considerable work before it is complete, and is posted here early
to weed out any issues with its initial approach and general direction.
Here are the instructions to test on a Calxeda Midway:
https://wiki.linaro.org/LEG/Engineering/Virtualization/Platform_Device_Passthrough_on_Midway
The code is based on today's:
git://git.qemu.org/qemu.git
and available on the 'platdevpassthrough' branch of:
git://git.linaro.org/people/kim.phillips/qemu.git
Thanks,
Kim
Kim Phillips (2):
hw/arm/virt: add a Calxeda XGMAC device
hw/misc/vfio: add vfio-platform support
hw/arm/virt.c | 24 +++++++-
hw/misc/vfio.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 168 insertions(+), 36 deletions(-)
--
1.9.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [RFC 1/2] hw/arm/virt: add a Calxeda XGMAC device
2014-02-26 2:37 [Qemu-devel] [RFC 0/2] platform device passthrough Kim Phillips
@ 2014-02-26 2:37 ` Kim Phillips
2014-03-05 4:27 ` Eric Auger
2014-02-26 2:37 ` [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support Kim Phillips
1 sibling, 1 reply; 12+ messages in thread
From: Kim Phillips @ 2014-02-26 2:37 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, kim.phillips, eric.auger, kim.phillips, agraf,
stuart.yoder, alex.williamson, Antonios Motakis, kvmarm,
christoffer.dall
This is a hack and only serves as an example of what needs to be
done to make the next RFC - add vfio-platform support - work
for development purposes on a Calxeda Midway system. We don't want
mach-virt to always create this ethernet device - DO NOT APPLY, etc.
Initial attempts to convince QEMU to create a memory mapped device
on the command line (e.g., -device vfio-platform,name=fff51000.ethernet)
would fail with "Parameter 'driver' expects pluggable device type".
Any guidance as to how to overcome this apparent design limitation
is welcome.
RAM is reduced from 30 to 1GiB such as to not overlap the xgmac device's
physical address. Not sure if the 30GiB RAM (or whatever the user sets
it to with -m) could be set up above 0x1_0000_0000, but there is probably
extra work needed to resolve this type of conflict.
note: vfio-platform interrupt support development may want interrupt
property data filled; here it's omitted for the time being.
Not-signed-off-by: Kim Phillips <kim.phillips@linaro.org>
---
hw/arm/virt.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 517f2fe..75edf33 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -65,6 +65,7 @@ enum {
VIRT_GIC_CPU,
VIRT_UART,
VIRT_MMIO,
+ VIRT_ETHERNET,
};
typedef struct MemMapEntry {
@@ -106,7 +107,8 @@ static const MemMapEntry a15memmap[] = {
[VIRT_MMIO] = { 0xa000000, 0x200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
/* 0x10000000 .. 0x40000000 reserved for PCI */
- [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
+ [VIRT_MEM] = { 0x40000000, 1ULL * 1024 * 1024 * 1024 },
+ [VIRT_ETHERNET] = { 0xfff51000, 0x1000 },
};
static const int a15irqmap[] = {
@@ -291,6 +293,25 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
g_free(nodename);
}
+static void create_ethernet(const VirtBoardInfo *vbi, qemu_irq *pic)
+{
+ char *nodename;
+ hwaddr base = vbi->memmap[VIRT_ETHERNET].base;
+ hwaddr size = vbi->memmap[VIRT_ETHERNET].size;
+ const char compat[] = "calxeda,hb-xgmac";
+
+ sysbus_create_simple("vfio-platform", base, NULL);
+
+ nodename = g_strdup_printf("/ethernet@%" PRIx64, base);
+ qemu_fdt_add_subnode(vbi->fdt, nodename);
+
+ /* Note that we can't use setprop_string because of the embedded NUL */
+ qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat));
+ qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base, 2, size);
+
+ g_free(nodename);
+}
+
static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
{
int i;
@@ -419,6 +440,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
}
create_uart(vbi, pic);
+ create_ethernet(vbi, pic);
/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
--
1.9.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support
2014-02-26 2:37 [Qemu-devel] [RFC 0/2] platform device passthrough Kim Phillips
2014-02-26 2:37 ` [Qemu-devel] [RFC 1/2] hw/arm/virt: add a Calxeda XGMAC device Kim Phillips
@ 2014-02-26 2:37 ` Kim Phillips
2014-02-28 18:03 ` Alex Williamson
2014-03-05 7:56 ` Eric Auger
1 sibling, 2 replies; 12+ messages in thread
From: Kim Phillips @ 2014-02-26 2:37 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, kim.phillips, eric.auger, kim.phillips, agraf,
stuart.yoder, alex.williamson, Antonios Motakis, kvmarm,
christoffer.dall
We basically add support for the SysBusDevice type in addition to the
existing PCIDevice support. This involves taking common code from the
existing vfio_initfn(), and putting it under a new vfio_find_get_group(),
that both vfio_initfn() and the new vfio_platform_realize() call.
Since realize() returns void, unlike PCIDevice's initfn(),
error codes are moved into the error message text with %m.
Some exceptions to the PCI path are added for platform devices,
mostly in the form of early returns, since less setup is needed.
I chose to reuse VFIODevice's config_size to determine whether
the device was a PCI device or a platform device, which might
need to change.
Currently only MMIO access is supported at this time. It works
because of qemu's stage 1 translation, but needs to be in stage 2
in case other entities than the guest OS want to access it.
A KVM patch to address this is in the works.
The perceived path for future QEMU development is:
- support allocating a variable number of regions
- VFIODevice's bars[] become dynamically allocated *regions
- VFIOBAR's device fd replaced with parent VFIODevice ptr,
to facilitate BAR r/w ops calling vfio_eoi()
- add support for interrupts
- verify and test platform dev unmap path
- test existing PCI path for any regressions
- add support for creating platform devices on the qemu command line
- currently device address specification is hardcoded for test
development on Calxeda Midway's fff51000.ethernet device
- reset is not supported and registration of reset functions is
bypassed for platform devices.
- there is no standard means of resetting a platform device,
unsure if it suffices to be handled at device--VFIO binding time
Signed-off-by: Kim Phillips <kim.phillips@linaro.org>
---
hw/misc/vfio.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 145 insertions(+), 35 deletions(-)
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
index 8db182f..eed24db 100644
--- a/hw/misc/vfio.c
+++ b/hw/misc/vfio.c
@@ -32,6 +32,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/pci/pci.h"
+#include "hw/sysbus.h"
#include "qemu-common.h"
#include "qemu/error-report.h"
#include "qemu/event_notifier.h"
@@ -166,7 +167,10 @@ typedef struct VFIOMSIXInfo {
} VFIOMSIXInfo;
typedef struct VFIODevice {
- PCIDevice pdev;
+ union {
+ PCIDevice pdev;
+ SysBusDevice sbdev;
+ };
int fd;
VFIOINTx intx;
unsigned int config_size;
@@ -180,6 +184,8 @@ typedef struct VFIODevice {
VFIOMSIXInfo *msix;
int nr_vectors; /* Number of MSI/MSIX vectors currently in use */
int interrupt; /* Current interrupt type */
+ char *name; /* platform device name, e.g., fff51000.ethernet */
+ int nr_regions; /* platform devices' number of regions */
VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */
VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */
PCIHostDeviceAddress host;
@@ -2497,8 +2503,6 @@ empty_region:
memory_region_init(submem, OBJECT(vdev), name, 0);
}
- memory_region_add_subregion(mem, offset, submem);
-
return ret;
}
@@ -2552,6 +2556,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
&bar->mmap_mem, &bar->mmap, size, 0, name)) {
error_report("%s unsupported. Performance may be slow", name);
}
+ memory_region_add_subregion(&bar->mem, 0, &bar->mmap_mem);
if (vdev->msix && vdev->msix->table_bar == nr) {
unsigned start;
@@ -2566,15 +2571,38 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
&vdev->msix->mmap, size, start, name)) {
error_report("%s unsupported. Performance may be slow", name);
}
+ memory_region_add_subregion(&bar->mem, start, &vdev->msix->mmap_mem);
}
vfio_bar_quirk_setup(vdev, nr);
}
+static void vfio_map_region(VFIODevice *vdev, int nr)
+{
+ VFIOBAR *bar = &vdev->bars[nr];
+ unsigned size = bar->size;
+ char name[64];
+
+ snprintf(name, sizeof(name), "VFIO %s region %d mmap", vdev->name, nr);
+
+ if (vfio_mmap_bar(vdev, bar, &bar->mem,
+ &bar->mmap_mem, &bar->mmap, size, 0, name)) {
+ error_report("error mmapping %s: %m", name);
+ }
+}
+
static void vfio_map_bars(VFIODevice *vdev)
{
int i;
+ if (!vdev->config_size) {
+ /* platform device */
+ for (i = 0; i < vdev->nr_regions; i++) {
+ vfio_map_region(vdev, i);
+ }
+ return;
+ }
+
for (i = 0; i < PCI_ROM_SLOT; i++) {
vfio_map_bar(vdev, i);
}
@@ -3144,7 +3172,8 @@ static void vfio_pci_reset_handler(void *opaque)
QLIST_FOREACH(group, &group_list, next) {
QLIST_FOREACH(vdev, &group->device_list, next) {
- if (vdev->needs_reset) {
+ /* HACK: restrict reset to PCI devices (have config_size) for now */
+ if (vdev->config_size && vdev->needs_reset) {
vfio_pci_hot_reset_multi(vdev);
}
}
@@ -3418,25 +3447,18 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
DPRINTF("Device %s flags: %u, regions: %u, irgs: %u\n", name,
dev_info.flags, dev_info.num_regions, dev_info.num_irqs);
- if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI)) {
- error_report("vfio: Um, this isn't a PCI device");
- goto error;
- }
-
+ vdev->nr_regions = dev_info.num_regions;
vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
- if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
+ if (dev_info.num_regions > PCI_NUM_REGIONS) ||
+ ((dev_info.flags & VFIO_DEVICE_FLAGS_PCI) &&
+ (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1)) {
error_report("vfio: unexpected number of io regions %u",
dev_info.num_regions);
goto error;
}
- if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
- error_report("vfio: unexpected number of irqs %u", dev_info.num_irqs);
- goto error;
- }
-
- for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) {
+ for (i = 0; i < dev_info.num_regions; i++) {
reg_info.index = i;
ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info);
@@ -3458,6 +3480,15 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
QLIST_INIT(&vdev->bars[i].quirks);
}
+ /* following is for PCI devices, at least for now */
+ if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI))
+ return 0;
+
+ if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
+ error_report("vfio: unexpected number of irqs %u", dev_info.num_irqs);
+ goto error;
+ }
+
reg_info.index = VFIO_PCI_CONFIG_REGION_INDEX;
ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info);
@@ -3659,32 +3690,25 @@ static void vfio_unregister_err_notifier(VFIODevice *vdev)
event_notifier_cleanup(&vdev->err_notifier);
}
-static int vfio_initfn(PCIDevice *pdev)
+static VFIOGroup *vfio_find_get_group(char *path)
{
- VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
VFIOGroup *group;
- char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name;
+ char iommu_group_path[PATH_MAX], *group_name;
ssize_t len;
struct stat st;
int groupid;
- int ret;
- /* Check that the host device exists */
- snprintf(path, sizeof(path),
- "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
- vdev->host.domain, vdev->host.bus, vdev->host.slot,
- vdev->host.function);
if (stat(path, &st) < 0) {
- error_report("vfio: error: no such host device: %s", path);
- return -errno;
+ error_report("vfio: error: no such host device: %s: %m", path);
+ return NULL;
}
strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1);
len = readlink(path, iommu_group_path, PATH_MAX);
if (len <= 0) {
- error_report("vfio: error no iommu_group for device");
- return -errno;
+ error_report("vfio: error no iommu_group for device: %m");
+ return NULL;
}
iommu_group_path[len] = 0;
@@ -3692,18 +3716,37 @@ static int vfio_initfn(PCIDevice *pdev)
if (sscanf(group_name, "%d", &groupid) != 1) {
error_report("vfio: error reading %s: %m", path);
- return -errno;
+ return NULL;
}
- DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain,
- vdev->host.bus, vdev->host.slot, vdev->host.function, groupid);
-
group = vfio_get_group(groupid);
if (!group) {
- error_report("vfio: failed to get group %d", groupid);
- return -ENOENT;
+ error_report("vfio: failed to get group %d: %m", groupid);
+ return NULL;
}
+ return group;
+}
+
+static int vfio_initfn(PCIDevice *pdev)
+{
+ VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+ VFIOGroup *group;
+ char path[PATH_MAX];
+ int ret;
+
+ /* Check that the host device exists */
+ snprintf(path, sizeof(path),
+ "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+
+ group = vfio_find_get_group(path);
+
+ DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain,
+ vdev->host.bus, vdev->host.slot, vdev->host.function,
+ group->groupid);
+
snprintf(path, sizeof(path), "%04x:%02x:%02x.%01x",
vdev->host.domain, vdev->host.bus, vdev->host.slot,
vdev->host.function);
@@ -3916,3 +3959,70 @@ static void register_vfio_pci_dev_type(void)
}
type_init(register_vfio_pci_dev_type)
+
+
+/*
+ * VFIO platform devices
+ */
+static void vfio_platform_realize(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
+ VFIODevice *vdev = DO_UPCAST(VFIODevice, sbdev, sbdev);
+ VFIOGroup *group;
+ char path[PATH_MAX];
+ int ret;
+
+ vdev->name = malloc(PATH_MAX);
+ strcpy(vdev->name, "fff51000.ethernet");
+
+ /* Check that the host device exists */
+ snprintf(path, sizeof(path),
+ "/sys/bus/platform/devices/%s/", vdev->name);
+
+ group = vfio_find_get_group(path);
+ if (!group) {
+ error_report("vfio: failed to get group for device %s", path);
+ return;
+ }
+
+ strcpy(path, vdev->name);
+ ret = vfio_get_device(group, path, vdev);
+ if (ret) {
+ error_report("vfio: failed to get device %s", path);
+ vfio_put_group(group);
+ return;
+ }
+
+ vfio_map_bars(vdev);
+
+ sysbus_init_mmio(sbdev, &vdev->bars[0].mmap_mem);
+}
+
+static const VMStateDescription vfio_platform_vmstate = {
+ .name = "vfio-platform",
+ .unmigratable = 1,
+};
+
+static void vfio_platform_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = vfio_platform_realize;
+ dc->vmsd = &vfio_platform_vmstate;
+ dc->desc = "VFIO-based platform device assignment";
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+static const TypeInfo vfio_platform_dev_info = {
+ .name = "vfio-platform",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(VFIODevice),
+ .class_init = vfio_platform_dev_class_init,
+};
+
+static void register_vfio_platform_dev_type(void)
+{
+ type_register_static(&vfio_platform_dev_info);
+}
+
+type_init(register_vfio_platform_dev_type)
--
1.9.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support
2014-02-26 2:37 ` [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support Kim Phillips
@ 2014-02-28 18:03 ` Alex Williamson
2014-03-05 0:24 ` Kim Phillips
2014-03-05 7:56 ` Eric Auger
1 sibling, 1 reply; 12+ messages in thread
From: Alex Williamson @ 2014-02-28 18:03 UTC (permalink / raw)
To: Kim Phillips
Cc: Peter Maydell, kim.phillips, eric.auger, stuart.yoder, qemu-devel,
agraf, Antonios Motakis, kvmarm, christoffer.dall
On Tue, 2014-02-25 at 20:37 -0600, Kim Phillips wrote:
> We basically add support for the SysBusDevice type in addition to the
> existing PCIDevice support. This involves taking common code from the
> existing vfio_initfn(), and putting it under a new vfio_find_get_group(),
> that both vfio_initfn() and the new vfio_platform_realize() call.
> Since realize() returns void, unlike PCIDevice's initfn(),
> error codes are moved into the error message text with %m.
> Some exceptions to the PCI path are added for platform devices,
> mostly in the form of early returns, since less setup is needed.
> I chose to reuse VFIODevice's config_size to determine whether
> the device was a PCI device or a platform device, which might
> need to change.
>
> Currently only MMIO access is supported at this time. It works
> because of qemu's stage 1 translation, but needs to be in stage 2
> in case other entities than the guest OS want to access it.
> A KVM patch to address this is in the works.
>
> The perceived path for future QEMU development is:
>
> - support allocating a variable number of regions
> - VFIODevice's bars[] become dynamically allocated *regions
> - VFIOBAR's device fd replaced with parent VFIODevice ptr,
> to facilitate BAR r/w ops calling vfio_eoi()
> - add support for interrupts
> - verify and test platform dev unmap path
> - test existing PCI path for any regressions
> - add support for creating platform devices on the qemu command line
> - currently device address specification is hardcoded for test
> development on Calxeda Midway's fff51000.ethernet device
> - reset is not supported and registration of reset functions is
> bypassed for platform devices.
> - there is no standard means of resetting a platform device,
> unsure if it suffices to be handled at device--VFIO binding time
On one hand, I had assumed we'd create a hw/misc/vfio/ directory and
perhaps split things into pci, common, vga, and platform. We already
need the pci vs vga split as there's lots of irrelevant and complicated
vga quirks that most people don't want to see. On the other hand, I'm
surprised how much of the PCI code you can re-use. Still, I think it
would be cleaner to create a VFIOPCIDevice and a VFIOPlatformDevice.
> Signed-off-by: Kim Phillips <kim.phillips@linaro.org>
> ---
> hw/misc/vfio.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 145 insertions(+), 35 deletions(-)
>
> diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
> index 8db182f..eed24db 100644
> --- a/hw/misc/vfio.c
> +++ b/hw/misc/vfio.c
> @@ -32,6 +32,7 @@
> #include "hw/pci/msi.h"
> #include "hw/pci/msix.h"
> #include "hw/pci/pci.h"
> +#include "hw/sysbus.h"
> #include "qemu-common.h"
> #include "qemu/error-report.h"
> #include "qemu/event_notifier.h"
> @@ -166,7 +167,10 @@ typedef struct VFIOMSIXInfo {
> } VFIOMSIXInfo;
>
> typedef struct VFIODevice {
> - PCIDevice pdev;
> + union {
> + PCIDevice pdev;
> + SysBusDevice sbdev;
> + };
> int fd;
> VFIOINTx intx;
> unsigned int config_size;
> @@ -180,6 +184,8 @@ typedef struct VFIODevice {
> VFIOMSIXInfo *msix;
> int nr_vectors; /* Number of MSI/MSIX vectors currently in use */
> int interrupt; /* Current interrupt type */
> + char *name; /* platform device name, e.g., fff51000.ethernet */
> + int nr_regions; /* platform devices' number of regions */
> VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */
> VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */
> PCIHostDeviceAddress host;
> @@ -2497,8 +2503,6 @@ empty_region:
> memory_region_init(submem, OBJECT(vdev), name, 0);
> }
>
> - memory_region_add_subregion(mem, offset, submem);
> -
The "mem" parameter to this function is never used if we do this, but
I'm not sure I buy into this change anyway, see below.
> return ret;
> }
>
> @@ -2552,6 +2556,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
> &bar->mmap_mem, &bar->mmap, size, 0, name)) {
> error_report("%s unsupported. Performance may be slow", name);
> }
> + memory_region_add_subregion(&bar->mem, 0, &bar->mmap_mem);
>
> if (vdev->msix && vdev->msix->table_bar == nr) {
> unsigned start;
> @@ -2566,15 +2571,38 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
> &vdev->msix->mmap, size, start, name)) {
> error_report("%s unsupported. Performance may be slow", name);
> }
> + memory_region_add_subregion(&bar->mem, start, &vdev->msix->mmap_mem);
> }
>
> vfio_bar_quirk_setup(vdev, nr);
> }
>
> +static void vfio_map_region(VFIODevice *vdev, int nr)
> +{
> + VFIOBAR *bar = &vdev->bars[nr];
> + unsigned size = bar->size;
> + char name[64];
> +
> + snprintf(name, sizeof(name), "VFIO %s region %d mmap", vdev->name, nr);
> +
> + if (vfio_mmap_bar(vdev, bar, &bar->mem,
> + &bar->mmap_mem, &bar->mmap, size, 0, name)) {
> + error_report("error mmapping %s: %m", name);
> + }
> +}
> +
> static void vfio_map_bars(VFIODevice *vdev)
> {
> int i;
>
> + if (!vdev->config_size) {
> + /* platform device */
> + for (i = 0; i < vdev->nr_regions; i++) {
> + vfio_map_region(vdev, i);
> + }
> + return;
> + }
I don't understand this, vfio_map_region() calls vfio_mmap_bar(), but
vfio_mmap_bar() has been gutted so that it only initializes the mmap
subregion, but never adds it. vfio_map_bar() does both the
initialization of the slow, read/write, memory region as well as adding
the mmap sub-region. I don't see where platform devices get a memory
region inserted anywhere into the guest address space.
> +
> for (i = 0; i < PCI_ROM_SLOT; i++) {
> vfio_map_bar(vdev, i);
> }
> @@ -3144,7 +3172,8 @@ static void vfio_pci_reset_handler(void *opaque)
>
> QLIST_FOREACH(group, &group_list, next) {
> QLIST_FOREACH(vdev, &group->device_list, next) {
> - if (vdev->needs_reset) {
> + /* HACK: restrict reset to PCI devices (have config_size) for now */
> + if (vdev->config_size && vdev->needs_reset) {
> vfio_pci_hot_reset_multi(vdev);
> }
> }
> @@ -3418,25 +3447,18 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
> DPRINTF("Device %s flags: %u, regions: %u, irgs: %u\n", name,
> dev_info.flags, dev_info.num_regions, dev_info.num_irqs);
>
> - if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI)) {
> - error_report("vfio: Um, this isn't a PCI device");
> - goto error;
> - }
> -
> + vdev->nr_regions = dev_info.num_regions;
> vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
>
> - if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
> + if (dev_info.num_regions > PCI_NUM_REGIONS) ||
> + ((dev_info.flags & VFIO_DEVICE_FLAGS_PCI) &&
> + (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1)) {
Now we start to have platform devices error out if they have more
regions than PCI knows about... That doesn't make much sense.
> error_report("vfio: unexpected number of io regions %u",
> dev_info.num_regions);
> goto error;
> }
>
> - if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
> - error_report("vfio: unexpected number of irqs %u", dev_info.num_irqs);
> - goto error;
> - }
> -
> - for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) {
> + for (i = 0; i < dev_info.num_regions; i++) {
> reg_info.index = i;
This would break PCI since there are region indexes beyond the BARs.
>
> ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info);
> @@ -3458,6 +3480,15 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
> QLIST_INIT(&vdev->bars[i].quirks);
> }
>
> + /* following is for PCI devices, at least for now */
> + if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI))
> + return 0;
> +
> + if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
> + error_report("vfio: unexpected number of irqs %u", dev_info.num_irqs);
> + goto error;
> + }
> +
> reg_info.index = VFIO_PCI_CONFIG_REGION_INDEX;
>
> ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info);
> @@ -3659,32 +3690,25 @@ static void vfio_unregister_err_notifier(VFIODevice *vdev)
> event_notifier_cleanup(&vdev->err_notifier);
> }
>
> -static int vfio_initfn(PCIDevice *pdev)
> +static VFIOGroup *vfio_find_get_group(char *path)
> {
> - VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
> VFIOGroup *group;
> - char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name;
> + char iommu_group_path[PATH_MAX], *group_name;
> ssize_t len;
> struct stat st;
> int groupid;
> - int ret;
>
> - /* Check that the host device exists */
> - snprintf(path, sizeof(path),
> - "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
> - vdev->host.domain, vdev->host.bus, vdev->host.slot,
> - vdev->host.function);
> if (stat(path, &st) < 0) {
> - error_report("vfio: error: no such host device: %s", path);
> - return -errno;
> + error_report("vfio: error: no such host device: %s: %m", path);
> + return NULL;
> }
>
> strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1);
>
> len = readlink(path, iommu_group_path, PATH_MAX);
> if (len <= 0) {
> - error_report("vfio: error no iommu_group for device");
> - return -errno;
> + error_report("vfio: error no iommu_group for device: %m");
> + return NULL;
> }
>
> iommu_group_path[len] = 0;
> @@ -3692,18 +3716,37 @@ static int vfio_initfn(PCIDevice *pdev)
>
> if (sscanf(group_name, "%d", &groupid) != 1) {
> error_report("vfio: error reading %s: %m", path);
> - return -errno;
> + return NULL;
> }
>
> - DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain,
> - vdev->host.bus, vdev->host.slot, vdev->host.function, groupid);
> -
> group = vfio_get_group(groupid);
> if (!group) {
> - error_report("vfio: failed to get group %d", groupid);
> - return -ENOENT;
> + error_report("vfio: failed to get group %d: %m", groupid);
> + return NULL;
> }
>
> + return group;
> +}
> +
> +static int vfio_initfn(PCIDevice *pdev)
> +{
> + VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
> + VFIOGroup *group;
> + char path[PATH_MAX];
> + int ret;
> +
> + /* Check that the host device exists */
> + snprintf(path, sizeof(path),
> + "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
> + vdev->host.domain, vdev->host.bus, vdev->host.slot,
> + vdev->host.function);
> +
> + group = vfio_find_get_group(path);
> +
> + DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain,
> + vdev->host.bus, vdev->host.slot, vdev->host.function,
> + group->groupid);
> +
> snprintf(path, sizeof(path), "%04x:%02x:%02x.%01x",
> vdev->host.domain, vdev->host.bus, vdev->host.slot,
> vdev->host.function);
> @@ -3916,3 +3959,70 @@ static void register_vfio_pci_dev_type(void)
> }
>
> type_init(register_vfio_pci_dev_type)
> +
> +
> +/*
> + * VFIO platform devices
> + */
> +static void vfio_platform_realize(DeviceState *dev, Error **errp)
> +{
> + SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
> + VFIODevice *vdev = DO_UPCAST(VFIODevice, sbdev, sbdev);
> + VFIOGroup *group;
> + char path[PATH_MAX];
> + int ret;
> +
> + vdev->name = malloc(PATH_MAX);
> + strcpy(vdev->name, "fff51000.ethernet");
> +
> + /* Check that the host device exists */
> + snprintf(path, sizeof(path),
> + "/sys/bus/platform/devices/%s/", vdev->name);
> +
> + group = vfio_find_get_group(path);
> + if (!group) {
> + error_report("vfio: failed to get group for device %s", path);
> + return;
> + }
> +
> + strcpy(path, vdev->name);
> + ret = vfio_get_device(group, path, vdev);
> + if (ret) {
> + error_report("vfio: failed to get device %s", path);
> + vfio_put_group(group);
> + return;
> + }
> +
> + vfio_map_bars(vdev);
> +
> + sysbus_init_mmio(sbdev, &vdev->bars[0].mmap_mem);
> +}
> +
> +static const VMStateDescription vfio_platform_vmstate = {
> + .name = "vfio-platform",
> + .unmigratable = 1,
> +};
> +
> +static void vfio_platform_dev_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->realize = vfio_platform_realize;
> + dc->vmsd = &vfio_platform_vmstate;
> + dc->desc = "VFIO-based platform device assignment";
> + set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +}
> +
> +static const TypeInfo vfio_platform_dev_info = {
> + .name = "vfio-platform",
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(VFIODevice),
> + .class_init = vfio_platform_dev_class_init,
> +};
> +
> +static void register_vfio_platform_dev_type(void)
> +{
> + type_register_static(&vfio_platform_dev_info);
> +}
> +
> +type_init(register_vfio_platform_dev_type)
This all looks reasonable, but I suspect it would be cleaner if
vfio_find_get_group() was in a common file along with basic mmap and
read/write access functions. Thanks,
Alex
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support
2014-02-28 18:03 ` Alex Williamson
@ 2014-03-05 0:24 ` Kim Phillips
2014-03-05 1:23 ` Alex Williamson
0 siblings, 1 reply; 12+ messages in thread
From: Kim Phillips @ 2014-03-05 0:24 UTC (permalink / raw)
To: alex.williamson
Cc: peter.maydell, kim.phillips, eric.auger, stuart.yoder, qemu-devel,
agraf, a.motakis, kvmarm, christoffer.dall
On Fri, 28 Feb 2014 11:03:18 -0700
Alex Williamson <alex.williamson@redhat.com> wrote:
> On Tue, 2014-02-25 at 20:37 -0600, Kim Phillips wrote:
> > - support allocating a variable number of regions
> > - VFIODevice's bars[] become dynamically allocated *regions
> > - VFIOBAR's device fd replaced with parent VFIODevice ptr,
> > to facilitate BAR r/w ops calling vfio_eoi()
>
> On one hand, I had assumed we'd create a hw/misc/vfio/ directory and
> perhaps split things into pci, common, vga, and platform. We already
> need the pci vs vga split as there's lots of irrelevant and complicated
> vga quirks that most people don't want to see. On the other hand, I'm
> surprised how much of the PCI code you can re-use. Still, I think it
> would be cleaner to create a VFIOPCIDevice and a VFIOPlatformDevice.
sounds good, had started down that path but reverted it because I too
realized how much code was indeed being reused. I'm ok with
VFIOPCIDevice and a separate VFIOPlatformDevice for now, thanks.
> > static void vfio_map_bars(VFIODevice *vdev)
> > {
> > int i;
> >
> > + if (!vdev->config_size) {
> > + /* platform device */
> > + for (i = 0; i < vdev->nr_regions; i++) {
> > + vfio_map_region(vdev, i);
> > + }
> > + return;
> > + }
>
> I don't understand this, vfio_map_region() calls vfio_mmap_bar(), but
> vfio_mmap_bar() has been gutted so that it only initializes the mmap
> subregion, but never adds it. vfio_map_bar() does both the
> initialization of the slow, read/write, memory region as well as adding
> the mmap sub-region. I don't see where platform devices get a memory
> region inserted anywhere into the guest address space.
it's being done by the board code via the first RFC/patch ("hw/arm/virt:
add a Calxeda XGMAC device"), and vfio_mmap_bar()'s call to
memory_region_init_ram_ptr().
Yeah, the slow, r/w ops region path isn't used, and I'm not sure how to
make it work without addressing the problems the first RFC presents.
> > - if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
> > + if (dev_info.num_regions > PCI_NUM_REGIONS) ||
> > + ((dev_info.flags & VFIO_DEVICE_FLAGS_PCI) &&
> > + (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1)) {
>
> Now we start to have platform devices error out if they have more
> regions than PCI knows about... That doesn't make much sense.
right, I should have made it more clear that the multiple-regions code
is sketchy in the "support allocating a variable number of regions"
blurb in the commit text of this RFC.
> > +static void register_vfio_platform_dev_type(void)
> > +{
> > + type_register_static(&vfio_platform_dev_info);
> > +}
> > +
> > +type_init(register_vfio_platform_dev_type)
>
> This all looks reasonable, but I suspect it would be cleaner if
> vfio_find_get_group() was in a common file along with basic mmap and
> read/write access functions. Thanks,
so rename existing hw/misc/vfio.c to its original name vfio-pci.c, and
load all common functions back into a vfio.c?
Kim
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support
2014-03-05 0:24 ` Kim Phillips
@ 2014-03-05 1:23 ` Alex Williamson
2014-03-05 11:28 ` Andreas Färber
0 siblings, 1 reply; 12+ messages in thread
From: Alex Williamson @ 2014-03-05 1:23 UTC (permalink / raw)
To: Kim Phillips
Cc: peter.maydell, kim.phillips, eric.auger, stuart.yoder, qemu-devel,
agraf, a.motakis, kvmarm, christoffer.dall
On Tue, 2014-03-04 at 18:24 -0600, Kim Phillips wrote:
> On Fri, 28 Feb 2014 11:03:18 -0700
> Alex Williamson <alex.williamson@redhat.com> wrote:
>
> > On Tue, 2014-02-25 at 20:37 -0600, Kim Phillips wrote:
> > > - support allocating a variable number of regions
> > > - VFIODevice's bars[] become dynamically allocated *regions
> > > - VFIOBAR's device fd replaced with parent VFIODevice ptr,
> > > to facilitate BAR r/w ops calling vfio_eoi()
> >
> > On one hand, I had assumed we'd create a hw/misc/vfio/ directory and
> > perhaps split things into pci, common, vga, and platform. We already
> > need the pci vs vga split as there's lots of irrelevant and complicated
> > vga quirks that most people don't want to see. On the other hand, I'm
> > surprised how much of the PCI code you can re-use. Still, I think it
> > would be cleaner to create a VFIOPCIDevice and a VFIOPlatformDevice.
>
> sounds good, had started down that path but reverted it because I too
> realized how much code was indeed being reused. I'm ok with
> VFIOPCIDevice and a separate VFIOPlatformDevice for now, thanks.
>
> > > static void vfio_map_bars(VFIODevice *vdev)
> > > {
> > > int i;
> > >
> > > + if (!vdev->config_size) {
> > > + /* platform device */
> > > + for (i = 0; i < vdev->nr_regions; i++) {
> > > + vfio_map_region(vdev, i);
> > > + }
> > > + return;
> > > + }
> >
> > I don't understand this, vfio_map_region() calls vfio_mmap_bar(), but
> > vfio_mmap_bar() has been gutted so that it only initializes the mmap
> > subregion, but never adds it. vfio_map_bar() does both the
> > initialization of the slow, read/write, memory region as well as adding
> > the mmap sub-region. I don't see where platform devices get a memory
> > region inserted anywhere into the guest address space.
>
> it's being done by the board code via the first RFC/patch ("hw/arm/virt:
> add a Calxeda XGMAC device"), and vfio_mmap_bar()'s call to
> memory_region_init_ram_ptr().
>
> Yeah, the slow, r/w ops region path isn't used, and I'm not sure how to
> make it work without addressing the problems the first RFC presents.
>
> > > - if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
> > > + if (dev_info.num_regions > PCI_NUM_REGIONS) ||
> > > + ((dev_info.flags & VFIO_DEVICE_FLAGS_PCI) &&
> > > + (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1)) {
> >
> > Now we start to have platform devices error out if they have more
> > regions than PCI knows about... That doesn't make much sense.
>
> right, I should have made it more clear that the multiple-regions code
> is sketchy in the "support allocating a variable number of regions"
> blurb in the commit text of this RFC.
>
> > > +static void register_vfio_platform_dev_type(void)
> > > +{
> > > + type_register_static(&vfio_platform_dev_info);
> > > +}
> > > +
> > > +type_init(register_vfio_platform_dev_type)
> >
> > This all looks reasonable, but I suspect it would be cleaner if
> > vfio_find_get_group() was in a common file along with basic mmap and
> > read/write access functions. Thanks,
>
> so rename existing hw/misc/vfio.c to its original name vfio-pci.c, and
> load all common functions back into a vfio.c?
I think hw/misc/vfio/{pci.c,common.c,platform.c,etc} Thanks,
Alex
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC 1/2] hw/arm/virt: add a Calxeda XGMAC device
2014-02-26 2:37 ` [Qemu-devel] [RFC 1/2] hw/arm/virt: add a Calxeda XGMAC device Kim Phillips
@ 2014-03-05 4:27 ` Eric Auger
2014-03-05 11:25 ` Andreas Färber
0 siblings, 1 reply; 12+ messages in thread
From: Eric Auger @ 2014-03-05 4:27 UTC (permalink / raw)
To: Kim Phillips
Cc: Peter Maydell, kim.phillips, agraf, stuart.yoder, qemu-devel,
alex.williamson, Antonios Motakis, kvmarm, Christoffer Dall
[-- Attachment #1: Type: text/plain, Size: 3913 bytes --]
Hi Kim,
- Parameter 'driver' expects pluggable device type
this can be fixed setting dc->cannot_instantiate_with_device_add_yet to
false in vfio_platform_dev_class_init. You do not get the error anymore.
However I must aknowledge I have not studies all possible side effects of
this setting and maybe there is a cleaner way to achieve the same result.
Then you can add additional properties in dc->props.
- location of the device in gpa space and impact on RAM size: my
understanding is that device could sit in another location than the hpa's
one and you are not compelled to use the same address.
- we effectively need to work on fdt tree generation for VFIO devices
Best Regards
Eric
On 26 February 2014 03:37, Kim Phillips <kim.phillips@linaro.org> wrote:
> This is a hack and only serves as an example of what needs to be
> done to make the next RFC - add vfio-platform support - work
> for development purposes on a Calxeda Midway system. We don't want
> mach-virt to always create this ethernet device - DO NOT APPLY, etc.
>
> Initial attempts to convince QEMU to create a memory mapped device
> on the command line (e.g., -device vfio-platform,name=fff51000.ethernet)
> would fail with "Parameter 'driver' expects pluggable device type".
> Any guidance as to how to overcome this apparent design limitation
> is welcome.
>
> RAM is reduced from 30 to 1GiB such as to not overlap the xgmac device's
> physical address. Not sure if the 30GiB RAM (or whatever the user sets
> it to with -m) could be set up above 0x1_0000_0000, but there is probably
> extra work needed to resolve this type of conflict.
>
> note: vfio-platform interrupt support development may want interrupt
> property data filled; here it's omitted for the time being.
>
> Not-signed-off-by: Kim Phillips <kim.phillips@linaro.org>
> ---
> hw/arm/virt.c | 24 +++++++++++++++++++++++-
> 1 file changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 517f2fe..75edf33 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -65,6 +65,7 @@ enum {
> VIRT_GIC_CPU,
> VIRT_UART,
> VIRT_MMIO,
> + VIRT_ETHERNET,
> };
>
> typedef struct MemMapEntry {
> @@ -106,7 +107,8 @@ static const MemMapEntry a15memmap[] = {
> [VIRT_MMIO] = { 0xa000000, 0x200 },
> /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that
> size */
> /* 0x10000000 .. 0x40000000 reserved for PCI */
> - [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
> + [VIRT_MEM] = { 0x40000000, 1ULL * 1024 * 1024 * 1024 },
> + [VIRT_ETHERNET] = { 0xfff51000, 0x1000 },
> };
>
> static const int a15irqmap[] = {
> @@ -291,6 +293,25 @@ static void create_uart(const VirtBoardInfo *vbi,
> qemu_irq *pic)
> g_free(nodename);
> }
>
> +static void create_ethernet(const VirtBoardInfo *vbi, qemu_irq *pic)
> +{
> + char *nodename;
> + hwaddr base = vbi->memmap[VIRT_ETHERNET].base;
> + hwaddr size = vbi->memmap[VIRT_ETHERNET].size;
> + const char compat[] = "calxeda,hb-xgmac";
> +
> + sysbus_create_simple("vfio-platform", base, NULL);
> +
> + nodename = g_strdup_printf("/ethernet@%" PRIx64, base);
> + qemu_fdt_add_subnode(vbi->fdt, nodename);
> +
> + /* Note that we can't use setprop_string because of the embedded NUL
> */
> + qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat,
> sizeof(compat));
> + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base, 2,
> size);
> +
> + g_free(nodename);
> +}
> +
> static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
> {
> int i;
> @@ -419,6 +440,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
> }
>
> create_uart(vbi, pic);
> + create_ethernet(vbi, pic);
>
> /* Create mmio transports, so the user can create virtio backends
> * (which will be automatically plugged in to the transports). If
> --
> 1.9.0
>
>
[-- Attachment #2: Type: text/html, Size: 4768 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support
2014-02-26 2:37 ` [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support Kim Phillips
2014-02-28 18:03 ` Alex Williamson
@ 2014-03-05 7:56 ` Eric Auger
1 sibling, 0 replies; 12+ messages in thread
From: Eric Auger @ 2014-03-05 7:56 UTC (permalink / raw)
To: Kim Phillips
Cc: Peter Maydell, kim.phillips, Alexander Graf, stuart.yoder,
qemu-devel, alex.williamson, Antonios Motakis, kvmarm,
Christoffer Dall
[-- Attachment #1: Type: text/plain, Size: 13497 bytes --]
Hi Kim,
1) I agree with Alex on the fact I would prefer to have the qemu-side
platform device code separated from PCI device one, both using a separate
generic helper code. Indeed calling functions referencing BAR in the
platform device does not look natural to me; although I understand the
code reuse rationale. This is also how the kernel side code is laid out.
2) about nr_regions. What is the number of nr_regions do you expect for
platform_devices? bars[] possible overshoot as already mentionned if
nr_regions > 6.
3) I understand you build nr_regions MemoryRegion (each mmaped on the hpa).
However I understand you only attach a single one to the SysBusDevice in
vfio_platform_realize:
sysbus_init_mmio(sbdev, &vdev->bars[0].mmap_mem); this MemRegion is
assigned a gpa in virt.c? is it the correct understanding? What is the mem
hierarchy that is targetted. In PCI there are subregions. In this device,
there would be a single layer or hierarchy?
4) vfio_unmap_bars should destroy the platform device mmaped regions
(vdev->mmap_mem and munmap the correspond hva (currently on slow regions
are munmapped and destroyed)
Best Regards
Eric
On 26 February 2014 03:37, Kim Phillips <kim.phillips@linaro.org> wrote:
> We basically add support for the SysBusDevice type in addition to the
> existing PCIDevice support. This involves taking common code from the
> existing vfio_initfn(), and putting it under a new vfio_find_get_group(),
> that both vfio_initfn() and the new vfio_platform_realize() call.
> Since realize() returns void, unlike PCIDevice's initfn(),
> error codes are moved into the error message text with %m.
> Some exceptions to the PCI path are added for platform devices,
> mostly in the form of early returns, since less setup is needed.
> I chose to reuse VFIODevice's config_size to determine whether
> the device was a PCI device or a platform device, which might
> need to change.
>
> Currently only MMIO access is supported at this time. It works
> because of qemu's stage 1 translation, but needs to be in stage 2
> in case other entities than the guest OS want to access it.
> A KVM patch to address this is in the works.
>
> The perceived path for future QEMU development is:
>
> - support allocating a variable number of regions
> - VFIODevice's bars[] become dynamically allocated *regions
> - VFIOBAR's device fd replaced with parent VFIODevice ptr,
> to facilitate BAR r/w ops calling vfio_eoi()
> - add support for interrupts
> - verify and test platform dev unmap path
> - test existing PCI path for any regressions
> - add support for creating platform devices on the qemu command line
> - currently device address specification is hardcoded for test
> development on Calxeda Midway's fff51000.ethernet device
> - reset is not supported and registration of reset functions is
> bypassed for platform devices.
> - there is no standard means of resetting a platform device,
> unsure if it suffices to be handled at device--VFIO binding time
>
> Signed-off-by: Kim Phillips <kim.phillips@linaro.org>
> ---
> hw/misc/vfio.c | 180
> ++++++++++++++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 145 insertions(+), 35 deletions(-)
>
> diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
> index 8db182f..eed24db 100644
> --- a/hw/misc/vfio.c
> +++ b/hw/misc/vfio.c
> @@ -32,6 +32,7 @@
> #include "hw/pci/msi.h"
> #include "hw/pci/msix.h"
> #include "hw/pci/pci.h"
> +#include "hw/sysbus.h"
> #include "qemu-common.h"
> #include "qemu/error-report.h"
> #include "qemu/event_notifier.h"
> @@ -166,7 +167,10 @@ typedef struct VFIOMSIXInfo {
> } VFIOMSIXInfo;
>
> typedef struct VFIODevice {
> - PCIDevice pdev;
> + union {
> + PCIDevice pdev;
> + SysBusDevice sbdev;
> + };
> int fd;
> VFIOINTx intx;
> unsigned int config_size;
> @@ -180,6 +184,8 @@ typedef struct VFIODevice {
> VFIOMSIXInfo *msix;
> int nr_vectors; /* Number of MSI/MSIX vectors currently in use */
> int interrupt; /* Current interrupt type */
> + char *name; /* platform device name, e.g., fff51000.ethernet */
> + int nr_regions; /* platform devices' number of regions */
> VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */
> VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */
> PCIHostDeviceAddress host;
> @@ -2497,8 +2503,6 @@ empty_region:
> memory_region_init(submem, OBJECT(vdev), name, 0);
> }
>
> - memory_region_add_subregion(mem, offset, submem);
> -
> return ret;
> }
>
> @@ -2552,6 +2556,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
> &bar->mmap_mem, &bar->mmap, size, 0, name)) {
> error_report("%s unsupported. Performance may be slow", name);
> }
> + memory_region_add_subregion(&bar->mem, 0, &bar->mmap_mem);
>
> if (vdev->msix && vdev->msix->table_bar == nr) {
> unsigned start;
> @@ -2566,15 +2571,38 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
> &vdev->msix->mmap, size, start, name)) {
> error_report("%s unsupported. Performance may be slow", name);
> }
> + memory_region_add_subregion(&bar->mem, start,
> &vdev->msix->mmap_mem);
> }
>
> vfio_bar_quirk_setup(vdev, nr);
> }
>
> +static void vfio_map_region(VFIODevice *vdev, int nr)
> +{
> + VFIOBAR *bar = &vdev->bars[nr];
> + unsigned size = bar->size;
> + char name[64];
> +
> + snprintf(name, sizeof(name), "VFIO %s region %d mmap", vdev->name,
> nr);
> +
> + if (vfio_mmap_bar(vdev, bar, &bar->mem,
> + &bar->mmap_mem, &bar->mmap, size, 0, name)) {
> + error_report("error mmapping %s: %m", name);
> + }
> +}
> +
> static void vfio_map_bars(VFIODevice *vdev)
> {
> int i;
>
> + if (!vdev->config_size) {
> + /* platform device */
> + for (i = 0; i < vdev->nr_regions; i++) {
> + vfio_map_region(vdev, i);
> + }
> + return;
> + }
> +
> for (i = 0; i < PCI_ROM_SLOT; i++) {
> vfio_map_bar(vdev, i);
> }
> @@ -3144,7 +3172,8 @@ static void vfio_pci_reset_handler(void *opaque)
>
> QLIST_FOREACH(group, &group_list, next) {
> QLIST_FOREACH(vdev, &group->device_list, next) {
> - if (vdev->needs_reset) {
> + /* HACK: restrict reset to PCI devices (have config_size) for
> now */
> + if (vdev->config_size && vdev->needs_reset) {
> vfio_pci_hot_reset_multi(vdev);
> }
> }
> @@ -3418,25 +3447,18 @@ static int vfio_get_device(VFIOGroup *group, const
> char *name, VFIODevice *vdev)
> DPRINTF("Device %s flags: %u, regions: %u, irgs: %u\n", name,
> dev_info.flags, dev_info.num_regions, dev_info.num_irqs);
>
> - if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI)) {
> - error_report("vfio: Um, this isn't a PCI device");
> - goto error;
> - }
> -
> + vdev->nr_regions = dev_info.num_regions;
> vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
>
> - if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
> + if (dev_info.num_regions > PCI_NUM_REGIONS) ||
> + ((dev_info.flags & VFIO_DEVICE_FLAGS_PCI) &&
> + (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1)) {
> error_report("vfio: unexpected number of io regions %u",
> dev_info.num_regions);
> goto error;
> }
>
> - if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
> - error_report("vfio: unexpected number of irqs %u",
> dev_info.num_irqs);
> - goto error;
> - }
> -
> - for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX;
> i++) {
> + for (i = 0; i < dev_info.num_regions; i++) {
> reg_info.index = i;
>
> ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info);
> @@ -3458,6 +3480,15 @@ static int vfio_get_device(VFIOGroup *group, const
> char *name, VFIODevice *vdev)
> QLIST_INIT(&vdev->bars[i].quirks);
> }
>
> + /* following is for PCI devices, at least for now */
> + if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI))
> + return 0;
> +
> + if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
> + error_report("vfio: unexpected number of irqs %u",
> dev_info.num_irqs);
> + goto error;
> + }
> +
> reg_info.index = VFIO_PCI_CONFIG_REGION_INDEX;
>
> ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info);
> @@ -3659,32 +3690,25 @@ static void
> vfio_unregister_err_notifier(VFIODevice *vdev)
> event_notifier_cleanup(&vdev->err_notifier);
> }
>
> -static int vfio_initfn(PCIDevice *pdev)
> +static VFIOGroup *vfio_find_get_group(char *path)
> {
> - VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
> VFIOGroup *group;
> - char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name;
> + char iommu_group_path[PATH_MAX], *group_name;
> ssize_t len;
> struct stat st;
> int groupid;
> - int ret;
>
> - /* Check that the host device exists */
> - snprintf(path, sizeof(path),
> - "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
> - vdev->host.domain, vdev->host.bus, vdev->host.slot,
> - vdev->host.function);
> if (stat(path, &st) < 0) {
> - error_report("vfio: error: no such host device: %s", path);
> - return -errno;
> + error_report("vfio: error: no such host device: %s: %m", path);
> + return NULL;
> }
>
> strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1);
>
> len = readlink(path, iommu_group_path, PATH_MAX);
> if (len <= 0) {
> - error_report("vfio: error no iommu_group for device");
> - return -errno;
> + error_report("vfio: error no iommu_group for device: %m");
> + return NULL;
> }
>
> iommu_group_path[len] = 0;
> @@ -3692,18 +3716,37 @@ static int vfio_initfn(PCIDevice *pdev)
>
> if (sscanf(group_name, "%d", &groupid) != 1) {
> error_report("vfio: error reading %s: %m", path);
> - return -errno;
> + return NULL;
> }
>
> - DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__,
> vdev->host.domain,
> - vdev->host.bus, vdev->host.slot, vdev->host.function,
> groupid);
> -
> group = vfio_get_group(groupid);
> if (!group) {
> - error_report("vfio: failed to get group %d", groupid);
> - return -ENOENT;
> + error_report("vfio: failed to get group %d: %m", groupid);
> + return NULL;
> }
>
> + return group;
> +}
> +
> +static int vfio_initfn(PCIDevice *pdev)
> +{
> + VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
> + VFIOGroup *group;
> + char path[PATH_MAX];
> + int ret;
> +
> + /* Check that the host device exists */
> + snprintf(path, sizeof(path),
> + "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
> + vdev->host.domain, vdev->host.bus, vdev->host.slot,
> + vdev->host.function);
> +
> + group = vfio_find_get_group(path);
> +
> + DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__,
> vdev->host.domain,
> + vdev->host.bus, vdev->host.slot, vdev->host.function,
> + group->groupid);
> +
> snprintf(path, sizeof(path), "%04x:%02x:%02x.%01x",
> vdev->host.domain, vdev->host.bus, vdev->host.slot,
> vdev->host.function);
> @@ -3916,3 +3959,70 @@ static void register_vfio_pci_dev_type(void)
> }
>
> type_init(register_vfio_pci_dev_type)
> +
> +
> +/*
> + * VFIO platform devices
> + */
> +static void vfio_platform_realize(DeviceState *dev, Error **errp)
> +{
> + SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
> + VFIODevice *vdev = DO_UPCAST(VFIODevice, sbdev, sbdev);
> + VFIOGroup *group;
> + char path[PATH_MAX];
> + int ret;
> +
> + vdev->name = malloc(PATH_MAX);
> + strcpy(vdev->name, "fff51000.ethernet");
> +
> + /* Check that the host device exists */
> + snprintf(path, sizeof(path),
> + "/sys/bus/platform/devices/%s/", vdev->name);
> +
> + group = vfio_find_get_group(path);
> + if (!group) {
> + error_report("vfio: failed to get group for device %s", path);
> + return;
> + }
> +
> + strcpy(path, vdev->name);
> + ret = vfio_get_device(group, path, vdev);
> + if (ret) {
> + error_report("vfio: failed to get device %s", path);
> + vfio_put_group(group);
> + return;
> + }
> +
> + vfio_map_bars(vdev);
> +
> + sysbus_init_mmio(sbdev, &vdev->bars[0].mmap_mem);
> +}
> +
> +static const VMStateDescription vfio_platform_vmstate = {
> + .name = "vfio-platform",
> + .unmigratable = 1,
> +};
> +
> +static void vfio_platform_dev_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->realize = vfio_platform_realize;
> + dc->vmsd = &vfio_platform_vmstate;
> + dc->desc = "VFIO-based platform device assignment";
> + set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +}
> +
> +static const TypeInfo vfio_platform_dev_info = {
> + .name = "vfio-platform",
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(VFIODevice),
> + .class_init = vfio_platform_dev_class_init,
> +};
> +
> +static void register_vfio_platform_dev_type(void)
> +{
> + type_register_static(&vfio_platform_dev_info);
> +}
> +
> +type_init(register_vfio_platform_dev_type)
> --
> 1.9.0
>
>
[-- Attachment #2: Type: text/html, Size: 15765 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC 1/2] hw/arm/virt: add a Calxeda XGMAC device
2014-03-05 4:27 ` Eric Auger
@ 2014-03-05 11:25 ` Andreas Färber
2014-03-06 2:27 ` Eric Auger
0 siblings, 1 reply; 12+ messages in thread
From: Andreas Färber @ 2014-03-05 11:25 UTC (permalink / raw)
To: Eric Auger, Kim Phillips
Cc: Peter Maydell, kim.phillips, stuart.yoder, Markus Armbruster,
qemu-devel, agraf, alex.williamson, Antonios Motakis, kvmarm,
Christoffer Dall
Hi,
Am 05.03.2014 05:27, schrieb Eric Auger:
> Hi Kim,
>
> - Parameter 'driver' expects pluggable device type
> this can be fixed setting dc->cannot_instantiate_with_device_add_yet to
> false in vfio_platform_dev_class_init. You do not get the error anymore.
> However I must aknowledge I have not studies all possible side effects
> of this setting and maybe there is a cleaner way to achieve the same
> result.
If the realize/init function sets up MMIO mappings and IRQs itself
(rather than expecting the code instantiating the device to do so) then
you are free to set that field to false.
In this case that would be vbi->memmap[VIRT_ETHERNET].base in
create_ethernet(), so I have doubts.
Regards,
Andreas
> Then you can add additional properties in dc->props.
> - location of the device in gpa space and impact on RAM size: my
> understanding is that device could sit in another location than the
> hpa's one and you are not compelled to use the same address.
> - we effectively need to work on fdt tree generation for VFIO devices
>
> Best Regards
>
> Eric
>
>
> On 26 February 2014 03:37, Kim Phillips <kim.phillips@linaro.org
> <mailto:kim.phillips@linaro.org>> wrote:
>
> This is a hack and only serves as an example of what needs to be
> done to make the next RFC - add vfio-platform support - work
> for development purposes on a Calxeda Midway system. We don't want
> mach-virt to always create this ethernet device - DO NOT APPLY, etc.
>
> Initial attempts to convince QEMU to create a memory mapped device
> on the command line (e.g., -device vfio-platform,name=fff51000.ethernet)
> would fail with "Parameter 'driver' expects pluggable device type".
> Any guidance as to how to overcome this apparent design limitation
> is welcome.
>
> RAM is reduced from 30 to 1GiB such as to not overlap the xgmac device's
> physical address. Not sure if the 30GiB RAM (or whatever the user sets
> it to with -m) could be set up above 0x1_0000_0000, but there is
> probably
> extra work needed to resolve this type of conflict.
>
> note: vfio-platform interrupt support development may want interrupt
> property data filled; here it's omitted for the time being.
>
> Not-signed-off-by: Kim Phillips <kim.phillips@linaro.org
> <mailto:kim.phillips@linaro.org>>
> ---
> hw/arm/virt.c | 24 +++++++++++++++++++++++-
> 1 file changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 517f2fe..75edf33 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -65,6 +65,7 @@ enum {
> VIRT_GIC_CPU,
> VIRT_UART,
> VIRT_MMIO,
> + VIRT_ETHERNET,
> };
>
> typedef struct MemMapEntry {
> @@ -106,7 +107,8 @@ static const MemMapEntry a15memmap[] = {
> [VIRT_MMIO] = { 0xa000000, 0x200 },
> /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of
> that size */
> /* 0x10000000 .. 0x40000000 reserved for PCI */
> - [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
> + [VIRT_MEM] = { 0x40000000, 1ULL * 1024 * 1024 * 1024 },
> + [VIRT_ETHERNET] = { 0xfff51000, 0x1000 },
> };
>
> static const int a15irqmap[] = {
> @@ -291,6 +293,25 @@ static void create_uart(const VirtBoardInfo
> *vbi, qemu_irq *pic)
> g_free(nodename);
> }
>
> +static void create_ethernet(const VirtBoardInfo *vbi, qemu_irq *pic)
> +{
> + char *nodename;
> + hwaddr base = vbi->memmap[VIRT_ETHERNET].base;
> + hwaddr size = vbi->memmap[VIRT_ETHERNET].size;
> + const char compat[] = "calxeda,hb-xgmac";
> +
> + sysbus_create_simple("vfio-platform", base, NULL);
> +
> + nodename = g_strdup_printf("/ethernet@%" PRIx64, base);
> + qemu_fdt_add_subnode(vbi->fdt, nodename);
> +
> + /* Note that we can't use setprop_string because of the
> embedded NUL */
> + qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat,
> sizeof(compat));
> + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2,
> base, 2, size);
> +
> + g_free(nodename);
> +}
> +
> static void create_virtio_devices(const VirtBoardInfo *vbi,
> qemu_irq *pic)
> {
> int i;
> @@ -419,6 +440,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
> }
>
> create_uart(vbi, pic);
> + create_ethernet(vbi, pic);
>
> /* Create mmio transports, so the user can create virtio backends
> * (which will be automatically plugged in to the transports). If
> --
> 1.9.0
>
>
--
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support
2014-03-05 1:23 ` Alex Williamson
@ 2014-03-05 11:28 ` Andreas Färber
2014-03-05 11:30 ` Paolo Bonzini
0 siblings, 1 reply; 12+ messages in thread
From: Andreas Färber @ 2014-03-05 11:28 UTC (permalink / raw)
To: Alex Williamson, Kim Phillips, Paolo Bonzini
Cc: peter.maydell, kim.phillips, stuart.yoder, eric.auger, qemu-devel,
agraf, a.motakis, kvmarm, christoffer.dall
Am 05.03.2014 02:23, schrieb Alex Williamson:
> On Tue, 2014-03-04 at 18:24 -0600, Kim Phillips wrote:
>> On Fri, 28 Feb 2014 11:03:18 -0700
>> Alex Williamson <alex.williamson@redhat.com> wrote:
>>
>>> This all looks reasonable, but I suspect it would be cleaner if
>>> vfio_find_get_group() was in a common file along with basic mmap and
>>> read/write access functions. Thanks,
>>
>> so rename existing hw/misc/vfio.c to its original name vfio-pci.c, and
>> load all common functions back into a vfio.c?
>
> I think hw/misc/vfio/{pci.c,common.c,platform.c,etc} Thanks,
What about hw/vfio/ then?
Andreas
--
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support
2014-03-05 11:28 ` Andreas Färber
@ 2014-03-05 11:30 ` Paolo Bonzini
0 siblings, 0 replies; 12+ messages in thread
From: Paolo Bonzini @ 2014-03-05 11:30 UTC (permalink / raw)
To: Andreas Färber, Alex Williamson, Kim Phillips
Cc: peter.maydell, kim.phillips, stuart.yoder, eric.auger, qemu-devel,
agraf, a.motakis, kvmarm, christoffer.dall
Il 05/03/2014 12:28, Andreas Färber ha scritto:
> Am 05.03.2014 02:23, schrieb Alex Williamson:
>> On Tue, 2014-03-04 at 18:24 -0600, Kim Phillips wrote:
>>> On Fri, 28 Feb 2014 11:03:18 -0700
>>> Alex Williamson <alex.williamson@redhat.com> wrote:
>>>
>>>> This all looks reasonable, but I suspect it would be cleaner if
>>>> vfio_find_get_group() was in a common file along with basic mmap and
>>>> read/write access functions. Thanks,
>>>
>>> so rename existing hw/misc/vfio.c to its original name vfio-pci.c, and
>>> load all common functions back into a vfio.c?
>>
>> I think hw/misc/vfio/{pci.c,common.c,platform.c,etc} Thanks,
>
> What about hw/vfio/ then?
Agreed.
Paolo
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC 1/2] hw/arm/virt: add a Calxeda XGMAC device
2014-03-05 11:25 ` Andreas Färber
@ 2014-03-06 2:27 ` Eric Auger
0 siblings, 0 replies; 12+ messages in thread
From: Eric Auger @ 2014-03-06 2:27 UTC (permalink / raw)
To: Andreas Färber
Cc: Peter Maydell, kim.phillips, stuart.yoder, Kim Phillips,
Markus Armbruster, qemu-devel, Alexander Graf, alex.williamson,
Antonios Motakis, kvmarm, Christoffer Dall
Hi Andreas
> If the realize/init function sets up MMIO mappings and IRQs itself
> (rather than expecting the code instantiating the device to do so) then
> you are free to set that field to false.
Thank you for the confirmation
> In this case that would be vbi->memmap[VIRT_ETHERNET].base in
> create_ethernet(), so I have doubts.
Indeed the intent is to move the hardcoded
address currently set in virt.c into something more dynamic in vfio.c' realize.
Best Regards
Eric
On 5 March 2014 12:25, Andreas Färber <afaerber@suse.de> wrote:
> Hi,
>
> Am 05.03.2014 05:27, schrieb Eric Auger:
>> Hi Kim,
>>
>> - Parameter 'driver' expects pluggable device type
>> this can be fixed setting dc->cannot_instantiate_with_device_add_yet to
>> false in vfio_platform_dev_class_init. You do not get the error anymore.
>> However I must aknowledge I have not studies all possible side effects
>> of this setting and maybe there is a cleaner way to achieve the same
>> result.
>
> If the realize/init function sets up MMIO mappings and IRQs itself
> (rather than expecting the code instantiating the device to do so) then
> you are free to set that field to false.
>
> In this case that would be vbi->memmap[VIRT_ETHERNET].base in
> create_ethernet(), so I have doubts.
>
> Regards,
> Andreas
>
>> Then you can add additional properties in dc->props.
>> - location of the device in gpa space and impact on RAM size: my
>> understanding is that device could sit in another location than the
>> hpa's one and you are not compelled to use the same address.
>> - we effectively need to work on fdt tree generation for VFIO devices
>>
>> Best Regards
>>
>> Eric
>>
>>
>> On 26 February 2014 03:37, Kim Phillips <kim.phillips@linaro.org
>> <mailto:kim.phillips@linaro.org>> wrote:
>>
>> This is a hack and only serves as an example of what needs to be
>> done to make the next RFC - add vfio-platform support - work
>> for development purposes on a Calxeda Midway system. We don't want
>> mach-virt to always create this ethernet device - DO NOT APPLY, etc.
>>
>> Initial attempts to convince QEMU to create a memory mapped device
>> on the command line (e.g., -device vfio-platform,name=fff51000.ethernet)
>> would fail with "Parameter 'driver' expects pluggable device type".
>> Any guidance as to how to overcome this apparent design limitation
>> is welcome.
>>
>> RAM is reduced from 30 to 1GiB such as to not overlap the xgmac device's
>> physical address. Not sure if the 30GiB RAM (or whatever the user sets
>> it to with -m) could be set up above 0x1_0000_0000, but there is
>> probably
>> extra work needed to resolve this type of conflict.
>>
>> note: vfio-platform interrupt support development may want interrupt
>> property data filled; here it's omitted for the time being.
>>
>> Not-signed-off-by: Kim Phillips <kim.phillips@linaro.org
>> <mailto:kim.phillips@linaro.org>>
>> ---
>> hw/arm/virt.c | 24 +++++++++++++++++++++++-
>> 1 file changed, 23 insertions(+), 1 deletion(-)
>>
>> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
>> index 517f2fe..75edf33 100644
>> --- a/hw/arm/virt.c
>> +++ b/hw/arm/virt.c
>> @@ -65,6 +65,7 @@ enum {
>> VIRT_GIC_CPU,
>> VIRT_UART,
>> VIRT_MMIO,
>> + VIRT_ETHERNET,
>> };
>>
>> typedef struct MemMapEntry {
>> @@ -106,7 +107,8 @@ static const MemMapEntry a15memmap[] = {
>> [VIRT_MMIO] = { 0xa000000, 0x200 },
>> /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of
>> that size */
>> /* 0x10000000 .. 0x40000000 reserved for PCI */
>> - [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
>> + [VIRT_MEM] = { 0x40000000, 1ULL * 1024 * 1024 * 1024 },
>> + [VIRT_ETHERNET] = { 0xfff51000, 0x1000 },
>> };
>>
>> static const int a15irqmap[] = {
>> @@ -291,6 +293,25 @@ static void create_uart(const VirtBoardInfo
>> *vbi, qemu_irq *pic)
>> g_free(nodename);
>> }
>>
>> +static void create_ethernet(const VirtBoardInfo *vbi, qemu_irq *pic)
>> +{
>> + char *nodename;
>> + hwaddr base = vbi->memmap[VIRT_ETHERNET].base;
>> + hwaddr size = vbi->memmap[VIRT_ETHERNET].size;
>> + const char compat[] = "calxeda,hb-xgmac";
>> +
>> + sysbus_create_simple("vfio-platform", base, NULL);
>> +
>> + nodename = g_strdup_printf("/ethernet@%" PRIx64, base);
>> + qemu_fdt_add_subnode(vbi->fdt, nodename);
>> +
>> + /* Note that we can't use setprop_string because of the
>> embedded NUL */
>> + qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat,
>> sizeof(compat));
>> + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2,
>> base, 2, size);
>> +
>> + g_free(nodename);
>> +}
>> +
>> static void create_virtio_devices(const VirtBoardInfo *vbi,
>> qemu_irq *pic)
>> {
>> int i;
>> @@ -419,6 +440,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
>> }
>>
>> create_uart(vbi, pic);
>> + create_ethernet(vbi, pic);
>>
>> /* Create mmio transports, so the user can create virtio backends
>> * (which will be automatically plugged in to the transports). If
>> --
>> 1.9.0
>>
>>
>
>
> --
> SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2014-03-06 2:27 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-26 2:37 [Qemu-devel] [RFC 0/2] platform device passthrough Kim Phillips
2014-02-26 2:37 ` [Qemu-devel] [RFC 1/2] hw/arm/virt: add a Calxeda XGMAC device Kim Phillips
2014-03-05 4:27 ` Eric Auger
2014-03-05 11:25 ` Andreas Färber
2014-03-06 2:27 ` Eric Auger
2014-02-26 2:37 ` [Qemu-devel] [RFC 2/2] hw/misc/vfio: add vfio-platform support Kim Phillips
2014-02-28 18:03 ` Alex Williamson
2014-03-05 0:24 ` Kim Phillips
2014-03-05 1:23 ` Alex Williamson
2014-03-05 11:28 ` Andreas Färber
2014-03-05 11:30 ` Paolo Bonzini
2014-03-05 7:56 ` Eric Auger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).