mirror of https://gitee.com/openkylin/qemu.git
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 = {
|
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,
|
||||||
|
|
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,
|
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__ */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 "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,25 +67,35 @@ 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,
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
(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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
47
hw/xics.c
47
hw/xics.c
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
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",
|
.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
|
|
@ -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;
|
||||||
|
|
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_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"
|
||||||
|
|
Loading…
Reference in New Issue