Patchwork [2/2,v2] Adding BAR0 for e500 PCI controller

login
register
mail settings
Submitter Bharat Bhushan
Date Oct. 9, 2012, 6:19 p.m.
Message ID <1349806750-17652-3-git-send-email-Bharat.Bhushan@freescale.com>
Download mbox | patch
Permalink /patch/190401/
State New
Headers show

Comments

Bharat Bhushan - Oct. 9, 2012, 6:19 p.m.
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 comaplex (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 a 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>
---
 hw/ppc/e500-ccsr.h |   17 +++++++++++++++++
 hw/ppc/e500.c      |   39 ++++++++++++++++++++++++++++++++++++++-
 hw/ppce500_pci.c   |   30 +++++++++++++++++++++++++++++-
 3 files changed, 84 insertions(+), 2 deletions(-)
 create mode 100644 hw/ppc/e500-ccsr.h
Andreas Färber - Oct. 9, 2012, 6:45 p.m.
Am 09.10.2012 20:19, schrieb Bharat Bhushan:
> 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 comaplex (TYPE1 header) and

"complex"

> 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 a address offsets in PCI address space, which will be

"with address offsets" or "with an address offset"

> 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>

This looks perfect except for typos above and one line of code that
maybe Alex can fix.

Reviewed-by: Andreas Färber <afaerber@suse.de>

> diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
> index 92b1dc0..58dbc1a 100644
> --- a/hw/ppce500_pci.c
> +++ b/hw/ppce500_pci.c

> @@ -307,6 +321,19 @@ static const VMStateDescription vmstate_ppce500_pci = {
>  
>  #include "exec-memory.h"
>  
> +static int e500_pcihost_bridge_initfn(PCIDevice *d)
> +{
> +    PPCE500PCIBridgeState *b = PPC_E500_PCI_BRIDGE(d);
> +    PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(),
> +                                  "/e500-ccsr"));
> +

> +    b->bar0 = ccsr->ccsr_space;

This copy-assignment is getting overwritten by the alias init in the
next line, so it would seem cleaner to drop this line now.

Andreas

> +    memory_region_init_alias(&b->bar0, "e500-pci-bar0", &ccsr->ccsr_space,
> +                             0, int128_get64(ccsr->ccsr_space.size));
> +    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0);
> +    return 0;
> +}
> +
>  static int e500_pcihost_initfn(SysBusDevice *dev)
>  {
>      PCIHostState *h;
Scott Wood - Oct. 9, 2012, 10:37 p.m.
On 10/09/2012 01:19:10 PM, Bharat Bhushan wrote:
> +static int e500_ccsr_initfn(SysBusDevice *dev)
> +{
> +    PPCE500CCSRState *pci_ccsr;
> +
> +    pci_ccsr = CCSR(dev);
> +    memory_region_init(&pci_ccsr->ccsr_space, "e500-ccsr",
> +                       MPC8544_CCSRBAR_SIZE);
> +    return 0;
> +}

Is this object supposed to represent CCSR (which is what the type name  
seems to imply, along with the existence of a different  
PPCE500PCIBridgeState) or PCI BAR0 (which is what pci_ccsr seems to  
imply, along with the fact that it's being added in the PCI patch)?

-Scott
Bharat Bhushan - Oct. 10, 2012, 1:22 a.m.
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Wednesday, October 10, 2012 4:08 AM
> To: Bhushan Bharat-R65777
> Cc: qemu-devel@nongnu.org; qemu-ppc@nongnu.org; agraf@suse.de; afaerber@suse.de;
> Bhushan Bharat-R65777
> Subject: Re: [Qemu-devel] [PATCH 2/2 v2] Adding BAR0 for e500 PCI controller
> 
> On 10/09/2012 01:19:10 PM, Bharat Bhushan wrote:
> > +static int e500_ccsr_initfn(SysBusDevice *dev) {
> > +    PPCE500CCSRState *pci_ccsr;
> > +
> > +    pci_ccsr = CCSR(dev);
> > +    memory_region_init(&pci_ccsr->ccsr_space, "e500-ccsr",
> > +                       MPC8544_CCSRBAR_SIZE);
> > +    return 0;
> > +}
> 
> Is this object supposed to represent CCSR (which is what the type name seems to
> imply, along with the existence of a different
> PPCE500PCIBridgeState) or PCI BAR0 (which is what pci_ccsr seems to imply, along
> with the fact that it's being added in the PCI patch)?

It is ccsr, I will correct this naming.

Thanks
-Bharat

Patch

diff --git a/hw/ppc/e500-ccsr.h b/hw/ppc/e500-ccsr.h
new file mode 100644
index 0000000..f20f51b
--- /dev/null
+++ b/hw/ppc/e500-ccsr.h
@@ -0,0 +1,17 @@ 
+#ifndef E500_CCSR_H
+#define E500_CCSR_H
+
+#include "../sysbus.h"
+
+typedef struct PPCE500CCSRState {
+    /*< private >*/
+    SysBusDevice parent;
+    /*< public >*/
+
+    MemoryRegion ccsr_space;
+} PPCE500CCSRState;
+
+#define TYPE_CCSR "e500-ccsr"
+#define CCSR(obj) OBJECT_CHECK(PPCE500CCSRState, (obj), TYPE_CCSR)
+
+#endif /* E500_CCSR_H */
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 187def2..d0433c2 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/pc.h"
@@ -425,6 +426,7 @@  void ppce500_init(PPCE500Params *params)
     CPUPPCState *firstenv = NULL;
     MemoryRegion *ccsr;
     SysBusDevice *s;
+    PPCE500CCSRState *pci_ccsr;
 
     /* Setup CPUs */
     if (params->cpu_model == NULL) {
@@ -482,7 +484,12 @@  void ppce500_init(PPCE500Params *params)
     memory_region_add_subregion(address_space_mem, 0, ram);
 
     ccsr = g_malloc0(sizeof(MemoryRegion));
-    memory_region_init(ccsr, "e500-ccsr", MPC8544_CCSRBAR_SIZE);
+    dev = qdev_create(NULL, "e500-ccsr");
+    object_property_add_child(qdev_get_machine(), "e500-ccsr",
+                              OBJECT(dev), NULL);
+    qdev_init_nofail(dev);
+    pci_ccsr = CCSR(dev);
+    ccsr = &pci_ccsr->ccsr_space;
     memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE, ccsr);
 
     /* MPIC */
@@ -596,3 +603,33 @@  void ppce500_init(PPCE500Params *params)
         kvmppc_init();
     }
 }
+
+static int e500_ccsr_initfn(SysBusDevice *dev)
+{
+    PPCE500CCSRState *pci_ccsr;
+
+    pci_ccsr = CCSR(dev);
+    memory_region_init(&pci_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)
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index 92b1dc0..58dbc1a 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -15,6 +15,7 @@ 
  */
 
 #include "hw.h"
+#include "hw/ppc/e500-ccsr.h"
 #include "pci.h"
 #include "pci_host.h"
 #include "bswap.h"
@@ -89,6 +90,19 @@  struct PPCE500PCIState {
     MemoryRegion iomem;
 };
 
+#define TYPE_PPC_E500_PCI_BRIDGE "e500-host-bridge"
+#define PPC_E500_PCI_BRIDGE(obj) \
+    OBJECT_CHECK(PPCE500PCIBridgeState, (obj), TYPE_PPC_E500_PCI_BRIDGE)
+
+struct PPCE500PCIBridgeState {
+    /*< private >*/
+    PCIDevice parent;
+    /*< public >*/
+
+    MemoryRegion bar0;
+};
+
+typedef struct PPCE500PCIBridgeState PPCE500PCIBridgeState;
 typedef struct PPCE500PCIState PPCE500PCIState;
 
 static uint64_t pci_reg_read4(void *opaque, target_phys_addr_t addr,
@@ -307,6 +321,19 @@  static const VMStateDescription vmstate_ppce500_pci = {
 
 #include "exec-memory.h"
 
+static int e500_pcihost_bridge_initfn(PCIDevice *d)
+{
+    PPCE500PCIBridgeState *b = PPC_E500_PCI_BRIDGE(d);
+    PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(),
+                                  "/e500-ccsr"));
+
+    b->bar0 = ccsr->ccsr_space;
+    memory_region_init_alias(&b->bar0, "e500-pci-bar0", &ccsr->ccsr_space,
+                             0, int128_get64(ccsr->ccsr_space.size));
+    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0);
+    return 0;
+}
+
 static int e500_pcihost_initfn(SysBusDevice *dev)
 {
     PCIHostState *h;
@@ -350,6 +377,7 @@  static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
+    k->init = e500_pcihost_bridge_initfn;
     k->vendor_id = PCI_VENDOR_ID_FREESCALE;
     k->device_id = PCI_DEVICE_ID_MPC8533E;
     k->class_id = PCI_CLASS_PROCESSOR_POWERPC;
@@ -359,7 +387,7 @@  static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
 static const TypeInfo e500_host_bridge_info = {
     .name          = "e500-host-bridge",
     .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
+    .instance_size = sizeof(PPCE500PCIBridgeState),
     .class_init    = e500_host_bridge_class_init,
 };