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:
commit
6d4e18925a
@ -180,8 +180,7 @@ static void msix_table_mmio_write(void *opaque, hwaddr addr,
|
||||
static const MemoryRegionOps msix_table_mmio_ops = {
|
||||
.read = msix_table_mmio_read,
|
||||
.write = msix_table_mmio_write,
|
||||
/* TODO: MSIX should be LITTLE_ENDIAN. */
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_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 = {
|
||||
.read = msix_pba_mmio_read,
|
||||
/* TODO: MSIX should be LITTLE_ENDIAN. */
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
|
1433
hw/openpic.c
1433
hw/openpic.c
File diff suppressed because it is too large
Load Diff
@ -11,8 +11,7 @@ enum {
|
||||
OPENPIC_OUTPUT_NB,
|
||||
};
|
||||
|
||||
qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
|
||||
qemu_irq **irqs, qemu_irq irq_out);
|
||||
qemu_irq *mpic_init (MemoryRegion *address_space, hwaddr base,
|
||||
int nb_cpus, qemu_irq **irqs, qemu_irq irq_out);
|
||||
#define OPENPIC_MODEL_RAVEN 0
|
||||
#define OPENPIC_MODEL_FSL_MPIC_20 1
|
||||
|
||||
#endif /* __OPENPIC_H__ */
|
||||
|
@ -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) += 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_events.o
|
||||
obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o
|
||||
# PowerPC 4xx boards
|
||||
obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
|
||||
obj-y += ppc440_bamboo.o
|
||||
|
17
hw/ppc/e500-ccsr.h
Normal file
17
hw/ppc/e500-ccsr.h
Normal 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 */
|
205
hw/ppc/e500.c
205
hw/ppc/e500.c
@ -17,6 +17,7 @@
|
||||
#include "config.h"
|
||||
#include "qemu-common.h"
|
||||
#include "e500.h"
|
||||
#include "e500-ccsr.h"
|
||||
#include "net.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/serial.h"
|
||||
@ -33,6 +34,7 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec-memory.h"
|
||||
#include "host-utils.h"
|
||||
#include "hw/ppce500_pci.h"
|
||||
|
||||
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
|
||||
#define UIMAGE_LOAD_BASE 0
|
||||
@ -46,13 +48,16 @@
|
||||
/* TODO: parameterize */
|
||||
#define MPC8544_CCSRBAR_BASE 0xE0000000ULL
|
||||
#define MPC8544_CCSRBAR_SIZE 0x00100000ULL
|
||||
#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000ULL)
|
||||
#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500ULL)
|
||||
#define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600ULL)
|
||||
#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000ULL)
|
||||
#define MPC8544_MPIC_REGS_OFFSET 0x40000ULL
|
||||
#define MPC8544_MSI_REGS_OFFSET 0x41600ULL
|
||||
#define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
|
||||
#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_IO 0xE1000000ULL
|
||||
#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000ULL)
|
||||
#define MPC8544_UTIL_OFFSET 0xe0000ULL
|
||||
#define MPC8544_SPIN_BASE 0xEF000000ULL
|
||||
|
||||
struct boot_info
|
||||
@ -62,25 +67,35 @@ struct boot_info
|
||||
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;
|
||||
const uint32_t tmp[] = {
|
||||
/* IDSEL 0x11 J17 Slot 1 */
|
||||
0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1,
|
||||
0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1,
|
||||
0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1,
|
||||
0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
|
||||
int i = 0;
|
||||
int slot;
|
||||
int pci_irq;
|
||||
int host_irq;
|
||||
int last_slot = first_slot + nr_slots;
|
||||
uint32_t *pci_map;
|
||||
|
||||
/* IDSEL 0x12 J16 Slot 2 */
|
||||
0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1,
|
||||
0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
|
||||
0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1,
|
||||
0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
|
||||
};
|
||||
for (i = 0; i < (7 * 8); i++) {
|
||||
pci_map[i] = cpu_to_be32(tmp[i]);
|
||||
*len = nr_slots * 4 * 7 * sizeof(uint32_t);
|
||||
pci_map = g_malloc(*len);
|
||||
|
||||
for (slot = first_slot; slot < last_slot; slot++) {
|
||||
for (pci_irq = 0; pci_irq < 4; pci_irq++) {
|
||||
pci_map[i++] = cpu_to_be32(slot << 11);
|
||||
pci_map[i++] = cpu_to_be32(0x0);
|
||||
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,
|
||||
@ -124,9 +139,12 @@ static int ppce500_load_device_tree(CPUPPCState *env,
|
||||
char soc[128];
|
||||
char mpic[128];
|
||||
uint32_t mpic_ph;
|
||||
uint32_t msi_ph;
|
||||
char gutil[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] =
|
||||
{
|
||||
0x2000000, 0x0, 0xc0000000,
|
||||
@ -267,13 +285,12 @@ static int ppce500_load_device_tree(CPUPPCState *env,
|
||||
/* XXX should contain a reasonable value */
|
||||
qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
|
||||
|
||||
snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc,
|
||||
MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
|
||||
snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
|
||||
qemu_devtree_add_subnode(fdt, mpic);
|
||||
qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
|
||||
qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
|
||||
qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
|
||||
MPC8544_CCSRBAR_BASE, 0x40000);
|
||||
qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
|
||||
0x40000);
|
||||
qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
|
||||
qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
|
||||
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
|
||||
* 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);
|
||||
dt_serial_create(fdt, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE,
|
||||
dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
|
||||
soc, mpic, "serial0", 0, true);
|
||||
|
||||
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_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
|
||||
qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE -
|
||||
MPC8544_CCSRBAR_BASE, 0x1000);
|
||||
qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
|
||||
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);
|
||||
qemu_devtree_add_subnode(fdt, pci);
|
||||
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_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
|
||||
0x0, 0x7);
|
||||
pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
|
||||
qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
|
||||
pci_map = pci_map_create(fdt, qemu_devtree_get_phandle(fdt, mpic),
|
||||
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_cells(fdt, pci, "interrupts", 24, 2);
|
||||
qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
|
||||
for (i = 0; i < 14; 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_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
|
||||
MPC8544_PCI_REGS_BASE, 0, 0x1000);
|
||||
@ -340,6 +378,7 @@ done:
|
||||
ret = fdt_size;
|
||||
|
||||
out:
|
||||
g_free(pci_map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -417,11 +456,14 @@ void ppce500_init(PPCE500Params *params)
|
||||
target_ulong dt_base = 0;
|
||||
target_ulong initrd_base = 0;
|
||||
target_long initrd_size=0;
|
||||
int i=0;
|
||||
int i = 0, j, k;
|
||||
unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
|
||||
qemu_irq **irqs, *mpic;
|
||||
DeviceState *dev;
|
||||
CPUPPCState *firstenv = NULL;
|
||||
MemoryRegion *ccsr_addr_space;
|
||||
SysBusDevice *s;
|
||||
PPCE500CCSRState *ccsr;
|
||||
|
||||
/* Setup CPUs */
|
||||
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_CINT] = input[PPCE500_INPUT_CINT];
|
||||
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);
|
||||
|
||||
@ -477,35 +520,69 @@ void ppce500_init(PPCE500Params *params)
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_add_subregion(address_space_mem, 0, ram);
|
||||
|
||||
/* MPIC */
|
||||
mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
|
||||
smp_cpus, irqs, NULL);
|
||||
dev = qdev_create(NULL, "e500-ccsr");
|
||||
object_property_add_child(qdev_get_machine(), "e500-ccsr",
|
||||
OBJECT(dev), NULL);
|
||||
qdev_init_nofail(dev);
|
||||
ccsr = CCSR(dev);
|
||||
ccsr_addr_space = &ccsr->ccsr_space;
|
||||
memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE,
|
||||
ccsr_addr_space);
|
||||
|
||||
if (!mpic) {
|
||||
cpu_abort(env, "MPIC failed to initialize\n");
|
||||
/* MPIC */
|
||||
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 */
|
||||
if (serial_hds[0]) {
|
||||
serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
|
||||
0, mpic[12+26], 399193,
|
||||
serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
|
||||
0, mpic[42], 399193,
|
||||
serial_hds[0], DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
if (serial_hds[1]) {
|
||||
serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
|
||||
0, mpic[12+26], 399193,
|
||||
serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
|
||||
0, mpic[42], 399193,
|
||||
serial_hds[1], DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
|
||||
mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
|
||||
mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
|
||||
NULL);
|
||||
dev = qdev_create(NULL, "e500-pcihost");
|
||||
qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
|
||||
qdev_init_nofail(dev);
|
||||
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");
|
||||
if (!pci_bus)
|
||||
printf("couldn't create PCI controller!\n");
|
||||
@ -578,3 +655,33 @@ void ppce500_init(PPCE500Params *params)
|
||||
kvmppc_init();
|
||||
}
|
||||
}
|
||||
|
||||
static int e500_ccsr_initfn(SysBusDevice *dev)
|
||||
{
|
||||
PPCE500CCSRState *ccsr;
|
||||
|
||||
ccsr = CCSR(dev);
|
||||
memory_region_init(&ccsr->ccsr_space, "e500-ccsr",
|
||||
MPC8544_CCSRBAR_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void e500_ccsr_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
k->init = e500_ccsr_initfn;
|
||||
}
|
||||
|
||||
static const TypeInfo e500_ccsr_info = {
|
||||
.name = TYPE_CCSR,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PPCE500CCSRState),
|
||||
.class_init = e500_ccsr_class_init,
|
||||
};
|
||||
|
||||
static void e500_register_types(void)
|
||||
{
|
||||
type_register_static(&e500_ccsr_info);
|
||||
}
|
||||
|
||||
type_init(e500_register_types)
|
||||
|
@ -9,6 +9,8 @@ typedef struct PPCE500Params {
|
||||
const char *kernel_cmdline;
|
||||
const char *initrd_filename;
|
||||
const char *cpu_model;
|
||||
int pci_first_slot;
|
||||
int pci_nr_slots;
|
||||
|
||||
/* e500-specific params */
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "e500.h"
|
||||
#include "../boards.h"
|
||||
#include "device_tree.h"
|
||||
#include "hw/pci.h"
|
||||
|
||||
static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
|
||||
{
|
||||
@ -40,6 +41,8 @@ static void e500plat_init(QEMUMachineInitArgs *args)
|
||||
.kernel_cmdline = kernel_cmdline,
|
||||
.initrd_filename = initrd_filename,
|
||||
.cpu_model = cpu_model,
|
||||
.pci_first_slot = 0x1,
|
||||
.pci_nr_slots = PCI_SLOT_MAX - 1,
|
||||
.fixup_devtree = e500plat_fixup_devtree,
|
||||
};
|
||||
|
||||
|
@ -40,6 +40,8 @@ static void mpc8544ds_init(QEMUMachineInitArgs *args)
|
||||
.kernel_cmdline = kernel_cmdline,
|
||||
.initrd_filename = initrd_filename,
|
||||
.cpu_model = cpu_model,
|
||||
.pci_first_slot = 0x11,
|
||||
.pci_nr_slots = 2,
|
||||
.fixup_devtree = mpc8544ds_fixup_devtree,
|
||||
};
|
||||
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include "hw/usb.h"
|
||||
#include "blockdev.h"
|
||||
#include "exec-memory.h"
|
||||
#include "sysbus.h"
|
||||
|
||||
#define MAX_IDE_BUS 2
|
||||
#define CFG_ADDR 0xf0000510
|
||||
@ -141,7 +142,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
|
||||
char *filename;
|
||||
qemu_irq *pic, **openpic_irqs;
|
||||
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);
|
||||
hwaddr kernel_base, initrd_base, cmdline_base = 0;
|
||||
long kernel_size, initrd_size;
|
||||
@ -156,6 +157,8 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
|
||||
void *fw_cfg;
|
||||
void *dbdma;
|
||||
int machine_arch;
|
||||
SysBusDevice *s;
|
||||
DeviceState *dev;
|
||||
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
|
||||
@ -320,7 +323,25 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
|
||||
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) {
|
||||
/* 970 gets a U3 bus */
|
||||
pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());
|
||||
|
@ -15,9 +15,11 @@
|
||||
*/
|
||||
|
||||
#include "hw.h"
|
||||
#include "hw/ppc/e500-ccsr.h"
|
||||
#include "pci.h"
|
||||
#include "pci_host.h"
|
||||
#include "bswap.h"
|
||||
#include "ppce500_pci.h"
|
||||
|
||||
#ifdef DEBUG_PCI
|
||||
#define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
|
||||
@ -86,12 +88,26 @@ struct PPCE500PCIState {
|
||||
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
|
||||
uint32_t gasket_time;
|
||||
qemu_irq irq[4];
|
||||
uint32_t first_slot;
|
||||
/* mmio maps */
|
||||
MemoryRegion container;
|
||||
MemoryRegion iomem;
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
int devno = pci_dev->devfn >> 3, ret = 0;
|
||||
int devno = pci_dev->devfn >> 3;
|
||||
int ret;
|
||||
|
||||
switch (devno) {
|
||||
/* Two PCI slot */
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
ret = (irq_num + devno - 0x10) % 4;
|
||||
break;
|
||||
default:
|
||||
printf("Error:%s:unknown dev number\n", __func__);
|
||||
}
|
||||
ret = ppce500_pci_map_irq_slot(devno, irq_num);
|
||||
|
||||
pci_debug("%s: devfn %x irq %d -> %d devno:%x\n", __func__,
|
||||
pci_dev->devfn, irq_num, ret, devno);
|
||||
@ -310,6 +319,24 @@ static const VMStateDescription vmstate_ppce500_pci = {
|
||||
|
||||
#include "exec-memory.h"
|
||||
|
||||
static int e500_pcihost_bridge_initfn(PCIDevice *d)
|
||||
{
|
||||
PPCE500PCIBridgeState *b = PPC_E500_PCI_BRIDGE(d);
|
||||
PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(),
|
||||
"/e500-ccsr"));
|
||||
|
||||
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)
|
||||
{
|
||||
PCIHostState *h;
|
||||
@ -329,7 +356,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
|
||||
|
||||
b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
|
||||
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;
|
||||
|
||||
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);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = e500_pcihost_bridge_initfn;
|
||||
k->vendor_id = PCI_VENDOR_ID_FREESCALE;
|
||||
k->device_id = PCI_DEVICE_ID_MPC8533E;
|
||||
k->class_id = PCI_CLASS_PROCESSOR_POWERPC;
|
||||
@ -364,16 +392,22 @@ static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
|
||||
static const TypeInfo e500_host_bridge_info = {
|
||||
.name = "e500-host-bridge",
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(PCIDevice),
|
||||
.instance_size = sizeof(PPCE500PCIBridgeState),
|
||||
.class_init = e500_host_bridge_class_init,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = e500_pcihost_initfn;
|
||||
dc->props = pcihost_properties;
|
||||
dc->vmsd = &vmstate_ppce500_pci;
|
||||
}
|
||||
|
||||
|
9
hw/ppce500_pci.h
Normal file
9
hw/ppce500_pci.h
Normal 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
|
35
hw/spapr.c
35
hw/spapr.c
@ -657,6 +657,36 @@ static void spapr_cpu_reset(void *opaque)
|
||||
(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 */
|
||||
static int spapr_vga_init(PCIBus *pci_bus)
|
||||
{
|
||||
@ -801,7 +831,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
|
||||
|
||||
/* Set up Interrupt Controller */
|
||||
spapr->icp = xics_system_init(XICS_IRQS);
|
||||
spapr->next_irq = 16;
|
||||
spapr->next_irq = XICS_IRQ_BASE;
|
||||
|
||||
/* Set up EPOW events infrastructure */
|
||||
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 */
|
||||
spapr_pci_rtas_init();
|
||||
|
||||
|
@ -6,11 +6,13 @@
|
||||
|
||||
struct VIOsPAPRBus;
|
||||
struct sPAPRPHBState;
|
||||
struct sPAPRNVRAM;
|
||||
struct icp_state;
|
||||
|
||||
typedef struct sPAPREnvironment {
|
||||
struct VIOsPAPRBus *vio_bus;
|
||||
QLIST_HEAD(, sPAPRPHBState) phbs;
|
||||
struct sPAPRNVRAM *nvram;
|
||||
struct icp_state *icp;
|
||||
|
||||
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,
|
||||
uint32_t nargs, target_ulong args,
|
||||
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,
|
||||
uint32_t token, uint32_t nargs, target_ulong args,
|
||||
uint32_t nret, target_ulong rets);
|
||||
|
@ -120,6 +120,12 @@ DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size)
|
||||
{
|
||||
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) {
|
||||
return NULL;
|
||||
}
|
||||
|
196
hw/spapr_nvram.c
Normal file
196
hw/spapr_nvram.c
Normal 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)
|
@ -242,7 +242,7 @@ target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
|
||||
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;
|
||||
|
||||
@ -258,7 +258,7 @@ void spapr_rtas_register(const char *name, spapr_rtas_fn fn)
|
||||
rtas_next->name = name;
|
||||
rtas_next->fn = fn;
|
||||
|
||||
rtas_next++;
|
||||
return (rtas_next++ - rtas_table) + TOKEN_BASE;
|
||||
}
|
||||
|
||||
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++) {
|
||||
struct rtas_call *call = &rtas_table[i];
|
||||
|
||||
if (!call->fn) {
|
||||
if (!call->name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
47
hw/xics.c
47
hw/xics.c
@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
#include "hw.h"
|
||||
#include "trace.h"
|
||||
#include "hw/spapr.h"
|
||||
#include "hw/xics.h"
|
||||
|
||||
@ -66,6 +67,8 @@ static void icp_check_ipi(struct icp_state *icp, int server)
|
||||
return;
|
||||
}
|
||||
|
||||
trace_xics_icp_check_ipi(server, ss->mfrr);
|
||||
|
||||
if (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)
|
||||
{
|
||||
uint32_t xirr;
|
||||
uint32_t xirr = ss->xirr;
|
||||
|
||||
qemu_irq_lower(ss->output);
|
||||
xirr = ss->xirr;
|
||||
ss->xirr = ss->pending_priority << 24;
|
||||
|
||||
trace_xics_icp_accept(xirr, ss->xirr);
|
||||
|
||||
return xirr;
|
||||
}
|
||||
|
||||
@ -134,6 +139,7 @@ static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
|
||||
|
||||
/* Send EOI -> ICS */
|
||||
ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
|
||||
trace_xics_icp_eoi(server, xirr, ss->xirr);
|
||||
ics_eoi(icp->ics, xirr & XISR_MASK);
|
||||
if (!XISR(ss)) {
|
||||
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;
|
||||
|
||||
trace_xics_icp_irq(server, nr, priority);
|
||||
|
||||
if ((priority >= CPPR(ss))
|
||||
|| (XISR(ss) && (ss->pending_priority <= priority))) {
|
||||
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->pending_priority = priority;
|
||||
trace_xics_icp_raise(ss->xirr, ss->pending_priority);
|
||||
qemu_irq_raise(ss->output);
|
||||
}
|
||||
}
|
||||
@ -170,13 +179,13 @@ struct ics_irq_state {
|
||||
#define XICS_STATUS_REJECTED 0x4
|
||||
#define XICS_STATUS_MASKED_PENDING 0x8
|
||||
uint8_t status;
|
||||
bool lsi;
|
||||
};
|
||||
|
||||
struct ics_state {
|
||||
int nr_irqs;
|
||||
int offset;
|
||||
qemu_irq *qirqs;
|
||||
bool *islsi;
|
||||
struct ics_irq_state *irqs;
|
||||
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;
|
||||
|
||||
trace_xics_set_irq_msi(srcno, srcno + ics->offset);
|
||||
|
||||
if (val) {
|
||||
if (irq->priority == 0xff) {
|
||||
irq->status |= XICS_STATUS_MASKED_PENDING;
|
||||
/* masked pending */ ;
|
||||
trace_xics_masked_pending();
|
||||
} else {
|
||||
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;
|
||||
|
||||
trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
|
||||
if (val) {
|
||||
irq->status |= XICS_STATUS_ASSERTED;
|
||||
} 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)
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
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->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);
|
||||
} else {
|
||||
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;
|
||||
|
||||
trace_xics_ics_reject(nr, nr - ics->offset);
|
||||
irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */
|
||||
irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */
|
||||
}
|
||||
@ -299,10 +313,8 @@ static void ics_resend(struct ics_state *ics)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ics->nr_irqs; i++) {
|
||||
struct ics_irq_state *irq = ics->irqs + i;
|
||||
|
||||
/* FIXME: filter by server#? */
|
||||
if (irq->lsi) {
|
||||
if (ics->islsi[i]) {
|
||||
resend_lsi(ics, i);
|
||||
} else {
|
||||
resend_msi(ics, i);
|
||||
@ -315,7 +327,9 @@ static void ics_eoi(struct ics_state *ics, int nr)
|
||||
int srcno = nr - ics->offset;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -337,7 +351,7 @@ void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi)
|
||||
{
|
||||
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,
|
||||
@ -495,16 +509,14 @@ static void xics_reset(void *opaque)
|
||||
|
||||
for (i = 0; i < icp->nr_servers; i++) {
|
||||
icp->ss[i].xirr = 0;
|
||||
icp->ss[i].pending_priority = 0;
|
||||
icp->ss[i].pending_priority = 0xff;
|
||||
icp->ss[i].mfrr = 0xff;
|
||||
/* Make all outputs are deasserted */
|
||||
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++) {
|
||||
/* Reset everything *except* the type */
|
||||
ics->irqs[i].server = 0;
|
||||
ics->irqs[i].status = 0;
|
||||
ics->irqs[i].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->nr_irqs = nr_irqs;
|
||||
ics->offset = 16;
|
||||
ics->offset = XICS_IRQ_BASE;
|
||||
ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state));
|
||||
ics->islsi = g_malloc0(nr_irqs * sizeof(bool));
|
||||
|
||||
icp->ics = ics;
|
||||
ics->icp = icp;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define __XICS_H__
|
||||
|
||||
#define XICS_IPI 0x2
|
||||
#define XICS_IRQ_BASE 0x10
|
||||
|
||||
struct icp_state;
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
|
||||
implementation for certain IBM POWER hardware. The sources are at
|
||||
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
|
||||
legacy x86 software to communicate with an attached serial console as
|
||||
|
BIN
pc-bios/slof.bin
BIN
pc-bios/slof.bin
Binary file not shown.
@ -579,6 +579,10 @@ static QemuOptsList qemu_machine_opts = {
|
||||
.name = "usb",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Set on/off to enable/disable usb",
|
||||
}, {
|
||||
.name = "nvram",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Drive backing persistent NVRAM",
|
||||
},
|
||||
{ /* End of list */ }
|
||||
},
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit f21f7a3f46b557eb5923f899ce8b4401b3cc6d91
|
||||
Subproject commit 0ad10f26c94a86a0c9c3970e53f9a9f6a744055d
|
@ -355,7 +355,7 @@ struct ppc6xx_tlb_t {
|
||||
|
||||
typedef struct ppcemb_tlb_t ppcemb_tlb_t;
|
||||
struct ppcemb_tlb_t {
|
||||
hwaddr RPN;
|
||||
uint64_t RPN;
|
||||
target_ulong EPN;
|
||||
target_ulong PID;
|
||||
target_ulong size;
|
||||
|
13
trace-events
13
trace-events
@ -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_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"
|
||||
|
||||
# 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"
|
||||
|
Loading…
Reference in New Issue
Block a user