qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Alvise Rigo <a.rigo@virtualopensystems.com>
To: qemu-devel@nongnu.org, rob.herring@linaro.org
Cc: Peter Maydell <peter.maydell@linaro.org>,
	tech@virtualopensystems.com,
	Alvise Rigo <a.rigo@virtualopensystems.com>
Subject: [Qemu-devel] [RFC PATCH 6/8] generic_pci: generate dt node after devices init
Date: Fri, 11 Jul 2014 09:21:08 +0200	[thread overview]
Message-ID: <1405063270-18902-7-git-send-email-a.rigo@virtualopensystems.com> (raw)
In-Reply-To: <1405063270-18902-1-git-send-email-a.rigo@virtualopensystems.com>

Keeping advantage of the finalize_dt QEMUMachine function, the mach-virt
machine now completes the device tree creation after that all the
generic devices have been instantiated. This allows to generate the
interrupt-map node according to the devices attached to the PCI bus.
These devices can be specified either as command line argument (like
-device lsi53c895a addr=0x5 ...) or explicitly inside the machine
definition with the pci_create_simple method.

Fill also the generic_pci state with the offsets and sizes of the memory
regions needed by the PCI system. The offset in the machine address
space of these regions (config, IO and memory) is specified by the
mach-virt platform.

TODO:
- Part of the ranges device node is still hardcoded.

Signed-off-by: Alvise Rigo <a.rigo@virtualopensystems.com>
---
 hw/arm/virt.c                     | 80 +++++++++++++++++++--------------
 hw/pci-host/generic-pci.c         | 94 +++++++++++++++++++++++++++++++++++++++
 include/hw/pci-host/pci_generic.h | 20 +++++++++
 3 files changed, 160 insertions(+), 34 deletions(-)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index a433902..e182282 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -358,44 +358,35 @@ static void create_pci_host(const VirtBoardInfo *vbi, qemu_irq *pic)
     PCIBus *pci_bus;
     DeviceState *dev;
     SysBusDevice *busdev;
-    uint32_t gic_phandle;
-    char *nodename;
-    int i;
+    PCIVPBState *ps;
+    int i, count = 0;
     hwaddr cfg_base = vbi->memmap[VIRT_PCI_CFG].base;
-    hwaddr cfg_size = vbi->memmap[VIRT_PCI_CFG].size;
     hwaddr io_base = vbi->memmap[VIRT_PCI_IO].base;
-    hwaddr io_size = vbi->memmap[VIRT_PCI_IO].size;
     hwaddr mem_base = vbi->memmap[VIRT_PCI_MEM].base;
-    hwaddr mem_size = vbi->memmap[VIRT_PCI_MEM].size;
-
-    nodename = g_strdup_printf("/pci@%" PRIx64, cfg_base);
-    qemu_fdt_add_subnode(vbi->fdt, nodename);
-    qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible",
-                            "pci-host-cam-generic");
-    qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "pci");
-    qemu_fdt_setprop_cell(vbi->fdt, nodename, "#address-cells", 0x3);
-    qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 0x1);
-
-    qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, cfg_base,
-                                                           2, cfg_size);
-
-    qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
-        1, 0x01000000, 2, 0x00000000, 2, io_base, 2, io_size,
-        1, 0x02000000, 2, 0x12000000, 2, mem_size, 2, mem_size);
-
-    gic_phandle = qemu_fdt_get_phandle(vbi->fdt, "/intc");
-    qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "interrupt-map-mask",
-        1, 0xf800, 1, 0x0, 1, 0x0, 1, 0x7);
-    qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "interrupt-map",
-        1, 0x0000, 2, 0x00000000, 1, 0x1, 1, gic_phandle, 1, 0, 1, 0x4, 1, 0x1,
-        1, 0x0800, 2, 0x00000000, 1, 0x1, 1, gic_phandle, 1, 0, 1, 0x5, 1, 0x1,
-        1, 0x1000, 2, 0x00000000, 1, 0x1, 1, gic_phandle, 1, 0, 1, 0x6, 1, 0x1,
-        1, 0x1800, 2, 0x00000000, 1, 0x1, 1, gic_phandle, 1, 0, 1, 0x7, 1, 0x1);
 
     dev = qdev_create(NULL, "generic_pci");
     busdev = SYS_BUS_DEVICE(dev);
+    ps = PCI_GEN(dev);
+
+    /* Set the mapping data in the device structure where:
+     * ptr[i] = base address
+     * ptr[i+1] = size
+     * i = 0 => config
+     * i = 2 => I/O
+     * i = 4 => memory
+     * These values are needed by the specific device code.
+     * */
+    hwaddr *ptr = g_malloc(6 * sizeof(hwaddr));
+    for (i = VIRT_PCI_CFG; i <= VIRT_PCI_MEM; i++) {
+        ptr[count++] = vbi->memmap[i].base;
+        ptr[count++] = vbi->memmap[i].size;
+    }
+    ps->dt_data.fdt = vbi->fdt;
+    ps->dt_data.irq_base = vbi->irqmap[VIRT_PCI_CFG];
+    ps->dt_data.addr_mapping = ptr;
+
     qdev_init_nofail(dev);
+
     sysbus_mmio_map(busdev, 0, cfg_base); /* PCI config */
     sysbus_mmio_map(busdev, 1, io_base);  /* PCI I/O */
     sysbus_mmio_map(busdev, 2, mem_base); /* PCI memory window */
@@ -407,8 +398,6 @@ static void create_pci_host(const VirtBoardInfo *vbi, qemu_irq *pic)
     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
     pci_create_simple(pci_bus, -1, "pci-ohci");
     pci_create_simple(pci_bus, -1, "lsi53c895a");
-
-    g_free(nodename);
 }
 
 static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
@@ -454,6 +443,29 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
     return board->fdt;
 }
 
+static void machvirt_finalize_dt(MachineState *machine)
+{
+    BusState *bus;
+    BusChild *child;
+    VirtBoardInfo *vbi;
+    /* TODO store somewhere the CPU model used */
+    vbi = find_machine_info("cortex-a15");
+
+    /* If the device has been successfully created, create also its
+     * device node in the dt. */
+    bus = sysbus_get_default();
+    QTAILQ_FOREACH(child, &bus->children, sibling) {
+        DeviceState *dev = child->child;
+        if (!strcmp(object_get_typename(OBJECT(dev)), TYPE_GENERIC_PCI)) {
+            GenericPCIClass *gpci = GENERIC_PCI_GET_CLASS(OBJECT(dev));
+            /* create device tree node */
+            gpci->gen_dt_node(dev);
+        }
+    }
+
+    arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
+}
+
 static void machvirt_init(MachineState *machine)
 {
     MemoryRegion *sysmem = get_system_memory();
@@ -542,13 +554,13 @@ static void machvirt_init(MachineState *machine)
     vbi->bootinfo.board_id = -1;
     vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
     vbi->bootinfo.get_dtb = machvirt_dtb;
-    arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
 }
 
 static QEMUMachine machvirt_a15_machine = {
     .name = "virt",
     .desc = "ARM Virtual Machine",
     .init = machvirt_init,
+    .finalize_dt = machvirt_finalize_dt,
     .max_cpus = 4,
 };
 
diff --git a/hw/pci-host/generic-pci.c b/hw/pci-host/generic-pci.c
index 75aae45..2068079 100644
--- a/hw/pci-host/generic-pci.c
+++ b/hw/pci-host/generic-pci.c
@@ -14,6 +14,7 @@
 #include "hw/sysbus.h"
 #include "hw/pci-host/pci_generic.h"
 #include "exec/address-spaces.h"
+#include "sysemu/device_tree.h"
 
 static const VMStateDescription pci_generic_host_vmstate = {
     .name = "generic-host-pci",
@@ -130,6 +131,96 @@ static void pci_generic_host_class_init(ObjectClass *klass, void *data)
     dc->cannot_instantiate_with_device_add_yet = true;
 }
 
+struct dt_irq_mapping {
+        DeviceState *dev;
+        uint32_t gic_phandle;
+        int base_irq_num;
+        uint64_t *data;
+};
+
+#define IRQ_MAPPING_CELLS 14
+/* Generate the irq_mapping data and return the number of the device attached
+ * to the device bus.
+ * */
+static int generate_int_mapping(struct dt_irq_mapping *irq_map)
+{
+    BusState *inner_bus;
+    BusChild *inner;
+    int num_slots = 0;
+    uint64_t *data_ptr = irq_map->data;
+
+    QLIST_FOREACH(inner_bus, &irq_map->dev->child_bus, sibling) {
+        QTAILQ_FOREACH(inner, &inner_bus->children, sibling) {
+            DeviceState *dev = inner->child;
+            PCIDevice *pdev = PCI_DEVICE(dev);
+            int pci_slot = PCI_SLOT(pdev->devfn);
+
+            uint64_t buffer[IRQ_MAPPING_CELLS] =
+            {1, pci_slot << 11, 2, 0x00000000, 1, 0x1,
+             1, irq_map->gic_phandle, 1, 0, 1, irq_map->base_irq_num + pci_slot,
+             1, 0x1};
+
+            memcpy(data_ptr, buffer, IRQ_MAPPING_CELLS * sizeof(*buffer));
+            num_slots++;
+            data_ptr += IRQ_MAPPING_CELLS;
+        }
+    }
+
+    return num_slots;
+}
+
+static void generate_dt_node(DeviceState *dev)
+{
+    PCIVPBState *s = PCI_GEN(dev);
+    char *nodename;
+    uint32_t gic_phandle;
+    int num_dev;
+    hwaddr *map = s->dt_data.addr_mapping;
+    void *fdt = s->dt_data.fdt;
+
+    nodename = g_strdup_printf("/pci@%" PRIx64, map[0]);
+    qemu_fdt_add_subnode(fdt, nodename);
+    qemu_fdt_setprop_string(fdt, nodename, "compatible",
+                            "pci-host-cam-generic");
+    qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci");
+    qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 0x3);
+    qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0x2);
+    qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 0x1);
+
+    /* config space */
+    qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", 2, map[0],
+                                                            2, map[1]);
+
+    qemu_fdt_setprop_sized_cells(fdt, nodename, "ranges",
+         1, 0x01000000, 2, 0x00000000, 2, map[2], 2, map[3],
+         1, 0x02000000, 2, 0x12000000, 2, map[4], 2, map[5]);
+
+    gic_phandle = qemu_fdt_get_phandle(fdt, "/intc");
+    qemu_fdt_setprop_sized_cells(fdt, nodename, "interrupt-map-mask",
+                                  1, 0xf800, 1, 0x0, 1, 0x0, 1, 0x7);
+
+    /* Generate the interrupt mapping according to the devices attached
+     * to the PCI bus of the device. */
+    uint64_t *int_mapping_data = g_malloc0(IRQ_MAPPING_CELLS * sizeof(uint64_t)
+                                                            * MAX_PCI_DEVICES);
+
+    struct dt_irq_mapping dt_map = {
+        .dev = dev,
+        .gic_phandle = gic_phandle,
+        .base_irq_num = s->dt_data.irq_base,
+        .data = int_mapping_data
+    };
+
+    num_dev = generate_int_mapping(&dt_map);
+    qemu_fdt_setprop_sized_cells_from_array(fdt, nodename, "interrupt-map",
+                        (num_dev * IRQ_MAPPING_CELLS)/2, int_mapping_data);
+
+    g_free(int_mapping_data);
+    g_free(nodename);
+    /* Once the dt node is created, this data is no longer necessary */
+    g_free(s->dt_data.addr_mapping);
+}
+
 static const TypeInfo pci_generic_host_info = {
     .name          = TYPE_GENERIC_PCI_HOST,
     .parent        = TYPE_PCI_DEVICE,
@@ -140,9 +231,11 @@ static const TypeInfo pci_generic_host_info = {
 static void pci_generic_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    GenericPCIClass *pc = GENERIC_PCI_CLASS(klass);
 
     dc->realize = pci_generic_host_realize;
     dc->vmsd = &pci_generic_host_vmstate;
+    pc->gen_dt_node = generate_dt_node;
 }
 
 static const TypeInfo pci_generic_info = {
@@ -151,6 +244,7 @@ static const TypeInfo pci_generic_info = {
     .instance_size = sizeof(PCIVPBState),
     .instance_init = pci_generic_host_init,
     .class_init    = pci_generic_class_init,
+    .class_size    = sizeof(GenericPCIClass),
 };
 
 static void generic_pci_host_register_types(void)
diff --git a/include/hw/pci-host/pci_generic.h b/include/hw/pci-host/pci_generic.h
index 2367d80..039549f 100644
--- a/include/hw/pci-host/pci_generic.h
+++ b/include/hw/pci-host/pci_generic.h
@@ -7,6 +7,12 @@
 
 #define MAX_PCI_DEVICES 10
 
+struct dt_data {
+    void *fdt;
+    int irq_base;
+    hwaddr *addr_mapping;
+};
+
 typedef struct {
     PCIHostState parent_obj;
 
@@ -22,8 +28,17 @@ typedef struct {
     MemoryRegion pci_mem_window;
     PCIBus pci_bus;
     PCIDevice pci_dev;
+    /* Device tree data set by the machine
+     */
+    struct dt_data dt_data;
 } PCIVPBState;
 
+typedef struct GenericPCIClass {
+    PCIDeviceClass parent_class;
+
+    void (*gen_dt_node)(DeviceState *dev);
+} GenericPCIClass;
+
 #define TYPE_GENERIC_PCI "generic_pci"
 #define PCI_GEN(obj) \
     OBJECT_CHECK(PCIVPBState, (obj), TYPE_GENERIC_PCI)
@@ -32,4 +47,9 @@ typedef struct {
 #define PCI_GEN_HOST(obj) \
     OBJECT_CHECK(PCIDevice, (obj), TYPE_GENERIC_PCIHOST)
 
+#define GENERIC_PCI_CLASS(klass) \
+     OBJECT_CLASS_CHECK(GenericPCIClass, (klass), TYPE_GENERIC_PCI)
+#define GENERIC_PCI_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(GenericPCIClass, (obj), TYPE_GENERIC_PCI)
+
 #endif
-- 
1.9.1

  parent reply	other threads:[~2014-07-11  7:21 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-07-11  7:21 [Qemu-devel] [RFC PATCH 0/8] Add Generic PCI host device update Alvise Rigo
2014-07-11  7:21 ` [Qemu-devel] [RFC PATCH 1/8] mach-virt: move GIC inside mach-virt structure Alvise Rigo
2014-07-11  7:21 ` [Qemu-devel] [RFC PATCH 2/8] mach-virt: improve PCI memory topology definition Alvise Rigo
2014-07-11  7:21 ` [Qemu-devel] [RFC PATCH 3/8] QEMUMachine: finalize_dt function Alvise Rigo
2014-07-11  7:21 ` [Qemu-devel] [RFC PATCH 4/8] generic_pci: create header file Alvise Rigo
2014-07-11  7:21 ` [Qemu-devel] [RFC PATCH 5/8] generic_pci: create own map irq function Alvise Rigo
2014-07-11  7:21 ` Alvise Rigo [this message]
2014-11-05 12:26   ` [Qemu-devel] [RFC PATCH 6/8] generic_pci: generate dt node after devices init Claudio Fontana
2014-11-06 10:27     ` alvise rigo
2014-07-11  7:21 ` [Qemu-devel] [RFC PATCH 7/8] generic_pci: realize device with machine data Alvise Rigo
2014-07-11  7:21 ` [Qemu-devel] [RFC PATCH 8/8] generic_pci: add interrupt map structures Alvise Rigo
2014-07-11  9:09 ` [Qemu-devel] [RFC PATCH 0/8] Add Generic PCI host device update Peter Maydell
2014-07-11  9:28   ` Alvise Rigo
2014-07-13 14:28     ` Rob Herring
2014-09-09 16:35     ` Claudio Fontana
2014-09-10  7:31       ` alvise rigo
2014-11-05 10:23 ` Claudio Fontana
2014-11-05 11:09   ` alvise rigo
2014-11-07 15:40 ` Claudio Fontana
2014-11-10 10:00   ` alvise rigo
2014-11-11  3:24     ` Ming Lei
2014-11-11  4:22       ` Ming Lei
2014-11-11 10:26         ` Claudio Fontana

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1405063270-18902-7-git-send-email-a.rigo@virtualopensystems.com \
    --to=a.rigo@virtualopensystems.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=rob.herring@linaro.org \
    --cc=tech@virtualopensystems.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).