aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/e500.c
diff options
context:
space:
mode:
authorBharat Bhushan <r65777@freescale.com>2012-10-10 04:28:28 +0000
committerAlexander Graf <agraf@suse.de>2012-12-14 13:12:54 +0100
commit3eddc1be1ccb26387f8f960f8a3d8c417064a91f (patch)
tree29e8050bfb7efeaae8df04fae39a228165d1d441 /hw/ppc/e500.c
parentdffb1dc29fb364aaafc41b34100a06517d7f065e (diff)
downloadqemu-3eddc1be1ccb26387f8f960f8a3d8c417064a91f.zip
qemu-3eddc1be1ccb26387f8f960f8a3d8c417064a91f.tar.gz
qemu-3eddc1be1ccb26387f8f960f8a3d8c417064a91f.tar.bz2
Adding BAR0 for e500 PCI controller
PCI Root complex have TYPE-1 configuration header while PCI endpoint have type-0 configuration header. The type-1 configuration header have a BAR (BAR0). In Freescale PCI controller BAR0 is used for mapping pci address space to CCSR address space. This can used for 2 purposes: 1) for MSI interrupt generation 2) Allow CCSR registers access when configured as PCI endpoint, which I am not sure is a use case with QEMU-KVM guest. What I observed is that when guest read the size of BAR0 of host controller configuration header (TYPE1 header) then it always reads it as 0. When looking into the QEMU hw/ppce500_pci.c, I do not find the PCI controller device registering BAR0. I do not find any other controller also doing so may they do not use BAR0. There are two issues when BAR0 is not there (which I can think of): 1) There should be BAR0 emulated for PCI Root complex (TYPE1 header) and when reading the size of BAR0, it should give size as per real h/w. 2) Do we need this BAR0 inbound address translation? When BAR0 is of non-zero size then it will be configured for PCI address space to local address(CCSR) space translation on inbound access. The primary use case is for MSI interrupt generation. The device is configured with an address offsets in PCI address space, which will be translated to MSI interrupt generation MPIC registers. Currently I do not understand the MSI interrupt generation mechanism in QEMU and also IIRC we do not use QEMU MSI interrupt mechanism on e500 guest machines. But this BAR0 will be used when using MSI on e500. I can see one more issue, There are ATMUs emulated in hw/ppce500_pci.c, but i do not see these being used for address translation. So far that works because pci address space and local address space are 1:1 mapped. BAR0 inbound translation + ATMU translation will complete the address translation of inbound traffic. Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com> [agraf: fix double variable assignment w/o read] Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/ppc/e500.c')
-rw-r--r--hw/ppc/e500.c55
1 files changed, 46 insertions, 9 deletions
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 8538933..47e2d41 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -17,6 +17,7 @@
#include "config.h"
#include "qemu-common.h"
#include "e500.h"
+#include "e500-ccsr.h"
#include "net.h"
#include "hw/hw.h"
#include "hw/serial.h"
@@ -422,8 +423,9 @@ void ppce500_init(PPCE500Params *params)
qemu_irq **irqs, *mpic;
DeviceState *dev;
CPUPPCState *firstenv = NULL;
- MemoryRegion *ccsr;
+ MemoryRegion *ccsr_addr_space;
SysBusDevice *s;
+ PPCE500CCSRState *ccsr;
/* Setup CPUs */
if (params->cpu_model == NULL) {
@@ -480,12 +482,17 @@ void ppce500_init(PPCE500Params *params)
vmstate_register_ram_global(ram);
memory_region_add_subregion(address_space_mem, 0, ram);
- ccsr = g_malloc0(sizeof(MemoryRegion));
- memory_region_init(ccsr, "e500-ccsr", MPC8544_CCSRBAR_SIZE);
- memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE, ccsr);
+ dev = qdev_create(NULL, "e500-ccsr");
+ object_property_add_child(qdev_get_machine(), "e500-ccsr",
+ OBJECT(dev), NULL);
+ qdev_init_nofail(dev);
+ ccsr = CCSR(dev);
+ ccsr_addr_space = &ccsr->ccsr_space;
+ memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE,
+ ccsr_addr_space);
/* MPIC */
- mpic = mpic_init(ccsr, MPC8544_MPIC_REGS_OFFSET,
+ mpic = mpic_init(ccsr_addr_space, MPC8544_MPIC_REGS_OFFSET,
smp_cpus, irqs, NULL);
if (!mpic) {
@@ -494,13 +501,13 @@ void ppce500_init(PPCE500Params *params)
/* Serial */
if (serial_hds[0]) {
- serial_mm_init(ccsr, MPC8544_SERIAL0_REGS_OFFSET,
+ serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
0, mpic[12+26], 399193,
serial_hds[0], DEVICE_BIG_ENDIAN);
}
if (serial_hds[1]) {
- serial_mm_init(ccsr, MPC8544_SERIAL1_REGS_OFFSET,
+ serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
0, mpic[12+26], 399193,
serial_hds[1], DEVICE_BIG_ENDIAN);
}
@@ -509,7 +516,7 @@ void ppce500_init(PPCE500Params *params)
dev = qdev_create(NULL, "mpc8544-guts");
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
- memory_region_add_subregion(ccsr, MPC8544_UTIL_OFFSET,
+ memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
sysbus_mmio_get_region(s, 0));
/* PCI */
@@ -520,7 +527,7 @@ void ppce500_init(PPCE500Params *params)
sysbus_connect_irq(s, 1, mpic[pci_irq_nrs[1]]);
sysbus_connect_irq(s, 2, mpic[pci_irq_nrs[2]]);
sysbus_connect_irq(s, 3, mpic[pci_irq_nrs[3]]);
- memory_region_add_subregion(ccsr, MPC8544_PCI_REGS_OFFSET,
+ memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
sysbus_mmio_get_region(s, 0));
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
@@ -595,3 +602,33 @@ void ppce500_init(PPCE500Params *params)
kvmppc_init();
}
}
+
+static int e500_ccsr_initfn(SysBusDevice *dev)
+{
+ PPCE500CCSRState *ccsr;
+
+ ccsr = CCSR(dev);
+ memory_region_init(&ccsr->ccsr_space, "e500-ccsr",
+ MPC8544_CCSRBAR_SIZE);
+ return 0;
+}
+
+static void e500_ccsr_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ k->init = e500_ccsr_initfn;
+}
+
+static const TypeInfo e500_ccsr_info = {
+ .name = TYPE_CCSR,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PPCE500CCSRState),
+ .class_init = e500_ccsr_class_init,
+};
+
+static void e500_register_types(void)
+{
+ type_register_static(&e500_ccsr_info);
+}
+
+type_init(e500_register_types)