From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44152) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WvNq6-0008DX-HH for qemu-devel@nongnu.org; Fri, 13 Jun 2014 05:32:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WvNq1-0000aN-I2 for qemu-devel@nongnu.org; Fri, 13 Jun 2014 05:32:02 -0400 From: "Bharat.Bhushan@freescale.com" Date: Fri, 13 Jun 2014 08:58:17 +0000 Message-ID: <82e7e0dc9c394667be2f2c48d6eb9702@DM2PR03MB574.namprd03.prod.outlook.com> References: <1401884936-12907-1-git-send-email-agraf@suse.de> <1401884936-12907-5-git-send-email-agraf@suse.de> In-Reply-To: <1401884936-12907-5-git-send-email-agraf@suse.de> Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [Qemu-devel] [PATCH 4/5] PPC: e500: Support platform devices List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Alexander Graf , "qemu-ppc@nongnu.org" Cc: "qemu-devel@nongnu.org" , "eric.auger@linaro.org" > -----Original Message----- > From: qemu-devel-bounces+bharat.bhushan=3Dfreescale.com@nongnu.org [mailt= o:qemu- > devel-bounces+bharat.bhushan=3Dfreescale.com@nongnu.org] On Behalf Of Ale= xander > Graf > Sent: Wednesday, June 04, 2014 5:59 PM > To: qemu-ppc@nongnu.org > Cc: qemu-devel@nongnu.org; eric.auger@linaro.org > Subject: [Qemu-devel] [PATCH 4/5] PPC: e500: Support platform devices >=20 > For e500 our approach to supporting platform devices is to create a simpl= e > bus from the guest's point of view within which we map platform devices > dynamically. >=20 > We allocate memory regions always within the "platform" hole in address > space and map IRQs to predetermined IRQ lines that are reserved for platf= orm > device usage. >=20 > This maps really nicely into device tree logic, so we can just tell the > guest about our virtual simple bus in device tree as well. >=20 > Signed-off-by: Alexander Graf > --- > default-configs/ppc-softmmu.mak | 1 + > default-configs/ppc64-softmmu.mak | 1 + > hw/ppc/e500.c | 221 ++++++++++++++++++++++++++++++++= ++++++ > hw/ppc/e500.h | 1 + > hw/ppc/e500plat.c | 1 + > 5 files changed, 225 insertions(+) >=20 > diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmm= u.mak > index 33f8d84..d6ec8b9 100644 > --- a/default-configs/ppc-softmmu.mak > +++ b/default-configs/ppc-softmmu.mak > @@ -45,6 +45,7 @@ CONFIG_PREP=3Dy > CONFIG_MAC=3Dy > CONFIG_E500=3Dy > CONFIG_OPENPIC_KVM=3D$(and $(CONFIG_E500),$(CONFIG_KVM)) > +CONFIG_PLATFORM=3Dy > # For PReP > CONFIG_MC146818RTC=3Dy > CONFIG_ETSEC=3Dy > diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64- > softmmu.mak > index 37a15b7..06677bf 100644 > --- a/default-configs/ppc64-softmmu.mak > +++ b/default-configs/ppc64-softmmu.mak > @@ -45,6 +45,7 @@ CONFIG_PSERIES=3Dy > CONFIG_PREP=3Dy > CONFIG_MAC=3Dy > CONFIG_E500=3Dy > +CONFIG_PLATFORM=3Dy > CONFIG_OPENPIC_KVM=3D$(and $(CONFIG_E500),$(CONFIG_KVM)) > # For pSeries > CONFIG_XICS=3D$(CONFIG_PSERIES) > diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c > index 33d54b3..bc26215 100644 > --- a/hw/ppc/e500.c > +++ b/hw/ppc/e500.c > @@ -36,6 +36,7 @@ > #include "exec/address-spaces.h" > #include "qemu/host-utils.h" > #include "hw/pci-host/ppce500.h" > +#include "hw/platform/device.h" >=20 > #define EPAPR_MAGIC (0x45504150) > #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" > @@ -47,6 +48,14 @@ >=20 > #define RAM_SIZES_ALIGN (64UL << 20) >=20 > +#define E500_PLATFORM_BASE 0xF0000000ULL > +#define E500_PLATFORM_HOLE (128ULL * 1024 * 1024) /* 128 MB */ > +#define E500_PLATFORM_PAGE_SHIFT 12 > +#define E500_PLATFORM_HOLE_PAGES (E500_PLATFORM_HOLE >> \ > + E500_PLATFORM_PAGE_SHIFT) > +#define E500_PLATFORM_FIRST_IRQ 5 How we come to value "5" ? How it is ensured that this does not overlap with IRQ numbers taken by PCI = devices (with no-msi case)? > +#define E500_PLATFORM_NUM_IRQS 10 > + > /* TODO: parameterize */ > #define MPC8544_CCSRBAR_BASE 0xE0000000ULL > #define MPC8544_CCSRBAR_SIZE 0x00100000ULL > @@ -122,6 +131,62 @@ static void dt_serial_create(void *fdt, unsigned lon= g long > offset, > } > } >=20 > +typedef struct PlatformDevtreeData { > + void *fdt; > + const char *mpic; > + int irq_start; > + const char *node; > +} PlatformDevtreeData; > + > +static int platform_device_create_devtree(Object *obj, void *opaque) > +{ > + PlatformDevtreeData *data =3D opaque; > + Object *dev; > + PlatformDeviceState *pdev; > + > + dev =3D object_dynamic_cast(obj, TYPE_PLATFORM_DEVICE); > + pdev =3D (PlatformDeviceState *)dev; > + > + if (!pdev) { > + /* Container, traverse it for children */ > + return object_child_foreach(obj, platform_device_create_devtree,= data); > + } > + > + return 0; > +} > + > +static void platform_create_devtree(void *fdt, const char *node, uint64_= t addr, > + const char *mpic, int irq_start, > + int nr_irqs) > +{ > + const char platcomp[] =3D "qemu,platform\0simple-bus"; > + PlatformDevtreeData data; > + > + /* Create a /platform node that we can put all devices into */ > + > + qemu_fdt_add_subnode(fdt, node); > + qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)= ); > + qemu_fdt_setprop_string(fdt, node, "device_type", "platform"); > + > + /* Our platform hole is less than 32bit big, so 1 cell is enough for > address > + and size */ > + qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); > + qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); > + qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, > + E500_PLATFORM_HOLE); > + > + qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); > + > + /* Loop through all devices and create nodes for known ones */ > + > + data.fdt =3D fdt; > + data.mpic =3D mpic; > + data.irq_start =3D irq_start; > + data.node =3D node; > + > + platform_device_create_devtree(qdev_get_machine(), &data); So I see dma device with two dm-channel then h/w device tree looks like : dma@100300 { #address-cells =3D <0x1>; #size-cells =3D <0x1>; compatible =3D "fsl,elo3-dma"; reg =3D <0x100300 0x4 0x100600 0x4>; ranges =3D <0x0 0x100100 0x500>; dma-channel@0 { compatible =3D "fsl,eloplus-dma-channel"; reg =3D <0x0 0x80>; interrupts =3D <0x1c 0x2 0x0 0x0>; }; dma-channel@80 { compatible =3D "fsl,eloplus-dma-channel"; reg =3D <0x80 0x80>; interrupts =3D <0x1d 0x2 0x0 0x0>; }; } Now for assigning same device to guest, We will unbind dma@ device from ker= nel and then bind with vfio-platform. 1) What will be my qemu command line for this ? I think this will be like: -device vfio-platform,vfio_device=3D"dma@100300",compat=3D"fsl,elo3-dma" Then how similar device tree will be created? It can happen then some dma h= ave 1 channel while other have more "n" channel.=20 That also reminds me that should we update documents for same " docs/qdev-d= evice-use.txt" > +} > + > static int ppce500_load_device_tree(MachineState *machine, > PPCE500Params *params, > hwaddr addr, > @@ -379,6 +444,12 @@ static int ppce500_load_device_tree(MachineState *ma= chine, > qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3); > qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci); >=20 > + if (params->has_platform) { > + platform_create_devtree(fdt, "/platform", E500_PLATFORM_BASE, > + mpic, E500_PLATFORM_FIRST_IRQ, > + E500_PLATFORM_NUM_IRQS); > + } > + > params->fixup_devtree(params, fdt); >=20 > if (toplevel_compat) { > @@ -618,6 +689,147 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *p= arams, > MemoryRegion *ccsr, > return mpic; > } >=20 > +typedef struct PlatformNotifier { > + Notifier notifier; > + MemoryRegion *address_space_mem; > + qemu_irq *mpic; > +} PlatformNotifier; > + > +typedef struct PlatformInitData { > + unsigned long *used_irqs; > + unsigned long *used_mem; > + MemoryRegion *mem; > + qemu_irq *irqs; > + int device_count; > +} PlatformInitData; > + > +static int platform_map_irq(unsigned long *used_irqs, qemu_irq *platform= _irqs, > + uint32_t *device_irqn, qemu_irq *device_irq) > +{ > + int max_irqs =3D E500_PLATFORM_NUM_IRQS; > + int irqn =3D *device_irqn; > + > + if (irqn =3D=3D (uint32_t)PLATFORM_DYNAMIC) { > + /* Find the first available IRQ */ > + irqn =3D find_first_zero_bit(used_irqs, max_irqs); > + } > + > + if ((irqn >=3D max_irqs) || test_and_set_bit(irqn, used_irqs)) { > + hw_error("e500: IRQ %d is already allocated or no free IRQ left"= , > irqn); > + } > + > + *device_irq =3D platform_irqs[irqn]; > + *device_irqn =3D irqn; > + > + return 0; > +} > + > +static int platform_map_region(unsigned long *used_mem, MemoryRegion *pm= em, > + uint64_t *device_addr, MemoryRegion *devi= ce_mem) > +{ > + uint64_t size =3D memory_region_size(device_mem); > + uint64_t page_size =3D (1 << E500_PLATFORM_PAGE_SHIFT); > + uint64_t page_mask =3D page_size - 1; > + uint64_t size_pages =3D (size + page_mask) >> E500_PLATFORM_PAGE_SHI= FT; > + hwaddr addr =3D *device_addr; > + int page; > + int i; > + > + page =3D addr >> E500_PLATFORM_PAGE_SHIFT; > + if (addr =3D=3D (uint64_t)PLATFORM_DYNAMIC) { > + uint64_t size_pages_align; > + > + /* Align the region to at least its own size granularity */ > + if (is_power_of_2(size_pages)) { > + size_pages_align =3D size_pages; > + } else { > + size_pages_align =3D pow2floor(size_pages) << 1; > + } > + > + /* Find the first available region that fits */ > + page =3D bitmap_find_next_zero_area(used_mem, E500_PLATFORM_HOLE= _PAGES, > 0, > + size_pages, size_pages_align); > + > + addr =3D (uint64_t)page << E500_PLATFORM_PAGE_SHIFT; > + } > + > + if (page >=3D E500_PLATFORM_HOLE_PAGES || test_bit(page, used_mem) |= | > + (find_next_bit(used_mem, E500_PLATFORM_HOLE_PAGES, page) < size_= pages)) > { > + hw_error("e500: Memory [%"PRIx64":%"PRIx64" is already allocated= or " > + "no slot left", addr, size); > + } > + > + for (i =3D page; i < (page + size_pages); i++) { > + set_bit(i, used_mem); > + } > + > + memory_region_add_subregion(pmem, addr, device_mem); > + *device_addr =3D addr; > + > + return 0; > +} > + > +static int platform_device_check(Object *obj, void *opaque) > +{ > + PlatformInitData *init =3D opaque; > + Object *dev; > + PlatformDeviceState *pdev; > + int i; > + > + dev =3D object_dynamic_cast(obj, TYPE_PLATFORM_DEVICE); > + pdev =3D (PlatformDeviceState *)dev; > + > + if (!pdev) { > + /* Container, traverse it for children */ > + return object_child_foreach(obj, platform_device_check, opaque); > + } > + > + /* Connect platform device to machine */ > + for (i =3D 0; i < pdev->num_irqs; i++) { > + platform_map_irq(init->used_irqs, init->irqs, &pdev->plat_irqs[i= ], > + pdev->irqs[i]); > + } > + > + for (i =3D 0; i < pdev->num_regions; i++) { > + platform_map_region(init->used_mem, init->mem, > + &pdev->plat_region_addrs[i], pdev->regions[i= ]); > + } > + > + return 0; > +} > + > +static void platform_devices_init(MemoryRegion *address_space_mem, > + qemu_irq *mpic) > +{ > + DECLARE_BITMAP(used_irqs, E500_PLATFORM_NUM_IRQS); > + DECLARE_BITMAP(used_mem, E500_PLATFORM_HOLE_PAGES); > + MemoryRegion *platform_region =3D g_new(MemoryRegion, 1); > + PlatformInitData init =3D { > + .used_irqs =3D used_irqs, > + .used_mem =3D used_mem, > + .mem =3D platform_region, > + .irqs =3D &mpic[E500_PLATFORM_FIRST_IRQ], > + }; > + > + memory_region_init(platform_region, NULL, "platform devices", > + E500_PLATFORM_HOLE); > + > + bitmap_clear(used_irqs, 0, E500_PLATFORM_NUM_IRQS); > + bitmap_clear(used_mem, 0, E500_PLATFORM_HOLE_PAGES); > + > + /* Loop through our internal device tree and attach any dangling dev= ice */ > + platform_device_check(qdev_get_machine(), &init); Can you please describe what we are trying to do here, what could be a "dan= gling device" ? Thanks -Bharat > + > + memory_region_add_subregion(address_space_mem, E500_PLATFORM_BASE, > + platform_region); > +} > + > +static void platform_devices_init_notify(Notifier *notifier, void *data) > +{ > + PlatformNotifier *pn =3D (PlatformNotifier *)notifier; > + platform_devices_init(pn->address_space_mem, pn->mpic); > +} > + > void ppce500_init(MachineState *machine, PPCE500Params *params) > { > MemoryRegion *address_space_mem =3D get_system_memory(); > @@ -770,6 +982,15 @@ void ppce500_init(MachineState *machine, PPCE500Para= ms > *params) > cur_base =3D (32 * 1024 * 1024); > } >=20 > + /* Platform Devices */ > + if (params->has_platform) { > + PlatformNotifier *notifier =3D g_new(PlatformNotifier, 1); > + notifier->notifier.notify =3D platform_devices_init_notify; > + notifier->address_space_mem =3D address_space_mem; > + notifier->mpic =3D mpic; > + qemu_add_machine_init_done_notifier(¬ifier->notifier); > + } > + > /* Load kernel. */ > if (machine->kernel_filename) { > kernel_base =3D cur_base; > diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h > index 08b25fa..3a588ed 100644 > --- a/hw/ppc/e500.h > +++ b/hw/ppc/e500.h > @@ -11,6 +11,7 @@ typedef struct PPCE500Params { > void (*fixup_devtree)(struct PPCE500Params *params, void *fdt); >=20 > int mpic_version; > + bool has_platform; > } PPCE500Params; >=20 > void ppce500_init(MachineState *machine, PPCE500Params *params); > diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c > index 27df31d..bb84283 100644 > --- a/hw/ppc/e500plat.c > +++ b/hw/ppc/e500plat.c > @@ -35,6 +35,7 @@ static void e500plat_init(MachineState *machine) > .pci_nr_slots =3D PCI_SLOT_MAX - 1, > .fixup_devtree =3D e500plat_fixup_devtree, > .mpic_version =3D OPENPIC_MODEL_FSL_MPIC_42, > + .has_platform =3D true, > }; >=20 > /* Older KVM versions don't support EPR which breaks guests when we > announce > -- > 1.8.1.4 >=20