Merge branch 'ppc-for-upstream' of git://repo.or.cz/qemu/agraf

* 'ppc-for-upstream' of git://repo.or.cz/qemu/agraf: (40 commits)
  pseries: Increase default NVRAM size
  target-ppc: Don't use hwaddr to represent hardware state
  PPC: e500: pci: Export slot2irq calculation
  PPC: E500plat: Make a lot of PCI slots available
  PPC: E500: Move PCI slot information into params
  PPC: E500: Generate dt pci irq map dynamically
  PPC: E500: PCI: Make IRQ calculation more generic
  PPC: E500: PCI: Make first slot qdev settable
  openpic: Accelerate pending irq search
  openpic: fix minor coding style issues
  MSI-X: Fix endianness
  PPC: e500: Declare pci bridge as bridge
  PPC: e500: Add MSI support
  openpic: add Shared MSI support
  openpic: make brr1 model specific
  openpic: convert to qdev
  openpic: remove irq_out
  openpic: rename openpic_t to OpenPICState
  openpic: convert simple reg operations to builtin bitops
  openpic: remove unused type variable
  ...
This commit is contained in:
Blue Swirl 2012-12-15 09:05:26 +00:00
commit 6d4e18925a
25 changed files with 1061 additions and 1026 deletions

View File

@ -180,8 +180,7 @@ static void msix_table_mmio_write(void *opaque, hwaddr addr,
static const MemoryRegionOps msix_table_mmio_ops = { static const MemoryRegionOps msix_table_mmio_ops = {
.read = msix_table_mmio_read, .read = msix_table_mmio_read,
.write = msix_table_mmio_write, .write = msix_table_mmio_write,
/* TODO: MSIX should be LITTLE_ENDIAN. */ .endianness = DEVICE_LITTLE_ENDIAN,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid = { .valid = {
.min_access_size = 4, .min_access_size = 4,
.max_access_size = 4, .max_access_size = 4,
@ -198,8 +197,7 @@ static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
static const MemoryRegionOps msix_pba_mmio_ops = { static const MemoryRegionOps msix_pba_mmio_ops = {
.read = msix_pba_mmio_read, .read = msix_pba_mmio_read,
/* TODO: MSIX should be LITTLE_ENDIAN. */ .endianness = DEVICE_LITTLE_ENDIAN,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid = { .valid = {
.min_access_size = 4, .min_access_size = 4,
.max_access_size = 4, .max_access_size = 4,

File diff suppressed because it is too large Load Diff

View File

@ -11,8 +11,7 @@ enum {
OPENPIC_OUTPUT_NB, OPENPIC_OUTPUT_NB,
}; };
qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus, #define OPENPIC_MODEL_RAVEN 0
qemu_irq **irqs, qemu_irq irq_out); #define OPENPIC_MODEL_FSL_MPIC_20 1
qemu_irq *mpic_init (MemoryRegion *address_space, hwaddr base,
int nb_cpus, qemu_irq **irqs, qemu_irq irq_out);
#endif /* __OPENPIC_H__ */ #endif /* __OPENPIC_H__ */

View File

@ -11,7 +11,7 @@ obj-y += ppc_newworld.o
obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o
obj-$(CONFIG_PSERIES) += spapr_events.o obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o
# PowerPC 4xx boards # PowerPC 4xx boards
obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
obj-y += ppc440_bamboo.o obj-y += ppc440_bamboo.o

17
hw/ppc/e500-ccsr.h Normal file
View File

@ -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 */

View File

@ -17,6 +17,7 @@
#include "config.h" #include "config.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "e500.h" #include "e500.h"
#include "e500-ccsr.h"
#include "net.h" #include "net.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/serial.h" #include "hw/serial.h"
@ -33,6 +34,7 @@
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "exec-memory.h" #include "exec-memory.h"
#include "host-utils.h" #include "host-utils.h"
#include "hw/ppce500_pci.h"
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
#define UIMAGE_LOAD_BASE 0 #define UIMAGE_LOAD_BASE 0
@ -46,13 +48,16 @@
/* TODO: parameterize */ /* TODO: parameterize */
#define MPC8544_CCSRBAR_BASE 0xE0000000ULL #define MPC8544_CCSRBAR_BASE 0xE0000000ULL
#define MPC8544_CCSRBAR_SIZE 0x00100000ULL #define MPC8544_CCSRBAR_SIZE 0x00100000ULL
#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000ULL) #define MPC8544_MPIC_REGS_OFFSET 0x40000ULL
#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500ULL) #define MPC8544_MSI_REGS_OFFSET 0x41600ULL
#define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600ULL) #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000ULL) #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
#define MPC8544_PCI_REGS_OFFSET 0x8000ULL
#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + \
MPC8544_PCI_REGS_OFFSET)
#define MPC8544_PCI_REGS_SIZE 0x1000ULL #define MPC8544_PCI_REGS_SIZE 0x1000ULL
#define MPC8544_PCI_IO 0xE1000000ULL #define MPC8544_PCI_IO 0xE1000000ULL
#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000ULL) #define MPC8544_UTIL_OFFSET 0xe0000ULL
#define MPC8544_SPIN_BASE 0xEF000000ULL #define MPC8544_SPIN_BASE 0xEF000000ULL
struct boot_info struct boot_info
@ -62,27 +67,37 @@ struct boot_info
uint32_t entry; uint32_t entry;
}; };
static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic) static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
int nr_slots, int *len)
{ {
int i; int i = 0;
const uint32_t tmp[] = { int slot;
/* IDSEL 0x11 J17 Slot 1 */ int pci_irq;
0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, int host_irq;
0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, int last_slot = first_slot + nr_slots;
0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, uint32_t *pci_map;
0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
/* IDSEL 0x12 J16 Slot 2 */ *len = nr_slots * 4 * 7 * sizeof(uint32_t);
0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, pci_map = g_malloc(*len);
0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, for (slot = first_slot; slot < last_slot; slot++) {
0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, for (pci_irq = 0; pci_irq < 4; pci_irq++) {
}; pci_map[i++] = cpu_to_be32(slot << 11);
for (i = 0; i < (7 * 8); i++) { pci_map[i++] = cpu_to_be32(0x0);
pci_map[i] = cpu_to_be32(tmp[i]); pci_map[i++] = cpu_to_be32(0x0);
pci_map[i++] = cpu_to_be32(pci_irq + 1);
pci_map[i++] = cpu_to_be32(mpic);
host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
pci_map[i++] = cpu_to_be32(host_irq + 1);
pci_map[i++] = cpu_to_be32(0x1);
} }
} }
assert((i * sizeof(uint32_t)) == *len);
return pci_map;
}
static void dt_serial_create(void *fdt, unsigned long long offset, static void dt_serial_create(void *fdt, unsigned long long offset,
const char *soc, const char *mpic, const char *soc, const char *mpic,
const char *alias, int idx, bool defcon) const char *alias, int idx, bool defcon)
@ -124,9 +139,12 @@ static int ppce500_load_device_tree(CPUPPCState *env,
char soc[128]; char soc[128];
char mpic[128]; char mpic[128];
uint32_t mpic_ph; uint32_t mpic_ph;
uint32_t msi_ph;
char gutil[128]; char gutil[128];
char pci[128]; char pci[128];
uint32_t pci_map[7 * 8]; char msi[128];
uint32_t *pci_map = NULL;
int len;
uint32_t pci_ranges[14] = uint32_t pci_ranges[14] =
{ {
0x2000000, 0x0, 0xc0000000, 0x2000000, 0x0, 0xc0000000,
@ -267,13 +285,12 @@ static int ppce500_load_device_tree(CPUPPCState *env,
/* XXX should contain a reasonable value */ /* XXX should contain a reasonable value */
qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, mpic); qemu_devtree_add_subnode(fdt, mpic);
qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic"); qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic"); qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE - qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
MPC8544_CCSRBAR_BASE, 0x40000); 0x40000);
qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0); qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2); qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
mpic_ph = qemu_devtree_alloc_phandle(fdt); mpic_ph = qemu_devtree_alloc_phandle(fdt);
@ -286,19 +303,37 @@ static int ppce500_load_device_tree(CPUPPCState *env,
* device it finds in the dt as serial output device. And we generate * device it finds in the dt as serial output device. And we generate
* devices in reverse order to the dt. * devices in reverse order to the dt.
*/ */
dt_serial_create(fdt, MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE, dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
soc, mpic, "serial1", 1, false); soc, mpic, "serial1", 1, false);
dt_serial_create(fdt, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE, dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
soc, mpic, "serial0", 0, true); soc, mpic, "serial0", 0, true);
snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE); MPC8544_UTIL_OFFSET);
qemu_devtree_add_subnode(fdt, gutil); qemu_devtree_add_subnode(fdt, gutil);
qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE - qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
MPC8544_CCSRBAR_BASE, 0x1000);
qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
qemu_devtree_add_subnode(fdt, msi);
qemu_devtree_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
qemu_devtree_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
msi_ph = qemu_devtree_alloc_phandle(fdt);
qemu_devtree_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
qemu_devtree_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
qemu_devtree_setprop_cells(fdt, msi, "interrupts",
0xe0, 0x0,
0xe1, 0x0,
0xe2, 0x0,
0xe3, 0x0,
0xe4, 0x0,
0xe5, 0x0,
0xe6, 0x0,
0xe7, 0x0);
qemu_devtree_setprop_cell(fdt, msi, "phandle", msi_ph);
qemu_devtree_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE); snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
qemu_devtree_add_subnode(fdt, pci); qemu_devtree_add_subnode(fdt, pci);
qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0); qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
@ -306,14 +341,17 @@ static int ppce500_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop_string(fdt, pci, "device_type", "pci"); qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
0x0, 0x7); 0x0, 0x7);
pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic)); pci_map = pci_map_create(fdt, qemu_devtree_get_phandle(fdt, mpic),
qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map)); params->pci_first_slot, params->pci_nr_slots,
&len);
qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, len);
qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic); qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2); qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255); qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
for (i = 0; i < 14; i++) { for (i = 0; i < 14; i++) {
pci_ranges[i] = cpu_to_be32(pci_ranges[i]); pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
} }
qemu_devtree_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
MPC8544_PCI_REGS_BASE, 0, 0x1000); MPC8544_PCI_REGS_BASE, 0, 0x1000);
@ -340,6 +378,7 @@ done:
ret = fdt_size; ret = fdt_size;
out: out:
g_free(pci_map);
return ret; return ret;
} }
@ -417,11 +456,14 @@ void ppce500_init(PPCE500Params *params)
target_ulong dt_base = 0; target_ulong dt_base = 0;
target_ulong initrd_base = 0; target_ulong initrd_base = 0;
target_long initrd_size=0; target_long initrd_size=0;
int i=0; int i = 0, j, k;
unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
qemu_irq **irqs, *mpic; qemu_irq **irqs, *mpic;
DeviceState *dev; DeviceState *dev;
CPUPPCState *firstenv = NULL; CPUPPCState *firstenv = NULL;
MemoryRegion *ccsr_addr_space;
SysBusDevice *s;
PPCE500CCSRState *ccsr;
/* Setup CPUs */ /* Setup CPUs */
if (params->cpu_model == NULL) { if (params->cpu_model == NULL) {
@ -450,7 +492,8 @@ void ppce500_init(PPCE500Params *params)
irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
env->mpic_cpu_base = MPC8544_MPIC_REGS_BASE + 0x20000; env->mpic_cpu_base = MPC8544_CCSRBAR_BASE +
MPC8544_MPIC_REGS_OFFSET + 0x20000;
ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500); ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
@ -477,35 +520,69 @@ void ppce500_init(PPCE500Params *params)
vmstate_register_ram_global(ram); vmstate_register_ram_global(ram);
memory_region_add_subregion(address_space_mem, 0, ram); memory_region_add_subregion(address_space_mem, 0, ram);
/* MPIC */ dev = qdev_create(NULL, "e500-ccsr");
mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE, object_property_add_child(qdev_get_machine(), "e500-ccsr",
smp_cpus, irqs, NULL); 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);
if (!mpic) { /* MPIC */
cpu_abort(env, "MPIC failed to initialize\n"); mpic = g_new(qemu_irq, 256);
dev = qdev_create(NULL, "openpic");
qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_FSL_MPIC_20);
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
k = 0;
for (i = 0; i < smp_cpus; i++) {
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
sysbus_connect_irq(s, k++, irqs[i][j]);
} }
}
for (i = 0; i < 256; i++) {
mpic[i] = qdev_get_gpio_in(dev, i);
}
memory_region_add_subregion(ccsr_addr_space, MPC8544_MPIC_REGS_OFFSET,
s->mmio[0].memory);
/* Serial */ /* Serial */
if (serial_hds[0]) { if (serial_hds[0]) {
serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE, serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
0, mpic[12+26], 399193, 0, mpic[42], 399193,
serial_hds[0], DEVICE_BIG_ENDIAN); serial_hds[0], DEVICE_BIG_ENDIAN);
} }
if (serial_hds[1]) { if (serial_hds[1]) {
serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE, serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
0, mpic[12+26], 399193, 0, mpic[42], 399193,
serial_hds[1], DEVICE_BIG_ENDIAN); serial_hds[1], DEVICE_BIG_ENDIAN);
} }
/* General Utility device */ /* General Utility device */
sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL); dev = qdev_create(NULL, "mpc8544-guts");
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
sysbus_mmio_get_region(s, 0));
/* PCI */ /* PCI */
dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE, dev = qdev_create(NULL, "e500-pcihost");
mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]], qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]], qdev_init_nofail(dev);
NULL); s = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(s, 0, mpic[pci_irq_nrs[0]]);
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_addr_space, MPC8544_PCI_REGS_OFFSET,
sysbus_mmio_get_region(s, 0));
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
if (!pci_bus) if (!pci_bus)
printf("couldn't create PCI controller!\n"); printf("couldn't create PCI controller!\n");
@ -578,3 +655,33 @@ void ppce500_init(PPCE500Params *params)
kvmppc_init(); 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)

View File

@ -9,6 +9,8 @@ typedef struct PPCE500Params {
const char *kernel_cmdline; const char *kernel_cmdline;
const char *initrd_filename; const char *initrd_filename;
const char *cpu_model; const char *cpu_model;
int pci_first_slot;
int pci_nr_slots;
/* e500-specific params */ /* e500-specific params */

View File

@ -14,6 +14,7 @@
#include "e500.h" #include "e500.h"
#include "../boards.h" #include "../boards.h"
#include "device_tree.h" #include "device_tree.h"
#include "hw/pci.h"
static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt) static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
{ {
@ -40,6 +41,8 @@ static void e500plat_init(QEMUMachineInitArgs *args)
.kernel_cmdline = kernel_cmdline, .kernel_cmdline = kernel_cmdline,
.initrd_filename = initrd_filename, .initrd_filename = initrd_filename,
.cpu_model = cpu_model, .cpu_model = cpu_model,
.pci_first_slot = 0x1,
.pci_nr_slots = PCI_SLOT_MAX - 1,
.fixup_devtree = e500plat_fixup_devtree, .fixup_devtree = e500plat_fixup_devtree,
}; };

View File

@ -40,6 +40,8 @@ static void mpc8544ds_init(QEMUMachineInitArgs *args)
.kernel_cmdline = kernel_cmdline, .kernel_cmdline = kernel_cmdline,
.initrd_filename = initrd_filename, .initrd_filename = initrd_filename,
.cpu_model = cpu_model, .cpu_model = cpu_model,
.pci_first_slot = 0x11,
.pci_nr_slots = 2,
.fixup_devtree = mpc8544ds_fixup_devtree, .fixup_devtree = mpc8544ds_fixup_devtree,
}; };

View File

@ -67,6 +67,7 @@
#include "hw/usb.h" #include "hw/usb.h"
#include "blockdev.h" #include "blockdev.h"
#include "exec-memory.h" #include "exec-memory.h"
#include "sysbus.h"
#define MAX_IDE_BUS 2 #define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510 #define CFG_ADDR 0xf0000510
@ -141,7 +142,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
char *filename; char *filename;
qemu_irq *pic, **openpic_irqs; qemu_irq *pic, **openpic_irqs;
MemoryRegion *unin_memory = g_new(MemoryRegion, 1); MemoryRegion *unin_memory = g_new(MemoryRegion, 1);
int linux_boot, i; int linux_boot, i, j, k;
MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1); MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1);
hwaddr kernel_base, initrd_base, cmdline_base = 0; hwaddr kernel_base, initrd_base, cmdline_base = 0;
long kernel_size, initrd_size; long kernel_size, initrd_size;
@ -156,6 +157,8 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
void *fw_cfg; void *fw_cfg;
void *dbdma; void *dbdma;
int machine_arch; int machine_arch;
SysBusDevice *s;
DeviceState *dev;
linux_boot = (kernel_filename != NULL); linux_boot = (kernel_filename != NULL);
@ -320,7 +323,25 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
exit(1); exit(1);
} }
} }
pic = openpic_init(&pic_mem, smp_cpus, openpic_irqs, NULL);
pic = g_new(qemu_irq, 64);
dev = qdev_create(NULL, "openpic");
qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_RAVEN);
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
pic_mem = s->mmio[0].memory;
k = 0;
for (i = 0; i < smp_cpus; i++) {
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
sysbus_connect_irq(s, k++, openpic_irqs[i][j]);
}
}
for (i = 0; i < 64; i++) {
pic[i] = qdev_get_gpio_in(dev, i);
}
if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) { if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
/* 970 gets a U3 bus */ /* 970 gets a U3 bus */
pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io()); pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());

View File

@ -15,9 +15,11 @@
*/ */
#include "hw.h" #include "hw.h"
#include "hw/ppc/e500-ccsr.h"
#include "pci.h" #include "pci.h"
#include "pci_host.h" #include "pci_host.h"
#include "bswap.h" #include "bswap.h"
#include "ppce500_pci.h"
#ifdef DEBUG_PCI #ifdef DEBUG_PCI
#define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) #define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
@ -86,12 +88,26 @@ struct PPCE500PCIState {
struct pci_inbound pib[PPCE500_PCI_NR_PIBS]; struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
uint32_t gasket_time; uint32_t gasket_time;
qemu_irq irq[4]; qemu_irq irq[4];
uint32_t first_slot;
/* mmio maps */ /* mmio maps */
MemoryRegion container; MemoryRegion container;
MemoryRegion iomem; MemoryRegion iomem;
MemoryRegion pio; MemoryRegion pio;
}; };
#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; typedef struct PPCE500PCIState PPCE500PCIState;
static uint64_t pci_reg_read4(void *opaque, hwaddr addr, static uint64_t pci_reg_read4(void *opaque, hwaddr addr,
@ -238,17 +254,10 @@ static const MemoryRegionOps e500_pci_reg_ops = {
static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num) static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
{ {
int devno = pci_dev->devfn >> 3, ret = 0; int devno = pci_dev->devfn >> 3;
int ret;
switch (devno) { ret = ppce500_pci_map_irq_slot(devno, irq_num);
/* Two PCI slot */
case 0x11:
case 0x12:
ret = (irq_num + devno - 0x10) % 4;
break;
default:
printf("Error:%s:unknown dev number\n", __func__);
}
pci_debug("%s: devfn %x irq %d -> %d devno:%x\n", __func__, pci_debug("%s: devfn %x irq %d -> %d devno:%x\n", __func__,
pci_dev->devfn, irq_num, ret, devno); pci_dev->devfn, irq_num, ret, devno);
@ -310,6 +319,24 @@ static const VMStateDescription vmstate_ppce500_pci = {
#include "exec-memory.h" #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"));
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
d->config[PCI_HEADER_TYPE] =
(d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
PCI_HEADER_TYPE_BRIDGE;
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) static int e500_pcihost_initfn(SysBusDevice *dev)
{ {
PCIHostState *h; PCIHostState *h;
@ -329,7 +356,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq, b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
mpc85xx_pci_map_irq, s->irq, address_space_mem, mpc85xx_pci_map_irq, s->irq, address_space_mem,
&s->pio, PCI_DEVFN(0x11, 0), 4); &s->pio, PCI_DEVFN(s->first_slot, 0), 4);
h->bus = b; h->bus = b;
pci_create_simple(b, 0, "e500-host-bridge"); pci_create_simple(b, 0, "e500-host-bridge");
@ -355,6 +382,7 @@ static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = e500_pcihost_bridge_initfn;
k->vendor_id = PCI_VENDOR_ID_FREESCALE; k->vendor_id = PCI_VENDOR_ID_FREESCALE;
k->device_id = PCI_DEVICE_ID_MPC8533E; k->device_id = PCI_DEVICE_ID_MPC8533E;
k->class_id = PCI_CLASS_PROCESSOR_POWERPC; k->class_id = PCI_CLASS_PROCESSOR_POWERPC;
@ -364,16 +392,22 @@ static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
static const TypeInfo e500_host_bridge_info = { static const TypeInfo e500_host_bridge_info = {
.name = "e500-host-bridge", .name = "e500-host-bridge",
.parent = TYPE_PCI_DEVICE, .parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice), .instance_size = sizeof(PPCE500PCIBridgeState),
.class_init = e500_host_bridge_class_init, .class_init = e500_host_bridge_class_init,
}; };
static Property pcihost_properties[] = {
DEFINE_PROP_UINT32("first_slot", PPCE500PCIState, first_slot, 0x11),
DEFINE_PROP_END_OF_LIST(),
};
static void e500_pcihost_class_init(ObjectClass *klass, void *data) static void e500_pcihost_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
k->init = e500_pcihost_initfn; k->init = e500_pcihost_initfn;
dc->props = pcihost_properties;
dc->vmsd = &vmstate_ppce500_pci; dc->vmsd = &vmstate_ppce500_pci;
} }

9
hw/ppce500_pci.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef PPCE500_PCI_H
#define PPCE500_PCI_H
static inline int ppce500_pci_map_irq_slot(int devno, int irq_num)
{
return (devno + irq_num) % 4;
}
#endif

View File

@ -657,6 +657,36 @@ static void spapr_cpu_reset(void *opaque)
(spapr->htab_shift - 18); (spapr->htab_shift - 18);
} }
static void spapr_create_nvram(sPAPREnvironment *spapr)
{
QemuOpts *machine_opts;
DeviceState *dev;
dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
if (machine_opts) {
const char *drivename;
drivename = qemu_opt_get(machine_opts, "nvram");
if (drivename) {
BlockDriverState *bs;
bs = bdrv_find(drivename);
if (!bs) {
fprintf(stderr, "No such block device \"%s\" for nvram\n",
drivename);
exit(1);
}
qdev_prop_set_drive_nofail(dev, "drive", bs);
}
}
qdev_init_nofail(dev);
spapr->nvram = (struct sPAPRNVRAM *)dev;
}
/* Returns whether we want to use VGA or not */ /* Returns whether we want to use VGA or not */
static int spapr_vga_init(PCIBus *pci_bus) static int spapr_vga_init(PCIBus *pci_bus)
{ {
@ -801,7 +831,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
/* Set up Interrupt Controller */ /* Set up Interrupt Controller */
spapr->icp = xics_system_init(XICS_IRQS); spapr->icp = xics_system_init(XICS_IRQS);
spapr->next_irq = 16; spapr->next_irq = XICS_IRQ_BASE;
/* Set up EPOW events infrastructure */ /* Set up EPOW events infrastructure */
spapr_events_init(spapr); spapr_events_init(spapr);
@ -818,6 +848,9 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
} }
} }
/* We always have at least the nvram device on VIO */
spapr_create_nvram(spapr);
/* Set up PCI */ /* Set up PCI */
spapr_pci_rtas_init(); spapr_pci_rtas_init();

View File

@ -6,11 +6,13 @@
struct VIOsPAPRBus; struct VIOsPAPRBus;
struct sPAPRPHBState; struct sPAPRPHBState;
struct sPAPRNVRAM;
struct icp_state; struct icp_state;
typedef struct sPAPREnvironment { typedef struct sPAPREnvironment {
struct VIOsPAPRBus *vio_bus; struct VIOsPAPRBus *vio_bus;
QLIST_HEAD(, sPAPRPHBState) phbs; QLIST_HEAD(, sPAPRPHBState) phbs;
struct sPAPRNVRAM *nvram;
struct icp_state *icp; struct icp_state *icp;
hwaddr ram_limit; hwaddr ram_limit;
@ -320,7 +322,7 @@ static inline void rtas_st(target_ulong phys, int n, uint32_t val)
typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token, typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token,
uint32_t nargs, target_ulong args, uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets); uint32_t nret, target_ulong rets);
void spapr_rtas_register(const char *name, spapr_rtas_fn fn); int spapr_rtas_register(const char *name, spapr_rtas_fn fn);
target_ulong spapr_rtas_call(sPAPREnvironment *spapr, target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs, target_ulong args, uint32_t token, uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets); uint32_t nret, target_ulong rets);

View File

@ -120,6 +120,12 @@ DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size)
{ {
sPAPRTCETable *tcet; sPAPRTCETable *tcet;
if (spapr_tce_find_by_liobn(liobn)) {
fprintf(stderr, "Attempted to create TCE table with duplicate"
" LIOBN 0x%x\n", liobn);
return NULL;
}
if (!window_size) { if (!window_size) {
return NULL; return NULL;
} }

196
hw/spapr_nvram.c Normal file
View File

@ -0,0 +1,196 @@
/*
* QEMU sPAPR NVRAM emulation
*
* Copyright (C) 2012 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 <sys/mman.h>
#include <libfdt.h>
#include "device_tree.h"
#include "hw/sysbus.h"
#include "hw/spapr.h"
#include "hw/spapr_vio.h"
typedef struct sPAPRNVRAM {
VIOsPAPRDevice sdev;
uint32_t size;
uint8_t *buf;
BlockDriverState *drive;
} sPAPRNVRAM;
#define MIN_NVRAM_SIZE 8192
#define DEFAULT_NVRAM_SIZE 65536
#define MAX_NVRAM_SIZE (UINT16_MAX * 16)
static void rtas_nvram_fetch(sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
sPAPRNVRAM *nvram = spapr->nvram;
hwaddr offset, buffer, len;
int alen;
void *membuf;
if ((nargs != 3) || (nret != 2)) {
rtas_st(rets, 0, -3);
return;
}
if (!nvram) {
rtas_st(rets, 0, -1);
rtas_st(rets, 1, 0);
return;
}
offset = rtas_ld(args, 0);
buffer = rtas_ld(args, 1);
len = rtas_ld(args, 2);
if (((offset + len) < offset)
|| ((offset + len) > nvram->size)) {
rtas_st(rets, 0, -3);
rtas_st(rets, 1, 0);
return;
}
membuf = cpu_physical_memory_map(buffer, &len, 1);
if (nvram->drive) {
alen = bdrv_pread(nvram->drive, offset, membuf, len);
} else {
assert(nvram->buf);
memcpy(membuf, nvram->buf + offset, len);
alen = len;
}
cpu_physical_memory_unmap(membuf, len, 1, len);
rtas_st(rets, 0, (alen < len) ? -1 : 0);
rtas_st(rets, 1, (alen < 0) ? 0 : alen);
}
static void rtas_nvram_store(sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
sPAPRNVRAM *nvram = spapr->nvram;
hwaddr offset, buffer, len;
int alen;
void *membuf;
if ((nargs != 3) || (nret != 2)) {
rtas_st(rets, 0, -3);
return;
}
if (!nvram) {
rtas_st(rets, 0, -1);
return;
}
offset = rtas_ld(args, 0);
buffer = rtas_ld(args, 1);
len = rtas_ld(args, 2);
if (((offset + len) < offset)
|| ((offset + len) > nvram->size)) {
rtas_st(rets, 0, -3);
return;
}
membuf = cpu_physical_memory_map(buffer, &len, 0);
if (nvram->drive) {
alen = bdrv_pwrite(nvram->drive, offset, membuf, len);
} else {
assert(nvram->buf);
memcpy(nvram->buf + offset, membuf, len);
alen = len;
}
cpu_physical_memory_unmap(membuf, len, 0, len);
rtas_st(rets, 0, (alen < len) ? -1 : 0);
rtas_st(rets, 1, (alen < 0) ? 0 : alen);
}
static int spapr_nvram_init(VIOsPAPRDevice *dev)
{
sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev;
if (nvram->drive) {
nvram->size = bdrv_getlength(nvram->drive);
} else {
nvram->size = DEFAULT_NVRAM_SIZE;
nvram->buf = g_malloc0(nvram->size);
}
if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {
fprintf(stderr, "spapr-nvram must be between %d and %d bytes in size\n",
MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
return -1;
}
spapr_rtas_register("nvram-fetch", rtas_nvram_fetch);
spapr_rtas_register("nvram-store", rtas_nvram_store);
return 0;
}
static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
{
sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev;
return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
}
static Property spapr_nvram_properties[] = {
DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev),
DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, drive),
DEFINE_PROP_END_OF_LIST(),
};
static void spapr_nvram_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->init = spapr_nvram_init;
k->devnode = spapr_nvram_devnode;
k->dt_name = "nvram";
k->dt_type = "nvram";
k->dt_compatible = "qemu,spapr-nvram";
dc->props = spapr_nvram_properties;
}
static const TypeInfo spapr_nvram_type_info = {
.name = "spapr-nvram",
.parent = TYPE_VIO_SPAPR_DEVICE,
.instance_size = sizeof(sPAPRNVRAM),
.class_init = spapr_nvram_class_init,
};
static void spapr_nvram_register_types(void)
{
type_register_static(&spapr_nvram_type_info);
}
type_init(spapr_nvram_register_types)

View File

@ -242,7 +242,7 @@ target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
return H_PARAMETER; return H_PARAMETER;
} }
void spapr_rtas_register(const char *name, spapr_rtas_fn fn) int spapr_rtas_register(const char *name, spapr_rtas_fn fn)
{ {
int i; int i;
@ -258,7 +258,7 @@ void spapr_rtas_register(const char *name, spapr_rtas_fn fn)
rtas_next->name = name; rtas_next->name = name;
rtas_next->fn = fn; rtas_next->fn = fn;
rtas_next++; return (rtas_next++ - rtas_table) + TOKEN_BASE;
} }
int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
@ -301,7 +301,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
for (i = 0; i < TOKEN_MAX; i++) { for (i = 0; i < TOKEN_MAX; i++) {
struct rtas_call *call = &rtas_table[i]; struct rtas_call *call = &rtas_table[i];
if (!call->fn) { if (!call->name) {
continue; continue;
} }

View File

@ -26,6 +26,7 @@
*/ */
#include "hw.h" #include "hw.h"
#include "trace.h"
#include "hw/spapr.h" #include "hw/spapr.h"
#include "hw/xics.h" #include "hw/xics.h"
@ -66,6 +67,8 @@ static void icp_check_ipi(struct icp_state *icp, int server)
return; return;
} }
trace_xics_icp_check_ipi(server, ss->mfrr);
if (XISR(ss)) { if (XISR(ss)) {
ics_reject(icp->ics, XISR(ss)); ics_reject(icp->ics, XISR(ss));
} }
@ -120,11 +123,13 @@ static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr)
static uint32_t icp_accept(struct icp_server_state *ss) static uint32_t icp_accept(struct icp_server_state *ss)
{ {
uint32_t xirr; uint32_t xirr = ss->xirr;
qemu_irq_lower(ss->output); qemu_irq_lower(ss->output);
xirr = ss->xirr;
ss->xirr = ss->pending_priority << 24; ss->xirr = ss->pending_priority << 24;
trace_xics_icp_accept(xirr, ss->xirr);
return xirr; return xirr;
} }
@ -134,6 +139,7 @@ static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
/* Send EOI -> ICS */ /* Send EOI -> ICS */
ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
trace_xics_icp_eoi(server, xirr, ss->xirr);
ics_eoi(icp->ics, xirr & XISR_MASK); ics_eoi(icp->ics, xirr & XISR_MASK);
if (!XISR(ss)) { if (!XISR(ss)) {
icp_resend(icp, server); icp_resend(icp, server);
@ -144,6 +150,8 @@ static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
{ {
struct icp_server_state *ss = icp->ss + server; struct icp_server_state *ss = icp->ss + server;
trace_xics_icp_irq(server, nr, priority);
if ((priority >= CPPR(ss)) if ((priority >= CPPR(ss))
|| (XISR(ss) && (ss->pending_priority <= priority))) { || (XISR(ss) && (ss->pending_priority <= priority))) {
ics_reject(icp->ics, nr); ics_reject(icp->ics, nr);
@ -153,6 +161,7 @@ static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
} }
ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
ss->pending_priority = priority; ss->pending_priority = priority;
trace_xics_icp_raise(ss->xirr, ss->pending_priority);
qemu_irq_raise(ss->output); qemu_irq_raise(ss->output);
} }
} }
@ -170,13 +179,13 @@ struct ics_irq_state {
#define XICS_STATUS_REJECTED 0x4 #define XICS_STATUS_REJECTED 0x4
#define XICS_STATUS_MASKED_PENDING 0x8 #define XICS_STATUS_MASKED_PENDING 0x8
uint8_t status; uint8_t status;
bool lsi;
}; };
struct ics_state { struct ics_state {
int nr_irqs; int nr_irqs;
int offset; int offset;
qemu_irq *qirqs; qemu_irq *qirqs;
bool *islsi;
struct ics_irq_state *irqs; struct ics_irq_state *irqs;
struct icp_state *icp; struct icp_state *icp;
}; };
@ -217,10 +226,12 @@ static void set_irq_msi(struct ics_state *ics, int srcno, int val)
{ {
struct ics_irq_state *irq = ics->irqs + srcno; struct ics_irq_state *irq = ics->irqs + srcno;
trace_xics_set_irq_msi(srcno, srcno + ics->offset);
if (val) { if (val) {
if (irq->priority == 0xff) { if (irq->priority == 0xff) {
irq->status |= XICS_STATUS_MASKED_PENDING; irq->status |= XICS_STATUS_MASKED_PENDING;
/* masked pending */ ; trace_xics_masked_pending();
} else { } else {
icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
} }
@ -231,6 +242,7 @@ static void set_irq_lsi(struct ics_state *ics, int srcno, int val)
{ {
struct ics_irq_state *irq = ics->irqs + srcno; struct ics_irq_state *irq = ics->irqs + srcno;
trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
if (val) { if (val) {
irq->status |= XICS_STATUS_ASSERTED; irq->status |= XICS_STATUS_ASSERTED;
} else { } else {
@ -242,9 +254,8 @@ static void set_irq_lsi(struct ics_state *ics, int srcno, int val)
static void ics_set_irq(void *opaque, int srcno, int val) static void ics_set_irq(void *opaque, int srcno, int val)
{ {
struct ics_state *ics = (struct ics_state *)opaque; struct ics_state *ics = (struct ics_state *)opaque;
struct ics_irq_state *irq = ics->irqs + srcno;
if (irq->lsi) { if (ics->islsi[srcno]) {
set_irq_lsi(ics, srcno, val); set_irq_lsi(ics, srcno, val);
} else { } else {
set_irq_msi(ics, srcno, val); set_irq_msi(ics, srcno, val);
@ -279,7 +290,9 @@ static void ics_write_xive(struct ics_state *ics, int nr, int server,
irq->priority = priority; irq->priority = priority;
irq->saved_priority = saved_priority; irq->saved_priority = saved_priority;
if (irq->lsi) { trace_xics_ics_write_xive(nr, srcno, server, priority);
if (ics->islsi[srcno]) {
write_xive_lsi(ics, srcno); write_xive_lsi(ics, srcno);
} else { } else {
write_xive_msi(ics, srcno); write_xive_msi(ics, srcno);
@ -290,6 +303,7 @@ static void ics_reject(struct ics_state *ics, int nr)
{ {
struct ics_irq_state *irq = ics->irqs + nr - ics->offset; struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
trace_xics_ics_reject(nr, nr - ics->offset);
irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */
irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */
} }
@ -299,10 +313,8 @@ static void ics_resend(struct ics_state *ics)
int i; int i;
for (i = 0; i < ics->nr_irqs; i++) { for (i = 0; i < ics->nr_irqs; i++) {
struct ics_irq_state *irq = ics->irqs + i;
/* FIXME: filter by server#? */ /* FIXME: filter by server#? */
if (irq->lsi) { if (ics->islsi[i]) {
resend_lsi(ics, i); resend_lsi(ics, i);
} else { } else {
resend_msi(ics, i); resend_msi(ics, i);
@ -315,7 +327,9 @@ static void ics_eoi(struct ics_state *ics, int nr)
int srcno = nr - ics->offset; int srcno = nr - ics->offset;
struct ics_irq_state *irq = ics->irqs + srcno; struct ics_irq_state *irq = ics->irqs + srcno;
if (irq->lsi) { trace_xics_ics_eoi(nr);
if (ics->islsi[srcno]) {
irq->status &= ~XICS_STATUS_SENT; irq->status &= ~XICS_STATUS_SENT;
} }
} }
@ -337,7 +351,7 @@ void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi)
{ {
assert(ics_valid_irq(icp->ics, irq)); assert(ics_valid_irq(icp->ics, irq));
icp->ics->irqs[irq - icp->ics->offset].lsi = lsi; icp->ics->islsi[irq - icp->ics->offset] = lsi;
} }
static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr, static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
@ -495,16 +509,14 @@ static void xics_reset(void *opaque)
for (i = 0; i < icp->nr_servers; i++) { for (i = 0; i < icp->nr_servers; i++) {
icp->ss[i].xirr = 0; icp->ss[i].xirr = 0;
icp->ss[i].pending_priority = 0; icp->ss[i].pending_priority = 0xff;
icp->ss[i].mfrr = 0xff; icp->ss[i].mfrr = 0xff;
/* Make all outputs are deasserted */ /* Make all outputs are deasserted */
qemu_set_irq(icp->ss[i].output, 0); qemu_set_irq(icp->ss[i].output, 0);
} }
memset(ics->irqs, 0, sizeof(struct ics_irq_state) * ics->nr_irqs);
for (i = 0; i < ics->nr_irqs; i++) { for (i = 0; i < ics->nr_irqs; i++) {
/* Reset everything *except* the type */
ics->irqs[i].server = 0;
ics->irqs[i].status = 0;
ics->irqs[i].priority = 0xff; ics->irqs[i].priority = 0xff;
ics->irqs[i].saved_priority = 0xff; ics->irqs[i].saved_priority = 0xff;
} }
@ -549,8 +561,9 @@ struct icp_state *xics_system_init(int nr_irqs)
ics = g_malloc0(sizeof(*ics)); ics = g_malloc0(sizeof(*ics));
ics->nr_irqs = nr_irqs; ics->nr_irqs = nr_irqs;
ics->offset = 16; ics->offset = XICS_IRQ_BASE;
ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state)); ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state));
ics->islsi = g_malloc0(nr_irqs * sizeof(bool));
icp->ics = ics; icp->ics = ics;
ics->icp = icp; ics->icp = icp;

View File

@ -28,6 +28,7 @@
#define __XICS_H__ #define __XICS_H__
#define XICS_IPI 0x2 #define XICS_IPI 0x2
#define XICS_IRQ_BASE 0x10
struct icp_state; struct icp_state;

View File

@ -17,7 +17,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at implementation for certain IBM POWER hardware. The sources are at
https://github.com/dgibson/SLOF, and the image currently in qemu is https://github.com/dgibson/SLOF, and the image currently in qemu is
built from git tag qemu-slof-20120731. built from git tag qemu-slof-20121018.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for - sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as legacy x86 software to communicate with an attached serial console as

Binary file not shown.

View File

@ -579,6 +579,10 @@ static QemuOptsList qemu_machine_opts = {
.name = "usb", .name = "usb",
.type = QEMU_OPT_BOOL, .type = QEMU_OPT_BOOL,
.help = "Set on/off to enable/disable usb", .help = "Set on/off to enable/disable usb",
}, {
.name = "nvram",
.type = QEMU_OPT_STRING,
.help = "Drive backing persistent NVRAM",
}, },
{ /* End of list */ } { /* End of list */ }
}, },

@ -1 +1 @@
Subproject commit f21f7a3f46b557eb5923f899ce8b4401b3cc6d91 Subproject commit 0ad10f26c94a86a0c9c3970e53f9a9f6a744055d

View File

@ -355,7 +355,7 @@ struct ppc6xx_tlb_t {
typedef struct ppcemb_tlb_t ppcemb_tlb_t; typedef struct ppcemb_tlb_t ppcemb_tlb_t;
struct ppcemb_tlb_t { struct ppcemb_tlb_t {
hwaddr RPN; uint64_t RPN;
target_ulong EPN; target_ulong EPN;
target_ulong PID; target_ulong PID;
target_ulong size; target_ulong size;

View File

@ -1022,3 +1022,16 @@ spapr_pci_rtas_ibm_change_msi(unsigned func, unsigned req) "func %u, requested %
spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "queries for #%u, IRQ%u" spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "queries for #%u, IRQ%u"
spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u" spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u"
spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u" spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u"
# hw/xics.c
xics_icp_check_ipi(int server, uint8_t mfrr) "CPU %d can take IPI mfrr=%#x"
xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR %#"PRIx32"->%#"PRIx32
xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR %#"PRIx32" new XIRR %#"PRIx32
xics_icp_irq(int server, int nr, uint8_t priority) "cpu %d trying to deliver irq %#"PRIx32" priority %#x"
xics_icp_raise(uint32_t xirr, uint8_t pending_priority) "raising IRQ new XIRR=%#x new pending priority=%#x"
xics_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq %#x]"
xics_masked_pending(void) "set_irq_msi: masked pending"
xics_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq %#x]"
xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq %#x [src %d] server %#x prio %#x"
xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]"
xics_ics_eoi(int nr) "ics_eoi: irq %#x"