qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [0/3] Bugfixes and updates for pseries
@ 2011-10-28  1:56 David Gibson
  2011-10-28  1:56 ` [Qemu-devel] [PATCH 1/3] ppc: Correctly handle errors reading ibm, vmx and ibm, dfp properties David Gibson
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: David Gibson @ 2011-10-28  1:56 UTC (permalink / raw)
  To: agraf, anthony; +Cc: qemu-ppc, qemu-devel

This series contains several updates for the pseries platform.  The
first two are trivial bugfixes and should certainly go in ASAP.

The third patch is rather more substantial - it adds PCI support to
pseries, however without IOMMU support in qemu it's fairly crippled -
only PCI devices which don't use DMA will work correctly.

I'm still hoping this can make it in before the hard freeze though.
It only touches pseries specific code, so it's unlikely to break
anything else.  It gets at least this part of the PCI code out there
for better testing and review.  Finally it does allow us to use
virtio_pci on pseries which is a significant gain in functionality,
even if no other PCI devices work.

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

* [Qemu-devel] [PATCH 1/3] ppc: Correctly handle errors reading ibm, vmx and ibm, dfp properties
  2011-10-28  1:56 [Qemu-devel] [0/3] Bugfixes and updates for pseries David Gibson
@ 2011-10-28  1:56 ` David Gibson
  2011-10-30 16:53   ` Alexander Graf
  2011-10-28  1:56 ` [Qemu-devel] [PATCH 2/3] pseries: Allow writes to KVM accelerated TCE table David Gibson
  2011-10-28  1:56 ` [Qemu-devel] [PATCH 3/3] pseries: Add partial support for PCI David Gibson
  2 siblings, 1 reply; 9+ messages in thread
From: David Gibson @ 2011-10-28  1:56 UTC (permalink / raw)
  To: agraf, anthony; +Cc: qemu-ppc, qemu-devel

kvmppc_read_int_cpu_dt() returns -1 on errors. However
kvmppc_host_cpu_def() assumes that it can use the return value
directly for setting the corresponding instruction support bits.  This
will give invalid results when kvmppc_read_int_cpu_dt() returns -1
(i.e. 0xffffffff).

In fact, it gets worse: the common case for -1 return values is when
the properties are simply not present.  On some machines this means
the features are not available but in other cases it just means that
the firmware on this platform does not provide this information.  So,
when there's an error reading the properties we really can't tell if
vmx or dfp is supported.

Therefore, this patch checks for -1 return values and falls back to
qemu's built in table of CPU capabilities in that case.

Reported-by: Nishanth Aravamudan <nacc@us.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target-ppc/kvm.c |   10 +++++++---
 1 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index a090d79..6b156be 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -912,9 +912,13 @@ const ppc_def_t *kvmppc_host_cpu_def(void)
 
     /* Now fix up the spec with information we can query from the host */
 
-    alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0);
-    alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1);
-    alter_insns(&spec->insns_flags2, PPC2_DFP, dfp);
+    if (vmx != -1) {
+        alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0);
+        alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1);
+    }
+    if (dfp != -1) {
+        alter_insns(&spec->insns_flags2, PPC2_DFP, dfp);
+    }
 
     return spec;
 }
-- 
1.7.7

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

* [Qemu-devel] [PATCH 2/3] pseries: Allow writes to KVM accelerated TCE table
  2011-10-28  1:56 [Qemu-devel] [0/3] Bugfixes and updates for pseries David Gibson
  2011-10-28  1:56 ` [Qemu-devel] [PATCH 1/3] ppc: Correctly handle errors reading ibm, vmx and ibm, dfp properties David Gibson
@ 2011-10-28  1:56 ` David Gibson
  2011-10-30 17:07   ` Alexander Graf
  2011-10-28  1:56 ` [Qemu-devel] [PATCH 3/3] pseries: Add partial support for PCI David Gibson
  2 siblings, 1 reply; 9+ messages in thread
From: David Gibson @ 2011-10-28  1:56 UTC (permalink / raw)
  To: agraf, anthony; +Cc: qemu-ppc, qemu-devel

Sufficiently recent kernels include a KVM call to accelerate use of
PAPR TCE tables (IOMMU), which are used by PAPR virtual IO devices.
This involves qemu mapping the TCE table in from a kernel obtained fd,
which currently we do with PROT_READ only.  This is a hangover from
early (never released) versions of this kernel interface which only
permitted read-only mappings and required us to destroy and recreate
the table when we needed to clear it from qemu.

Now, the kernel permits read-write mappings, and we rely on this to
clear the table in spapr_vio_quiesce_one().  However, due to
insufficient testing, I forgot to update the actual mapping of the
table in kvmppc_create_spapr_tce() to add PROT_WRITE to the mmap().

This patch corrects the oversight.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target-ppc/kvm.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 6b156be..1663be0 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -850,7 +850,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
     len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE) * sizeof(VIOsPAPR_RTCE);
     /* FIXME: round this up to page size */
 
-    table = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+    table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
     if (table == MAP_FAILED) {
         close(fd);
         return NULL;
-- 
1.7.7

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

* [Qemu-devel] [PATCH 3/3] pseries: Add partial support for PCI
  2011-10-28  1:56 [Qemu-devel] [0/3] Bugfixes and updates for pseries David Gibson
  2011-10-28  1:56 ` [Qemu-devel] [PATCH 1/3] ppc: Correctly handle errors reading ibm, vmx and ibm, dfp properties David Gibson
  2011-10-28  1:56 ` [Qemu-devel] [PATCH 2/3] pseries: Allow writes to KVM accelerated TCE table David Gibson
@ 2011-10-28  1:56 ` David Gibson
  2011-10-30 17:06   ` Alexander Graf
  2 siblings, 1 reply; 9+ messages in thread
From: David Gibson @ 2011-10-28  1:56 UTC (permalink / raw)
  To: agraf, anthony; +Cc: qemu-ppc, qemu-devel

From: Alexey Kardashevskiy <aik@au1.ibm.com>

This patch adds a PCI bus to the pseries machine.  This instantiates
the qemu generic PCI bus code, advertises a PCI host bridge in the
guest's device tree and implements the RTAS methods specified by PAPR
to access PCI config space.  It also sets up the memory regions we
need to provide windows into the PCI memory and IO space, and
advertises those to the guest.

However, because qemu can't yet emulate an IOMMU, which is mandatory on
pseries, PCI devices which use DMA (i.e. most of them) will not work with
this code alone.  Still, this is enough to support the virtio_pci device
(which probably _should_ use emulated PCI DMA, but is specced to use
direct hypervisor access to guest physical memory instead).

Signed-off-by: Alexey Kardashevskiy <aik@au1.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 Makefile.target |    3 +
 hw/spapr.c      |   36 ++++-
 hw/spapr.h      |    2 +
 hw/spapr_pci.c  |  515 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/spapr_pci.h  |   59 +++++++
 5 files changed, 611 insertions(+), 4 deletions(-)
 create mode 100644 hw/spapr_pci.c
 create mode 100644 hw/spapr_pci.h

diff --git a/Makefile.target b/Makefile.target
index fe5f6f7..f3eb842 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -248,6 +248,9 @@ obj-ppc-y += ppc_newworld.o
 # IBM pSeries (sPAPR)
 obj-ppc-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
 obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
+ifeq ($(CONFIG_PCI),y)
+obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o
+endif
 # PowerPC 4xx boards
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-ppc-y += ppc440.o ppc440_bamboo.o
diff --git a/hw/spapr.c b/hw/spapr.c
index 933af32..bdaa938 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -39,10 +39,12 @@
 
 #include "hw/spapr.h"
 #include "hw/spapr_vio.h"
+#include "hw/spapr_pci.h"
 #include "hw/xics.h"
 
 #include "kvm.h"
 #include "kvm_ppc.h"
+#include "pci.h"
 
 #include "exec-memory.h"
 
@@ -62,6 +64,11 @@
 #define MAX_CPUS                256
 #define XICS_IRQS		1024
 
+#define SPAPR_PCI_BUID          0x800000020000001ULL
+#define SPAPR_PCI_MEM_WIN_ADDR  (0x10000000000ULL + 0xA0000000)
+#define SPAPR_PCI_MEM_WIN_SIZE  0x20000000
+#define SPAPR_PCI_IO_WIN_ADDR   (0x10000000000ULL + 0x80000000)
+
 #define PHANDLE_XICP            0x00001111
 
 sPAPREnvironment *spapr;
@@ -146,6 +153,14 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
                        &end_prop, sizeof(end_prop))));
     _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
 
+    /*
+     * Because we don't always invoke any firmware, we can't rely on
+     * that to do BAR allocation.  Long term, we should probably do
+     * that ourselves, but for now, this setting (plus advertising the
+     * current BARs as 0) causes sufficiently recent kernels to to the
+     * BAR assignment themselves */
+    _FDT((fdt_property_cell(fdt, "linux,pci-probe-only", 0)));
+
     _FDT((fdt_end_node(fdt)));
 
     /* memory node(s) */
@@ -308,6 +323,7 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
 {
     int ret;
     void *fdt;
+    sPAPRPHBState *phb;
 
     fdt = g_malloc(FDT_MAX_SIZE);
 
@@ -320,6 +336,15 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
         exit(1);
     }
 
+    QLIST_FOREACH(phb, &spapr->phbs, list) {
+        ret = spapr_populate_pci_devices(phb, PHANDLE_XICP, fdt);
+    }
+
+    if (ret < 0) {
+        fprintf(stderr, "couldn't setup PCI devices in fdt\n");
+        exit(1);
+    }
+
     /* RTAS */
     ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
     if (ret < 0) {
@@ -478,6 +503,12 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         }
     }
 
+    /* Set up PCI */
+    spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID,
+                     SPAPR_PCI_MEM_WIN_ADDR,
+                     SPAPR_PCI_MEM_WIN_SIZE,
+                     SPAPR_PCI_IO_WIN_ADDR);
+
     for (i = 0; i < nb_nics; i++) {
         NICInfo *nd = &nd_table[i];
 
@@ -488,10 +519,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         if (strcmp(nd->model, "ibmveth") == 0) {
             spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd);
         } else {
-            fprintf(stderr, "pSeries (sPAPR) platform does not support "
-                    "NIC model '%s' (only ibmveth is supported)\n",
-                    nd->model);
-            exit(1);
+            pci_nic_init_nofail(&nd_table[i], nd->model, NULL);
         }
     }
 
diff --git a/hw/spapr.h b/hw/spapr.h
index 6657c33..5689797 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -2,12 +2,14 @@
 #define __HW_SPAPR_H__
 
 #include "hw/xics.h"
+#include "spapr_pci.h"
 
 struct VIOsPAPRBus;
 struct icp_state;
 
 typedef struct sPAPREnvironment {
     struct VIOsPAPRBus *vio_bus;
+    QLIST_HEAD(, sPAPRPHBState) phbs;
     struct icp_state *icp;
 
     target_phys_addr_t ram_limit;
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
new file mode 100644
index 0000000..a907747
--- /dev/null
+++ b/hw/spapr_pci.c
@@ -0,0 +1,515 @@
+/*
+ * QEMU sPAPR PCI host originated from Uninorth PCI host
+ *
+ * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation.
+ * Copyright (C) 2011 David Gibson, IBM Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "pci.h"
+#include "pci_host.h"
+#include "hw/spapr.h"
+#include "hw/spapr_pci.h"
+#include "exec-memory.h"
+#include <libfdt.h>
+
+#include "hw/pci_internals.h"
+
+static const uint32_t bars[] = {
+    PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1,
+    PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3,
+    PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5
+    /*, PCI_ROM_ADDRESS*/
+};
+
+static PCIDevice *find_dev(sPAPREnvironment *spapr,
+                           uint64_t buid, uint32_t config_addr)
+{
+    DeviceState *qdev;
+    int devfn = (config_addr >> 8) & 0xFF;
+    sPAPRPHBState *phb;
+
+    QLIST_FOREACH(phb, &spapr->phbs, list) {
+        if (phb->buid != buid) {
+            continue;
+        }
+
+        QLIST_FOREACH(qdev, &phb->host_state.bus->qbus.children, sibling) {
+            PCIDevice *dev = (PCIDevice *)qdev;
+            if (dev->devfn == devfn) {
+                return dev;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
+                                     uint32_t token, uint32_t nargs,
+                                     target_ulong args,
+                                     uint32_t nret, target_ulong rets)
+{
+    uint32_t val, size, addr;
+    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+    PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
+
+    if (!dev) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+    size = rtas_ld(args, 3);
+    addr = rtas_ld(args, 0) & 0xFF;
+    val = pci_default_read_config(dev, addr, size);
+    rtas_st(rets, 0, 0);
+    rtas_st(rets, 1, val);
+}
+
+static void rtas_read_pci_config(sPAPREnvironment *spapr,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+    uint32_t val, size, addr;
+    PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
+
+    if (!dev) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+    size = rtas_ld(args, 1);
+    addr = rtas_ld(args, 0) & 0xFF;
+    val = pci_default_read_config(dev, addr, size);
+    rtas_st(rets, 0, 0);
+    rtas_st(rets, 1, val);
+}
+
+static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
+                                      uint32_t token, uint32_t nargs,
+                                      target_ulong args,
+                                      uint32_t nret, target_ulong rets)
+{
+    uint32_t val, size, addr;
+    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+    PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
+
+    if (!dev) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+    val = rtas_ld(args, 4);
+    size = rtas_ld(args, 3);
+    addr = rtas_ld(args, 0) & 0xFF;
+    pci_default_write_config(dev, addr, val, size);
+    rtas_st(rets, 0, 0);
+}
+
+static void rtas_write_pci_config(sPAPREnvironment *spapr,
+                                  uint32_t token, uint32_t nargs,
+                                  target_ulong args,
+                                  uint32_t nret, target_ulong rets)
+{
+    uint32_t val, size, addr;
+    PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
+
+    if (!dev) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+    val = rtas_ld(args, 2);
+    size = rtas_ld(args, 1);
+    addr = rtas_ld(args, 0) & 0xFF;
+    pci_default_write_config(dev, addr, val, size);
+    rtas_st(rets, 0, 0);
+}
+
+static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    /*
+     * Here we need to convert pci_dev + irq_num to some unique value
+     * which is less than number of IRQs on the specific bus (now it
+     * is 16).  At the moment irq_num == device_id (number of the
+     * slot?)
+     * FIXME: we should swizzle in fn and irq_num
+     */
+    return (pci_dev->devfn >> 3) % SPAPR_PCI_NUM_LSI;
+}
+
+static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
+{
+    /*
+     * Here we use the number returned by pci_spapr_map_irq to find a
+     * corresponding qemu_irq.
+     */
+    sPAPRPHBState *phb = opaque;
+
+    qemu_set_irq(phb->lsi_table[irq_num].qirq, level);
+}
+
+static int spapr_phb_init(SysBusDevice *s)
+{
+    sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s);
+    int i;
+
+    /* Initialize the LSI table */
+    for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) {
+        qemu_irq qirq;
+        uint32_t num;
+
+        qirq = spapr_allocate_irq(0, &num);
+        if (!qirq) {
+            return -1;
+        }
+
+        phb->lsi_table[i].dt_irq = num;
+        phb->lsi_table[i].qirq = qirq;
+    }
+
+    return 0;
+}
+
+static int spapr_main_pci_host_init(PCIDevice *d)
+{
+    return 0;
+}
+
+static PCIDeviceInfo spapr_main_pci_host_info = {
+    .qdev.name = "spapr-pci-host-bridge",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = spapr_main_pci_host_init,
+};
+
+static void spapr_register_devices(void)
+{
+    sysbus_register_dev("spapr-pci-host-bridge", sizeof(sPAPRPHBState),
+                        spapr_phb_init);
+    pci_qdev_register(&spapr_main_pci_host_info);
+}
+
+device_init(spapr_register_devices)
+
+static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
+{
+    switch (size) {
+    case 1:
+        return cpu_inb(addr);
+    case 2:
+        return cpu_inw(addr);
+    case 4:
+        return cpu_inl(addr);
+    }
+    assert(0);
+}
+
+static void spapr_io_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t data, unsigned size)
+{
+    switch (size) {
+    case 1:
+        cpu_outb(addr, data);
+        return;
+    case 2:
+        cpu_outw(addr, data);
+        return;
+    case 4:
+        cpu_outl(addr, data);
+        return;
+    }
+    assert(0);
+}
+
+static MemoryRegionOps spapr_io_ops = {
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .read = spapr_io_read,
+    .write = spapr_io_write
+};
+
+void spapr_create_phb(sPAPREnvironment *spapr,
+                      const char *busname, uint64_t buid,
+                      uint64_t mem_win_addr, uint64_t mem_win_size,
+                      uint64_t io_win_addr)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    sPAPRPHBState *phb;
+    PCIBus *bus;
+    char namebuf[strlen(busname)+11];
+
+    dev = qdev_create(NULL, "spapr-pci-host-bridge");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    phb = FROM_SYSBUS(sPAPRPHBState, s);
+
+    phb->mem_win_addr = mem_win_addr;
+
+    sprintf(namebuf, "%s-mem", busname);
+    memory_region_init(&phb->memspace, namebuf, INT64_MAX);
+
+    sprintf(namebuf, "%s-memwindow", busname);
+    memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace,
+                             SPAPR_PCI_MEM_WIN_BUS_OFFSET, mem_win_size);
+    memory_region_add_subregion(get_system_memory(), mem_win_addr,
+                                &phb->memwindow);
+
+    phb->io_win_addr = io_win_addr;
+
+    /* On ppc, we only have MMIO no specific IO space from the CPU
+     * perspective.  In theory we ought to be able to embed the PCI IO
+     * memory region direction in the system memory space.  However,
+     * if any of the IO BAR subregions use the old_portio mechanism,
+     * that won't be processed properly unless accessed from the
+     * system io address space.  This hack to bounce things via
+     * system_io works around the problem until all the users of
+     * old_portion are updated */
+    sprintf(namebuf, "%s-io", busname);
+    memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
+    /* FIXME: fix to support multiple PHBs */
+    memory_region_add_subregion(get_system_io(), 0, &phb->iospace);
+
+    sprintf(namebuf, "%s-iowindow", busname);
+    memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb,
+                          namebuf, SPAPR_PCI_IO_WIN_SIZE);
+    memory_region_add_subregion(get_system_memory(), io_win_addr,
+                                &phb->iowindow);
+
+    phb->host_state.bus = bus = pci_register_bus(&phb->busdev.qdev, busname,
+                                                 pci_spapr_set_irq,
+                                                 pci_spapr_map_irq,
+                                                 phb,
+                                                 &phb->memspace, &phb->iospace,
+                                                 PCI_DEVFN(0, 0),
+                                                 SPAPR_PCI_NUM_LSI);
+
+    spapr_rtas_register("read-pci-config", rtas_read_pci_config);
+    spapr_rtas_register("write-pci-config", rtas_write_pci_config);
+    spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
+    spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
+
+    /*
+     * This is a workaround to disable PCI devices resetting as we do
+     * BAR allocation on the QEMU side and reset destroys this
+     * configuration.
+     */
+    bus->qbus.info->reset = NULL;
+
+    QLIST_INSERT_HEAD(&spapr->phbs, phb, list);
+
+    /* pci_bus_set_mem_base(bus, mem_va_start - SPAPR_PCI_MEM_BAR_START); */
+}
+
+/* Macros to operate with address in OF binding to PCI */
+#define b_x(x, p, l)    (((x) & ((1<<(l))-1)) << (p))
+#define b_n(x)          b_x((x), 31, 1) /* 0 if relocatable */
+#define b_p(x)          b_x((x), 30, 1) /* 1 if prefetchable */
+#define b_t(x)          b_x((x), 29, 1) /* 1 if the address is aliased */
+#define b_ss(x)         b_x((x), 24, 2) /* the space code */
+#define b_bbbbbbbb(x)   b_x((x), 16, 8) /* bus number */
+#define b_ddddd(x)      b_x((x), 11, 5) /* device number */
+#define b_fff(x)        b_x((x), 8, 3)  /* function number */
+#define b_rrrrrrrr(x)   b_x((x), 0, 8)  /* register number */
+
+static uint32_t regtype_to_ss(uint8_t type)
+{
+    if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+        return 3;
+    }
+    if (type == PCI_BASE_ADDRESS_SPACE_IO) {
+        return 1;
+    }
+    return 2;
+}
+
+int spapr_populate_pci_devices(sPAPRPHBState *phb,
+                               uint32_t xics_phandle,
+                               void *fdt)
+{
+    PCIBus *bus = phb->host_state.bus;
+    int bus_off, node_off = 0, devid, fn, i, n, devices;
+    DeviceState *qdev;
+    char nodename[256];
+    struct {
+        uint32_t hi;
+        uint64_t addr;
+        uint64_t size;
+    } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1],
+          assigned_addresses[PCI_NUM_REGIONS];
+    uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
+    struct {
+        uint32_t hi;
+        uint64_t child;
+        uint64_t parent;
+        uint64_t size;
+    } __attribute__((packed)) ranges[] = {
+        {
+            cpu_to_be32(b_ss(1)), cpu_to_be64(0),
+            cpu_to_be64(phb->io_win_addr),
+            cpu_to_be64(memory_region_size(&phb->iospace)),
+        },
+        {
+            cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET),
+            cpu_to_be64(phb->mem_win_addr),
+            cpu_to_be64(memory_region_size(&phb->memwindow)),
+        },
+    };
+    uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 };
+    uint32_t interrupt_map_mask[] = {
+        cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0};
+    uint32_t interrupt_map[bus->nirq][7];
+
+    /* Start populating the FDT */
+    sprintf(nodename, "pci@%" PRIx64, phb->buid);
+    bus_off = fdt_add_subnode(fdt, 0, nodename);
+    if (bus_off < 0) {
+        return bus_off;
+    }
+
+#define _FDT(exp) \
+    do { \
+        int ret = (exp);                                           \
+        if (ret < 0) {                                             \
+            return ret;                                            \
+        }                                                          \
+    } while (0)
+
+    /* Write PHB properties */
+    _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
+    _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
+    _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
+    _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
+    _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
+    _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
+    _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
+                     &interrupt_map_mask, sizeof(interrupt_map_mask)));
+
+    /* Populate PCI devices and allocate IRQs */
+    devices = 0;
+    QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+        PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+        int irq_index = pci_spapr_map_irq(dev, 0);
+        uint32_t *irqmap = interrupt_map[devices];
+        uint8_t *config = dev->config;
+
+        devid = dev->devfn >> 3;
+        fn = dev->devfn & 7;
+
+        sprintf(nodename, "pci@%u,%u", devid, fn);
+
+        /* Allocate interrupt from the map */
+        if (devid > bus->nirq)  {
+            printf("Unexpected behaviour in spapr_populate_pci_devices,"
+                    "wrong devid %u\n", devid);
+            exit(-1);
+        }
+        irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn));
+        irqmap[1] = 0;
+        irqmap[2] = 0;
+        irqmap[3] = 0;
+        irqmap[4] = cpu_to_be32(xics_phandle);
+        irqmap[5] = cpu_to_be32(phb->lsi_table[irq_index].dt_irq);
+        irqmap[6] = cpu_to_be32(0x8);
+
+        /* Add node to FDT */
+        node_off = fdt_add_subnode(fdt, bus_off, nodename);
+        if (node_off < 0) {
+            return node_off;
+        }
+
+        _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id",
+                              pci_get_word(&config[PCI_VENDOR_ID])));
+        _FDT(fdt_setprop_cell(fdt, node_off, "device-id",
+                              pci_get_word(&config[PCI_DEVICE_ID])));
+        _FDT(fdt_setprop_cell(fdt, node_off, "revision-id",
+                              pci_get_byte(&config[PCI_REVISION_ID])));
+        _FDT(fdt_setprop_cell(fdt, node_off, "class-code",
+                              pci_get_long(&config[PCI_CLASS_REVISION]) >> 8));
+        _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id",
+                              pci_get_word(&config[PCI_SUBSYSTEM_ID])));
+        _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id",
+                              pci_get_word(&config[PCI_SUBSYSTEM_VENDOR_ID])));
+
+        /* Config space region comes first */
+        reg[0].hi = cpu_to_be32(
+            b_n(0) |
+            b_p(0) |
+            b_t(0) |
+            b_ss(0/*config*/) |
+            b_bbbbbbbb(0) |
+            b_ddddd(devid) |
+            b_fff(fn));
+        reg[0].addr = 0;
+        reg[0].size = 0;
+
+        n = 0;
+        for (i = 0; i < PCI_NUM_REGIONS; ++i) {
+            if (0 == dev->io_regions[i].size) {
+                continue;
+            }
+
+            reg[n+1].hi = cpu_to_be32(
+                b_n(0) |
+                b_p(0) |
+                b_t(0) |
+                b_ss(regtype_to_ss(dev->io_regions[i].type)) |
+                b_bbbbbbbb(0) |
+                b_ddddd(devid) |
+                b_fff(fn) |
+                b_rrrrrrrr(bars[i]));
+            reg[n+1].addr = 0;
+            reg[n+1].size = cpu_to_be64(dev->io_regions[i].size);
+
+            assigned_addresses[n].hi = cpu_to_be32(
+                b_n(1) |
+                b_p(0) |
+                b_t(0) |
+                b_ss(regtype_to_ss(dev->io_regions[i].type)) |
+                b_bbbbbbbb(0) |
+                b_ddddd(devid) |
+                b_fff(fn) |
+                b_rrrrrrrr(bars[i]));
+
+            /*
+             * Writing zeroes to assigned_addresses causes the guest kernel to
+             * reassign BARs
+             */
+            assigned_addresses[n].addr = cpu_to_be64(dev->io_regions[i].addr);
+            assigned_addresses[n].size = reg[n+1].size;
+
+            ++n;
+        }
+        _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1)));
+        _FDT(fdt_setprop(fdt, node_off, "assigned-addresses",
+                         assigned_addresses,
+                         sizeof(assigned_addresses[0])*(n)));
+        _FDT(fdt_setprop_cell(fdt, node_off, "interrupts",
+                              pci_get_byte(&config[PCI_INTERRUPT_PIN])));
+
+        ++devices;
+    }
+
+    /* Write interrupt map */
+    _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
+                     devices * sizeof(interrupt_map[0])));
+
+    return 0;
+}
diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h
new file mode 100644
index 0000000..4bb8dfb
--- /dev/null
+++ b/hw/spapr_pci.h
@@ -0,0 +1,59 @@
+/*
+ * QEMU SPAPR PCI BUS definitions
+ *
+ * Copyright (c) 2011 Alexey Kardashevskiy <aik@au1.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#if !defined(__HW_SPAPR_PCI_H__)
+#define __HW_SPAPR_PCI_H__
+
+#include "hw/pci_host.h"
+#include "hw/xics.h"
+
+typedef struct sPAPREnvironment sPAPREnvironment;
+
+#define SPAPR_PCI_NUM_LSI   16
+
+typedef struct sPAPRPHBState {
+    SysBusDevice busdev;
+    PCIHostState host_state;
+
+    uint64_t buid;
+
+    MemoryRegion memspace, iospace;
+    target_phys_addr_t mem_win_addr, io_win_addr;
+    MemoryRegion memwindow, iowindow;
+
+    struct {
+        uint32_t dt_irq;
+        qemu_irq qirq;
+    } lsi_table[SPAPR_PCI_NUM_LSI];
+
+    QLIST_ENTRY(sPAPRPHBState) list;
+} sPAPRPHBState;
+
+#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
+#define SPAPR_PCI_IO_WIN_SIZE        0x10000
+
+void spapr_create_phb(sPAPREnvironment *spapr,
+                      const char *busname, uint64_t buid,
+                      uint64_t mem_win_addr, uint64_t mem_win_size,
+                      uint64_t io_win_addr);
+
+int spapr_populate_pci_devices(sPAPRPHBState *phb,
+                               uint32_t xics_phandle,
+                               void *fdt);
+
+#endif /* __HW_SPAPR_PCI_H__ */
-- 
1.7.7

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

* Re: [Qemu-devel] [PATCH 1/3] ppc: Correctly handle errors reading ibm, vmx and ibm, dfp properties
  2011-10-28  1:56 ` [Qemu-devel] [PATCH 1/3] ppc: Correctly handle errors reading ibm, vmx and ibm, dfp properties David Gibson
@ 2011-10-30 16:53   ` Alexander Graf
  2011-10-31  0:01     ` [Qemu-devel] [Qemu-ppc] " David Gibson
  0 siblings, 1 reply; 9+ messages in thread
From: Alexander Graf @ 2011-10-30 16:53 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel


On 28.10.2011, at 03:56, David Gibson wrote:

> kvmppc_read_int_cpu_dt() returns -1 on errors. However
> kvmppc_host_cpu_def() assumes that it can use the return value
> directly for setting the corresponding instruction support bits.  This
> will give invalid results when kvmppc_read_int_cpu_dt() returns -1
> (i.e. 0xffffffff).
> 
> In fact, it gets worse: the common case for -1 return values is when
> the properties are simply not present.  On some machines this means
> the features are not available but in other cases it just means that
> the firmware on this platform does not provide this information.  So,
> when there's an error reading the properties we really can't tell if
> vmx or dfp is supported.
> 
> Therefore, this patch checks for -1 return values and falls back to
> qemu's built in table of CPU capabilities in that case.
> 
> Reported-by: Nishanth Aravamudan <nacc@us.ibm.com>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

I already have this patch in my tree, though with different author. I've added Nishanth as Reported-by on it now and you as Acked-by, if you're ok with that.


Alex

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

* Re: [Qemu-devel] [PATCH 3/3] pseries: Add partial support for PCI
  2011-10-28  1:56 ` [Qemu-devel] [PATCH 3/3] pseries: Add partial support for PCI David Gibson
@ 2011-10-30 17:06   ` Alexander Graf
  2011-10-31  1:48     ` [Qemu-devel] [Qemu-ppc] " David Gibson
  0 siblings, 1 reply; 9+ messages in thread
From: Alexander Graf @ 2011-10-30 17:06 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel


On 28.10.2011, at 03:56, David Gibson wrote:

> From: Alexey Kardashevskiy <aik@au1.ibm.com>
> 
> This patch adds a PCI bus to the pseries machine.  This instantiates
> the qemu generic PCI bus code, advertises a PCI host bridge in the
> guest's device tree and implements the RTAS methods specified by PAPR
> to access PCI config space.  It also sets up the memory regions we
> need to provide windows into the PCI memory and IO space, and
> advertises those to the guest.
> 
> However, because qemu can't yet emulate an IOMMU, which is mandatory on
> pseries, PCI devices which use DMA (i.e. most of them) will not work with
> this code alone.  Still, this is enough to support the virtio_pci device
> (which probably _should_ use emulated PCI DMA, but is specced to use
> direct hypervisor access to guest physical memory instead).
> 
> Signed-off-by: Alexey Kardashevskiy <aik@au1.ibm.com>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> Makefile.target |    3 +
> hw/spapr.c      |   36 ++++-
> hw/spapr.h      |    2 +
> hw/spapr_pci.c  |  515 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> hw/spapr_pci.h  |   59 +++++++
> 5 files changed, 611 insertions(+), 4 deletions(-)
> create mode 100644 hw/spapr_pci.c
> create mode 100644 hw/spapr_pci.h
> 
> diff --git a/Makefile.target b/Makefile.target
> index fe5f6f7..f3eb842 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -248,6 +248,9 @@ obj-ppc-y += ppc_newworld.o
> # IBM pSeries (sPAPR)
> obj-ppc-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
> obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
> +ifeq ($(CONFIG_PCI),y)
> +obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o
> +endif

You make it conditional here ...

> # PowerPC 4xx boards
> obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
> obj-ppc-y += ppc440.o ppc440_bamboo.o
> diff --git a/hw/spapr.c b/hw/spapr.c
> index 933af32..bdaa938 100644
> --- a/hw/spapr.c
> +++ b/hw/spapr.c
> @@ -39,10 +39,12 @@
> 
> #include "hw/spapr.h"
> #include "hw/spapr_vio.h"
> +#include "hw/spapr_pci.h"
> #include "hw/xics.h"
> 
> #include "kvm.h"
> #include "kvm_ppc.h"
> +#include "pci.h"

... but not here. Just throw away the condition above. We don't need to support -M pseries without PCI.

> 
> #include "exec-memory.h"
> 
> @@ -62,6 +64,11 @@
> #define MAX_CPUS                256
> #define XICS_IRQS		1024
> 
> +#define SPAPR_PCI_BUID          0x800000020000001ULL
> +#define SPAPR_PCI_MEM_WIN_ADDR  (0x10000000000ULL + 0xA0000000)
> +#define SPAPR_PCI_MEM_WIN_SIZE  0x20000000
> +#define SPAPR_PCI_IO_WIN_ADDR   (0x10000000000ULL + 0x80000000)
> +
> #define PHANDLE_XICP            0x00001111
> 
> sPAPREnvironment *spapr;
> @@ -146,6 +153,14 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
>                        &end_prop, sizeof(end_prop))));
>     _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
> 
> +    /*
> +     * Because we don't always invoke any firmware, we can't rely on
> +     * that to do BAR allocation.  Long term, we should probably do
> +     * that ourselves, but for now, this setting (plus advertising the
> +     * current BARs as 0) causes sufficiently recent kernels to to the
> +     * BAR assignment themselves */
> +    _FDT((fdt_property_cell(fdt, "linux,pci-probe-only", 0)));
> +
>     _FDT((fdt_end_node(fdt)));
> 
>     /* memory node(s) */
> @@ -308,6 +323,7 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
> {
>     int ret;
>     void *fdt;
> +    sPAPRPHBState *phb;
> 
>     fdt = g_malloc(FDT_MAX_SIZE);
> 
> @@ -320,6 +336,15 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
>         exit(1);
>     }
> 
> +    QLIST_FOREACH(phb, &spapr->phbs, list) {
> +        ret = spapr_populate_pci_devices(phb, PHANDLE_XICP, fdt);
> +    }
> +
> +    if (ret < 0) {
> +        fprintf(stderr, "couldn't setup PCI devices in fdt\n");
> +        exit(1);
> +    }
> +
>     /* RTAS */
>     ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
>     if (ret < 0) {
> @@ -478,6 +503,12 @@ static void ppc_spapr_init(ram_addr_t ram_size,
>         }
>     }
> 
> +    /* Set up PCI */
> +    spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID,
> +                     SPAPR_PCI_MEM_WIN_ADDR,
> +                     SPAPR_PCI_MEM_WIN_SIZE,
> +                     SPAPR_PCI_IO_WIN_ADDR);
> +
>     for (i = 0; i < nb_nics; i++) {
>         NICInfo *nd = &nd_table[i];
> 
> @@ -488,10 +519,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
>         if (strcmp(nd->model, "ibmveth") == 0) {
>             spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd);
>         } else {
> -            fprintf(stderr, "pSeries (sPAPR) platform does not support "
> -                    "NIC model '%s' (only ibmveth is supported)\n",
> -                    nd->model);
> -            exit(1);
> +            pci_nic_init_nofail(&nd_table[i], nd->model, NULL);
>         }
>     }
> 
> diff --git a/hw/spapr.h b/hw/spapr.h
> index 6657c33..5689797 100644
> --- a/hw/spapr.h
> +++ b/hw/spapr.h
> @@ -2,12 +2,14 @@
> #define __HW_SPAPR_H__
> 
> #include "hw/xics.h"
> +#include "spapr_pci.h"
> 
> struct VIOsPAPRBus;
> struct icp_state;
> 
> typedef struct sPAPREnvironment {
>     struct VIOsPAPRBus *vio_bus;
> +    QLIST_HEAD(, sPAPRPHBState) phbs;
>     struct icp_state *icp;
> 
>     target_phys_addr_t ram_limit;
> diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
> new file mode 100644
> index 0000000..a907747
> --- /dev/null
> +++ b/hw/spapr_pci.c
> @@ -0,0 +1,515 @@
> +/*
> + * QEMU sPAPR PCI host originated from Uninorth PCI host
> + *
> + * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation.
> + * Copyright (C) 2011 David Gibson, IBM Corporation.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +#include "hw.h"
> +#include "pci.h"
> +#include "pci_host.h"
> +#include "hw/spapr.h"
> +#include "hw/spapr_pci.h"
> +#include "exec-memory.h"
> +#include <libfdt.h>
> +
> +#include "hw/pci_internals.h"
> +
> +static const uint32_t bars[] = {
> +    PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1,
> +    PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3,
> +    PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5
> +    /*, PCI_ROM_ADDRESS*/
> +};
> +
> +static PCIDevice *find_dev(sPAPREnvironment *spapr,
> +                           uint64_t buid, uint32_t config_addr)
> +{
> +    DeviceState *qdev;
> +    int devfn = (config_addr >> 8) & 0xFF;
> +    sPAPRPHBState *phb;
> +
> +    QLIST_FOREACH(phb, &spapr->phbs, list) {
> +        if (phb->buid != buid) {
> +            continue;
> +        }
> +
> +        QLIST_FOREACH(qdev, &phb->host_state.bus->qbus.children, sibling) {
> +            PCIDevice *dev = (PCIDevice *)qdev;
> +            if (dev->devfn == devfn) {
> +                return dev;
> +            }
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
> +static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
> +                                     uint32_t token, uint32_t nargs,
> +                                     target_ulong args,
> +                                     uint32_t nret, target_ulong rets)
> +{
> +    uint32_t val, size, addr;
> +    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
> +    PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
> +
> +    if (!dev) {
> +        rtas_st(rets, 0, -1);
> +        return;
> +    }
> +    size = rtas_ld(args, 3);
> +    addr = rtas_ld(args, 0) & 0xFF;
> +    val = pci_default_read_config(dev, addr, size);
> +    rtas_st(rets, 0, 0);
> +    rtas_st(rets, 1, val);
> +}
> +
> +static void rtas_read_pci_config(sPAPREnvironment *spapr,
> +                                 uint32_t token, uint32_t nargs,
> +                                 target_ulong args,
> +                                 uint32_t nret, target_ulong rets)
> +{
> +    uint32_t val, size, addr;
> +    PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
> +
> +    if (!dev) {
> +        rtas_st(rets, 0, -1);
> +        return;
> +    }
> +    size = rtas_ld(args, 1);
> +    addr = rtas_ld(args, 0) & 0xFF;
> +    val = pci_default_read_config(dev, addr, size);
> +    rtas_st(rets, 0, 0);
> +    rtas_st(rets, 1, val);
> +}
> +
> +static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
> +                                      uint32_t token, uint32_t nargs,
> +                                      target_ulong args,
> +                                      uint32_t nret, target_ulong rets)
> +{
> +    uint32_t val, size, addr;
> +    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
> +    PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
> +
> +    if (!dev) {
> +        rtas_st(rets, 0, -1);
> +        return;
> +    }
> +    val = rtas_ld(args, 4);
> +    size = rtas_ld(args, 3);
> +    addr = rtas_ld(args, 0) & 0xFF;
> +    pci_default_write_config(dev, addr, val, size);
> +    rtas_st(rets, 0, 0);
> +}
> +
> +static void rtas_write_pci_config(sPAPREnvironment *spapr,
> +                                  uint32_t token, uint32_t nargs,
> +                                  target_ulong args,
> +                                  uint32_t nret, target_ulong rets)
> +{
> +    uint32_t val, size, addr;
> +    PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
> +
> +    if (!dev) {
> +        rtas_st(rets, 0, -1);
> +        return;
> +    }
> +    val = rtas_ld(args, 2);
> +    size = rtas_ld(args, 1);
> +    addr = rtas_ld(args, 0) & 0xFF;
> +    pci_default_write_config(dev, addr, val, size);
> +    rtas_st(rets, 0, 0);
> +}
> +
> +static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num)
> +{
> +    /*
> +     * Here we need to convert pci_dev + irq_num to some unique value
> +     * which is less than number of IRQs on the specific bus (now it
> +     * is 16).  At the moment irq_num == device_id (number of the
> +     * slot?)
> +     * FIXME: we should swizzle in fn and irq_num
> +     */
> +    return (pci_dev->devfn >> 3) % SPAPR_PCI_NUM_LSI;
> +}
> +
> +static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
> +{
> +    /*
> +     * Here we use the number returned by pci_spapr_map_irq to find a
> +     * corresponding qemu_irq.
> +     */
> +    sPAPRPHBState *phb = opaque;
> +
> +    qemu_set_irq(phb->lsi_table[irq_num].qirq, level);
> +}
> +
> +static int spapr_phb_init(SysBusDevice *s)
> +{
> +    sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s);
> +    int i;
> +
> +    /* Initialize the LSI table */
> +    for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) {
> +        qemu_irq qirq;
> +        uint32_t num;
> +
> +        qirq = spapr_allocate_irq(0, &num);
> +        if (!qirq) {
> +            return -1;
> +        }
> +
> +        phb->lsi_table[i].dt_irq = num;
> +        phb->lsi_table[i].qirq = qirq;
> +    }
> +
> +    return 0;
> +}
> +
> +static int spapr_main_pci_host_init(PCIDevice *d)
> +{
> +    return 0;
> +}
> +
> +static PCIDeviceInfo spapr_main_pci_host_info = {
> +    .qdev.name = "spapr-pci-host-bridge",
> +    .qdev.size = sizeof(PCIDevice),
> +    .init      = spapr_main_pci_host_init,
> +};
> +
> +static void spapr_register_devices(void)
> +{
> +    sysbus_register_dev("spapr-pci-host-bridge", sizeof(sPAPRPHBState),
> +                        spapr_phb_init);
> +    pci_qdev_register(&spapr_main_pci_host_info);
> +}
> +
> +device_init(spapr_register_devices)
> +
> +static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr,
> +                              unsigned size)
> +{
> +    switch (size) {
> +    case 1:
> +        return cpu_inb(addr);
> +    case 2:
> +        return cpu_inw(addr);
> +    case 4:
> +        return cpu_inl(addr);
> +    }
> +    assert(0);
> +}
> +
> +static void spapr_io_write(void *opaque, target_phys_addr_t addr,
> +                           uint64_t data, unsigned size)
> +{
> +    switch (size) {
> +    case 1:
> +        cpu_outb(addr, data);
> +        return;
> +    case 2:
> +        cpu_outw(addr, data);
> +        return;
> +    case 4:
> +        cpu_outl(addr, data);
> +        return;
> +    }
> +    assert(0);
> +}
> +
> +static MemoryRegionOps spapr_io_ops = {
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .read = spapr_io_read,
> +    .write = spapr_io_write
> +};
> +
> +void spapr_create_phb(sPAPREnvironment *spapr,
> +                      const char *busname, uint64_t buid,
> +                      uint64_t mem_win_addr, uint64_t mem_win_size,
> +                      uint64_t io_win_addr)
> +{
> +    DeviceState *dev;
> +    SysBusDevice *s;
> +    sPAPRPHBState *phb;
> +    PCIBus *bus;
> +    char namebuf[strlen(busname)+11];
> +
> +    dev = qdev_create(NULL, "spapr-pci-host-bridge");
> +    qdev_init_nofail(dev);
> +    s = sysbus_from_qdev(dev);
> +    phb = FROM_SYSBUS(sPAPRPHBState, s);
> +
> +    phb->mem_win_addr = mem_win_addr;
> +
> +    sprintf(namebuf, "%s-mem", busname);
> +    memory_region_init(&phb->memspace, namebuf, INT64_MAX);
> +
> +    sprintf(namebuf, "%s-memwindow", busname);
> +    memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace,
> +                             SPAPR_PCI_MEM_WIN_BUS_OFFSET, mem_win_size);
> +    memory_region_add_subregion(get_system_memory(), mem_win_addr,
> +                                &phb->memwindow);
> +
> +    phb->io_win_addr = io_win_addr;
> +
> +    /* On ppc, we only have MMIO no specific IO space from the CPU
> +     * perspective.  In theory we ought to be able to embed the PCI IO
> +     * memory region direction in the system memory space.  However,
> +     * if any of the IO BAR subregions use the old_portio mechanism,
> +     * that won't be processed properly unless accessed from the
> +     * system io address space.  This hack to bounce things via
> +     * system_io works around the problem until all the users of
> +     * old_portion are updated */
> +    sprintf(namebuf, "%s-io", busname);
> +    memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
> +    /* FIXME: fix to support multiple PHBs */
> +    memory_region_add_subregion(get_system_io(), 0, &phb->iospace);
> +
> +    sprintf(namebuf, "%s-iowindow", busname);
> +    memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb,
> +                          namebuf, SPAPR_PCI_IO_WIN_SIZE);
> +    memory_region_add_subregion(get_system_memory(), io_win_addr,
> +                                &phb->iowindow);
> +
> +    phb->host_state.bus = bus = pci_register_bus(&phb->busdev.qdev, busname,
> +                                                 pci_spapr_set_irq,
> +                                                 pci_spapr_map_irq,
> +                                                 phb,
> +                                                 &phb->memspace, &phb->iospace,
> +                                                 PCI_DEVFN(0, 0),
> +                                                 SPAPR_PCI_NUM_LSI);
> +
> +    spapr_rtas_register("read-pci-config", rtas_read_pci_config);
> +    spapr_rtas_register("write-pci-config", rtas_write_pci_config);
> +    spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
> +    spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
> +
> +    /*
> +     * This is a workaround to disable PCI devices resetting as we do
> +     * BAR allocation on the QEMU side and reset destroys this
> +     * configuration.
> +     */
> +    bus->qbus.info->reset = NULL;

Eh. What? So you're breaking reset for all PCI devices? How do you reboot?


Alex

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

* Re: [Qemu-devel] [PATCH 2/3] pseries: Allow writes to KVM accelerated TCE table
  2011-10-28  1:56 ` [Qemu-devel] [PATCH 2/3] pseries: Allow writes to KVM accelerated TCE table David Gibson
@ 2011-10-30 17:07   ` Alexander Graf
  0 siblings, 0 replies; 9+ messages in thread
From: Alexander Graf @ 2011-10-30 17:07 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel


On 28.10.2011, at 03:56, David Gibson wrote:

> Sufficiently recent kernels include a KVM call to accelerate use of
> PAPR TCE tables (IOMMU), which are used by PAPR virtual IO devices.
> This involves qemu mapping the TCE table in from a kernel obtained fd,
> which currently we do with PROT_READ only.  This is a hangover from
> early (never released) versions of this kernel interface which only
> permitted read-only mappings and required us to destroy and recreate
> the table when we needed to clear it from qemu.
> 
> Now, the kernel permits read-write mappings, and we rely on this to
> clear the table in spapr_vio_quiesce_one().  However, due to
> insufficient testing, I forgot to update the actual mapping of the
> table in kvmppc_create_spapr_tce() to add PROT_WRITE to the mmap().
> 
> This patch corrects the oversight.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

Thanks, applied to ppc-next.


Alex

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

* Re: [Qemu-devel] [Qemu-ppc] [PATCH 1/3] ppc: Correctly handle errors reading ibm, vmx and ibm, dfp properties
  2011-10-30 16:53   ` Alexander Graf
@ 2011-10-31  0:01     ` David Gibson
  0 siblings, 0 replies; 9+ messages in thread
From: David Gibson @ 2011-10-31  0:01 UTC (permalink / raw)
  To: Alexander Graf; +Cc: qemu-ppc, qemu-devel

On Sun, Oct 30, 2011 at 05:53:13PM +0100, Alexander Graf wrote:
> 
> On 28.10.2011, at 03:56, David Gibson wrote:
> 
> > kvmppc_read_int_cpu_dt() returns -1 on errors. However
> > kvmppc_host_cpu_def() assumes that it can use the return value
> > directly for setting the corresponding instruction support bits.  This
> > will give invalid results when kvmppc_read_int_cpu_dt() returns -1
> > (i.e. 0xffffffff).
> > 
> > In fact, it gets worse: the common case for -1 return values is when
> > the properties are simply not present.  On some machines this means
> > the features are not available but in other cases it just means that
> > the firmware on this platform does not provide this information.  So,
> > when there's an error reading the properties we really can't tell if
> > vmx or dfp is supported.
> > 
> > Therefore, this patch checks for -1 return values and falls back to
> > qemu's built in table of CPU capabilities in that case.
> > 
> > Reported-by: Nishanth Aravamudan <nacc@us.ibm.com>
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> 
> I already have this patch in my tree, though with different
> author.

Yeah, I realised that not long after I sent it.

> I've added Nishanth as Reported-by on it now and you as
> Acked-by, if you're ok with that.

Ok, thanks.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

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

* Re: [Qemu-devel] [Qemu-ppc] [PATCH 3/3] pseries: Add partial support for PCI
  2011-10-30 17:06   ` Alexander Graf
@ 2011-10-31  1:48     ` David Gibson
  0 siblings, 0 replies; 9+ messages in thread
From: David Gibson @ 2011-10-31  1:48 UTC (permalink / raw)
  To: Alexander Graf; +Cc: qemu-ppc, qemu-devel

On Sun, Oct 30, 2011 at 06:06:51PM +0100, Alexander Graf wrote:
> 
> On 28.10.2011, at 03:56, David Gibson wrote:
> 
> > From: Alexey Kardashevskiy <aik@au1.ibm.com>
> > 
> > This patch adds a PCI bus to the pseries machine.  This instantiates
> > the qemu generic PCI bus code, advertises a PCI host bridge in the
> > guest's device tree and implements the RTAS methods specified by PAPR
> > to access PCI config space.  It also sets up the memory regions we
> > need to provide windows into the PCI memory and IO space, and
> > advertises those to the guest.
> > 
> > However, because qemu can't yet emulate an IOMMU, which is mandatory on
> > pseries, PCI devices which use DMA (i.e. most of them) will not work with
> > this code alone.  Still, this is enough to support the virtio_pci device
> > (which probably _should_ use emulated PCI DMA, but is specced to use
> > direct hypervisor access to guest physical memory instead).
> > 
> > Signed-off-by: Alexey Kardashevskiy <aik@au1.ibm.com>
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> > Makefile.target |    3 +
> > hw/spapr.c      |   36 ++++-
> > hw/spapr.h      |    2 +
> > hw/spapr_pci.c  |  515 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > hw/spapr_pci.h  |   59 +++++++
> > 5 files changed, 611 insertions(+), 4 deletions(-)
> > create mode 100644 hw/spapr_pci.c
> > create mode 100644 hw/spapr_pci.h
> > 
> > diff --git a/Makefile.target b/Makefile.target
> > index fe5f6f7..f3eb842 100644
> > --- a/Makefile.target
> > +++ b/Makefile.target
> > @@ -248,6 +248,9 @@ obj-ppc-y += ppc_newworld.o
> > # IBM pSeries (sPAPR)
> > obj-ppc-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
> > obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
> > +ifeq ($(CONFIG_PCI),y)
> > +obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o
> > +endif
> 
> You make it conditional here ...
> 
> > # PowerPC 4xx boards
> > obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
> > obj-ppc-y += ppc440.o ppc440_bamboo.o
> > diff --git a/hw/spapr.c b/hw/spapr.c
> > index 933af32..bdaa938 100644
> > --- a/hw/spapr.c
> > +++ b/hw/spapr.c
> > @@ -39,10 +39,12 @@
> > 
> > #include "hw/spapr.h"
> > #include "hw/spapr_vio.h"
> > +#include "hw/spapr_pci.h"
> > #include "hw/xics.h"
> > 
> > #include "kvm.h"
> > #include "kvm_ppc.h"
> > +#include "pci.h"
> 
> ... but not here. Just throw away the condition above. We don't need
> to support -M pseries without PCI.

Good point, revision in next version.

[snip]
> > +    spapr_rtas_register("read-pci-config", rtas_read_pci_config);
> > +    spapr_rtas_register("write-pci-config", rtas_write_pci_config);
> > +    spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
> > +    spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
> > +
> > +    /*
> > +     * This is a workaround to disable PCI devices resetting as we do
> > +     * BAR allocation on the QEMU side and reset destroys this
> > +     * configuration.
> > +     */
> > +    bus->qbus.info->reset = NULL;
> 
> Eh. What? So you're breaking reset for all PCI devices? How do you
> reboot?

Oops.  That leaked in fromt he patch which adds PCI BAR allocation
(it's a workaround for the reset clobbering our allocations which we
haven't had a chance to fix properly yet).  Put back where it belongs
now.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

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

end of thread, other threads:[~2011-10-31  1:49 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-28  1:56 [Qemu-devel] [0/3] Bugfixes and updates for pseries David Gibson
2011-10-28  1:56 ` [Qemu-devel] [PATCH 1/3] ppc: Correctly handle errors reading ibm, vmx and ibm, dfp properties David Gibson
2011-10-30 16:53   ` Alexander Graf
2011-10-31  0:01     ` [Qemu-devel] [Qemu-ppc] " David Gibson
2011-10-28  1:56 ` [Qemu-devel] [PATCH 2/3] pseries: Allow writes to KVM accelerated TCE table David Gibson
2011-10-30 17:07   ` Alexander Graf
2011-10-28  1:56 ` [Qemu-devel] [PATCH 3/3] pseries: Add partial support for PCI David Gibson
2011-10-30 17:06   ` Alexander Graf
2011-10-31  1:48     ` [Qemu-devel] [Qemu-ppc] " David Gibson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).