All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines
@ 2015-02-16  9:54 Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 01/17] acpi: added needed acpi constructs Marcel Apfelbaum
                   ` (16 more replies)
  0 siblings, 17 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

Series status:
The series is fully functional. The reason is still RFC is because depends on Igor's ACPI
series that is still in the mailing list. Once it gets accepted I'll resend this series
rebased on it.
 - Limitations:
   - Pxb's bus does not support hotplug. It will be addressed on top of this series
     because is already getting to big.

You are more than welcome to try using:
   -device pxb-device,id=pxb,bus_nr=4,numa_node=1 -device e1000,bus=pxb,addr=0x1 -bios <patched with the above series>

v1->v2:
 - Add support for multiple pxb devices.
 - Attach pxb's bus to specific NUMA node.
 - Got rid of the hacks from prev version.
 - Tested also for Win7 and Fedora 20, and for virtio blk devices.
 - Several bug-fixes resulting in a stable version ready for submission.

This series depends on:
 - [SeaBIOS] [PATCH V2 0/2] fw/pci: better support for multiple host bridges
 - [Qemu-devel] [PATCH v4 0/3] pc: acpi-build: make linker & RSDP tables dynamic
 - [PATCH v3 00/52] ACPI refactoring: replace template patching with C AML API

Reasoning:
We need multiple primary busess for a few reasons, the most important one
is to be able to associate a pass-trough device with a guest NUMA node.
The OS-es are able to associate a NUMA node only to a primary bus, not to
a specific PCI device or a pci-2-pci bridge.
PC machines support multiple NUMA nodes for CPUs and memory, however the IO
was not yet supported.

patch 1 adds the necessary acpi constructs based on Igor's series
patch 2-5 implements acpi code needed to expose the pxb's primary bus to guests
patch 6 separates the pci_bus code into a designated file
patch 7-11 handles the implicit assumptions in code that only one primary bus can exist
patch 12 handles the actual implementation of the PXB devices
patch 13-14 enables the device
patch 15 implements PXB map_irq function, (can be squashed into the actual PXB)
patch 16-17 adds NUMA support

Marcel Apfelbaum (17):
  acpi: added needed acpi constructs
  hw/acpi: add support for multiple root busses
  hw/apci: add _PRT method for extra root busses
  hw/acpi: add _CRS method for extra root busses
  hw/acpi: remove from root bus 0 the crs resources used by other busses.
  hw/pci: move pci bus related code to separate files
  hw/pci: made pci_bus_is_root a PCIBusClass method
  hw/pci: made pci_bus_num a PCIBusClass method
  hw/pci: introduce TYPE_PCI_MAIN_HOST_BRIDGE interface
  hw/pci: removed 'rootbus nr is 0' assumption from qmp_pci_query
  hw/pci: implement iteration over multiple host bridges
  hw/pci: introduce PCI Expander Bridge (PXB)
  hw/pci: inform bios if the system has more than one pci bridge
  hw/pci: piix - suport multiple host bridges
  hw/pxb: add map_irq func
  hw/pci_bus: add support for NUMA nodes
  hw/pxb: add numa_node parameter

 arch_init.c                         |   1 +
 hw/acpi/acpi-build-utils.c          | 107 +++++++-
 hw/alpha/typhoon.c                  |   1 +
 hw/i386/acpi-build.c                | 357 ++++++++++++++++++++++++-
 hw/i386/kvm/pci-assign.c            |   1 +
 hw/i386/pc.c                        |  13 +
 hw/mips/gt64xxx_pci.c               |   1 +
 hw/pci-bridge/Makefile.objs         |   1 +
 hw/pci-bridge/pci_expander_bridge.c | 208 +++++++++++++++
 hw/pci-host/bonito.c                |   1 +
 hw/pci-host/grackle.c               |   1 +
 hw/pci-host/piix.c                  |  63 ++++-
 hw/pci-host/ppce500.c               |   1 +
 hw/pci-host/q35.c                   |   5 +
 hw/pci-host/uninorth.c              |   1 +
 hw/pci/Makefile.objs                |   2 +-
 hw/pci/pci-hotplug-old.c            |   1 +
 hw/pci/pci.c                        | 501 +---------------------------------
 hw/pci/pci_bus.c                    | 517 ++++++++++++++++++++++++++++++++++++
 hw/pci/pci_host.c                   |   6 +
 hw/ppc/ppc4xx_pci.c                 |   1 +
 hw/scsi/megasas.c                   |   1 +
 hw/sh4/r2d.c                        |   1 +
 hw/sh4/sh_pci.c                     |   1 +
 hw/vfio/pci.c                       |   1 +
 hw/xen/xen_pt.c                     |   1 +
 include/hw/acpi/acpi-build-utils.h  |  12 +
 include/hw/pci/pci.h                |   6 +-
 include/hw/pci/pci_bus.h            |  35 +++
 include/hw/pci/pci_host.h           |  11 +
 include/sysemu/sysemu.h             |   1 +
 31 files changed, 1348 insertions(+), 512 deletions(-)
 create mode 100644 hw/pci-bridge/pci_expander_bridge.c
 create mode 100644 hw/pci/pci_bus.c

-- 
2.1.0

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 01/17] acpi: added needed acpi constructs
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 02/17] hw/acpi: add support for multiple root busses Marcel Apfelbaum
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/acpi/acpi-build-utils.c         | 107 +++++++++++++++++++++++++++++++++++--
 include/hw/acpi/acpi-build-utils.h |  12 +++++
 2 files changed, 116 insertions(+), 3 deletions(-)

diff --git a/hw/acpi/acpi-build-utils.c b/hw/acpi/acpi-build-utils.c
index 58f88cd..19cd146 100644
--- a/hw/acpi/acpi-build-utils.c
+++ b/hw/acpi/acpi-build-utils.c
@@ -439,6 +439,26 @@ AcpiAml acpi_and(AcpiAml arg1, AcpiAml arg2)
     return var;
 }
 
+AcpiAml acpi_or(AcpiAml arg1, AcpiAml arg2)
+{
+    AcpiAml var = aml_allocate_internal(0, NON_BLOCK);
+    build_append_byte(var.buf, 0x7D); /* AndOp */
+    aml_append(&var, arg1);
+    aml_append(&var, arg2);
+    build_append_int(var.buf, 0x00); /* NullNameOp */
+    return var;
+}
+
+AcpiAml acpi_add(AcpiAml arg1, AcpiAml arg2)
+{
+    AcpiAml var = aml_allocate_internal(0, NON_BLOCK);
+    build_append_byte(var.buf, 0x72); /* AddOp */
+    aml_append(&var, arg1);
+    aml_append(&var, arg2);
+    build_append_int(var.buf, 0x00); /* NullNameOp */
+    return var;
+}
+
 /* ACPI 5.0: 20.2.5.3 Type 1 Opcodes Encoding: DefNotify */
 AcpiAml acpi_notify(AcpiAml arg1, AcpiAml arg2)
 {
@@ -518,6 +538,53 @@ AcpiAml acpi_equal(AcpiAml arg1, AcpiAml arg2)
     build_append_byte(var.buf, 0x93); /* LequalOp */
     aml_append(&var, arg1);
     aml_append(&var, arg2);
+    return var;
+}
+
+AcpiAml acpi_increment(AcpiAml arg1)
+{
+    AcpiAml var = aml_allocate_internal(0, NON_BLOCK);
+    build_append_byte(var.buf, 0x75); /* LequalOp */
+    aml_append(&var, arg1);
+    return var;
+}
+
+AcpiAml acpi_lless(AcpiAml arg1, AcpiAml arg2)
+{
+    AcpiAml var = aml_allocate_internal(0, NON_BLOCK);
+    build_append_byte(var.buf, 0x95); /* LequalOp */
+    aml_append(&var, arg1);
+    aml_append(&var, arg2);
+//    build_append_int(var.buf, 0x00); /* NullNameOp */
+    return var;
+}
+
+AcpiAml acpi_shiftright(AcpiAml arg1, int count)
+{
+    AcpiAml var = aml_allocate_internal(0, NON_BLOCK);
+    build_append_byte(var.buf, 0x7A); /* RightShiftOp */
+    aml_append(&var, arg1);
+    aml_append(&var, acpi_int(count));
+    build_append_int(var.buf, 0x00); /* NullNameOp */
+    return var;
+}
+
+AcpiAml acpi_shiftleft(AcpiAml arg1, int count)
+{
+    AcpiAml var = aml_allocate_internal(0, NON_BLOCK);
+    build_append_byte(var.buf, 0x79); /* RightLeftOp */
+    aml_append(&var, arg1);
+    aml_append(&var, acpi_int(count));
+    build_append_int(var.buf, 0x00); /* NullNameOp */
+    return var;
+}
+
+AcpiAml acpi_index(AcpiAml arg1, AcpiAml idx)
+{
+    AcpiAml var = aml_allocate_internal(0, NON_BLOCK);
+    build_append_byte(var.buf, 0x88); /* IndexOp */
+    aml_append(&var, arg1);
+    aml_append(&var, idx);
     build_append_int(var.buf, 0x00); /* NullNameOp */
     return var;
 }
@@ -530,6 +597,13 @@ AcpiAml acpi_if(AcpiAml predicate)
     return var;
 }
 
+AcpiAml acpi_while(AcpiAml predicate)
+{
+    AcpiAml var = aml_allocate_internal(0xA2 /* WhileOp */, PACKAGE);
+    aml_append(&var, predicate);
+    return var;
+}
+
 /* ACPI 5.0: 20.2.5.2 Named Objects Encoding: DefMethod */
 AcpiAml acpi_method(const char *name, int arg_count)
 {
@@ -652,14 +726,41 @@ AcpiAml GCC_FMT_ATTR(1, 2) acpi_string(const char *name_format, ...)
     return var;
 }
 
-/* ACPI 5.0: 20.2.6.2 Local Objects Encoding: Local0Op */
-AcpiAml acpi_local0(void)
+/* ACPI 5.0: 20.2.6.2 Local Objects Encoding: LocalXOp */
+static AcpiAml acpi_local(uint8_t index)
 {
     AcpiAml var = aml_allocate_internal(0, NON_BLOCK);
-    build_append_byte(var.buf, 0x60); /* Local0Op */
+
+    assert(index < 8);
+    build_append_byte(var.buf, 0x60 + index); /* Local0Op */
     return var;
 }
 
+AcpiAml acpi_local0(void)
+{
+    return acpi_local(0);
+}
+
+AcpiAml acpi_local1(void)
+{
+    return acpi_local(1);
+}
+
+AcpiAml acpi_local2(void)
+{
+    return acpi_local(2);
+}
+
+AcpiAml acpi_local3(void)
+{
+    return acpi_local(3);
+}
+
+AcpiAml acpi_local4(void)
+{
+    return acpi_local(4);
+}
+
 /* ACPI 5.0: 20.2.5.4 Type 2 Opcodes Encoding: DefVarPackage */
 AcpiAml acpi_varpackage(uint32_t num_elements)
 {
diff --git a/include/hw/acpi/acpi-build-utils.h b/include/hw/acpi/acpi-build-utils.h
index 868d439..e39a82d 100644
--- a/include/hw/acpi/acpi-build-utils.h
+++ b/include/hw/acpi/acpi-build-utils.h
@@ -108,6 +108,8 @@ AcpiAml acpi_arg2(void);
 AcpiAml acpi_arg3(void);
 AcpiAml acpi_store(AcpiAml val, AcpiAml target);
 AcpiAml acpi_and(AcpiAml arg1, AcpiAml arg2);
+AcpiAml acpi_or(AcpiAml arg1, AcpiAml arg2);
+AcpiAml acpi_add(AcpiAml arg1, AcpiAml arg2);
 AcpiAml acpi_notify(AcpiAml arg1, AcpiAml arg2);
 AcpiAml acpi_call1(const char *method, AcpiAml arg1);
 AcpiAml acpi_call2(const char *method, AcpiAml arg1, AcpiAml arg2);
@@ -123,7 +125,16 @@ AcpiAml acpi_named_field(const char *name, unsigned length);
 AcpiAml acpi_reserved_field(unsigned length);
 AcpiAml GCC_FMT_ATTR(1, 2) acpi_string(const char *name_format, ...);
 AcpiAml acpi_local0(void);
+AcpiAml acpi_local1(void);
+AcpiAml acpi_local2(void);
+AcpiAml acpi_local3(void);
+AcpiAml acpi_local4(void);
+AcpiAml acpi_increment(AcpiAml arg1);
 AcpiAml acpi_equal(AcpiAml arg1, AcpiAml arg2);
+AcpiAml acpi_lless(AcpiAml arg1, AcpiAml arg2);
+AcpiAml acpi_index(AcpiAml arg1, AcpiAml idx);
+AcpiAml acpi_shiftright(AcpiAml arg1, int count);
+AcpiAml acpi_shiftleft(AcpiAml arg1, int count);
 AcpiAml GCC_FMT_ATTR(4, 5)
 acpi_processor(uint8_t proc_id, uint32_t pblk_addr, uint8_t pblk_len,
                const char *name_format, ...);
@@ -155,6 +166,7 @@ AcpiAml acpi_def_block(const char *signature, uint8_t revision,
                        const char *oem_id, const char *oem_table_id,
                        uint32_t oem_revision);
 AcpiAml acpi_if(AcpiAml predicate);
+AcpiAml acpi_while(AcpiAml predicate);
 AcpiAml acpi_method(const char *name, int arg_count);
 AcpiAml GCC_FMT_ATTR(1, 2) acpi_scope(const char *name_format, ...);
 AcpiAml GCC_FMT_ATTR(1, 2) acpi_device(const char *name_format, ...);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 02/17] hw/acpi: add support for multiple root busses
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 01/17] acpi: added needed acpi constructs Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 03/17] hw/apci: add _PRT method for extra " Marcel Apfelbaum
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

If the machine has several root busses, we need to add them to
acpi in order to be properly detected by guests.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/i386/acpi-build.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index e7db85d..fedcb2e 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -60,6 +60,8 @@
 #include "qom/qom-qobject.h"
 #include "exec/ram_addr.h"
 
+#include "qmp-commands.h"
+
 /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
  * -M pc-i440fx-2.0.  Even if the actual amount of AML generated grows
  * a little bit, there should be plenty of free space since the DSDT
@@ -661,6 +663,36 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
     ssdt =
         acpi_def_block("SSDT", 1, ACPI_BUILD_APPNAME6, ACPI_BUILD_APPNAME4, 1);
 
+    {
+        PciInfoList *info_list, *info;
+        Error *err = NULL;
+
+        info_list = qmp_query_pci(&err);
+        if (err) {
+            error_free(err);
+            return;
+        }
+
+        for (info = info_list; info; info = info->next) {
+            PciInfo *bus_info = info->value;
+
+            if (bus_info->bus == 0) {
+                continue;
+            }
+
+            scope = acpi_scope("\\_SB");
+            dev = acpi_device("PC%.02X", (uint8_t)bus_info->bus);
+            aml_append(&dev, acpi_name_decl("_UID",
+                acpi_string("PC%.02X", (uint8_t)bus_info->bus)));
+            aml_append(&dev, acpi_name_decl("_HID", acpi_string("PNP0A03")));
+            aml_append(&dev,
+                acpi_name_decl("_BBN", acpi_int((uint8_t)bus_info->bus)));
+            aml_append(&scope, dev);
+            aml_append(&ssdt, scope);
+        }
+        qapi_free_PciInfoList(info_list);
+    }
+
     scope = acpi_scope("\\_SB.PCI0");
     /* build PCI0._CRS */
     crs = acpi_resource_template();
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 03/17] hw/apci: add _PRT method for extra root busses
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 01/17] acpi: added needed acpi constructs Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 02/17] hw/acpi: add support for multiple root busses Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 04/17] hw/acpi: add _CRS " Marcel Apfelbaum
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/i386/acpi-build.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index fedcb2e..ee1a50a 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -643,6 +643,82 @@ static void build_append_pci_bus_devices(AcpiAml *parent_scope, PCIBus *bus,
     aml_append(parent_scope, method);
 }
 
+static AcpiAml build_prt(void)
+{
+    AcpiAml method, pkg, if_ctx, while_ctx;
+
+    method = acpi_method("_PRT", 0);
+
+    aml_append(&method, acpi_store(acpi_package(128), acpi_local0()));
+    aml_append(&method, acpi_store(acpi_int(0), acpi_local1()));
+    while_ctx = acpi_while(acpi_lless(acpi_local1(), acpi_int(128)));
+    {
+        aml_append(&while_ctx,
+                acpi_store(acpi_shiftright(acpi_local1(), 2),
+                    acpi_local2()));
+        aml_append(&while_ctx, acpi_store(
+                    acpi_and(acpi_add(acpi_local1(), acpi_local2()), acpi_int(3)), acpi_local3()));
+
+        if_ctx = acpi_if(acpi_equal(acpi_local3(), acpi_int(0)));
+        {
+            pkg = acpi_package(4);
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&pkg, acpi_name("LNKD"));
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&if_ctx, acpi_store(pkg, acpi_local4()));
+        }
+        aml_append(&while_ctx, if_ctx);
+
+        if_ctx = acpi_if(acpi_equal(acpi_local3(), acpi_int(1)));
+        {
+            pkg = acpi_package(4);
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&pkg, acpi_name("LNKA"));
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&if_ctx, acpi_store(pkg, acpi_local4()));
+        }
+        aml_append(&while_ctx, if_ctx);
+
+        if_ctx = acpi_if(acpi_equal(acpi_local3(), acpi_int(2)));
+        {
+            pkg = acpi_package(4);
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&pkg, acpi_name("LNKB"));
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&if_ctx, acpi_store(pkg, acpi_local4()));
+        }
+        aml_append(&while_ctx, if_ctx);
+
+        if_ctx = acpi_if(acpi_equal(acpi_local3(), acpi_int(3)));
+        {
+            pkg = acpi_package(4);
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&pkg, acpi_name("LNKC"));
+            aml_append(&pkg, acpi_int(0));
+            aml_append(&if_ctx, acpi_store(pkg, acpi_local4()));
+        }
+        aml_append(&while_ctx, if_ctx);
+
+        aml_append(&while_ctx, acpi_store(
+                    acpi_or(acpi_shiftleft(acpi_local2(), 16), acpi_int(0xFFFF)),
+                    acpi_index(acpi_local4(), acpi_int(0))));
+        aml_append(&while_ctx, acpi_store(
+                    acpi_and(acpi_local1(), acpi_int(3)),
+                    acpi_index(acpi_local4(), acpi_int(1))));
+        aml_append(&while_ctx, acpi_store(
+                    acpi_local4(), acpi_index(acpi_local0(), acpi_local1())));
+        aml_append(&while_ctx, acpi_increment(acpi_local1()));
+    }
+    aml_append(&method, while_ctx);
+    aml_append(&method, acpi_return(acpi_local0()));
+
+    return method;
+ }
+
 static void
 build_ssdt(AcpiAml *table_aml, GArray *linker,
            AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc,
@@ -687,6 +763,7 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
             aml_append(&dev, acpi_name_decl("_HID", acpi_string("PNP0A03")));
             aml_append(&dev,
                 acpi_name_decl("_BBN", acpi_int((uint8_t)bus_info->bus)));
+            aml_append(&dev, build_prt());
             aml_append(&scope, dev);
             aml_append(&ssdt, scope);
         }
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 04/17] hw/acpi: add _CRS method for extra root busses
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (2 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 03/17] hw/apci: add _PRT method for extra " Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16 10:07   ` Igor Mammedov
  2015-02-16 12:06   ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 05/17] hw/acpi: remove from root bus 0 the crs resources used by other busses Marcel Apfelbaum
                   ` (12 subsequent siblings)
  16 siblings, 2 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

Save the IO/mem/bus numbers ranges assigned to the extra root busses
to be removed from the root bus 0 range.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/i386/acpi-build.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 146 insertions(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index ee1a50a..0822a20 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -719,6 +719,145 @@ static AcpiAml build_prt(void)
     return method;
  }
 
+typedef struct PciRangeEntry {
+    QLIST_ENTRY(PciRangeEntry) entry;
+    int64_t base;
+    int64_t limit;
+} PciRangeEntry;
+
+typedef QLIST_HEAD(PciRangeQ, PciRangeEntry) PciRangeQ;
+
+static void pci_range_insert(PciRangeQ *list, int64_t base, int64_t limit) {
+    PciRangeEntry *entry, *next, *e;
+
+    if (!base) {
+        return;
+    }
+
+   if (limit - base + 1 < 0x1000)
+       limit = base + 0x1000 - 1;
+
+    e = g_malloc(sizeof(*entry));
+    e->base = base;
+    e->limit = limit;
+
+    if (QLIST_EMPTY(list)) {
+        QLIST_INSERT_HEAD(list, e, entry);
+    } else {
+        QLIST_FOREACH_SAFE(entry, list, entry, next) {
+            if (base < entry->base) {
+                QLIST_INSERT_BEFORE(entry, e, entry);
+                break;
+            } else if (!next) {
+                QLIST_INSERT_AFTER(entry, e, entry);
+                break;
+            }
+        }
+    }
+}
+
+static void pci_range_list_free(PciRangeQ *list)
+{
+    PciRangeEntry *entry, *next;
+
+    QLIST_FOREACH_SAFE(entry, list, entry, next) {
+        QLIST_REMOVE(entry, entry);
+        g_free(entry);
+    }
+}
+
+static AcpiAml build_crs(PcPciInfo *pci, PciInfo *bus_info,
+                         PciRangeQ *io_ranges, PciRangeQ *mem_ranges)
+{
+    PciDeviceInfoList *dev_list;
+    PciMemoryRange range;
+    AcpiAml crs;
+    uint8_t max_bus;
+
+    crs = acpi_resource_template();
+    max_bus = bus_info->bus;
+
+    for (dev_list = bus_info->devices; dev_list; dev_list = dev_list->next) {
+        PciMemoryRegionList *region;
+
+        for (region = dev_list->value->regions; region; region = region->next) {
+            range.base = region->value->address;
+            range.limit = region->value->address + region->value->size - 1;
+
+            if (!strcmp(region->value->type, "io")) {
+                aml_append(&crs,
+                        acpi_word_io(acpi_min_fixed, acpi_max_fixed,
+                            acpi_pos_decode, acpi_entire_range,
+                            0x0000,
+                            range.base,
+                            range.limit,
+                            0x0000,
+                            range.limit - range.base + 1));
+                pci_range_insert(io_ranges, range.base, range.limit);
+            } else { /* "memory" */
+                aml_append(&crs,
+                        acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
+                            acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
+                            0,
+                            range.base,
+                            range.limit,
+                            0,
+                            range.limit - range.base + 1));
+                pci_range_insert(mem_ranges, range.base, range.limit);
+            }
+        }
+
+        if (dev_list->value->has_pci_bridge) {
+            PciBridgeInfo *bridge_info = dev_list->value->pci_bridge;
+
+            if (bridge_info->bus.subordinate > max_bus) {
+                max_bus = bridge_info->bus.subordinate;
+            }
+
+            range = *bridge_info->bus.io_range;
+            aml_append(&crs,
+                    acpi_word_io(acpi_min_fixed, acpi_max_fixed,
+                        acpi_pos_decode, acpi_entire_range,
+                        0x0000,
+                        range.base,
+                        range.limit,
+                        0x0000,
+                        range.limit - range.base + 1));
+            pci_range_insert(io_ranges, range.base, range.limit);
+
+            range = *bridge_info->bus.memory_range;
+            aml_append(&crs,
+                    acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
+                        acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
+                        0,
+                        range.base,
+                        range.limit,
+                        0,
+                        range.limit - range.base + 1));
+            pci_range_insert(mem_ranges, range.base, range.limit);
+
+            range = *bridge_info->bus.prefetchable_range;
+            aml_append(&crs,
+                    acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
+                        acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
+                        0,
+                        range.base,
+                        range.limit,
+                        0,
+                        range.limit - range.base + 1));
+            pci_range_insert(mem_ranges, range.base, range.limit);
+        }
+    }
+
+    aml_append(&crs,
+        acpi_word_bus_number(acpi_min_fixed, acpi_max_fixed,
+                             acpi_pos_decode,
+                             0x0000, bus_info->bus, max_bus,
+                             0x0000, max_bus - bus_info->bus + 1));
+
+    return crs;
+}
+
 static void
 build_ssdt(AcpiAml *table_aml, GArray *linker,
            AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc,
@@ -729,6 +868,8 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
     unsigned acpi_cpus = guest_info->apic_id_limit;
     AcpiAml pkg, scope, dev, method, crs, field, ifctx, ssdt;
     int i;
+    PciRangeQ io_ranges = QLIST_HEAD_INITIALIZER(io_ranges);
+    PciRangeQ mem_ranges = QLIST_HEAD_INITIALIZER(mem_ranges);
 
     /* The current AML generator can cover the APIC ID range [0..255],
      * inclusive, for VCPU hotplug. */
@@ -764,9 +905,14 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
             aml_append(&dev,
                 acpi_name_decl("_BBN", acpi_int((uint8_t)bus_info->bus)));
             aml_append(&dev, build_prt());
+            crs = build_crs(pci, bus_info, &io_ranges, &mem_ranges);
+            aml_append(&dev, acpi_name_decl("_CRS", crs));
             aml_append(&scope, dev);
             aml_append(&ssdt, scope);
         }
+
+        pci_range_list_free(&io_ranges);
+        pci_range_list_free(&mem_ranges);
         qapi_free_PciInfoList(info_list);
     }
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 05/17] hw/acpi: remove from root bus 0 the crs resources used by other busses.
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (3 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 04/17] hw/acpi: add _CRS " Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 06/17] hw/pci: move pci bus related code to separate files Marcel Apfelbaum
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

If multiple root busses are used, root bus 0 cannot use all the
pci holes ranges. Remove the IO/mem ranges used by the other
primary busses.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/i386/acpi-build.c | 85 ++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 73 insertions(+), 12 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 0822a20..b2b0036 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -870,6 +870,9 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
     int i;
     PciRangeQ io_ranges = QLIST_HEAD_INITIALIZER(io_ranges);
     PciRangeQ mem_ranges = QLIST_HEAD_INITIALIZER(mem_ranges);
+    PciMemoryRange range;
+    PciRangeEntry *entry;
+    int root_bus_limit = 0xFF;
 
     /* The current AML generator can cover the APIC ID range [0..255],
      * inclusive, for VCPU hotplug. */
@@ -897,6 +900,10 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
                 continue;
             }
 
+            if (bus_info->bus < root_bus_limit) {
+                root_bus_limit = bus_info->bus - 1;
+            }
+
             scope = acpi_scope("\\_SB");
             dev = acpi_device("PC%.02X", (uint8_t)bus_info->bus);
             aml_append(&dev, acpi_name_decl("_UID",
@@ -911,8 +918,6 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
             aml_append(&ssdt, scope);
         }
 
-        pci_range_list_free(&io_ranges);
-        pci_range_list_free(&mem_ranges);
         qapi_free_PciInfoList(info_list);
     }
 
@@ -921,26 +926,79 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
     crs = acpi_resource_template();
     aml_append(&crs,
         acpi_word_bus_number(acpi_min_fixed, acpi_max_fixed, acpi_pos_decode,
-                             0x0000, 0x0000, 0x00FF, 0x0000, 0x0100));
+                             0x0000, 0x0, root_bus_limit,
+                             0x0000, root_bus_limit + 1));
+
     aml_append(&crs, acpi_io(acpi_decode16, 0x0CF8, 0x0CF8, 0x01, 0x08));
 
     aml_append(&crs,
         acpi_word_io(acpi_min_fixed, acpi_max_fixed,
                      acpi_pos_decode, acpi_entire_range,
                      0x0000, 0x0000, 0x0CF7, 0x0000, 0x0CF8));
-    aml_append(&crs,
-        acpi_word_io(acpi_min_fixed, acpi_max_fixed,
-                     acpi_pos_decode, acpi_entire_range,
-                     0x0000, 0x0D00, 0xFFFF, 0x0000, 0xF300));
+
+    /* prepare PCI IO ranges */
+    range.base = 0x0D00;
+    range.limit = 0xFFFF;
+    if (QLIST_EMPTY(&io_ranges)) {
+        aml_append(&crs,
+            acpi_word_io(acpi_min_fixed, acpi_max_fixed,
+                         acpi_pos_decode, acpi_entire_range,
+                         0x0000, range.base, range.limit,
+                         0x0000, range.limit - range.base + 1));
+    } else {
+        QLIST_FOREACH(entry, &io_ranges, entry) {
+            if (range.base < entry->base) {
+                aml_append(&crs,
+                    acpi_word_io(acpi_min_fixed, acpi_max_fixed,
+                                 acpi_pos_decode, acpi_entire_range,
+                                 0x0000, range.base, entry->base - 1,
+                                 0x0000, entry->base - range.base));
+            }
+            range.base = entry->limit + 1;
+            if (!QLIST_NEXT(entry, entry)) {
+                aml_append(&crs,
+                    acpi_word_io(acpi_min_fixed, acpi_max_fixed,
+                                 acpi_pos_decode, acpi_entire_range,
+                                 0x0000, range.base, range.limit,
+                                 0x0000, range.limit - range.base + 1));
+            }
+        }
+    }
+
     aml_append(&crs,
         acpi_dword_memory(acpi_pos_decode, acpi_min_fixed, acpi_max_fixed,
                           acpi_cacheable, acpi_ReadWrite,
                           0, 0x000A0000, 0x000BFFFF, 0, 0x00020000));
-    aml_append(&crs,
-        acpi_dword_memory(acpi_pos_decode, acpi_min_fixed, acpi_max_fixed,
-                          acpi_non_cacheable, acpi_ReadWrite,
-                          0, pci->w32.begin, pci->w32.end - 1, 0,
-                          pci->w32.end - pci->w32.begin));
+
+    /* prepare PCI memory ranges */
+    range.base = pci->w32.begin;
+    range.limit = pci->w32.end - 1;
+    if (QLIST_EMPTY(&mem_ranges)) {
+        aml_append(&crs,
+            acpi_dword_memory(acpi_pos_decode, acpi_min_fixed, acpi_max_fixed,
+                              acpi_non_cacheable, acpi_ReadWrite,
+                              0, range.base, range.limit,
+                              0, range.limit - range.base + 1));
+    } else {
+        QLIST_FOREACH(entry, &mem_ranges, entry) {
+            if (range.base < entry->base) {
+                aml_append(&crs,
+                    acpi_dword_memory(acpi_pos_decode, acpi_min_fixed, acpi_max_fixed,
+                                      acpi_non_cacheable, acpi_ReadWrite,
+                                      0, range.base, entry->base - 1,
+                                      0, entry->base - range.base));
+            }
+            range.base = entry->limit + 1;
+            if (!QLIST_NEXT(entry, entry)) {
+                aml_append(&crs,
+                    acpi_dword_memory(acpi_pos_decode, acpi_min_fixed, acpi_max_fixed,
+                                      acpi_non_cacheable, acpi_ReadWrite,
+                                      0, range.base, range.limit,
+                                      0, range.base - range.limit + 1));
+            }
+        }
+    }
+
     if (pci->w64.begin) {
         aml_append(&crs,
             acpi_qword_memory(acpi_pos_decode, acpi_min_fixed, acpi_max_fixed,
@@ -950,6 +1008,9 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
     }
     aml_append(&scope, acpi_name_decl("_CRS", crs));
 
+    pci_range_list_free(&io_ranges);
+    pci_range_list_free(&mem_ranges);
+
     /* reserve PCIHP resources */
     if (pm->pcihp_io_len) {
         dev = acpi_device("PHPR");
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 06/17] hw/pci: move pci bus related code to separate files
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (4 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 05/17] hw/acpi: remove from root bus 0 the crs resources used by other busses Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 07/17] hw/pci: made pci_bus_is_root a PCIBusClass method Marcel Apfelbaum
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

From: Marcel Apfelbaum <marcel.a@redhat.com>

This refactoring moves all the code needed (recursively)
to register TYPE_PCI_BUS type to a new file hw/pci/pci_bus.c .
This allows to properly add new functionality to the pci bus class.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 arch_init.c              |   1 +
 hw/alpha/typhoon.c       |   1 +
 hw/mips/gt64xxx_pci.c    |   1 +
 hw/pci-host/bonito.c     |   1 +
 hw/pci-host/grackle.c    |   1 +
 hw/pci-host/piix.c       |   1 +
 hw/pci-host/ppce500.c    |   1 +
 hw/pci-host/q35.c        |   1 +
 hw/pci-host/uninorth.c   |   1 +
 hw/pci/Makefile.objs     |   2 +-
 hw/pci/pci.c             | 472 +--------------------------------------------
 hw/pci/pci_bus.c         | 491 +++++++++++++++++++++++++++++++++++++++++++++++
 hw/ppc/ppc4xx_pci.c      |   1 +
 hw/sh4/r2d.c             |   1 +
 hw/sh4/sh_pci.c          |   1 +
 include/hw/pci/pci.h     |   3 +-
 include/hw/pci/pci_bus.h |   8 +
 17 files changed, 514 insertions(+), 474 deletions(-)
 create mode 100644 hw/pci/pci_bus.c

diff --git a/arch_init.c b/arch_init.c
index 89c8fa4..f2f7452 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -37,6 +37,7 @@
 #include "audio/audio.h"
 #include "hw/i386/pc.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/audio/audio.h"
 #include "sysemu/kvm.h"
 #include "migration/migration.h"
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
index 5310006..c8be8a6 100644
--- a/hw/alpha/typhoon.c
+++ b/hw/alpha/typhoon.c
@@ -8,6 +8,7 @@
 
 #include "cpu.h"
 #include "hw/hw.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/devices.h"
 #include "sysemu/sysemu.h"
 #include "alpha_sys.h"
diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c
index 1f2fe5f..6856bb0 100644
--- a/hw/mips/gt64xxx_pci.c
+++ b/hw/mips/gt64xxx_pci.c
@@ -25,6 +25,7 @@
 #include "hw/hw.h"
 #include "hw/mips/mips.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_host.h"
 #include "hw/i386/pc.h"
 #include "exec/address-spaces.h"
diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c
index 56292ad..72d6e12 100644
--- a/hw/pci-host/bonito.c
+++ b/hw/pci-host/bonito.c
@@ -41,6 +41,7 @@
 
 #include "hw/hw.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/i386/pc.h"
 #include "hw/mips/mips.h"
 #include "hw/pci/pci_host.h"
diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c
index 6c7cfdb..7ee6417 100644
--- a/hw/pci-host/grackle.c
+++ b/hw/pci-host/grackle.c
@@ -26,6 +26,7 @@
 #include "hw/pci/pci_host.h"
 #include "hw/ppc/mac.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 
 /* debug Grackle */
 //#define DEBUG_GRACKLE
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index 1530038..f7cfbc8 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -25,6 +25,7 @@
 #include "hw/hw.h"
 #include "hw/i386/pc.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_host.h"
 #include "hw/isa/isa.h"
 #include "hw/sysbus.h"
diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
index 574f8b2..a6aef6a 100644
--- a/hw/pci-host/ppce500.c
+++ b/hw/pci-host/ppce500.c
@@ -17,6 +17,7 @@
 #include "hw/hw.h"
 #include "hw/ppc/e500-ccsr.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_host.h"
 #include "qemu/bswap.h"
 #include "hw/pci-host/ppce500.h"
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index b20bad8..c36fefa 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -28,6 +28,7 @@
  * THE SOFTWARE.
  */
 #include "hw/hw.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci-host/q35.h"
 #include "qapi/visitor.h"
 
diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c
index 21f805f..c9cc570 100644
--- a/hw/pci-host/uninorth.c
+++ b/hw/pci-host/uninorth.c
@@ -24,6 +24,7 @@
 #include "hw/hw.h"
 #include "hw/ppc/mac.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_host.h"
 
 /* debug UniNorth */
diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs
index 80f8aa6..63aa4c5 100644
--- a/hw/pci/Makefile.objs
+++ b/hw/pci/Makefile.objs
@@ -1,4 +1,4 @@
-common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
+common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bus.o
 common-obj-$(CONFIG_PCI) += msix.o msi.o
 common-obj-$(CONFIG_PCI) += shpc.o
 common-obj-$(CONFIG_PCI) += slotid_cap.o
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 371699c..933ef65 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -44,11 +44,6 @@
 # define PCI_DPRINTF(format, ...)       do { } while (0)
 #endif
 
-static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
-static char *pcibus_get_dev_path(DeviceState *dev);
-static char *pcibus_get_fw_dev_path(DeviceState *dev);
-static void pcibus_reset(BusState *qbus);
-
 static Property pci_props[] = {
     DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
     DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
@@ -60,58 +55,11 @@ static Property pci_props[] = {
     DEFINE_PROP_END_OF_LIST()
 };
 
-static const VMStateDescription vmstate_pcibus = {
-    .name = "PCIBUS",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT32_EQUAL(nirq, PCIBus),
-        VMSTATE_VARRAY_INT32(irq_count, PCIBus,
-                             nirq, 0, vmstate_info_int32,
-                             int32_t),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void pci_bus_realize(BusState *qbus, Error **errp)
-{
-    PCIBus *bus = PCI_BUS(qbus);
-
-    vmstate_register(NULL, -1, &vmstate_pcibus, bus);
-}
-
-static void pci_bus_unrealize(BusState *qbus, Error **errp)
-{
-    PCIBus *bus = PCI_BUS(qbus);
-
-    vmstate_unregister(NULL, &vmstate_pcibus, bus);
-}
-
-static void pci_bus_class_init(ObjectClass *klass, void *data)
-{
-    BusClass *k = BUS_CLASS(klass);
-
-    k->print_dev = pcibus_dev_print;
-    k->get_dev_path = pcibus_get_dev_path;
-    k->get_fw_dev_path = pcibus_get_fw_dev_path;
-    k->realize = pci_bus_realize;
-    k->unrealize = pci_bus_unrealize;
-    k->reset = pcibus_reset;
-}
-
-static const TypeInfo pci_bus_info = {
-    .name = TYPE_PCI_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(PCIBus),
-    .class_init = pci_bus_class_init,
-};
-
 static const TypeInfo pcie_bus_info = {
     .name = TYPE_PCIE_BUS,
     .parent = TYPE_PCI_BUS,
 };
 
-static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
 static void pci_update_mappings(PCIDevice *d);
 static void pci_irq_handler(void *opaque, int irq_num, int level);
 static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom);
@@ -184,7 +132,7 @@ void pci_device_deassert_intx(PCIDevice *dev)
     }
 }
 
-static void pci_do_device_reset(PCIDevice *dev)
+void pci_do_device_reset(PCIDevice *dev)
 {
     int r;
 
@@ -229,27 +177,6 @@ void pci_device_reset(PCIDevice *dev)
     pci_do_device_reset(dev);
 }
 
-/*
- * Trigger pci bus reset under a given bus.
- * Called via qbus_reset_all on RST# assert, after the devices
- * have been reset qdev_reset_all-ed already.
- */
-static void pcibus_reset(BusState *qbus)
-{
-    PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus);
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
-        if (bus->devices[i]) {
-            pci_do_device_reset(bus->devices[i]);
-        }
-    }
-
-    for (i = 0; i < bus->nirq; i++) {
-        assert(bus->irq_count[i] == 0);
-    }
-}
-
 static void pci_host_bus_register(PCIBus *bus, DeviceState *parent)
 {
     PCIHostState *host_bridge = PCI_HOST_BRIDGE(parent);
@@ -1286,74 +1213,6 @@ int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
     return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS;
 }
 
-/***********************************************************/
-/* monitor info on PCI */
-
-typedef struct {
-    uint16_t class;
-    const char *desc;
-    const char *fw_name;
-    uint16_t fw_ign_bits;
-} pci_class_desc;
-
-static const pci_class_desc pci_class_descriptions[] =
-{
-    { 0x0001, "VGA controller", "display"},
-    { 0x0100, "SCSI controller", "scsi"},
-    { 0x0101, "IDE controller", "ide"},
-    { 0x0102, "Floppy controller", "fdc"},
-    { 0x0103, "IPI controller", "ipi"},
-    { 0x0104, "RAID controller", "raid"},
-    { 0x0106, "SATA controller"},
-    { 0x0107, "SAS controller"},
-    { 0x0180, "Storage controller"},
-    { 0x0200, "Ethernet controller", "ethernet"},
-    { 0x0201, "Token Ring controller", "token-ring"},
-    { 0x0202, "FDDI controller", "fddi"},
-    { 0x0203, "ATM controller", "atm"},
-    { 0x0280, "Network controller"},
-    { 0x0300, "VGA controller", "display", 0x00ff},
-    { 0x0301, "XGA controller"},
-    { 0x0302, "3D controller"},
-    { 0x0380, "Display controller"},
-    { 0x0400, "Video controller", "video"},
-    { 0x0401, "Audio controller", "sound"},
-    { 0x0402, "Phone"},
-    { 0x0403, "Audio controller", "sound"},
-    { 0x0480, "Multimedia controller"},
-    { 0x0500, "RAM controller", "memory"},
-    { 0x0501, "Flash controller", "flash"},
-    { 0x0580, "Memory controller"},
-    { 0x0600, "Host bridge", "host"},
-    { 0x0601, "ISA bridge", "isa"},
-    { 0x0602, "EISA bridge", "eisa"},
-    { 0x0603, "MC bridge", "mca"},
-    { 0x0604, "PCI bridge", "pci-bridge"},
-    { 0x0605, "PCMCIA bridge", "pcmcia"},
-    { 0x0606, "NUBUS bridge", "nubus"},
-    { 0x0607, "CARDBUS bridge", "cardbus"},
-    { 0x0608, "RACEWAY bridge"},
-    { 0x0680, "Bridge"},
-    { 0x0700, "Serial port", "serial"},
-    { 0x0701, "Parallel port", "parallel"},
-    { 0x0800, "Interrupt controller", "interrupt-controller"},
-    { 0x0801, "DMA controller", "dma-controller"},
-    { 0x0802, "Timer", "timer"},
-    { 0x0803, "RTC", "rtc"},
-    { 0x0900, "Keyboard", "keyboard"},
-    { 0x0901, "Pen", "pen"},
-    { 0x0902, "Mouse", "mouse"},
-    { 0x0A00, "Dock station", "dock", 0x00ff},
-    { 0x0B00, "i386 cpu", "cpu", 0x00ff},
-    { 0x0c00, "Fireware contorller", "fireware"},
-    { 0x0c01, "Access bus controller", "access-bus"},
-    { 0x0c02, "SSA controller", "ssa"},
-    { 0x0c03, "USB controller", "usb"},
-    { 0x0c04, "Fibre channel controller", "fibre-channel"},
-    { 0x0c05, "SMBus"},
-    { 0, NULL}
-};
-
 static void pci_for_each_device_under_bus(PCIBus *bus,
                                           void (*fn)(PCIBus *b, PCIDevice *d,
                                                      void *opaque),
@@ -1381,161 +1240,6 @@ void pci_for_each_device(PCIBus *bus, int bus_num,
     }
 }
 
-static const pci_class_desc *get_class_desc(int class)
-{
-    const pci_class_desc *desc;
-
-    desc = pci_class_descriptions;
-    while (desc->desc && class != desc->class) {
-        desc++;
-    }
-
-    return desc;
-}
-
-static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
-
-static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
-{
-    PciMemoryRegionList *head = NULL, *cur_item = NULL;
-    int i;
-
-    for (i = 0; i < PCI_NUM_REGIONS; i++) {
-        const PCIIORegion *r = &dev->io_regions[i];
-        PciMemoryRegionList *region;
-
-        if (!r->size) {
-            continue;
-        }
-
-        region = g_malloc0(sizeof(*region));
-        region->value = g_malloc0(sizeof(*region->value));
-
-        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-            region->value->type = g_strdup("io");
-        } else {
-            region->value->type = g_strdup("memory");
-            region->value->has_prefetch = true;
-            region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH);
-            region->value->has_mem_type_64 = true;
-            region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
-        }
-
-        region->value->bar = i;
-        region->value->address = r->addr;
-        region->value->size = r->size;
-
-        /* XXX: waiting for the qapi to support GSList */
-        if (!cur_item) {
-            head = cur_item = region;
-        } else {
-            cur_item->next = region;
-            cur_item = region;
-        }
-    }
-
-    return head;
-}
-
-static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
-                                           int bus_num)
-{
-    PciBridgeInfo *info;
-
-    info = g_malloc0(sizeof(*info));
-
-    info->bus.number = dev->config[PCI_PRIMARY_BUS];
-    info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
-    info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
-
-    info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
-    info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
-    info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
-
-    info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
-    info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
-    info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
-
-    info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range));
-    info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
-    info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
-
-    if (dev->config[PCI_SECONDARY_BUS] != 0) {
-        PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]);
-        if (child_bus) {
-            info->has_devices = true;
-            info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]);
-        }
-    }
-
-    return info;
-}
-
-static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
-                                           int bus_num)
-{
-    const pci_class_desc *desc;
-    PciDeviceInfo *info;
-    uint8_t type;
-    int class;
-
-    info = g_malloc0(sizeof(*info));
-    info->bus = bus_num;
-    info->slot = PCI_SLOT(dev->devfn);
-    info->function = PCI_FUNC(dev->devfn);
-
-    class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
-    info->class_info.q_class = class;
-    desc = get_class_desc(class);
-    if (desc->desc) {
-        info->class_info.has_desc = true;
-        info->class_info.desc = g_strdup(desc->desc);
-    }
-
-    info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
-    info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
-    info->regions = qmp_query_pci_regions(dev);
-    info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
-
-    if (dev->config[PCI_INTERRUPT_PIN] != 0) {
-        info->has_irq = true;
-        info->irq = dev->config[PCI_INTERRUPT_LINE];
-    }
-
-    type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
-    if (type == PCI_HEADER_TYPE_BRIDGE) {
-        info->has_pci_bridge = true;
-        info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
-    }
-
-    return info;
-}
-
-static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
-{
-    PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
-    PCIDevice *dev;
-    int devfn;
-
-    for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
-        dev = bus->devices[devfn];
-        if (dev) {
-            info = g_malloc0(sizeof(*info));
-            info->value = qmp_query_pci_device(dev, bus, bus_num);
-
-            /* XXX: waiting for the qapi to support GSList */
-            if (!cur_item) {
-                head = cur_item = info;
-            } else {
-                cur_item->next = info;
-                cur_item = info;
-            }
-        }
-    }
-
-    return head;
-}
-
 static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
 {
     PciInfo *info = NULL;
@@ -1660,50 +1364,6 @@ PCIDevice *pci_vga_init(PCIBus *bus)
     }
 }
 
-/* Whether a given bus number is in range of the secondary
- * bus of the given bridge device. */
-static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
-{
-    return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) &
-             PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ &&
-        dev->config[PCI_SECONDARY_BUS] < bus_num &&
-        bus_num <= dev->config[PCI_SUBORDINATE_BUS];
-}
-
-static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
-{
-    PCIBus *sec;
-
-    if (!bus) {
-        return NULL;
-    }
-
-    if (pci_bus_num(bus) == bus_num) {
-        return bus;
-    }
-
-    /* Consider all bus numbers in range for the host pci bridge. */
-    if (!pci_bus_is_root(bus) &&
-        !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
-        return NULL;
-    }
-
-    /* try child bus */
-    for (; bus; bus = sec) {
-        QLIST_FOREACH(sec, &bus->child, sibling) {
-            assert(!pci_bus_is_root(sec));
-            if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
-                return sec;
-            }
-            if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) {
-                break;
-            }
-        }
-    }
-
-    return NULL;
-}
-
 void pci_for_each_bus_depth_first(PCIBus *bus,
                                   void *(*begin)(PCIBus *bus, void *parent_state),
                                   void (*end)(PCIBus *bus, void *state),
@@ -2106,135 +1766,6 @@ uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
     return pci_find_capability_list(pdev, cap_id, NULL);
 }
 
-static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent)
-{
-    PCIDevice *d = (PCIDevice *)dev;
-    const pci_class_desc *desc;
-    char ctxt[64];
-    PCIIORegion *r;
-    int i, class;
-
-    class = pci_get_word(d->config + PCI_CLASS_DEVICE);
-    desc = pci_class_descriptions;
-    while (desc->desc && class != desc->class)
-        desc++;
-    if (desc->desc) {
-        snprintf(ctxt, sizeof(ctxt), "%s", desc->desc);
-    } else {
-        snprintf(ctxt, sizeof(ctxt), "Class %04x", class);
-    }
-
-    monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, "
-                   "pci id %04x:%04x (sub %04x:%04x)\n",
-                   indent, "", ctxt, pci_bus_num(d->bus),
-                   PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),
-                   pci_get_word(d->config + PCI_VENDOR_ID),
-                   pci_get_word(d->config + PCI_DEVICE_ID),
-                   pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID),
-                   pci_get_word(d->config + PCI_SUBSYSTEM_ID));
-    for (i = 0; i < PCI_NUM_REGIONS; i++) {
-        r = &d->io_regions[i];
-        if (!r->size)
-            continue;
-        monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS
-                       " [0x%"FMT_PCIBUS"]\n",
-                       indent, "",
-                       i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem",
-                       r->addr, r->addr + r->size - 1);
-    }
-}
-
-static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len)
-{
-    PCIDevice *d = (PCIDevice *)dev;
-    const char *name = NULL;
-    const pci_class_desc *desc =  pci_class_descriptions;
-    int class = pci_get_word(d->config + PCI_CLASS_DEVICE);
-
-    while (desc->desc &&
-          (class & ~desc->fw_ign_bits) !=
-          (desc->class & ~desc->fw_ign_bits)) {
-        desc++;
-    }
-
-    if (desc->desc) {
-        name = desc->fw_name;
-    }
-
-    if (name) {
-        pstrcpy(buf, len, name);
-    } else {
-        snprintf(buf, len, "pci%04x,%04x",
-                 pci_get_word(d->config + PCI_VENDOR_ID),
-                 pci_get_word(d->config + PCI_DEVICE_ID));
-    }
-
-    return buf;
-}
-
-static char *pcibus_get_fw_dev_path(DeviceState *dev)
-{
-    PCIDevice *d = (PCIDevice *)dev;
-    char path[50], name[33];
-    int off;
-
-    off = snprintf(path, sizeof(path), "%s@%x",
-                   pci_dev_fw_name(dev, name, sizeof name),
-                   PCI_SLOT(d->devfn));
-    if (PCI_FUNC(d->devfn))
-        snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn));
-    return g_strdup(path);
-}
-
-static char *pcibus_get_dev_path(DeviceState *dev)
-{
-    PCIDevice *d = container_of(dev, PCIDevice, qdev);
-    PCIDevice *t;
-    int slot_depth;
-    /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function.
-     * 00 is added here to make this format compatible with
-     * domain:Bus:Slot.Func for systems without nested PCI bridges.
-     * Slot.Function list specifies the slot and function numbers for all
-     * devices on the path from root to the specific device. */
-    const char *root_bus_path;
-    int root_bus_len;
-    char slot[] = ":SS.F";
-    int slot_len = sizeof slot - 1 /* For '\0' */;
-    int path_len;
-    char *path, *p;
-    int s;
-
-    root_bus_path = pci_root_bus_path(d);
-    root_bus_len = strlen(root_bus_path);
-
-    /* Calculate # of slots on path between device and root. */;
-    slot_depth = 0;
-    for (t = d; t; t = t->bus->parent_dev) {
-        ++slot_depth;
-    }
-
-    path_len = root_bus_len + slot_len * slot_depth;
-
-    /* Allocate memory, fill in the terminating null byte. */
-    path = g_malloc(path_len + 1 /* For '\0' */);
-    path[path_len] = '\0';
-
-    memcpy(path, root_bus_path, root_bus_len);
-
-    /* Fill in slot numbers. We walk up from device to root, so need to print
-     * them in the reverse order, last to first. */
-    p = path + path_len;
-    for (t = d; t; t = t->bus->parent_dev) {
-        p -= slot_len;
-        s = snprintf(slot, sizeof slot, ":%02x.%x",
-                     PCI_SLOT(t->devfn), PCI_FUNC(t->devfn));
-        assert(s == slot_len);
-        memcpy(p, slot, slot_len);
-    }
-
-    return path;
-}
-
 static int pci_qdev_find_recursive(PCIBus *bus,
                                    const char *id, PCIDevice **pdev)
 {
@@ -2377,7 +1908,6 @@ static const TypeInfo pci_device_type_info = {
 
 static void pci_register_types(void)
 {
-    type_register_static(&pci_bus_info);
     type_register_static(&pcie_bus_info);
     type_register_static(&pci_device_type_info);
 }
diff --git a/hw/pci/pci_bus.c b/hw/pci/pci_bus.c
new file mode 100644
index 0000000..d156194
--- /dev/null
+++ b/hw/pci/pci_bus.c
@@ -0,0 +1,491 @@
+/*
+ * PCI Bus
+ *
+ * Copyright (C) 2014 Red Hat Inc
+ *
+ * Authors:
+ *   Marcel Apfelbaum <marcel.a@redhat.com> (split out from pci.c)
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_bridge.h"
+#include "monitor/monitor.h"
+
+typedef struct {
+    uint16_t class;
+    const char *desc;
+    const char *fw_name;
+    uint16_t fw_ign_bits;
+} pci_class_desc;
+
+static const pci_class_desc pci_class_descriptions[] = {
+    { 0x0001, "VGA controller", "display"},
+    { 0x0100, "SCSI controller", "scsi"},
+    { 0x0101, "IDE controller", "ide"},
+    { 0x0102, "Floppy controller", "fdc"},
+    { 0x0103, "IPI controller", "ipi"},
+    { 0x0104, "RAID controller", "raid"},
+    { 0x0106, "SATA controller"},
+    { 0x0107, "SAS controller"},
+    { 0x0180, "Storage controller"},
+    { 0x0200, "Ethernet controller", "ethernet"},
+    { 0x0201, "Token Ring controller", "token-ring"},
+    { 0x0202, "FDDI controller", "fddi"},
+    { 0x0203, "ATM controller", "atm"},
+    { 0x0280, "Network controller"},
+    { 0x0300, "VGA controller", "display", 0x00ff},
+    { 0x0301, "XGA controller"},
+    { 0x0302, "3D controller"},
+    { 0x0380, "Display controller"},
+    { 0x0400, "Video controller", "video"},
+    { 0x0401, "Audio controller", "sound"},
+    { 0x0402, "Phone"},
+    { 0x0403, "Audio controller", "sound"},
+    { 0x0480, "Multimedia controller"},
+    { 0x0500, "RAM controller", "memory"},
+    { 0x0501, "Flash controller", "flash"},
+    { 0x0580, "Memory controller"},
+    { 0x0600, "Host bridge", "host"},
+    { 0x0601, "ISA bridge", "isa"},
+    { 0x0602, "EISA bridge", "eisa"},
+    { 0x0603, "MC bridge", "mca"},
+    { 0x0604, "PCI bridge", "pci-bridge"},
+    { 0x0605, "PCMCIA bridge", "pcmcia"},
+    { 0x0606, "NUBUS bridge", "nubus"},
+    { 0x0607, "CARDBUS bridge", "cardbus"},
+    { 0x0608, "RACEWAY bridge"},
+    { 0x0680, "Bridge"},
+    { 0x0700, "Serial port", "serial"},
+    { 0x0701, "Parallel port", "parallel"},
+    { 0x0800, "Interrupt controller", "interrupt-controller"},
+    { 0x0801, "DMA controller", "dma-controller"},
+    { 0x0802, "Timer", "timer"},
+    { 0x0803, "RTC", "rtc"},
+    { 0x0900, "Keyboard", "keyboard"},
+    { 0x0901, "Pen", "pen"},
+    { 0x0902, "Mouse", "mouse"},
+    { 0x0A00, "Dock station", "dock", 0x00ff},
+    { 0x0B00, "i386 cpu", "cpu", 0x00ff},
+    { 0x0c00, "Fireware contorller", "fireware"},
+    { 0x0c01, "Access bus controller", "access-bus"},
+    { 0x0c02, "SSA controller", "ssa"},
+    { 0x0c03, "USB controller", "usb"},
+    { 0x0c04, "Fibre channel controller", "fibre-channel"},
+    { 0x0c05, "SMBus"},
+    { 0, NULL}
+};
+
+/* Whether a given bus number is in range of the secondary
+ * bus of the given bridge device. */
+static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
+{
+    return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) &
+             PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ &&
+        dev->config[PCI_SECONDARY_BUS] < bus_num &&
+        bus_num <= dev->config[PCI_SUBORDINATE_BUS];
+}
+
+PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
+{
+    PCIBus *sec;
+
+    if (!bus) {
+        return NULL;
+    }
+
+    if (pci_bus_num(bus) == bus_num) {
+        return bus;
+    }
+
+    /* Consider all bus numbers in range for the host pci bridge. */
+    if (!pci_bus_is_root(bus) &&
+        !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
+        return NULL;
+    }
+
+    /* try child bus */
+    for (; bus; bus = sec) {
+        QLIST_FOREACH(sec, &bus->child, sibling) {
+            assert(!pci_bus_is_root(sec));
+            if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
+                return sec;
+            }
+            if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) {
+                break;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+static const pci_class_desc *get_class_desc(int class)
+{
+    const pci_class_desc *desc;
+
+    desc = pci_class_descriptions;
+    while (desc->desc && class != desc->class) {
+        desc++;
+    }
+
+    return desc;
+}
+
+static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
+{
+    PciMemoryRegionList *head = NULL, *cur_item = NULL;
+    int i;
+
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        const PCIIORegion *r = &dev->io_regions[i];
+        PciMemoryRegionList *region;
+
+        if (!r->size) {
+            continue;
+        }
+
+        region = g_malloc0(sizeof(*region));
+        region->value = g_malloc0(sizeof(*region->value));
+
+        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+            region->value->type = g_strdup("io");
+        } else {
+            region->value->type = g_strdup("memory");
+            region->value->has_prefetch = true;
+            region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH);
+            region->value->has_mem_type_64 = true;
+            region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
+        }
+
+        region->value->bar = i;
+        region->value->address = r->addr;
+        region->value->size = r->size;
+
+        /* XXX: waiting for the qapi to support GSList */
+        if (!cur_item) {
+            head = cur_item = region;
+        } else {
+            cur_item->next = region;
+            cur_item = region;
+        }
+    }
+
+    return head;
+}
+
+static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
+                                           int bus_num)
+{
+    PciBridgeInfo *info;
+
+    info = g_malloc0(sizeof(*info));
+
+    info->bus.number = dev->config[PCI_PRIMARY_BUS];
+    info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
+    info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
+
+    info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
+    info->bus.io_range->base = pci_bridge_get_base(dev,
+                    PCI_BASE_ADDRESS_SPACE_IO);
+    info->bus.io_range->limit =
+                    pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
+
+    info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
+    info->bus.memory_range->base =
+                    pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
+    info->bus.memory_range->limit =
+                    pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
+
+    info->bus.prefetchable_range =
+                    g_malloc0(sizeof(*info->bus.prefetchable_range));
+    info->bus.prefetchable_range->base =
+                    pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
+    info->bus.prefetchable_range->limit =
+                    pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
+
+    if (dev->config[PCI_SECONDARY_BUS] != 0) {
+        PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]);
+        if (child_bus) {
+            info->has_devices = true;
+            info->devices = qmp_query_pci_devices(child_bus,
+                                                  dev->config[PCI_SECONDARY_BUS]);
+        }
+    }
+
+    return info;
+}
+
+static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
+                                           int bus_num)
+{
+    const pci_class_desc *desc;
+    PciDeviceInfo *info;
+    uint8_t type;
+    int class;
+
+    info = g_malloc0(sizeof(*info));
+    info->bus = bus_num;
+    info->slot = PCI_SLOT(dev->devfn);
+    info->function = PCI_FUNC(dev->devfn);
+
+    class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
+    info->class_info.q_class = class;
+    desc = get_class_desc(class);
+    if (desc->desc) {
+        info->class_info.has_desc = true;
+        info->class_info.desc = g_strdup(desc->desc);
+    }
+
+    info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
+    info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
+    info->regions = qmp_query_pci_regions(dev);
+    info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
+
+    if (dev->config[PCI_INTERRUPT_PIN] != 0) {
+        info->has_irq = true;
+        info->irq = dev->config[PCI_INTERRUPT_LINE];
+    }
+
+    type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
+    if (type == PCI_HEADER_TYPE_BRIDGE) {
+        info->has_pci_bridge = true;
+        info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
+    }
+
+    return info;
+}
+
+PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
+{
+    PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
+    PCIDevice *dev;
+    int devfn;
+
+    for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+        dev = bus->devices[devfn];
+        if (dev) {
+            info = g_malloc0(sizeof(*info));
+            info->value = qmp_query_pci_device(dev, bus, bus_num);
+
+            /* XXX: waiting for the qapi to support GSList */
+            if (!cur_item) {
+                head = cur_item = info;
+            } else {
+                cur_item->next = info;
+                cur_item = info;
+            }
+        }
+    }
+
+    return head;
+}
+
+
+static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    PCIDevice *d = (PCIDevice *)dev;
+    const pci_class_desc *desc;
+    char ctxt[64];
+    PCIIORegion *r;
+    int i, class;
+
+    class = pci_get_word(d->config + PCI_CLASS_DEVICE);
+    desc = pci_class_descriptions;
+    while (desc->desc && class != desc->class) {
+        desc++;
+    }
+    if (desc->desc) {
+        snprintf(ctxt, sizeof(ctxt), "%s", desc->desc);
+    } else {
+        snprintf(ctxt, sizeof(ctxt), "Class %04x", class);
+    }
+
+    monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, "
+                   "pci id %04x:%04x (sub %04x:%04x)\n",
+                   indent, "", ctxt, pci_bus_num(d->bus),
+                   PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),
+                   pci_get_word(d->config + PCI_VENDOR_ID),
+                   pci_get_word(d->config + PCI_DEVICE_ID),
+                   pci_get_word(d->config + PCI_SUBSYSTEM_VENDOR_ID),
+                   pci_get_word(d->config + PCI_SUBSYSTEM_ID));
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        r = &d->io_regions[i];
+        if (!r->size) {
+            continue;
+        }
+        monitor_printf(mon, "%*sbar %d: %s at 0x%"FMT_PCIBUS
+                       " [0x%"FMT_PCIBUS"]\n",
+                       indent, "",
+                       i, r->type & PCI_BASE_ADDRESS_SPACE_IO ? "i/o" : "mem",
+                       r->addr, r->addr + r->size - 1);
+    }
+}
+
+static char *pcibus_get_dev_path(DeviceState *dev)
+{
+    PCIDevice *d = container_of(dev, PCIDevice, qdev);
+    PCIDevice *t;
+    int slot_depth;
+    /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function.
+     * 00 is added here to make this format compatible with
+     * domain:Bus:Slot.Func for systems without nested PCI bridges.
+     * Slot.Function list specifies the slot and function numbers for all
+     * devices on the path from root to the specific device. */
+    const char *root_bus_path;
+    int root_bus_len;
+    char slot[] = ":SS.F";
+    int slot_len = sizeof slot - 1 /* For '\0' */;
+    int path_len;
+    char *path, *p;
+    int s;
+
+    root_bus_path = pci_root_bus_path(d);
+    root_bus_len = strlen(root_bus_path);
+
+    /* Calculate # of slots on path between device and root. */;
+    slot_depth = 0;
+    for (t = d; t; t = t->bus->parent_dev) {
+        ++slot_depth;
+    }
+
+    path_len = root_bus_len + slot_len * slot_depth;
+
+    /* Allocate memory, fill in the terminating null byte. */
+    path = g_malloc(path_len + 1 /* For '\0' */);
+    path[path_len] = '\0';
+
+    memcpy(path, root_bus_path, root_bus_len);
+
+    /* Fill in slot numbers. We walk up from device to root, so need to print
+     * them in the reverse order, last to first. */
+    p = path + path_len;
+    for (t = d; t; t = t->bus->parent_dev) {
+        p -= slot_len;
+        s = snprintf(slot, sizeof slot, ":%02x.%x",
+                     PCI_SLOT(t->devfn), PCI_FUNC(t->devfn));
+        assert(s == slot_len);
+        memcpy(p, slot, slot_len);
+    }
+
+    return path;
+}
+
+static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len)
+{
+    PCIDevice *d = (PCIDevice *)dev;
+    const char *name = NULL;
+    const pci_class_desc *desc =  pci_class_descriptions;
+    int class = pci_get_word(d->config + PCI_CLASS_DEVICE);
+
+    while (desc->desc &&
+          (class & ~desc->fw_ign_bits) !=
+          (desc->class & ~desc->fw_ign_bits)) {
+        desc++;
+    }
+
+    if (desc->desc) {
+        name = desc->fw_name;
+    }
+
+    if (name) {
+        pstrcpy(buf, len, name);
+    } else {
+        snprintf(buf, len, "pci%04x,%04x",
+                 pci_get_word(d->config + PCI_VENDOR_ID),
+                 pci_get_word(d->config + PCI_DEVICE_ID));
+    }
+
+    return buf;
+}
+
+static char *pcibus_get_fw_dev_path(DeviceState *dev)
+{
+    PCIDevice *d = (PCIDevice *)dev;
+    char path[50], name[33];
+    int off;
+
+    off = snprintf(path, sizeof(path), "%s@%x",
+                   pci_dev_fw_name(dev, name, sizeof name),
+                   PCI_SLOT(d->devfn));
+    if (PCI_FUNC(d->devfn)) {
+        snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn));
+    }
+    return g_strdup(path);
+}
+
+static const VMStateDescription vmstate_pcibus = {
+    .name = "PCIBUS",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32_EQUAL(nirq, PCIBus),
+        VMSTATE_VARRAY_INT32(irq_count, PCIBus,
+                             nirq, 0, vmstate_info_int32,
+                             int32_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pci_bus_realize(BusState *qbus, Error **errp)
+{
+    PCIBus *bus = PCI_BUS(qbus);
+
+    vmstate_register(NULL, -1, &vmstate_pcibus, bus);
+}
+
+static void pci_bus_unrealize(BusState *qbus, Error **errp)
+{
+    PCIBus *bus = PCI_BUS(qbus);
+
+    vmstate_unregister(NULL, &vmstate_pcibus, bus);
+}
+
+/*
+ * Trigger pci bus reset under a given bus.
+ * Called via qbus_reset_all on RST# assert, after the devices
+ * have been reset qdev_reset_all-ed already.
+ */
+static void pcibus_reset(BusState *qbus)
+{
+    PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus);
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
+        if (bus->devices[i]) {
+            pci_do_device_reset(bus->devices[i]);
+        }
+    }
+
+    for (i = 0; i < bus->nirq; i++) {
+        assert(bus->irq_count[i] == 0);
+    }
+}
+
+static void pci_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->print_dev = pcibus_dev_print;
+    k->get_dev_path = pcibus_get_dev_path;
+    k->get_fw_dev_path = pcibus_get_fw_dev_path;
+    k->realize = pci_bus_realize;
+    k->unrealize = pci_bus_unrealize;
+    k->reset = pcibus_reset;
+}
+
+static const TypeInfo pci_bus_info = {
+    .name = TYPE_PCI_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(PCIBus),
+    .class_init = pci_bus_class_init,
+};
+
+static void pci_bus_register_types(void)
+{
+    type_register_static(&pci_bus_info);
+}
+
+type_init(pci_bus_register_types)
diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c
index 0bb3cdb..f5847bc 100644
--- a/hw/ppc/ppc4xx_pci.c
+++ b/hw/ppc/ppc4xx_pci.c
@@ -23,6 +23,7 @@
 #include "hw/ppc/ppc.h"
 #include "hw/ppc/ppc4xx.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_host.h"
 #include "exec/address-spaces.h"
 
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index 12f44d2..80d3c43 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -30,6 +30,7 @@
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "net/net.h"
 #include "sh7750_regs.h"
 #include "hw/ide.h"
diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c
index a2f6d9e..f02e998 100644
--- a/hw/sh4/sh_pci.c
+++ b/hw/sh4/sh_pci.c
@@ -24,6 +24,7 @@
 #include "hw/sysbus.h"
 #include "hw/sh4/sh.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_host.h"
 #include "qemu/bswap.h"
 #include "exec/address-spaces.h"
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 97a83d3..966e9cd 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -335,8 +335,6 @@ typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
 typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin);
 
-#define TYPE_PCI_BUS "PCI"
-#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
 #define TYPE_PCIE_BUS "PCIE"
 
 bool pci_bus_is_express(PCIBus *bus);
@@ -368,6 +366,7 @@ void pci_bus_fire_intx_routing_notifier(PCIBus *bus);
 void pci_device_set_intx_routing_notifier(PCIDevice *dev,
                                           PCIINTxRoutingNotifier notifier);
 void pci_device_reset(PCIDevice *dev);
+void pci_do_device_reset(PCIDevice *dev);
 
 PCIDevice *pci_nic_init(NICInfo *nd, PCIBus *rootbus,
                         const char *default_model,
diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
index fabaeee..ea427a3 100644
--- a/include/hw/pci/pci_bus.h
+++ b/include/hw/pci/pci_bus.h
@@ -1,6 +1,8 @@
 #ifndef QEMU_PCI_BUS_H
 #define QEMU_PCI_BUS_H
 
+#include "hw/pci/pci.h"
+
 /*
  * PCI Bus and Bridge datastructures.
  *
@@ -8,6 +10,12 @@
  * use accessor functions in pci.h, pci_bridge.h
  */
 
+PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
+PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
+
+#define TYPE_PCI_BUS "PCI"
+#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
+
 struct PCIBus {
     BusState qbus;
     PCIIOMMUFunc iommu_fn;
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 07/17] hw/pci: made pci_bus_is_root a PCIBusClass method
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (5 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 06/17] hw/pci: move pci bus related code to separate files Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 08/17] hw/pci: made pci_bus_num " Marcel Apfelbaum
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

From: Marcel Apfelbaum <marcel.a@redhat.com>

Refactoring it as a method of PCIBusClass will allow
different implementations for subclasses.

Removed the assumption that the root bus does not
have a parent device because is specific only
to the default class implementation.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/pci/pci.c             | 11 ++++-------
 hw/pci/pci_bus.c         |  9 +++++++++
 hw/vfio/pci.c            |  1 +
 include/hw/pci/pci.h     |  1 -
 include/hw/pci/pci_bus.h | 15 +++++++++++++++
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 933ef65..0b4e138 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -204,7 +204,10 @@ PCIBus *pci_device_root_bus(const PCIDevice *d)
 {
     PCIBus *bus = d->bus;
 
-    while ((d = bus->parent_dev) != NULL) {
+    while (!pci_bus_is_root(bus)) {
+        d = bus->parent_dev;
+        assert(d != NULL);
+
         bus = d->bus;
     }
 
@@ -217,7 +220,6 @@ const char *pci_root_bus_path(PCIDevice *dev)
     PCIHostState *host_bridge = PCI_HOST_BRIDGE(rootbus->qbus.parent);
     PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_GET_CLASS(host_bridge);
 
-    assert(!rootbus->parent_dev);
     assert(host_bridge->bus == rootbus);
 
     if (hc->root_bus_path) {
@@ -249,11 +251,6 @@ bool pci_bus_is_express(PCIBus *bus)
     return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
 }
 
-bool pci_bus_is_root(PCIBus *bus)
-{
-    return !bus->parent_dev;
-}
-
 void pci_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent,
                          const char *name,
                          MemoryRegion *address_space_mem,
diff --git a/hw/pci/pci_bus.c b/hw/pci/pci_bus.c
index d156194..0922a75 100644
--- a/hw/pci/pci_bus.c
+++ b/hw/pci/pci_bus.c
@@ -464,9 +464,15 @@ static void pcibus_reset(BusState *qbus)
     }
 }
 
+static bool pcibus_is_root(PCIBus *bus)
+{
+    return !bus->parent_dev;
+}
+
 static void pci_bus_class_init(ObjectClass *klass, void *data)
 {
     BusClass *k = BUS_CLASS(klass);
+    PCIBusClass *pbc = PCI_BUS_CLASS(klass);
 
     k->print_dev = pcibus_dev_print;
     k->get_dev_path = pcibus_get_dev_path;
@@ -474,11 +480,14 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
     k->realize = pci_bus_realize;
     k->unrealize = pci_bus_unrealize;
     k->reset = pcibus_reset;
+
+    pbc->is_root = pcibus_is_root;
 }
 
 static const TypeInfo pci_bus_info = {
     .name = TYPE_PCI_BUS,
     .parent = TYPE_BUS,
+    .class_size = sizeof(PCIBusClass),
     .instance_size = sizeof(PCIBus),
     .class_init = pci_bus_class_init,
 };
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 014a92c..a6f3179 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -32,6 +32,7 @@
 #include "hw/pci/msi.h"
 #include "hw/pci/msix.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "qemu-common.h"
 #include "qemu/error-report.h"
 #include "qemu/event_notifier.h"
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 966e9cd..7b2567a 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -338,7 +338,6 @@ typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin);
 #define TYPE_PCIE_BUS "PCIE"
 
 bool pci_bus_is_express(PCIBus *bus);
-bool pci_bus_is_root(PCIBus *bus);
 void pci_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent,
                          const char *name,
                          MemoryRegion *address_space_mem,
diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
index ea427a3..306ef10 100644
--- a/include/hw/pci/pci_bus.h
+++ b/include/hw/pci/pci_bus.h
@@ -15,6 +15,16 @@ PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
 
 #define TYPE_PCI_BUS "PCI"
 #define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
+#define PCI_BUS_CLASS(klass) OBJECT_CLASS_CHECK(PCIBusClass, (klass), TYPE_PCI_BUS)
+#define PCI_BUS_GET_CLASS(obj) OBJECT_GET_CLASS(PCIBusClass, (obj), TYPE_PCI_BUS)
+
+typedef struct PCIBusClass {
+    /*< private >*/
+    BusClass parent_class;
+    /*< public >*/
+
+    bool (*is_root)(PCIBus *bus);
+} PCIBusClass;
 
 struct PCIBus {
     BusState qbus;
@@ -39,6 +49,11 @@ struct PCIBus {
     int *irq_count;
 };
 
+static inline bool pci_bus_is_root(PCIBus *bus)
+{
+    return PCI_BUS_GET_CLASS(bus)->is_root(bus);
+}
+
 typedef struct PCIBridgeWindows PCIBridgeWindows;
 
 /*
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 08/17] hw/pci: made pci_bus_num a PCIBusClass method
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (6 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 07/17] hw/pci: made pci_bus_is_root a PCIBusClass method Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 09/17] hw/pci: introduce TYPE_PCI_MAIN_HOST_BRIDGE interface Marcel Apfelbaum
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

From: Marcel Apfelbaum <marcel.a@redhat.com>

Refactoring it as a method of PCIBusClass will allow
different implementations for subclasses.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/i386/kvm/pci-assign.c |  1 +
 hw/pci/pci-hotplug-old.c |  1 +
 hw/pci/pci.c             |  7 -------
 hw/pci/pci_bus.c         | 10 ++++++++++
 hw/scsi/megasas.c        |  1 +
 hw/xen/xen_pt.c          |  1 +
 include/hw/pci/pci.h     |  1 -
 include/hw/pci/pci_bus.h |  6 ++++++
 8 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c
index bb206da..fa67b1d 100644
--- a/hw/i386/kvm/pci-assign.c
+++ b/hw/i386/kvm/pci-assign.c
@@ -35,6 +35,7 @@
 #include "qemu/range.h"
 #include "sysemu/sysemu.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci/msi.h"
 #include "kvm_i386.h"
 
diff --git a/hw/pci/pci-hotplug-old.c b/hw/pci/pci-hotplug-old.c
index 0c09c72..6f208d8 100644
--- a/hw/pci/pci-hotplug-old.c
+++ b/hw/pci/pci-hotplug-old.c
@@ -27,6 +27,7 @@
 #include "hw/hw.h"
 #include "hw/boards.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "net/net.h"
 #include "hw/i386/pc.h"
 #include "monitor/monitor.h"
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 0b4e138..dccb3d1 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -300,13 +300,6 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
     return bus;
 }
 
-int pci_bus_num(PCIBus *s)
-{
-    if (pci_bus_is_root(s))
-        return 0;       /* pci host bridge */
-    return s->parent_dev->config[PCI_SECONDARY_BUS];
-}
-
 static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
 {
     PCIDevice *s = container_of(pv, PCIDevice, config);
diff --git a/hw/pci/pci_bus.c b/hw/pci/pci_bus.c
index 0922a75..ed99208 100644
--- a/hw/pci/pci_bus.c
+++ b/hw/pci/pci_bus.c
@@ -469,6 +469,15 @@ static bool pcibus_is_root(PCIBus *bus)
     return !bus->parent_dev;
 }
 
+static int pcibus_num(PCIBus *bus)
+{
+    if (pcibus_is_root(bus)) {
+        return 0;       /* pci host bridge */
+    }
+
+    return bus->parent_dev->config[PCI_SECONDARY_BUS];
+}
+
 static void pci_bus_class_init(ObjectClass *klass, void *data)
 {
     BusClass *k = BUS_CLASS(klass);
@@ -482,6 +491,7 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
     k->reset = pcibus_reset;
 
     pbc->is_root = pcibus_is_root;
+    pbc->bus_num = pcibus_num;
 }
 
 static const TypeInfo pci_bus_info = {
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 4852237..fa4e3d0 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -20,6 +20,7 @@
 
 #include "hw/hw.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "sysemu/dma.h"
 #include "sysemu/block-backend.h"
 #include "hw/pci/msi.h"
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index f2893b2..cf56a48 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -55,6 +55,7 @@
 #include <sys/ioctl.h>
 
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/xen/xen.h"
 #include "hw/xen/xen_backend.h"
 #include "xen_pt.h"
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 7b2567a..b7e24d4 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -376,7 +376,6 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
 
 PCIDevice *pci_vga_init(PCIBus *bus);
 
-int pci_bus_num(PCIBus *s);
 void pci_for_each_device(PCIBus *bus, int bus_num,
                          void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque),
                          void *opaque);
diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
index 306ef10..553814e 100644
--- a/include/hw/pci/pci_bus.h
+++ b/include/hw/pci/pci_bus.h
@@ -24,6 +24,7 @@ typedef struct PCIBusClass {
     /*< public >*/
 
     bool (*is_root)(PCIBus *bus);
+    int (*bus_num)(PCIBus *bus);
 } PCIBusClass;
 
 struct PCIBus {
@@ -54,6 +55,11 @@ static inline bool pci_bus_is_root(PCIBus *bus)
     return PCI_BUS_GET_CLASS(bus)->is_root(bus);
 }
 
+static inline int pci_bus_num(PCIBus *bus)
+{
+    return PCI_BUS_GET_CLASS(bus)->bus_num(bus);
+}
+
 typedef struct PCIBridgeWindows PCIBridgeWindows;
 
 /*
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 09/17] hw/pci: introduce TYPE_PCI_MAIN_HOST_BRIDGE interface
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (7 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 08/17] hw/pci: made pci_bus_num " Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 10/17] hw/pci: removed 'rootbus nr is 0' assumption from qmp_pci_query Marcel Apfelbaum
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

From: Marcel Apfelbaum <marcel.a@redhat.com>

This is a marker interface used to differentiate the
"default" host bridge on a system with multiple host bridges.
This differentiation is required only for pc machines for now
by the ACPI subsystem.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/i386/acpi-build.c      | 9 ++++++---
 hw/pci-host/piix.c        | 5 +++++
 hw/pci-host/q35.c         | 4 ++++
 hw/pci/pci_host.c         | 6 ++++++
 include/hw/pci/pci_host.h | 7 +++++++
 5 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b2b0036..cee150b 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -250,7 +250,8 @@ static void acpi_get_pci_info(PcPciInfo *info)
     Object *pci_host;
     bool ambiguous;
 
-    pci_host = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous);
+    pci_host = object_resolve_path_type("", TYPE_PCI_MAIN_HOST_BRIDGE,
+                                        &ambiguous);
     g_assert(!ambiguous);
     g_assert(pci_host);
 
@@ -1267,7 +1268,8 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
             PCIBus *bus = NULL;
             bool ambiguous;
 
-            pci_host = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous);
+            pci_host = object_resolve_path_type("", TYPE_PCI_MAIN_HOST_BRIDGE,
+                                                &ambiguous);
             if (!ambiguous && pci_host) {
                 bus = PCI_HOST_BRIDGE(pci_host)->bus;
             }
@@ -1610,7 +1612,8 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
     QObject *o;
     bool ambiguous;
 
-    pci_host = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous);
+    pci_host = object_resolve_path_type("", TYPE_PCI_MAIN_HOST_BRIDGE,
+                                        &ambiguous);
     g_assert(!ambiguous);
     g_assert(pci_host);
 
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index f7cfbc8..970b9e9 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -767,6 +767,11 @@ static const TypeInfo i440fx_pcihost_info = {
     .instance_size = sizeof(I440FXState),
     .instance_init = i440fx_pcihost_initfn,
     .class_init    = i440fx_pcihost_class_init,
+    .interfaces    = (InterfaceInfo[]) {
+        { TYPE_PCI_MAIN_HOST_BRIDGE },
+        { }
+    }
+
 };
 
 static void i440fx_register_types(void)
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index c36fefa..bd41465 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -193,6 +193,10 @@ static const TypeInfo q35_host_info = {
     .instance_size = sizeof(Q35PCIHost),
     .instance_init = q35_host_initfn,
     .class_init = q35_host_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_PCI_MAIN_HOST_BRIDGE },
+        { }
+    }
 };
 
 /****************************************************************************
diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c
index 3e26f92..87180c8 100644
--- a/hw/pci/pci_host.c
+++ b/hw/pci/pci_host.c
@@ -175,6 +175,11 @@ const MemoryRegionOps pci_host_data_be_ops = {
     .endianness = DEVICE_BIG_ENDIAN,
 };
 
+static const TypeInfo pci_main_host_interface_info = {
+    .name          = TYPE_PCI_MAIN_HOST_BRIDGE,
+    .parent        = TYPE_INTERFACE,
+};
+
 static const TypeInfo pci_host_type_info = {
     .name = TYPE_PCI_HOST_BRIDGE,
     .parent = TYPE_SYS_BUS_DEVICE,
@@ -185,6 +190,7 @@ static const TypeInfo pci_host_type_info = {
 
 static void pci_host_register_types(void)
 {
+    type_register_static(&pci_main_host_interface_info);
     type_register_static(&pci_host_type_info);
 }
 
diff --git a/include/hw/pci/pci_host.h b/include/hw/pci/pci_host.h
index ba31595..3c72e26 100644
--- a/include/hw/pci/pci_host.h
+++ b/include/hw/pci/pci_host.h
@@ -30,6 +30,13 @@
 
 #include "hw/sysbus.h"
 
+/**
+ * Marker interface for classes whose instances can
+ * be main host bridges. It is intended to be used
+ * when the QOM tree includes multiple host bridges.
+ */
+#define TYPE_PCI_MAIN_HOST_BRIDGE "pci-main-host-bridge"
+
 #define TYPE_PCI_HOST_BRIDGE "pci-host-bridge"
 #define PCI_HOST_BRIDGE(obj) \
     OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE)
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 10/17] hw/pci: removed 'rootbus nr is 0' assumption from qmp_pci_query
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (8 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 09/17] hw/pci: introduce TYPE_PCI_MAIN_HOST_BRIDGE interface Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 11/17] hw/pci: implement iteration over multiple host bridges Marcel Apfelbaum
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

From: Marcel Apfelbaum <marcel.a@redhat.com>

Use the newer pci_bus_num to correctly get the root bus number.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/pci/pci.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index dccb3d1..bf31168 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1251,7 +1251,8 @@ PciInfoList *qmp_query_pci(Error **errp)
 
     QLIST_FOREACH(host_bridge, &pci_host_bridges, next) {
         info = g_malloc0(sizeof(*info));
-        info->value = qmp_query_pci_bus(host_bridge->bus, 0);
+        info->value = qmp_query_pci_bus(host_bridge->bus,
+                                        pci_bus_num(host_bridge->bus));
 
         /* XXX: waiting for the qapi to support GSList */
         if (!cur_item) {
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 11/17] hw/pci: implement iteration over multiple host bridges
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (9 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 10/17] hw/pci: removed 'rootbus nr is 0' assumption from qmp_pci_query Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 12/17] hw/pci: introduce PCI Expander Bridge (PXB) Marcel Apfelbaum
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

From: Marcel Apfelbaum <marcel.a@redhat.com>

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/pci/pci.c              | 8 ++++----
 include/hw/pci/pci_host.h | 4 ++++
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index bf31168..d0d0035 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -68,7 +68,7 @@ static void pci_del_option_rom(PCIDevice *pdev);
 static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
 static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
 
-static QLIST_HEAD(, PCIHostState) pci_host_bridges;
+struct PCIHostQ pci_host_bridges = QLIST_HEAD_INITIALIZER(pci_host_bridges);
 
 static int pci_bar(PCIDevice *d, int reg)
 {
@@ -189,7 +189,7 @@ PCIBus *pci_find_primary_bus(void)
     PCIBus *primary_bus = NULL;
     PCIHostState *host;
 
-    QLIST_FOREACH(host, &pci_host_bridges, next) {
+    HOST_BRIDGE_FOREACH(host) {
         if (primary_bus) {
             /* We have multiple root buses, refuse to select a primary */
             return NULL;
@@ -1249,7 +1249,7 @@ PciInfoList *qmp_query_pci(Error **errp)
     PciInfoList *info, *head = NULL, *cur_item = NULL;
     PCIHostState *host_bridge;
 
-    QLIST_FOREACH(host_bridge, &pci_host_bridges, next) {
+    HOST_BRIDGE_FOREACH(host_bridge) {
         info = g_malloc0(sizeof(*info));
         info->value = qmp_query_pci_bus(host_bridge->bus,
                                         pci_bus_num(host_bridge->bus));
@@ -1778,7 +1778,7 @@ int pci_qdev_find_device(const char *id, PCIDevice **pdev)
     PCIHostState *host_bridge;
     int rc = -ENODEV;
 
-    QLIST_FOREACH(host_bridge, &pci_host_bridges, next) {
+    HOST_BRIDGE_FOREACH(host_bridge) {
         int tmp = pci_qdev_find_recursive(host_bridge->bus, id, pdev);
         if (!tmp) {
             rc = 0;
diff --git a/include/hw/pci/pci_host.h b/include/hw/pci/pci_host.h
index 3c72e26..ba5272f 100644
--- a/include/hw/pci/pci_host.h
+++ b/include/hw/pci/pci_host.h
@@ -63,6 +63,10 @@ typedef struct PCIHostBridgeClass {
     const char *(*root_bus_path)(PCIHostState *, PCIBus *);
 } PCIHostBridgeClass;
 
+QLIST_HEAD(PCIHostQ, PCIHostState);
+extern struct PCIHostQ pci_host_bridges;
+#define HOST_BRIDGE_FOREACH(host) QLIST_FOREACH(host, &pci_host_bridges, next)
+
 /* common internal helpers for PCI/PCIe hosts, cut off overflows */
 void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
                                   uint32_t limit, uint32_t val, uint32_t len);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 12/17] hw/pci: introduce PCI Expander Bridge (PXB)
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (10 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 11/17] hw/pci: implement iteration over multiple host bridges Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16 12:58   ` Alexander Graf
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 13/17] hw/pci: inform bios if the system has more than one pci bridge Marcel Apfelbaum
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

From: Marcel Apfelbaum <marcel.a@redhat.com>

PXB is a "light-weight" host bridge whose purpose is to enable
the main host bridge to support multiple PCI root buses.

As oposed to PCI-2-PCI bridge's secondary bus, PXB's bus
is a primary bus and can be associated with a NUMA node
(different from the main host bridge) allowing the guest OS
to recognize the proximity of a pass-through device to
other resources as RAM and CPUs.

The PXB is composed from:
 - A primary PCI bus (can be associated with a NUMA node)
   Acts like a normal pci bus and from the functionality point
   of view is an "expansion" of the bus behind the
   main host bridge.
 - A pci-2-pci bridge behind the primary PCI bus where the actual
   devices will be attached.
 - A host-bridge PCI device
   Situated on the bus behind the main host bridge, allows
   the BIOS to configure the bus number and IO/mem resources.
   It does not have its own config/data register for configuration
   cycles, this being handled by the main host bridge.
-  A host-bridge sysbus to comply with QEMU current design.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/pci-bridge/Makefile.objs         |   1 +
 hw/pci-bridge/pci_expander_bridge.c | 173 ++++++++++++++++++++++++++++++++++++
 include/hw/pci/pci.h                |   1 +
 3 files changed, 175 insertions(+)
 create mode 100644 hw/pci-bridge/pci_expander_bridge.c

diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs
index 968b369..632e442 100644
--- a/hw/pci-bridge/Makefile.objs
+++ b/hw/pci-bridge/Makefile.objs
@@ -1,4 +1,5 @@
 common-obj-y += pci_bridge_dev.o
+common-obj-y += pci_expander_bridge.o
 common-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
 common-obj-y += i82801b11.o
 # NewWorld PowerMac
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
new file mode 100644
index 0000000..941f3c8
--- /dev/null
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -0,0 +1,173 @@
+/*
+ * PCI Expander Bridge Device Emulation
+ *
+ * Copyright (C) 2014 Red Hat Inc
+ *
+ * Authors:
+ *   Marcel Apfelbaum <marcel.a@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_host.h"
+#include "hw/pci/pci_bus.h"
+#include "qemu/range.h"
+#include "qemu/error-report.h"
+
+#define TYPE_PXB_BUS "pxb-bus"
+#define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS)
+
+typedef struct PXBBus {
+    /*< private >*/
+    PCIBus parent_obj;
+    /*< public >*/
+
+    char bus_path[8];
+} PXBBus;
+
+#define TYPE_PXB_DEVICE "pxb-device"
+#define PXB_DEV(obj) OBJECT_CHECK(PXBDev, (obj), TYPE_PXB_DEVICE)
+
+typedef struct PXBDev {
+    /*< private >*/
+    PCIDevice parent_obj;
+    /*< public >*/
+
+    uint8_t bus_nr;
+} PXBDev;
+
+#define TYPE_PXB_HOST "pxb-host"
+
+static int pxb_bus_num(PCIBus *bus)
+{
+    PXBDev *pxb = PXB_DEV(bus->parent_dev);
+
+    return pxb->bus_nr;
+}
+
+static bool pxb_is_root(PCIBus *bus)
+{
+    return true; /* by definition */
+}
+
+static void pxb_bus_class_init(ObjectClass *class, void *data)
+{
+    PCIBusClass *pbc = PCI_BUS_CLASS(class);
+
+    pbc->bus_num = pxb_bus_num;
+    pbc->is_root = pxb_is_root;
+}
+
+static const TypeInfo pxb_bus_info = {
+    .name          = TYPE_PXB_BUS,
+    .parent        = TYPE_PCI_BUS,
+    .instance_size = sizeof(PXBBus),
+    .class_init    = pxb_bus_class_init,
+};
+
+static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
+                                          PCIBus *rootbus)
+{
+    PXBBus *bus = PXB_BUS(rootbus);
+
+    snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus));
+    return bus->bus_path;
+}
+
+static void pxb_host_class_init(ObjectClass *class, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(class);
+    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
+
+    dc->fw_name = "pci";
+    hc->root_bus_path = pxb_host_root_bus_path;
+}
+
+static const TypeInfo pxb_host_info = {
+    .name          = TYPE_PXB_HOST,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .class_init    = pxb_host_class_init,
+};
+
+static int pxb_dev_initfn(PCIDevice *dev)
+{
+    PXBDev *pxb = PXB_DEV(dev);
+    DeviceState *ds, *bds;
+    PCIHostState *phs;
+    PCIBus *bus;
+    const char *dev_name = NULL;
+
+    HOST_BRIDGE_FOREACH(phs) {
+        if (pxb->bus_nr == pci_bus_num(phs->bus)) {
+            error_report("Bus nr %d is already used by %s.",
+                         pxb->bus_nr, phs->bus->qbus.name);
+            return -EINVAL;
+        }
+    }
+
+    if (dev->qdev.id && *dev->qdev.id) {
+        dev_name = dev->qdev.id;
+    }
+
+    ds = qdev_create(NULL, TYPE_PXB_HOST);
+    bus = pci_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS);
+
+    bus->parent_dev = dev;
+    bus->address_space_mem = dev->bus->address_space_mem;
+    bus->address_space_io = dev->bus->address_space_io;
+    bus->map_irq = pci_swizzle_map_irq_fn;
+
+    bds = qdev_create(BUS(bus), "pci-bridge");
+    bds->id = dev_name;
+    qdev_prop_set_uint8(bds, "chassis_nr", pxb->bus_nr);
+
+    PCI_HOST_BRIDGE(ds)->bus = bus;
+
+    qdev_init_nofail(ds);
+    qdev_init_nofail(bds);
+
+    pci_word_test_and_set_mask(dev->config + PCI_STATUS,
+                               PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
+
+    return 0;
+}
+
+static Property pxb_dev_properties[] = {
+    /* Note: 0 is not a legal a PXB bus number. */
+    DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxb_dev_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pxb_dev_initfn;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT;
+    k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+
+    dc->desc = "PCI Expander Bridge";
+    dc->props = pxb_dev_properties;
+}
+
+static const TypeInfo pxb_dev_info = {
+    .name          = TYPE_PXB_DEVICE,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PXBDev),
+    .class_init    = pxb_dev_class_init,
+};
+
+static void pxb_register_types(void)
+{
+    type_register_static(&pxb_bus_info);
+    type_register_static(&pxb_host_info);
+    type_register_static(&pxb_dev_info);
+}
+
+type_init(pxb_register_types)
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index b7e24d4..e936528 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -89,6 +89,7 @@
 #define PCI_DEVICE_ID_REDHAT_SERIAL4     0x0004
 #define PCI_DEVICE_ID_REDHAT_TEST        0x0005
 #define PCI_DEVICE_ID_REDHAT_SDHCI       0x0007
+#define PCI_DEVICE_ID_REDHAT_PXB         0x0008
 #define PCI_DEVICE_ID_REDHAT_QXL         0x0100
 
 #define FMT_PCIBUS                      PRIx64
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 13/17] hw/pci: inform bios if the system has more than one pci bridge
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (11 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 12/17] hw/pci: introduce PCI Expander Bridge (PXB) Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 14/17] hw/pci: piix - suport multiple host bridges Marcel Apfelbaum
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

From: Marcel Apfelbaum <marcel.a@redhat.com>

The bios looks for 'etc/extra-pci-roots' to decide if
is going to scan further buses after bus 0 tree.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/i386/pc.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index e07f1fa..9ef0917 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1073,9 +1073,22 @@ typedef struct PcGuestInfoState {
 static
 void pc_guest_info_machine_done(Notifier *notifier, void *data)
 {
+    PCIHostState *host;
+    int hosts = 0;
     PcGuestInfoState *guest_info_state = container_of(notifier,
                                                       PcGuestInfoState,
                                                       machine_done);
+    HOST_BRIDGE_FOREACH(host) {
+        hosts++;
+    }
+
+    if (hosts && guest_info_state->info.fw_cfg) {
+        uint64_t *val = g_malloc(sizeof(*val));
+        *val = cpu_to_le64(hosts - 1);
+        fw_cfg_add_file(guest_info_state->info.fw_cfg,
+                        "etc/extra-pci-roots", val, sizeof(*val));
+    }
+
     acpi_setup(&guest_info_state->info);
 }
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 14/17] hw/pci: piix - suport multiple host bridges
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (12 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 13/17] hw/pci: inform bios if the system has more than one pci bridge Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16 13:00   ` Alexander Graf
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 15/17] hw/pxb: add map_irq func Marcel Apfelbaum
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

From: Marcel Apfelbaum <marcel.a@redhat.com>

Instead of assuming it has only one bus, it
enumerates all the host bridges until it finds
the one with bus number corresponding with the
config register.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/pci-host/piix.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 56 insertions(+), 1 deletion(-)

diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index 970b9e9..7310b4c 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -255,6 +255,61 @@ static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v,
     visit_type_uint64(v, &w64.end, name, errp);
 }
 
+static PCIBus *i440fx_find_primary_bus(int bus_num)
+{
+    PCIHostState *host;
+    PCIBus *bus = NULL;
+    int current = -1;
+
+    HOST_BRIDGE_FOREACH(host) {
+        int b = pci_bus_num(host->bus);
+        if (b <= bus_num && b > current) {
+            current = b;
+            bus = host->bus;
+        }
+    }
+
+    return bus;
+}
+
+static void i440fx_pcihost_data_write(void *opaque, hwaddr addr,
+                                      uint64_t val, unsigned len)
+{
+    uint32_t config_reg = PCI_HOST_BRIDGE(opaque)->config_reg;
+
+    if (config_reg & (1u << 31)) {
+        int bus_num = (config_reg >> 16) & 0xFF;
+        PCIBus *bus = i440fx_find_primary_bus(bus_num);
+
+        if (bus) {
+            pci_data_write(bus, config_reg | (addr & 3), val, len);
+        }
+    }
+}
+
+static uint64_t i440fx_pcihost_data_read(void *opaque,
+                                         hwaddr addr, unsigned len)
+{
+    uint32_t config_reg = PCI_HOST_BRIDGE(opaque)->config_reg;
+
+    if (config_reg & (1U << 31)) {
+        int bus_num = (config_reg >> 16) & 0xFF;
+        PCIBus *bus = i440fx_find_primary_bus(bus_num);
+
+        if (bus) {
+            return pci_data_read(bus, config_reg | (addr & 3), len);
+        }
+    }
+
+    return 0xffffffff;
+}
+
+const MemoryRegionOps i440fx_pcihost_data_le_ops = {
+    .read = i440fx_pcihost_data_read,
+    .write = i440fx_pcihost_data_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static void i440fx_pcihost_initfn(Object *obj)
 {
     PCIHostState *s = PCI_HOST_BRIDGE(obj);
@@ -262,7 +317,7 @@ static void i440fx_pcihost_initfn(Object *obj)
 
     memory_region_init_io(&s->conf_mem, obj, &pci_host_conf_le_ops, s,
                           "pci-conf-idx", 4);
-    memory_region_init_io(&s->data_mem, obj, &pci_host_data_le_ops, s,
+    memory_region_init_io(&s->data_mem, obj, &i440fx_pcihost_data_le_ops, s,
                           "pci-conf-data", 4);
 
     object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int",
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel]  [PATCH RFC V2 15/17] hw/pxb: add map_irq func
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (13 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 14/17] hw/pci: piix - suport multiple host bridges Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 16/17] hw/pci_bus: add support for NUMA nodes Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 17/17] hw/pxb: add numa_node parameter Marcel Apfelbaum
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

The bios does not index the pxb slot number when
it computes the IRQ because it resides on bus 0
and not on the current bus.
However Qemu routes the irq through bus 0 and adds
the pxb slot to the IRQ computation.

Synchronize between bios and Qemu by canceling
pxb's effect.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/pci-bridge/pci_expander_bridge.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 941f3c8..1126841 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -92,6 +92,24 @@ static const TypeInfo pxb_host_info = {
     .class_init    = pxb_host_class_init,
 };
 
+
+static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
+{
+    PCIDevice *pxb = pci_dev->bus->parent_dev;
+
+    /*
+     * The bios does not index the pxb slot number when
+     * it computes the IRQ because it resides on bus 0
+     * and not on the current bus.
+     * However Qemu routes the irq through bus 0 and adds
+     * the pxb slot to the IRQ computation.
+     *
+     * Synchronize between bios and Qemu by canceling
+     * pxb's effect.
+     */
+    return pin - PCI_SLOT(pxb->devfn);
+}
+
 static int pxb_dev_initfn(PCIDevice *dev)
 {
     PXBDev *pxb = PXB_DEV(dev);
@@ -118,7 +136,7 @@ static int pxb_dev_initfn(PCIDevice *dev)
     bus->parent_dev = dev;
     bus->address_space_mem = dev->bus->address_space_mem;
     bus->address_space_io = dev->bus->address_space_io;
-    bus->map_irq = pci_swizzle_map_irq_fn;
+    bus->map_irq = pxb_map_irq_fn;
 
     bds = qdev_create(BUS(bus), "pci-bridge");
     bds->id = dev_name;
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 16/17] hw/pci_bus: add support for NUMA nodes
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (14 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 15/17] hw/pxb: add map_irq func Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 17/17] hw/pxb: add numa_node parameter Marcel Apfelbaum
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

PCI root buses can be attached to a specific NUMA node.
PCI buses are not attached be default to a NUMA node.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/pci/pci_bus.c         | 7 +++++++
 include/hw/pci/pci_bus.h | 6 ++++++
 include/sysemu/sysemu.h  | 1 +
 3 files changed, 14 insertions(+)

diff --git a/hw/pci/pci_bus.c b/hw/pci/pci_bus.c
index ed99208..15882a7 100644
--- a/hw/pci/pci_bus.c
+++ b/hw/pci/pci_bus.c
@@ -13,6 +13,7 @@
 #include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_bridge.h"
 #include "monitor/monitor.h"
+#include "sysemu/sysemu.h"
 
 typedef struct {
     uint16_t class;
@@ -478,6 +479,11 @@ static int pcibus_num(PCIBus *bus)
     return bus->parent_dev->config[PCI_SECONDARY_BUS];
 }
 
+static uint16_t pcibus_numa_node(PCIBus *bus)
+{
+    return NUMA_NODE_UNASSIGNED;
+}
+
 static void pci_bus_class_init(ObjectClass *klass, void *data)
 {
     BusClass *k = BUS_CLASS(klass);
@@ -492,6 +498,7 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
 
     pbc->is_root = pcibus_is_root;
     pbc->bus_num = pcibus_num;
+    pbc->numa_node = pcibus_numa_node;
 }
 
 static const TypeInfo pci_bus_info = {
diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
index 553814e..75cd1fa 100644
--- a/include/hw/pci/pci_bus.h
+++ b/include/hw/pci/pci_bus.h
@@ -25,6 +25,7 @@ typedef struct PCIBusClass {
 
     bool (*is_root)(PCIBus *bus);
     int (*bus_num)(PCIBus *bus);
+    uint16_t (*numa_node)(PCIBus *bus);
 } PCIBusClass;
 
 struct PCIBus {
@@ -60,6 +61,11 @@ static inline int pci_bus_num(PCIBus *bus)
     return PCI_BUS_GET_CLASS(bus)->bus_num(bus);
 }
 
+static inline int pci_bus_numa_node(PCIBus *bus)
+{
+    return PCI_BUS_GET_CLASS(bus)->numa_node(bus);
+}
+
 typedef struct PCIBridgeWindows PCIBridgeWindows;
 
 /*
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 748d059..252b9ea 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -139,6 +139,7 @@ extern const char *mem_path;
 extern int mem_prealloc;
 
 #define MAX_NODES 128
+#define NUMA_NODE_UNASSIGNED MAX_NODES
 
 /* The following shall be true for all CPUs:
  *   cpu->cpu_index < max_cpus <= MAX_CPUMASK_BITS
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH RFC V2 17/17] hw/pxb: add numa_node parameter
  2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
                   ` (15 preceding siblings ...)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 16/17] hw/pci_bus: add support for NUMA nodes Marcel Apfelbaum
@ 2015-02-16  9:54 ` Marcel Apfelbaum
  16 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16  9:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, marcel, alex.williamson,
	kevin, qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

The pxb can be attach to and existing numa node by specifying
numa_node option that equals the desired numa nodeid.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/i386/acpi-build.c                | 12 ++++++++++++
 hw/pci-bridge/pci_expander_bridge.c | 17 +++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index cee150b..3da1333 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -896,6 +896,7 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
 
         for (info = info_list; info; info = info->next) {
             PciInfo *bus_info = info->value;
+            PCIHostState *host;
 
             if (bus_info->bus == 0) {
                 continue;
@@ -912,6 +913,17 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
             aml_append(&dev, acpi_name_decl("_HID", acpi_string("PNP0A03")));
             aml_append(&dev,
                 acpi_name_decl("_BBN", acpi_int((uint8_t)bus_info->bus)));
+
+            HOST_BRIDGE_FOREACH(host) {
+                if (pci_bus_num(host->bus) == bus_info->bus) {
+                    int numa_node = pci_bus_numa_node(host->bus);
+                    if (numa_node != NUMA_NODE_UNASSIGNED) {
+                        aml_append(&dev,
+                            acpi_name_decl("_PXM", acpi_int(numa_node)));
+                    }
+                }
+            }
+
             aml_append(&dev, build_prt());
             crs = build_crs(pci, bus_info, &io_ranges, &mem_ranges);
             aml_append(&dev, acpi_name_decl("_CRS", crs));
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 1126841..2e793e2 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -16,6 +16,7 @@
 #include "hw/pci/pci_bus.h"
 #include "qemu/range.h"
 #include "qemu/error-report.h"
+#include "sysemu/sysemu.h"
 
 #define TYPE_PXB_BUS "pxb-bus"
 #define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS)
@@ -37,6 +38,7 @@ typedef struct PXBDev {
     /*< public >*/
 
     uint8_t bus_nr;
+    uint16_t numa_node;
 } PXBDev;
 
 #define TYPE_PXB_HOST "pxb-host"
@@ -53,12 +55,20 @@ static bool pxb_is_root(PCIBus *bus)
     return true; /* by definition */
 }
 
+static uint16_t pxb_bus_numa_node(PCIBus *bus)
+{
+    PXBDev *pxb = PXB_DEV(bus->parent_dev);
+
+    return pxb->numa_node;
+}
+
 static void pxb_bus_class_init(ObjectClass *class, void *data)
 {
     PCIBusClass *pbc = PCI_BUS_CLASS(class);
 
     pbc->bus_num = pxb_bus_num;
     pbc->is_root = pxb_is_root;
+    pbc->numa_node = pxb_bus_numa_node;
 }
 
 static const TypeInfo pxb_bus_info = {
@@ -126,6 +136,12 @@ static int pxb_dev_initfn(PCIDevice *dev)
         }
     }
 
+    if (pxb->numa_node != NUMA_NODE_UNASSIGNED &&
+        pxb->numa_node >= nb_numa_nodes) {
+        error_report("Illegal numa node %d.", pxb->numa_node);
+        return -EINVAL;
+    }
+
     if (dev->qdev.id && *dev->qdev.id) {
         dev_name = dev->qdev.id;
     }
@@ -157,6 +173,7 @@ static int pxb_dev_initfn(PCIDevice *dev)
 static Property pxb_dev_properties[] = {
     /* Note: 0 is not a legal a PXB bus number. */
     DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
+    DEFINE_PROP_UINT16("numa_node", PXBDev, numa_node, NUMA_NODE_UNASSIGNED),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH RFC V2 04/17] hw/acpi: add _CRS method for extra root busses
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 04/17] hw/acpi: add _CRS " Marcel Apfelbaum
@ 2015-02-16 10:07   ` Igor Mammedov
  2015-02-16 10:19     ` Marcel Apfelbaum
  2015-02-16 11:37     ` Michael S. Tsirkin
  2015-02-16 12:06   ` Marcel Apfelbaum
  1 sibling, 2 replies; 27+ messages in thread
From: Igor Mammedov @ 2015-02-16 10:07 UTC (permalink / raw)
  To: Marcel Apfelbaum
  Cc: seabios, kraxel, mst, quintela, qemu-devel, agraf,
	alex.williamson, kevin, qemu-ppc, hare, amit.shah, pbonzini,
	leon.alrae, aurelien, rth

On Mon, 16 Feb 2015 11:54:04 +0200
Marcel Apfelbaum <marcel@redhat.com> wrote:

> Save the IO/mem/bus numbers ranges assigned to the extra root busses
> to be removed from the root bus 0 range.
Is it possible to make BIOS program extra buses and root bus 0
in sane way so their resources won't intersect?
That way QEMU will be able to just read resources from root buses
and generate AML in the same manner for every root bus instead of
collect->exclude hack and special casing root bus 0.

> 
> Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
> ---
>  hw/i386/acpi-build.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 146 insertions(+)
> 
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index ee1a50a..0822a20 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -719,6 +719,145 @@ static AcpiAml build_prt(void)
>      return method;
>   }
>  
> +typedef struct PciRangeEntry {
> +    QLIST_ENTRY(PciRangeEntry) entry;
> +    int64_t base;
> +    int64_t limit;
> +} PciRangeEntry;
> +
> +typedef QLIST_HEAD(PciRangeQ, PciRangeEntry) PciRangeQ;
> +
> +static void pci_range_insert(PciRangeQ *list, int64_t base, int64_t limit) {
> +    PciRangeEntry *entry, *next, *e;
> +
> +    if (!base) {
> +        return;
> +    }
> +
> +   if (limit - base + 1 < 0x1000)
> +       limit = base + 0x1000 - 1;
> +
> +    e = g_malloc(sizeof(*entry));
> +    e->base = base;
> +    e->limit = limit;
> +
> +    if (QLIST_EMPTY(list)) {
> +        QLIST_INSERT_HEAD(list, e, entry);
> +    } else {
> +        QLIST_FOREACH_SAFE(entry, list, entry, next) {
> +            if (base < entry->base) {
> +                QLIST_INSERT_BEFORE(entry, e, entry);
> +                break;
> +            } else if (!next) {
> +                QLIST_INSERT_AFTER(entry, e, entry);
> +                break;
> +            }
> +        }
> +    }
> +}
> +
> +static void pci_range_list_free(PciRangeQ *list)
> +{
> +    PciRangeEntry *entry, *next;
> +
> +    QLIST_FOREACH_SAFE(entry, list, entry, next) {
> +        QLIST_REMOVE(entry, entry);
> +        g_free(entry);
> +    }
> +}
> +
> +static AcpiAml build_crs(PcPciInfo *pci, PciInfo *bus_info,
> +                         PciRangeQ *io_ranges, PciRangeQ *mem_ranges)
> +{
> +    PciDeviceInfoList *dev_list;
> +    PciMemoryRange range;
> +    AcpiAml crs;
> +    uint8_t max_bus;
> +
> +    crs = acpi_resource_template();
> +    max_bus = bus_info->bus;
> +
> +    for (dev_list = bus_info->devices; dev_list; dev_list = dev_list->next) {
> +        PciMemoryRegionList *region;
> +
> +        for (region = dev_list->value->regions; region; region = region->next) {
> +            range.base = region->value->address;
> +            range.limit = region->value->address + region->value->size - 1;
> +
> +            if (!strcmp(region->value->type, "io")) {
> +                aml_append(&crs,
> +                        acpi_word_io(acpi_min_fixed, acpi_max_fixed,
> +                            acpi_pos_decode, acpi_entire_range,
> +                            0x0000,
> +                            range.base,
> +                            range.limit,
> +                            0x0000,
> +                            range.limit - range.base + 1));
> +                pci_range_insert(io_ranges, range.base, range.limit);
> +            } else { /* "memory" */
> +                aml_append(&crs,
> +                        acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
> +                            acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
> +                            0,
> +                            range.base,
> +                            range.limit,
> +                            0,
> +                            range.limit - range.base + 1));
> +                pci_range_insert(mem_ranges, range.base, range.limit);
> +            }
> +        }
> +
> +        if (dev_list->value->has_pci_bridge) {
> +            PciBridgeInfo *bridge_info = dev_list->value->pci_bridge;
> +
> +            if (bridge_info->bus.subordinate > max_bus) {
> +                max_bus = bridge_info->bus.subordinate;
> +            }
> +
> +            range = *bridge_info->bus.io_range;
> +            aml_append(&crs,
> +                    acpi_word_io(acpi_min_fixed, acpi_max_fixed,
> +                        acpi_pos_decode, acpi_entire_range,
> +                        0x0000,
> +                        range.base,
> +                        range.limit,
> +                        0x0000,
> +                        range.limit - range.base + 1));
> +            pci_range_insert(io_ranges, range.base, range.limit);
> +
> +            range = *bridge_info->bus.memory_range;
> +            aml_append(&crs,
> +                    acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
> +                        acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
> +                        0,
> +                        range.base,
> +                        range.limit,
> +                        0,
> +                        range.limit - range.base + 1));
> +            pci_range_insert(mem_ranges, range.base, range.limit);
> +
> +            range = *bridge_info->bus.prefetchable_range;
> +            aml_append(&crs,
> +                    acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
> +                        acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
> +                        0,
> +                        range.base,
> +                        range.limit,
> +                        0,
> +                        range.limit - range.base + 1));
> +            pci_range_insert(mem_ranges, range.base, range.limit);
> +        }
> +    }
> +
> +    aml_append(&crs,
> +        acpi_word_bus_number(acpi_min_fixed, acpi_max_fixed,
> +                             acpi_pos_decode,
> +                             0x0000, bus_info->bus, max_bus,
> +                             0x0000, max_bus - bus_info->bus + 1));
> +
> +    return crs;
> +}
> +
>  static void
>  build_ssdt(AcpiAml *table_aml, GArray *linker,
>             AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc,
> @@ -729,6 +868,8 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
>      unsigned acpi_cpus = guest_info->apic_id_limit;
>      AcpiAml pkg, scope, dev, method, crs, field, ifctx, ssdt;
>      int i;
> +    PciRangeQ io_ranges = QLIST_HEAD_INITIALIZER(io_ranges);
> +    PciRangeQ mem_ranges = QLIST_HEAD_INITIALIZER(mem_ranges);
>  
>      /* The current AML generator can cover the APIC ID range [0..255],
>       * inclusive, for VCPU hotplug. */
> @@ -764,9 +905,14 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
>              aml_append(&dev,
>                  acpi_name_decl("_BBN", acpi_int((uint8_t)bus_info->bus)));
>              aml_append(&dev, build_prt());
> +            crs = build_crs(pci, bus_info, &io_ranges, &mem_ranges);
> +            aml_append(&dev, acpi_name_decl("_CRS", crs));
>              aml_append(&scope, dev);
>              aml_append(&ssdt, scope);
>          }
> +
> +        pci_range_list_free(&io_ranges);
> +        pci_range_list_free(&mem_ranges);
>          qapi_free_PciInfoList(info_list);
>      }
>  

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH RFC V2 04/17] hw/acpi: add _CRS method for extra root busses
  2015-02-16 10:07   ` Igor Mammedov
@ 2015-02-16 10:19     ` Marcel Apfelbaum
  2015-02-16 11:37     ` Michael S. Tsirkin
  1 sibling, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16 10:19 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: seabios, kraxel, mst, quintela, qemu-devel, agraf,
	alex.williamson, kevin, qemu-ppc, hare, amit.shah, pbonzini,
	leon.alrae, aurelien, rth

On 02/16/2015 12:07 PM, Igor Mammedov wrote:
> On Mon, 16 Feb 2015 11:54:04 +0200
> Marcel Apfelbaum <marcel@redhat.com> wrote:
>
>> Save the IO/mem/bus numbers ranges assigned to the extra root busses
>> to be removed from the root bus 0 range.
Hi Igor,
Thanks for the review.

> Is it possible to make BIOS program extra buses and root bus 0
> in sane way so their resources won't intersect?

It is possible and actually the first version was coded like that,
however the version was rejected by the BIOS review because
the resources allocation would not be optimal.
This is the best way to allocate the resources so no space
will be wasted.

> That way QEMU will be able to just read resources from root buses
> and generate AML in the same manner for every root bus instead of
> collect->exclude hack and special casing root bus 0.
This implementation supports actually the possibility to read resources
also for bus 0, I chose this approach to have Bus 0 (and all busses behind it)
the only owner of the unused/hot-pluggable memory ranges. The extra roots are
hot-pluggable because they have a pci-2-pci bridge behind.

Thanks,
Marcel

>
>>
>> Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
>> ---
>>   hw/i386/acpi-build.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 146 insertions(+)
>>
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index ee1a50a..0822a20 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -719,6 +719,145 @@ static AcpiAml build_prt(void)
>>       return method;
>>    }
>>
>> +typedef struct PciRangeEntry {
>> +    QLIST_ENTRY(PciRangeEntry) entry;
>> +    int64_t base;
>> +    int64_t limit;
>> +} PciRangeEntry;
>> +
>> +typedef QLIST_HEAD(PciRangeQ, PciRangeEntry) PciRangeQ;
>> +
>> +static void pci_range_insert(PciRangeQ *list, int64_t base, int64_t limit) {
>> +    PciRangeEntry *entry, *next, *e;
>> +
>> +    if (!base) {
>> +        return;
>> +    }
>> +
>> +   if (limit - base + 1 < 0x1000)
>> +       limit = base + 0x1000 - 1;
>> +
>> +    e = g_malloc(sizeof(*entry));
>> +    e->base = base;
>> +    e->limit = limit;
>> +
>> +    if (QLIST_EMPTY(list)) {
>> +        QLIST_INSERT_HEAD(list, e, entry);
>> +    } else {
>> +        QLIST_FOREACH_SAFE(entry, list, entry, next) {
>> +            if (base < entry->base) {
>> +                QLIST_INSERT_BEFORE(entry, e, entry);
>> +                break;
>> +            } else if (!next) {
>> +                QLIST_INSERT_AFTER(entry, e, entry);
>> +                break;
>> +            }
>> +        }
>> +    }
>> +}
>> +
>> +static void pci_range_list_free(PciRangeQ *list)
>> +{
>> +    PciRangeEntry *entry, *next;
>> +
>> +    QLIST_FOREACH_SAFE(entry, list, entry, next) {
>> +        QLIST_REMOVE(entry, entry);
>> +        g_free(entry);
>> +    }
>> +}
>> +
>> +static AcpiAml build_crs(PcPciInfo *pci, PciInfo *bus_info,
>> +                         PciRangeQ *io_ranges, PciRangeQ *mem_ranges)
>> +{
>> +    PciDeviceInfoList *dev_list;
>> +    PciMemoryRange range;
>> +    AcpiAml crs;
>> +    uint8_t max_bus;
>> +
>> +    crs = acpi_resource_template();
>> +    max_bus = bus_info->bus;
>> +
>> +    for (dev_list = bus_info->devices; dev_list; dev_list = dev_list->next) {
>> +        PciMemoryRegionList *region;
>> +
>> +        for (region = dev_list->value->regions; region; region = region->next) {
>> +            range.base = region->value->address;
>> +            range.limit = region->value->address + region->value->size - 1;
>> +
>> +            if (!strcmp(region->value->type, "io")) {
>> +                aml_append(&crs,
>> +                        acpi_word_io(acpi_min_fixed, acpi_max_fixed,
>> +                            acpi_pos_decode, acpi_entire_range,
>> +                            0x0000,
>> +                            range.base,
>> +                            range.limit,
>> +                            0x0000,
>> +                            range.limit - range.base + 1));
>> +                pci_range_insert(io_ranges, range.base, range.limit);
>> +            } else { /* "memory" */
>> +                aml_append(&crs,
>> +                        acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
>> +                            acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
>> +                            0,
>> +                            range.base,
>> +                            range.limit,
>> +                            0,
>> +                            range.limit - range.base + 1));
>> +                pci_range_insert(mem_ranges, range.base, range.limit);
>> +            }
>> +        }
>> +
>> +        if (dev_list->value->has_pci_bridge) {
>> +            PciBridgeInfo *bridge_info = dev_list->value->pci_bridge;
>> +
>> +            if (bridge_info->bus.subordinate > max_bus) {
>> +                max_bus = bridge_info->bus.subordinate;
>> +            }
>> +
>> +            range = *bridge_info->bus.io_range;
>> +            aml_append(&crs,
>> +                    acpi_word_io(acpi_min_fixed, acpi_max_fixed,
>> +                        acpi_pos_decode, acpi_entire_range,
>> +                        0x0000,
>> +                        range.base,
>> +                        range.limit,
>> +                        0x0000,
>> +                        range.limit - range.base + 1));
>> +            pci_range_insert(io_ranges, range.base, range.limit);
>> +
>> +            range = *bridge_info->bus.memory_range;
>> +            aml_append(&crs,
>> +                    acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
>> +                        acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
>> +                        0,
>> +                        range.base,
>> +                        range.limit,
>> +                        0,
>> +                        range.limit - range.base + 1));
>> +            pci_range_insert(mem_ranges, range.base, range.limit);
>> +
>> +            range = *bridge_info->bus.prefetchable_range;
>> +            aml_append(&crs,
>> +                    acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
>> +                        acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
>> +                        0,
>> +                        range.base,
>> +                        range.limit,
>> +                        0,
>> +                        range.limit - range.base + 1));
>> +            pci_range_insert(mem_ranges, range.base, range.limit);
>> +        }
>> +    }
>> +
>> +    aml_append(&crs,
>> +        acpi_word_bus_number(acpi_min_fixed, acpi_max_fixed,
>> +                             acpi_pos_decode,
>> +                             0x0000, bus_info->bus, max_bus,
>> +                             0x0000, max_bus - bus_info->bus + 1));
>> +
>> +    return crs;
>> +}
>> +
>>   static void
>>   build_ssdt(AcpiAml *table_aml, GArray *linker,
>>              AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc,
>> @@ -729,6 +868,8 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
>>       unsigned acpi_cpus = guest_info->apic_id_limit;
>>       AcpiAml pkg, scope, dev, method, crs, field, ifctx, ssdt;
>>       int i;
>> +    PciRangeQ io_ranges = QLIST_HEAD_INITIALIZER(io_ranges);
>> +    PciRangeQ mem_ranges = QLIST_HEAD_INITIALIZER(mem_ranges);
>>
>>       /* The current AML generator can cover the APIC ID range [0..255],
>>        * inclusive, for VCPU hotplug. */
>> @@ -764,9 +905,14 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
>>               aml_append(&dev,
>>                   acpi_name_decl("_BBN", acpi_int((uint8_t)bus_info->bus)));
>>               aml_append(&dev, build_prt());
>> +            crs = build_crs(pci, bus_info, &io_ranges, &mem_ranges);
>> +            aml_append(&dev, acpi_name_decl("_CRS", crs));
>>               aml_append(&scope, dev);
>>               aml_append(&ssdt, scope);
>>           }
>> +
>> +        pci_range_list_free(&io_ranges);
>> +        pci_range_list_free(&mem_ranges);
>>           qapi_free_PciInfoList(info_list);
>>       }
>>
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH RFC V2 04/17] hw/acpi: add _CRS method for extra root busses
  2015-02-16 10:07   ` Igor Mammedov
  2015-02-16 10:19     ` Marcel Apfelbaum
@ 2015-02-16 11:37     ` Michael S. Tsirkin
  1 sibling, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2015-02-16 11:37 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: kraxel, quintela, seabios, qemu-devel, agraf, amit.shah,
	alex.williamson, kevin, qemu-ppc, hare, Marcel Apfelbaum,
	pbonzini, leon.alrae, aurelien, rth

On Mon, Feb 16, 2015 at 11:07:06AM +0100, Igor Mammedov wrote:
> On Mon, 16 Feb 2015 11:54:04 +0200
> Marcel Apfelbaum <marcel@redhat.com> wrote:
> 
> > Save the IO/mem/bus numbers ranges assigned to the extra root busses
> > to be removed from the root bus 0 range.
> Is it possible to make BIOS program extra buses and root bus 0
> in sane way so their resources won't intersect?
> That way QEMU will be able to just read resources from root buses
> and generate AML in the same manner for every root bus instead of
> collect->exclude hack and special casing root bus 0.

Even if it is, I think it's cleaner not to assume specific
guest behaviour.
Since it's not a lot of code to handle arbitrary configurations,
it's easier to just do it generically.

> > 
> > Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
> > ---
> >  hw/i386/acpi-build.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 146 insertions(+)
> > 
> > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> > index ee1a50a..0822a20 100644
> > --- a/hw/i386/acpi-build.c
> > +++ b/hw/i386/acpi-build.c
> > @@ -719,6 +719,145 @@ static AcpiAml build_prt(void)
> >      return method;
> >   }
> >  
> > +typedef struct PciRangeEntry {
> > +    QLIST_ENTRY(PciRangeEntry) entry;
> > +    int64_t base;
> > +    int64_t limit;
> > +} PciRangeEntry;
> > +
> > +typedef QLIST_HEAD(PciRangeQ, PciRangeEntry) PciRangeQ;
> > +
> > +static void pci_range_insert(PciRangeQ *list, int64_t base, int64_t limit) {
> > +    PciRangeEntry *entry, *next, *e;
> > +
> > +    if (!base) {
> > +        return;
> > +    }
> > +
> > +   if (limit - base + 1 < 0x1000)
> > +       limit = base + 0x1000 - 1;
> > +
> > +    e = g_malloc(sizeof(*entry));
> > +    e->base = base;
> > +    e->limit = limit;
> > +
> > +    if (QLIST_EMPTY(list)) {
> > +        QLIST_INSERT_HEAD(list, e, entry);
> > +    } else {
> > +        QLIST_FOREACH_SAFE(entry, list, entry, next) {
> > +            if (base < entry->base) {
> > +                QLIST_INSERT_BEFORE(entry, e, entry);
> > +                break;
> > +            } else if (!next) {
> > +                QLIST_INSERT_AFTER(entry, e, entry);
> > +                break;
> > +            }
> > +        }
> > +    }
> > +}
> > +
> > +static void pci_range_list_free(PciRangeQ *list)
> > +{
> > +    PciRangeEntry *entry, *next;
> > +
> > +    QLIST_FOREACH_SAFE(entry, list, entry, next) {
> > +        QLIST_REMOVE(entry, entry);
> > +        g_free(entry);
> > +    }
> > +}
> > +
> > +static AcpiAml build_crs(PcPciInfo *pci, PciInfo *bus_info,
> > +                         PciRangeQ *io_ranges, PciRangeQ *mem_ranges)
> > +{
> > +    PciDeviceInfoList *dev_list;
> > +    PciMemoryRange range;
> > +    AcpiAml crs;
> > +    uint8_t max_bus;
> > +
> > +    crs = acpi_resource_template();
> > +    max_bus = bus_info->bus;
> > +
> > +    for (dev_list = bus_info->devices; dev_list; dev_list = dev_list->next) {
> > +        PciMemoryRegionList *region;
> > +
> > +        for (region = dev_list->value->regions; region; region = region->next) {
> > +            range.base = region->value->address;
> > +            range.limit = region->value->address + region->value->size - 1;
> > +
> > +            if (!strcmp(region->value->type, "io")) {
> > +                aml_append(&crs,
> > +                        acpi_word_io(acpi_min_fixed, acpi_max_fixed,
> > +                            acpi_pos_decode, acpi_entire_range,
> > +                            0x0000,
> > +                            range.base,
> > +                            range.limit,
> > +                            0x0000,
> > +                            range.limit - range.base + 1));
> > +                pci_range_insert(io_ranges, range.base, range.limit);
> > +            } else { /* "memory" */
> > +                aml_append(&crs,
> > +                        acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
> > +                            acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
> > +                            0,
> > +                            range.base,
> > +                            range.limit,
> > +                            0,
> > +                            range.limit - range.base + 1));
> > +                pci_range_insert(mem_ranges, range.base, range.limit);
> > +            }
> > +        }
> > +
> > +        if (dev_list->value->has_pci_bridge) {
> > +            PciBridgeInfo *bridge_info = dev_list->value->pci_bridge;
> > +
> > +            if (bridge_info->bus.subordinate > max_bus) {
> > +                max_bus = bridge_info->bus.subordinate;
> > +            }
> > +
> > +            range = *bridge_info->bus.io_range;
> > +            aml_append(&crs,
> > +                    acpi_word_io(acpi_min_fixed, acpi_max_fixed,
> > +                        acpi_pos_decode, acpi_entire_range,
> > +                        0x0000,
> > +                        range.base,
> > +                        range.limit,
> > +                        0x0000,
> > +                        range.limit - range.base + 1));
> > +            pci_range_insert(io_ranges, range.base, range.limit);
> > +
> > +            range = *bridge_info->bus.memory_range;
> > +            aml_append(&crs,
> > +                    acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
> > +                        acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
> > +                        0,
> > +                        range.base,
> > +                        range.limit,
> > +                        0,
> > +                        range.limit - range.base + 1));
> > +            pci_range_insert(mem_ranges, range.base, range.limit);
> > +
> > +            range = *bridge_info->bus.prefetchable_range;
> > +            aml_append(&crs,
> > +                    acpi_dword_memory(acpi_pos_decode, acpi_min_fixed,
> > +                        acpi_max_fixed, acpi_non_cacheable, acpi_ReadWrite,
> > +                        0,
> > +                        range.base,
> > +                        range.limit,
> > +                        0,
> > +                        range.limit - range.base + 1));
> > +            pci_range_insert(mem_ranges, range.base, range.limit);
> > +        }
> > +    }
> > +
> > +    aml_append(&crs,
> > +        acpi_word_bus_number(acpi_min_fixed, acpi_max_fixed,
> > +                             acpi_pos_decode,
> > +                             0x0000, bus_info->bus, max_bus,
> > +                             0x0000, max_bus - bus_info->bus + 1));
> > +
> > +    return crs;
> > +}
> > +
> >  static void
> >  build_ssdt(AcpiAml *table_aml, GArray *linker,
> >             AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc,
> > @@ -729,6 +868,8 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
> >      unsigned acpi_cpus = guest_info->apic_id_limit;
> >      AcpiAml pkg, scope, dev, method, crs, field, ifctx, ssdt;
> >      int i;
> > +    PciRangeQ io_ranges = QLIST_HEAD_INITIALIZER(io_ranges);
> > +    PciRangeQ mem_ranges = QLIST_HEAD_INITIALIZER(mem_ranges);
> >  
> >      /* The current AML generator can cover the APIC ID range [0..255],
> >       * inclusive, for VCPU hotplug. */
> > @@ -764,9 +905,14 @@ build_ssdt(AcpiAml *table_aml, GArray *linker,
> >              aml_append(&dev,
> >                  acpi_name_decl("_BBN", acpi_int((uint8_t)bus_info->bus)));
> >              aml_append(&dev, build_prt());
> > +            crs = build_crs(pci, bus_info, &io_ranges, &mem_ranges);
> > +            aml_append(&dev, acpi_name_decl("_CRS", crs));
> >              aml_append(&scope, dev);
> >              aml_append(&ssdt, scope);
> >          }
> > +
> > +        pci_range_list_free(&io_ranges);
> > +        pci_range_list_free(&mem_ranges);
> >          qapi_free_PciInfoList(info_list);
> >      }
> >  

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH RFC V2 04/17] hw/acpi: add _CRS method for extra root busses
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 04/17] hw/acpi: add _CRS " Marcel Apfelbaum
  2015-02-16 10:07   ` Igor Mammedov
@ 2015-02-16 12:06   ` Marcel Apfelbaum
  1 sibling, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16 12:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: seabios, kraxel, mst, quintela, agraf, alex.williamson, kevin,
	qemu-ppc, hare, imammedo, amit.shah, pbonzini, leon.alrae,
	aurelien, rth

On 02/16/2015 11:54 AM, Marcel Apfelbaum wrote:
> Save the IO/mem/bus numbers ranges assigned to the extra root busses
> to be removed from the root bus 0 range.
>
> Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
> ---
>   hw/i386/acpi-build.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 146 insertions(+)
>
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index ee1a50a..0822a20 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -719,6 +719,145 @@ static AcpiAml build_prt(void)
>       return method;
>    }
>
> +typedef struct PciRangeEntry {
> +    QLIST_ENTRY(PciRangeEntry) entry;
> +    int64_t base;
> +    int64_t limit;
> +} PciRangeEntry;
> +
> +typedef QLIST_HEAD(PciRangeQ, PciRangeEntry) PciRangeQ;
> +
> +static void pci_range_insert(PciRangeQ *list, int64_t base, int64_t limit) {
> +    PciRangeEntry *entry, *next, *e;
> +
> +    if (!base) {
> +        return;
> +    }
> +
> +   if (limit - base + 1 < 0x1000)
> +       limit = base + 0x1000 - 1;
The above hack is not needed anymore, it was needed before:
  - [PATCH v4 0/3] pc: acpi-build: make linker & RSDP tables dynamic
as a temp solution.

I will remove it from the next version.
Thanks,
Marcel

[...]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH RFC V2 12/17] hw/pci: introduce PCI Expander Bridge (PXB)
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 12/17] hw/pci: introduce PCI Expander Bridge (PXB) Marcel Apfelbaum
@ 2015-02-16 12:58   ` Alexander Graf
  2015-02-16 13:00     ` Marcel Apfelbaum
  0 siblings, 1 reply; 27+ messages in thread
From: Alexander Graf @ 2015-02-16 12:58 UTC (permalink / raw)
  To: Marcel Apfelbaum, qemu-devel
  Cc: seabios, kraxel, mst, quintela, alex.williamson, kevin, qemu-ppc,
	hare, imammedo, amit.shah, pbonzini, leon.alrae, aurelien, rth



On 16.02.15 10:54, Marcel Apfelbaum wrote:
> From: Marcel Apfelbaum <marcel.a@redhat.com>
> 
> PXB is a "light-weight" host bridge whose purpose is to enable
> the main host bridge to support multiple PCI root buses.
> 
> As oposed to PCI-2-PCI bridge's secondary bus, PXB's bus
> is a primary bus and can be associated with a NUMA node
> (different from the main host bridge) allowing the guest OS
> to recognize the proximity of a pass-through device to
> other resources as RAM and CPUs.
> 
> The PXB is composed from:
>  - A primary PCI bus (can be associated with a NUMA node)
>    Acts like a normal pci bus and from the functionality point
>    of view is an "expansion" of the bus behind the
>    main host bridge.
>  - A pci-2-pci bridge behind the primary PCI bus where the actual
>    devices will be attached.
>  - A host-bridge PCI device
>    Situated on the bus behind the main host bridge, allows
>    the BIOS to configure the bus number and IO/mem resources.
>    It does not have its own config/data register for configuration
>    cycles, this being handled by the main host bridge.
> -  A host-bridge sysbus to comply with QEMU current design.
> 
> Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
> ---
>  hw/pci-bridge/Makefile.objs         |   1 +
>  hw/pci-bridge/pci_expander_bridge.c | 173 ++++++++++++++++++++++++++++++++++++
>  include/hw/pci/pci.h                |   1 +
>  3 files changed, 175 insertions(+)
>  create mode 100644 hw/pci-bridge/pci_expander_bridge.c
> 
> diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs
> index 968b369..632e442 100644
> --- a/hw/pci-bridge/Makefile.objs
> +++ b/hw/pci-bridge/Makefile.objs
> @@ -1,4 +1,5 @@
>  common-obj-y += pci_bridge_dev.o
> +common-obj-y += pci_expander_bridge.o
>  common-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
>  common-obj-y += i82801b11.o
>  # NewWorld PowerMac
> diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
> new file mode 100644
> index 0000000..941f3c8
> --- /dev/null
> +++ b/hw/pci-bridge/pci_expander_bridge.c
> @@ -0,0 +1,173 @@
> +/*
> + * PCI Expander Bridge Device Emulation
> + *
> + * Copyright (C) 2014 Red Hat Inc
> + *
> + * Authors:
> + *   Marcel Apfelbaum <marcel.a@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pci_bus.h"
> +#include "hw/pci/pci_host.h"
> +#include "hw/pci/pci_bus.h"
> +#include "qemu/range.h"
> +#include "qemu/error-report.h"
> +
> +#define TYPE_PXB_BUS "pxb-bus"
> +#define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS)
> +
> +typedef struct PXBBus {
> +    /*< private >*/
> +    PCIBus parent_obj;
> +    /*< public >*/
> +
> +    char bus_path[8];
> +} PXBBus;
> +
> +#define TYPE_PXB_DEVICE "pxb-device"
> +#define PXB_DEV(obj) OBJECT_CHECK(PXBDev, (obj), TYPE_PXB_DEVICE)
> +
> +typedef struct PXBDev {
> +    /*< private >*/
> +    PCIDevice parent_obj;
> +    /*< public >*/
> +
> +    uint8_t bus_nr;
> +} PXBDev;
> +
> +#define TYPE_PXB_HOST "pxb-host"
> +
> +static int pxb_bus_num(PCIBus *bus)
> +{
> +    PXBDev *pxb = PXB_DEV(bus->parent_dev);
> +
> +    return pxb->bus_nr;
> +}
> +
> +static bool pxb_is_root(PCIBus *bus)
> +{
> +    return true; /* by definition */
> +}
> +
> +static void pxb_bus_class_init(ObjectClass *class, void *data)
> +{
> +    PCIBusClass *pbc = PCI_BUS_CLASS(class);
> +
> +    pbc->bus_num = pxb_bus_num;
> +    pbc->is_root = pxb_is_root;
> +}
> +
> +static const TypeInfo pxb_bus_info = {
> +    .name          = TYPE_PXB_BUS,
> +    .parent        = TYPE_PCI_BUS,
> +    .instance_size = sizeof(PXBBus),
> +    .class_init    = pxb_bus_class_init,
> +};
> +
> +static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
> +                                          PCIBus *rootbus)
> +{
> +    PXBBus *bus = PXB_BUS(rootbus);
> +
> +    snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus));
> +    return bus->bus_path;
> +}
> +
> +static void pxb_host_class_init(ObjectClass *class, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(class);
> +    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
> +
> +    dc->fw_name = "pci";
> +    hc->root_bus_path = pxb_host_root_bus_path;
> +}
> +
> +static const TypeInfo pxb_host_info = {
> +    .name          = TYPE_PXB_HOST,
> +    .parent        = TYPE_PCI_HOST_BRIDGE,
> +    .class_init    = pxb_host_class_init,
> +};
> +
> +static int pxb_dev_initfn(PCIDevice *dev)
> +{
> +    PXBDev *pxb = PXB_DEV(dev);
> +    DeviceState *ds, *bds;
> +    PCIHostState *phs;
> +    PCIBus *bus;
> +    const char *dev_name = NULL;
> +
> +    HOST_BRIDGE_FOREACH(phs) {
> +        if (pxb->bus_nr == pci_bus_num(phs->bus)) {
> +            error_report("Bus nr %d is already used by %s.",
> +                         pxb->bus_nr, phs->bus->qbus.name);
> +            return -EINVAL;
> +        }
> +    }
> +
> +    if (dev->qdev.id && *dev->qdev.id) {
> +        dev_name = dev->qdev.id;
> +    }
> +
> +    ds = qdev_create(NULL, TYPE_PXB_HOST);
> +    bus = pci_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS);
> +
> +    bus->parent_dev = dev;
> +    bus->address_space_mem = dev->bus->address_space_mem;
> +    bus->address_space_io = dev->bus->address_space_io;
> +    bus->map_irq = pci_swizzle_map_irq_fn;
> +
> +    bds = qdev_create(BUS(bus), "pci-bridge");
> +    bds->id = dev_name;
> +    qdev_prop_set_uint8(bds, "chassis_nr", pxb->bus_nr);
> +
> +    PCI_HOST_BRIDGE(ds)->bus = bus;
> +
> +    qdev_init_nofail(ds);
> +    qdev_init_nofail(bds);
> +
> +    pci_word_test_and_set_mask(dev->config + PCI_STATUS,
> +                               PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
> +    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
> +
> +    return 0;
> +}
> +
> +static Property pxb_dev_properties[] = {
> +    /* Note: 0 is not a legal a PXB bus number. */
> +    DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void pxb_dev_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    k->init = pxb_dev_initfn;
> +    k->vendor_id = PCI_VENDOR_ID_REDHAT;
> +    k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
> +    k->class_id = PCI_CLASS_BRIDGE_HOST;
> +
> +    dc->desc = "PCI Expander Bridge";
> +    dc->props = pxb_dev_properties;
> +}
> +
> +static const TypeInfo pxb_dev_info = {
> +    .name          = TYPE_PXB_DEVICE,
> +    .parent        = TYPE_PCI_DEVICE,
> +    .instance_size = sizeof(PXBDev),
> +    .class_init    = pxb_dev_class_init,
> +};
> +
> +static void pxb_register_types(void)
> +{
> +    type_register_static(&pxb_bus_info);
> +    type_register_static(&pxb_host_info);
> +    type_register_static(&pxb_dev_info);
> +}
> +
> +type_init(pxb_register_types)
> diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
> index b7e24d4..e936528 100644
> --- a/include/hw/pci/pci.h
> +++ b/include/hw/pci/pci.h
> @@ -89,6 +89,7 @@
>  #define PCI_DEVICE_ID_REDHAT_SERIAL4     0x0004
>  #define PCI_DEVICE_ID_REDHAT_TEST        0x0005
>  #define PCI_DEVICE_ID_REDHAT_SDHCI       0x0007
> +#define PCI_DEVICE_ID_REDHAT_PXB         0x0008

This collides with the new PCI root device that should be in the tree by
now :).


Alex

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH RFC V2 14/17] hw/pci: piix - suport multiple host bridges
  2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 14/17] hw/pci: piix - suport multiple host bridges Marcel Apfelbaum
@ 2015-02-16 13:00   ` Alexander Graf
  2015-02-16 13:29     ` Marcel Apfelbaum
  0 siblings, 1 reply; 27+ messages in thread
From: Alexander Graf @ 2015-02-16 13:00 UTC (permalink / raw)
  To: Marcel Apfelbaum, qemu-devel
  Cc: seabios, kraxel, mst, quintela, alex.williamson, kevin, qemu-ppc,
	hare, imammedo, amit.shah, pbonzini, leon.alrae, aurelien, rth



On 16.02.15 10:54, Marcel Apfelbaum wrote:
> From: Marcel Apfelbaum <marcel.a@redhat.com>
> 
> Instead of assuming it has only one bus, it
> enumerates all the host bridges until it finds
> the one with bus number corresponding with the
> config register.
> 
> Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>

How 440 specific is this? Wouldn't we need similar code for q35 and gpxe?


Alex

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH RFC V2 12/17] hw/pci: introduce PCI Expander Bridge (PXB)
  2015-02-16 12:58   ` Alexander Graf
@ 2015-02-16 13:00     ` Marcel Apfelbaum
  0 siblings, 0 replies; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16 13:00 UTC (permalink / raw)
  To: Alexander Graf, qemu-devel
  Cc: seabios, kraxel, mst, quintela, alex.williamson, kevin, qemu-ppc,
	hare, imammedo, amit.shah, pbonzini, leon.alrae, aurelien, rth

On 02/16/2015 02:58 PM, Alexander Graf wrote:
>
>
> On 16.02.15 10:54, Marcel Apfelbaum wrote:
>> From: Marcel Apfelbaum <marcel.a@redhat.com>
>>
>> PXB is a "light-weight" host bridge whose purpose is to enable
>> the main host bridge to support multiple PCI root buses.
>>
>> As oposed to PCI-2-PCI bridge's secondary bus, PXB's bus
>> is a primary bus and can be associated with a NUMA node
>> (different from the main host bridge) allowing the guest OS
>> to recognize the proximity of a pass-through device to
>> other resources as RAM and CPUs.
>>
>> The PXB is composed from:
>>   - A primary PCI bus (can be associated with a NUMA node)
>>     Acts like a normal pci bus and from the functionality point
>>     of view is an "expansion" of the bus behind the
>>     main host bridge.
>>   - A pci-2-pci bridge behind the primary PCI bus where the actual
>>     devices will be attached.
>>   - A host-bridge PCI device
>>     Situated on the bus behind the main host bridge, allows
>>     the BIOS to configure the bus number and IO/mem resources.
>>     It does not have its own config/data register for configuration
>>     cycles, this being handled by the main host bridge.
>> -  A host-bridge sysbus to comply with QEMU current design.
>>
>> Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
>> ---
>>   hw/pci-bridge/Makefile.objs         |   1 +
>>   hw/pci-bridge/pci_expander_bridge.c | 173 ++++++++++++++++++++++++++++++++++++
>>   include/hw/pci/pci.h                |   1 +
>>   3 files changed, 175 insertions(+)
>>   create mode 100644 hw/pci-bridge/pci_expander_bridge.c
>>
>> diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs
>> index 968b369..632e442 100644
>> --- a/hw/pci-bridge/Makefile.objs
>> +++ b/hw/pci-bridge/Makefile.objs
>> @@ -1,4 +1,5 @@
>>   common-obj-y += pci_bridge_dev.o
>> +common-obj-y += pci_expander_bridge.o
>>   common-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
>>   common-obj-y += i82801b11.o
>>   # NewWorld PowerMac
>> diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
>> new file mode 100644
>> index 0000000..941f3c8
>> --- /dev/null
>> +++ b/hw/pci-bridge/pci_expander_bridge.c
>> @@ -0,0 +1,173 @@
>> +/*
>> + * PCI Expander Bridge Device Emulation
>> + *
>> + * Copyright (C) 2014 Red Hat Inc
>> + *
>> + * Authors:
>> + *   Marcel Apfelbaum <marcel.a@redhat.com>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + */
>> +
>> +#include "hw/pci/pci.h"
>> +#include "hw/pci/pci_bus.h"
>> +#include "hw/pci/pci_host.h"
>> +#include "hw/pci/pci_bus.h"
>> +#include "qemu/range.h"
>> +#include "qemu/error-report.h"
>> +
>> +#define TYPE_PXB_BUS "pxb-bus"
>> +#define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS)
>> +
>> +typedef struct PXBBus {
>> +    /*< private >*/
>> +    PCIBus parent_obj;
>> +    /*< public >*/
>> +
>> +    char bus_path[8];
>> +} PXBBus;
>> +
>> +#define TYPE_PXB_DEVICE "pxb-device"
>> +#define PXB_DEV(obj) OBJECT_CHECK(PXBDev, (obj), TYPE_PXB_DEVICE)
>> +
>> +typedef struct PXBDev {
>> +    /*< private >*/
>> +    PCIDevice parent_obj;
>> +    /*< public >*/
>> +
>> +    uint8_t bus_nr;
>> +} PXBDev;
>> +
>> +#define TYPE_PXB_HOST "pxb-host"
>> +
>> +static int pxb_bus_num(PCIBus *bus)
>> +{
>> +    PXBDev *pxb = PXB_DEV(bus->parent_dev);
>> +
>> +    return pxb->bus_nr;
>> +}
>> +
>> +static bool pxb_is_root(PCIBus *bus)
>> +{
>> +    return true; /* by definition */
>> +}
>> +
>> +static void pxb_bus_class_init(ObjectClass *class, void *data)
>> +{
>> +    PCIBusClass *pbc = PCI_BUS_CLASS(class);
>> +
>> +    pbc->bus_num = pxb_bus_num;
>> +    pbc->is_root = pxb_is_root;
>> +}
>> +
>> +static const TypeInfo pxb_bus_info = {
>> +    .name          = TYPE_PXB_BUS,
>> +    .parent        = TYPE_PCI_BUS,
>> +    .instance_size = sizeof(PXBBus),
>> +    .class_init    = pxb_bus_class_init,
>> +};
>> +
>> +static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
>> +                                          PCIBus *rootbus)
>> +{
>> +    PXBBus *bus = PXB_BUS(rootbus);
>> +
>> +    snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus));
>> +    return bus->bus_path;
>> +}
>> +
>> +static void pxb_host_class_init(ObjectClass *class, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(class);
>> +    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
>> +
>> +    dc->fw_name = "pci";
>> +    hc->root_bus_path = pxb_host_root_bus_path;
>> +}
>> +
>> +static const TypeInfo pxb_host_info = {
>> +    .name          = TYPE_PXB_HOST,
>> +    .parent        = TYPE_PCI_HOST_BRIDGE,
>> +    .class_init    = pxb_host_class_init,
>> +};
>> +
>> +static int pxb_dev_initfn(PCIDevice *dev)
>> +{
>> +    PXBDev *pxb = PXB_DEV(dev);
>> +    DeviceState *ds, *bds;
>> +    PCIHostState *phs;
>> +    PCIBus *bus;
>> +    const char *dev_name = NULL;
>> +
>> +    HOST_BRIDGE_FOREACH(phs) {
>> +        if (pxb->bus_nr == pci_bus_num(phs->bus)) {
>> +            error_report("Bus nr %d is already used by %s.",
>> +                         pxb->bus_nr, phs->bus->qbus.name);
>> +            return -EINVAL;
>> +        }
>> +    }
>> +
>> +    if (dev->qdev.id && *dev->qdev.id) {
>> +        dev_name = dev->qdev.id;
>> +    }
>> +
>> +    ds = qdev_create(NULL, TYPE_PXB_HOST);
>> +    bus = pci_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS);
>> +
>> +    bus->parent_dev = dev;
>> +    bus->address_space_mem = dev->bus->address_space_mem;
>> +    bus->address_space_io = dev->bus->address_space_io;
>> +    bus->map_irq = pci_swizzle_map_irq_fn;
>> +
>> +    bds = qdev_create(BUS(bus), "pci-bridge");
>> +    bds->id = dev_name;
>> +    qdev_prop_set_uint8(bds, "chassis_nr", pxb->bus_nr);
>> +
>> +    PCI_HOST_BRIDGE(ds)->bus = bus;
>> +
>> +    qdev_init_nofail(ds);
>> +    qdev_init_nofail(bds);
>> +
>> +    pci_word_test_and_set_mask(dev->config + PCI_STATUS,
>> +                               PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
>> +    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
>> +
>> +    return 0;
>> +}
>> +
>> +static Property pxb_dev_properties[] = {
>> +    /* Note: 0 is not a legal a PXB bus number. */
>> +    DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
>> +    DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static void pxb_dev_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>> +
>> +    k->init = pxb_dev_initfn;
>> +    k->vendor_id = PCI_VENDOR_ID_REDHAT;
>> +    k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
>> +    k->class_id = PCI_CLASS_BRIDGE_HOST;
>> +
>> +    dc->desc = "PCI Expander Bridge";
>> +    dc->props = pxb_dev_properties;
>> +}
>> +
>> +static const TypeInfo pxb_dev_info = {
>> +    .name          = TYPE_PXB_DEVICE,
>> +    .parent        = TYPE_PCI_DEVICE,
>> +    .instance_size = sizeof(PXBDev),
>> +    .class_init    = pxb_dev_class_init,
>> +};
>> +
>> +static void pxb_register_types(void)
>> +{
>> +    type_register_static(&pxb_bus_info);
>> +    type_register_static(&pxb_host_info);
>> +    type_register_static(&pxb_dev_info);
>> +}
>> +
>> +type_init(pxb_register_types)
>> diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
>> index b7e24d4..e936528 100644
>> --- a/include/hw/pci/pci.h
>> +++ b/include/hw/pci/pci.h
>> @@ -89,6 +89,7 @@
>>   #define PCI_DEVICE_ID_REDHAT_SERIAL4     0x0004
>>   #define PCI_DEVICE_ID_REDHAT_TEST        0x0005
>>   #define PCI_DEVICE_ID_REDHAT_SDHCI       0x0007
>> +#define PCI_DEVICE_ID_REDHAT_PXB         0x0008
>
> This collides with the new PCI root device that should be in the tree by
> now :).
I'll try to keep up! :)
I'll handle it once I rebase.

Thanks,
Marcel

>
>
> Alex
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH RFC V2 14/17] hw/pci: piix - suport multiple host bridges
  2015-02-16 13:00   ` Alexander Graf
@ 2015-02-16 13:29     ` Marcel Apfelbaum
  2015-02-20 14:33       ` Alexander Graf
  0 siblings, 1 reply; 27+ messages in thread
From: Marcel Apfelbaum @ 2015-02-16 13:29 UTC (permalink / raw)
  To: Alexander Graf, qemu-devel
  Cc: seabios, kraxel, mst, quintela, alex.williamson, kevin, qemu-ppc,
	hare, imammedo, amit.shah, pbonzini, leon.alrae, aurelien, rth

On 02/16/2015 03:00 PM, Alexander Graf wrote:
>
>
> On 16.02.15 10:54, Marcel Apfelbaum wrote:
>> From: Marcel Apfelbaum <marcel.a@redhat.com>
>>
>> Instead of assuming it has only one bus, it
>> enumerates all the host bridges until it finds
>> the one with bus number corresponding with the
>> config register.
>>
>> Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
>
Hi Alexander,
Thank you for the review.


> How 440 specific is this? Wouldn't we need similar code for q35 and gpxe?
For gpxe: I have no idea.
For Q35: PCI Express have native support for extra root bridges by
having multiple Root Complexes(RC), but in this case each RC
handles its separate configuration space.

It may be possible to use the same hack as in PC to expose a
PCIe Root Port as a different host bridge and a primary bus behind
it, but it is out of this series scope.

The series aims to address the limitation that PC machines support
NUMA nodes for CPU/memory but not PCI.

Anyway, we can move the code when neeeded, but since it will
take some and the implementation is not certain, for the moment
is 440 specific.


Thanks,
Marcel
>
>
> Alex
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH RFC V2 14/17] hw/pci: piix - suport multiple host bridges
  2015-02-16 13:29     ` Marcel Apfelbaum
@ 2015-02-20 14:33       ` Alexander Graf
  0 siblings, 0 replies; 27+ messages in thread
From: Alexander Graf @ 2015-02-20 14:33 UTC (permalink / raw)
  To: Marcel Apfelbaum, qemu-devel
  Cc: seabios, kraxel, mst, quintela, alex.williamson, kevin, qemu-ppc,
	hare, imammedo, amit.shah, pbonzini, leon.alrae, aurelien, rth



On 16.02.15 14:29, Marcel Apfelbaum wrote:
> On 02/16/2015 03:00 PM, Alexander Graf wrote:
>>
>>
>> On 16.02.15 10:54, Marcel Apfelbaum wrote:
>>> From: Marcel Apfelbaum <marcel.a@redhat.com>
>>>
>>> Instead of assuming it has only one bus, it
>>> enumerates all the host bridges until it finds
>>> the one with bus number corresponding with the
>>> config register.
>>>
>>> Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
>>
> Hi Alexander,
> Thank you for the review.
> 
> 
>> How 440 specific is this? Wouldn't we need similar code for q35 and gpxe?
> For gpxe: I have no idea.
> For Q35: PCI Express have native support for extra root bridges by
> having multiple Root Complexes(RC), but in this case each RC
> handles its separate configuration space.
> 
> It may be possible to use the same hack as in PC to expose a
> PCIe Root Port as a different host bridge and a primary bus behind
> it, but it is out of this series scope.
> 
> The series aims to address the limitation that PC machines support
> NUMA nodes for CPU/memory but not PCI.
> 
> Anyway, we can move the code when neeeded, but since it will
> take some and the implementation is not certain, for the moment
> is 440 specific.

Sorry, I didn't realize that this was legacy PCI specific :).


Alex

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2015-02-20 14:33 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-16  9:54 [Qemu-devel] [PATCH RFC V2 00/17] hw/pc: implement multiple primary busses for pc machines Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 01/17] acpi: added needed acpi constructs Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 02/17] hw/acpi: add support for multiple root busses Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 03/17] hw/apci: add _PRT method for extra " Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 04/17] hw/acpi: add _CRS " Marcel Apfelbaum
2015-02-16 10:07   ` Igor Mammedov
2015-02-16 10:19     ` Marcel Apfelbaum
2015-02-16 11:37     ` Michael S. Tsirkin
2015-02-16 12:06   ` Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 05/17] hw/acpi: remove from root bus 0 the crs resources used by other busses Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 06/17] hw/pci: move pci bus related code to separate files Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 07/17] hw/pci: made pci_bus_is_root a PCIBusClass method Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 08/17] hw/pci: made pci_bus_num " Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 09/17] hw/pci: introduce TYPE_PCI_MAIN_HOST_BRIDGE interface Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 10/17] hw/pci: removed 'rootbus nr is 0' assumption from qmp_pci_query Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 11/17] hw/pci: implement iteration over multiple host bridges Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 12/17] hw/pci: introduce PCI Expander Bridge (PXB) Marcel Apfelbaum
2015-02-16 12:58   ` Alexander Graf
2015-02-16 13:00     ` Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 13/17] hw/pci: inform bios if the system has more than one pci bridge Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 14/17] hw/pci: piix - suport multiple host bridges Marcel Apfelbaum
2015-02-16 13:00   ` Alexander Graf
2015-02-16 13:29     ` Marcel Apfelbaum
2015-02-20 14:33       ` Alexander Graf
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 15/17] hw/pxb: add map_irq func Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 16/17] hw/pci_bus: add support for NUMA nodes Marcel Apfelbaum
2015-02-16  9:54 ` [Qemu-devel] [PATCH RFC V2 17/17] hw/pxb: add numa_node parameter Marcel Apfelbaum

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.