Merge branch 'ppc-for-upstream' of git://github.com/agraf/qemu
* 'ppc-for-upstream' of git://github.com/agraf/qemu: PPC: spapr: iommu: rework traces spapr: add "stop-self" RTAS call required to support hot CPU unplug PPC: KVM: Compile fix for qemu_notify_event pseries: Add H_SET_MODE hcall to change guest exception endianness xics: move registration of global state to realize() spapr-pci: rework MSI/MSIX target-ppc: Use #define instead of opencoding SLB valid bit spapr-pci: fix config space access to support bridges target-ppc: fix bit extraction for FPBF and FPL ppc405_boards: Don't enforce presence of firmware for qtest ppc405_uc: Disable debug output ppc405_boards: Disable debug output ppc: virtex_ml507: QEMU_OPTION_dtb support for this machine. disas/ppc.c: Fix little endian disassembly target-ppc: POWER7 supports the MSR_LE bit target-ppc: USE LPCR_ILE to control exception endian on POWER7 pseries: Fix stalls on hypervisor virtual console PPC: E500: Generate device tree on reset
This commit is contained in:
commit
32f3bd6d4d
@ -5157,7 +5157,8 @@ int
|
||||
print_insn_ppc (bfd_vma memaddr, struct disassemble_info *info)
|
||||
{
|
||||
int dialect = (char *) info->private_data - (char *) 0;
|
||||
return print_insn_powerpc (memaddr, info, 1, dialect);
|
||||
return print_insn_powerpc (memaddr, info, info->endian == BFD_ENDIAN_BIG,
|
||||
dialect);
|
||||
}
|
||||
|
||||
/* Print a big endian PowerPC instruction. */
|
||||
|
@ -47,6 +47,8 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
|
||||
buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
|
||||
}
|
||||
|
||||
qemu_chr_accept_input(dev->chardev);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -642,6 +642,17 @@ static void xics_realize(DeviceState *dev, Error **errp)
|
||||
ICSState *ics = icp->ics;
|
||||
int i;
|
||||
|
||||
/* Registration of global state belongs into realize */
|
||||
spapr_rtas_register("ibm,set-xive", rtas_set_xive);
|
||||
spapr_rtas_register("ibm,get-xive", rtas_get_xive);
|
||||
spapr_rtas_register("ibm,int-off", rtas_int_off);
|
||||
spapr_rtas_register("ibm,int-on", rtas_int_on);
|
||||
|
||||
spapr_register_hypercall(H_CPPR, h_cppr);
|
||||
spapr_register_hypercall(H_IPI, h_ipi);
|
||||
spapr_register_hypercall(H_XIRR, h_xirr);
|
||||
spapr_register_hypercall(H_EOI, h_eoi);
|
||||
|
||||
ics->nr_irqs = icp->nr_irqs;
|
||||
ics->offset = XICS_IRQ_BASE;
|
||||
ics->icp = icp;
|
||||
@ -678,16 +689,6 @@ static void xics_class_init(ObjectClass *oc, void *data)
|
||||
dc->realize = xics_realize;
|
||||
dc->props = xics_properties;
|
||||
dc->reset = xics_reset;
|
||||
|
||||
spapr_rtas_register("ibm,set-xive", rtas_set_xive);
|
||||
spapr_rtas_register("ibm,get-xive", rtas_get_xive);
|
||||
spapr_rtas_register("ibm,int-off", rtas_int_off);
|
||||
spapr_rtas_register("ibm,int-on", rtas_int_on);
|
||||
|
||||
spapr_register_hypercall(H_CPPR, h_cppr);
|
||||
spapr_register_hypercall(H_IPI, h_ipi);
|
||||
spapr_register_hypercall(H_XIRR, h_xirr);
|
||||
spapr_register_hypercall(H_EOI, h_eoi);
|
||||
}
|
||||
|
||||
static const TypeInfo xics_info = {
|
||||
|
@ -123,13 +123,14 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
|
||||
}
|
||||
}
|
||||
|
||||
static int ppce500_load_device_tree(CPUPPCState *env,
|
||||
QEMUMachineInitArgs *args,
|
||||
static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
|
||||
PPCE500Params *params,
|
||||
hwaddr addr,
|
||||
hwaddr initrd_base,
|
||||
hwaddr initrd_size)
|
||||
hwaddr initrd_size,
|
||||
bool dry_run)
|
||||
{
|
||||
CPUPPCState *env = first_cpu->env_ptr;
|
||||
int ret = -1;
|
||||
uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) };
|
||||
int fdt_size;
|
||||
@ -369,12 +370,10 @@ static int ppce500_load_device_tree(CPUPPCState *env,
|
||||
}
|
||||
|
||||
done:
|
||||
if (!dry_run) {
|
||||
qemu_devtree_dumpdtb(fdt, fdt_size);
|
||||
ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
cpu_physical_memory_write(addr, fdt, fdt_size);
|
||||
}
|
||||
g_free(fdt);
|
||||
ret = fdt_size;
|
||||
|
||||
out:
|
||||
@ -383,6 +382,41 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct DeviceTreeParams {
|
||||
QEMUMachineInitArgs args;
|
||||
PPCE500Params params;
|
||||
hwaddr addr;
|
||||
hwaddr initrd_base;
|
||||
hwaddr initrd_size;
|
||||
} DeviceTreeParams;
|
||||
|
||||
static void ppce500_reset_device_tree(void *opaque)
|
||||
{
|
||||
DeviceTreeParams *p = opaque;
|
||||
ppce500_load_device_tree(&p->args, &p->params, p->addr, p->initrd_base,
|
||||
p->initrd_size, false);
|
||||
}
|
||||
|
||||
static int ppce500_prep_device_tree(QEMUMachineInitArgs *args,
|
||||
PPCE500Params *params,
|
||||
hwaddr addr,
|
||||
hwaddr initrd_base,
|
||||
hwaddr initrd_size)
|
||||
{
|
||||
DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
|
||||
p->args = *args;
|
||||
p->params = *params;
|
||||
p->addr = addr;
|
||||
p->initrd_base = initrd_base;
|
||||
p->initrd_size = initrd_size;
|
||||
|
||||
qemu_register_reset(ppce500_reset_device_tree, p);
|
||||
|
||||
/* Issue the device tree loader once, so that we get the size of the blob */
|
||||
return ppce500_load_device_tree(args, params, addr, initrd_base,
|
||||
initrd_size, true);
|
||||
}
|
||||
|
||||
/* Create -kernel TLB entries for BookE. */
|
||||
static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
|
||||
{
|
||||
@ -746,7 +780,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
||||
struct boot_info *boot_info;
|
||||
int dt_size;
|
||||
|
||||
dt_size = ppce500_load_device_tree(env, args, params, dt_base,
|
||||
dt_size = ppce500_prep_device_tree(args, params, dt_base,
|
||||
initrd_base, initrd_size);
|
||||
if (dt_size < 0) {
|
||||
fprintf(stderr, "couldn't load device tree\n");
|
||||
|
@ -27,9 +27,11 @@
|
||||
#include "hw/timer/m48t59.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "block/block.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/loader.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "exec/address-spaces.h"
|
||||
@ -42,7 +44,7 @@
|
||||
|
||||
#define USE_FLASH_BIOS
|
||||
|
||||
#define DEBUG_BOARD_INIT
|
||||
//#define DEBUG_BOARD_INIT
|
||||
|
||||
/*****************************************************************************/
|
||||
/* PPC405EP reference board (IBM) */
|
||||
@ -252,17 +254,20 @@ static void ref405ep_init(QEMUMachineInitArgs *args)
|
||||
if (filename) {
|
||||
bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
|
||||
g_free(filename);
|
||||
} else {
|
||||
bios_size = -1;
|
||||
}
|
||||
if (bios_size < 0 || bios_size > BIOS_SIZE) {
|
||||
fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
|
||||
bios_name);
|
||||
error_report("Could not load PowerPC BIOS '%s'", bios_name);
|
||||
exit(1);
|
||||
}
|
||||
bios_size = (bios_size + 0xfff) & ~0xfff;
|
||||
memory_region_set_readonly(bios, true);
|
||||
memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
|
||||
} else if (!qtest_enabled() || kernel_filename != NULL) {
|
||||
error_report("Could not load PowerPC BIOS '%s'", bios_name);
|
||||
exit(1);
|
||||
} else {
|
||||
/* Avoid an uninitialized variable warning */
|
||||
bios_size = -1;
|
||||
}
|
||||
memory_region_set_readonly(bios, true);
|
||||
}
|
||||
/* Register FPGA */
|
||||
#ifdef DEBUG_BOARD_INIT
|
||||
@ -353,9 +358,9 @@ static void ref405ep_init(QEMUMachineInitArgs *args)
|
||||
bdloc = 0;
|
||||
}
|
||||
#ifdef DEBUG_BOARD_INIT
|
||||
printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
|
||||
printf("%s: Done\n", __func__);
|
||||
#endif
|
||||
printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
|
||||
}
|
||||
|
||||
static QEMUMachine ref405ep_machine = {
|
||||
@ -569,17 +574,17 @@ static void taihu_405ep_init(QEMUMachineInitArgs *args)
|
||||
if (filename) {
|
||||
bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
|
||||
g_free(filename);
|
||||
} else {
|
||||
bios_size = -1;
|
||||
}
|
||||
if (bios_size < 0 || bios_size > BIOS_SIZE) {
|
||||
fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
|
||||
bios_name);
|
||||
error_report("Could not load PowerPC BIOS '%s'", bios_name);
|
||||
exit(1);
|
||||
}
|
||||
bios_size = (bios_size + 0xfff) & ~0xfff;
|
||||
memory_region_set_readonly(bios, true);
|
||||
memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
|
||||
} else if (!qtest_enabled()) {
|
||||
error_report("Could not load PowerPC BIOS '%s'", bios_name);
|
||||
exit(1);
|
||||
}
|
||||
memory_region_set_readonly(bios, true);
|
||||
}
|
||||
/* Register Linux flash */
|
||||
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
|
||||
|
@ -30,15 +30,15 @@
|
||||
#include "qemu/log.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
#define DEBUG_OPBA
|
||||
#define DEBUG_SDRAM
|
||||
#define DEBUG_GPIO
|
||||
#define DEBUG_SERIAL
|
||||
#define DEBUG_OCM
|
||||
//#define DEBUG_OPBA
|
||||
//#define DEBUG_SDRAM
|
||||
//#define DEBUG_GPIO
|
||||
//#define DEBUG_SERIAL
|
||||
//#define DEBUG_OCM
|
||||
//#define DEBUG_I2C
|
||||
#define DEBUG_GPT
|
||||
#define DEBUG_MAL
|
||||
#define DEBUG_CLOCKS
|
||||
//#define DEBUG_GPT
|
||||
//#define DEBUG_MAL
|
||||
//#define DEBUG_CLOCKS
|
||||
//#define DEBUG_CLOCKS_LL
|
||||
|
||||
ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
|
||||
|
@ -88,6 +88,9 @@ int spapr_allocate_irq(int hint, bool lsi)
|
||||
|
||||
if (hint) {
|
||||
irq = hint;
|
||||
if (hint >= spapr->next_irq) {
|
||||
spapr->next_irq = hint + 1;
|
||||
}
|
||||
/* FIXME: we should probably check for collisions somehow */
|
||||
} else {
|
||||
irq = spapr->next_irq++;
|
||||
@ -103,22 +106,39 @@ int spapr_allocate_irq(int hint, bool lsi)
|
||||
return irq;
|
||||
}
|
||||
|
||||
/* Allocate block of consequtive IRQs, returns a number of the first */
|
||||
int spapr_allocate_irq_block(int num, bool lsi)
|
||||
/*
|
||||
* Allocate block of consequtive IRQs, returns a number of the first.
|
||||
* If msi==true, aligns the first IRQ number to num.
|
||||
*/
|
||||
int spapr_allocate_irq_block(int num, bool lsi, bool msi)
|
||||
{
|
||||
int first = -1;
|
||||
int i;
|
||||
int i, hint = 0;
|
||||
|
||||
/*
|
||||
* MSIMesage::data is used for storing VIRQ so
|
||||
* it has to be aligned to num to support multiple
|
||||
* MSI vectors. MSI-X is not affected by this.
|
||||
* The hint is used for the first IRQ, the rest should
|
||||
* be allocated continously.
|
||||
*/
|
||||
if (msi) {
|
||||
assert((num == 1) || (num == 2) || (num == 4) ||
|
||||
(num == 8) || (num == 16) || (num == 32));
|
||||
hint = (spapr->next_irq + num - 1) & ~(num - 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
int irq;
|
||||
|
||||
irq = spapr_allocate_irq(0, lsi);
|
||||
irq = spapr_allocate_irq(hint, lsi);
|
||||
if (!irq) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 == i) {
|
||||
first = irq;
|
||||
hint = 0;
|
||||
}
|
||||
|
||||
/* If the above doesn't create a consecutive block then that's
|
||||
@ -262,7 +282,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||
uint32_t start_prop = cpu_to_be32(initrd_base);
|
||||
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
|
||||
char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
|
||||
"\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk";
|
||||
"\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk\0hcall-set-mode";
|
||||
char qemu_hypertas_prop[] = "hcall-memop1";
|
||||
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
|
||||
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
|
||||
@ -1214,6 +1234,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
|
||||
spapr_create_nvram(spapr);
|
||||
|
||||
/* Set up PCI */
|
||||
spapr_pci_msi_init(spapr, SPAPR_PCI_MSI_WINDOW);
|
||||
spapr_pci_rtas_init();
|
||||
|
||||
phb = spapr_create_phb(spapr, 0);
|
||||
|
@ -657,6 +657,54 @@ static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUState *cs;
|
||||
target_ulong mflags = args[0];
|
||||
target_ulong resource = args[1];
|
||||
target_ulong value1 = args[2];
|
||||
target_ulong value2 = args[3];
|
||||
target_ulong ret = H_P2;
|
||||
|
||||
if (resource == H_SET_MODE_ENDIAN) {
|
||||
if (value1) {
|
||||
ret = H_P3;
|
||||
goto out;
|
||||
}
|
||||
if (value2) {
|
||||
ret = H_P4;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (mflags) {
|
||||
case H_SET_MODE_ENDIAN_BIG:
|
||||
for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
|
||||
PowerPCCPU *cp = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cp->env;
|
||||
env->spr[SPR_LPCR] &= ~LPCR_ILE;
|
||||
}
|
||||
ret = H_SUCCESS;
|
||||
break;
|
||||
|
||||
case H_SET_MODE_ENDIAN_LITTLE:
|
||||
for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
|
||||
PowerPCCPU *cp = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cp->env;
|
||||
env->spr[SPR_LPCR] |= LPCR_ILE;
|
||||
}
|
||||
ret = H_SUCCESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = H_UNSUPPORTED_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
|
||||
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
|
||||
|
||||
@ -734,6 +782,8 @@ static void hypercall_register_types(void)
|
||||
|
||||
/* qemu/KVM-PPC specific hcalls */
|
||||
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
|
||||
|
||||
spapr_register_hypercall(H_SET_MODE, h_set_mode);
|
||||
}
|
||||
|
||||
type_init(hypercall_register_types)
|
||||
|
@ -22,13 +22,12 @@
|
||||
#include "kvm_ppc.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "trace.h"
|
||||
|
||||
#include "hw/ppc/spapr.h"
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
/* #define DEBUG_TCE */
|
||||
|
||||
enum sPAPRTCEAccess {
|
||||
SPAPR_TCE_FAULT = 0,
|
||||
SPAPR_TCE_RO = 1,
|
||||
@ -61,44 +60,28 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
|
||||
{
|
||||
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
|
||||
uint64_t tce;
|
||||
|
||||
#ifdef DEBUG_TCE
|
||||
fprintf(stderr, "spapr_tce_translate liobn=0x%" PRIx32 " addr=0x"
|
||||
DMA_ADDR_FMT "\n", tcet->liobn, addr);
|
||||
#endif
|
||||
|
||||
if (tcet->bypass) {
|
||||
return (IOMMUTLBEntry) {
|
||||
IOMMUTLBEntry ret = {
|
||||
.target_as = &address_space_memory,
|
||||
.iova = 0,
|
||||
.translated_addr = 0,
|
||||
.addr_mask = ~(hwaddr)0,
|
||||
.perm = IOMMU_RW,
|
||||
.perm = IOMMU_NONE,
|
||||
};
|
||||
}
|
||||
|
||||
if (tcet->bypass) {
|
||||
ret.perm = IOMMU_RW;
|
||||
} else if (addr < tcet->window_size) {
|
||||
/* Check if we are in bound */
|
||||
if (addr >= tcet->window_size) {
|
||||
#ifdef DEBUG_TCE
|
||||
fprintf(stderr, "spapr_tce_translate out of bounds\n");
|
||||
#endif
|
||||
return (IOMMUTLBEntry) { .perm = IOMMU_NONE };
|
||||
}
|
||||
|
||||
tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT];
|
||||
ret.iova = addr & ~SPAPR_TCE_PAGE_MASK;
|
||||
ret.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK;
|
||||
ret.addr_mask = SPAPR_TCE_PAGE_MASK;
|
||||
ret.perm = tce;
|
||||
}
|
||||
trace_spapr_iommu_xlate(tcet->liobn, addr, ret.iova, ret.perm,
|
||||
ret.addr_mask);
|
||||
|
||||
#ifdef DEBUG_TCE
|
||||
fprintf(stderr, " -> *paddr=0x%llx, *len=0x%llx\n",
|
||||
(tce & ~SPAPR_TCE_PAGE_MASK), SPAPR_TCE_PAGE_MASK + 1);
|
||||
#endif
|
||||
|
||||
return (IOMMUTLBEntry) {
|
||||
.target_as = &address_space_memory,
|
||||
.iova = addr & ~SPAPR_TCE_PAGE_MASK,
|
||||
.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK,
|
||||
.addr_mask = SPAPR_TCE_PAGE_MASK,
|
||||
.perm = tce,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spapr_tce_table_pre_load(void *opaque)
|
||||
@ -150,10 +133,7 @@ static int spapr_tce_table_realize(DeviceState *dev)
|
||||
}
|
||||
tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT;
|
||||
|
||||
#ifdef DEBUG_TCE
|
||||
fprintf(stderr, "spapr_iommu: New TCE table @ %p, liobn=0x%x, "
|
||||
"table @ %p, fd=%d\n", tcet, liobn, tcet->table, tcet->fd);
|
||||
#endif
|
||||
trace_spapr_iommu_new_table(tcet->liobn, tcet, tcet->table, tcet->fd);
|
||||
|
||||
memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops,
|
||||
"iommu-spapr", UINT64_MAX);
|
||||
@ -250,20 +230,17 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong liobn = args[0];
|
||||
target_ulong ioba = args[1];
|
||||
target_ulong tce = args[2];
|
||||
target_ulong ret = H_PARAMETER;
|
||||
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
|
||||
|
||||
ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
|
||||
|
||||
if (tcet) {
|
||||
return put_tce_emu(tcet, ioba, tce);
|
||||
ret = put_tce_emu(tcet, ioba, tce);
|
||||
}
|
||||
#ifdef DEBUG_TCE
|
||||
fprintf(stderr, "%s on liobn=" TARGET_FMT_lx /*%s*/
|
||||
" ioba 0x" TARGET_FMT_lx " TCE 0x" TARGET_FMT_lx "\n",
|
||||
__func__, liobn, /*dev->qdev.id, */ioba, tce);
|
||||
#endif
|
||||
trace_spapr_iommu_put(liobn, ioba, tce, ret);
|
||||
|
||||
return H_PARAMETER;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
|
||||
|
@ -65,22 +65,14 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid,
|
||||
{
|
||||
sPAPRPHBState *sphb = find_phb(spapr, buid);
|
||||
PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
|
||||
BusState *bus = BUS(phb->bus);
|
||||
BusChild *kid;
|
||||
int bus_num = (config_addr >> 16) & 0xFF;
|
||||
int devfn = (config_addr >> 8) & 0xFF;
|
||||
|
||||
if (!phb) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
||||
PCIDevice *dev = (PCIDevice *)kid->child;
|
||||
if (dev->devfn == devfn) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return pci_find_device(phb->bus, bus_num, devfn);
|
||||
}
|
||||
|
||||
static uint32_t rtas_pci_cfgaddr(uint32_t arg)
|
||||
@ -258,11 +250,11 @@ static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
|
||||
* This is required for msi_notify()/msix_notify() which
|
||||
* will write at the addresses via spapr_msi_write().
|
||||
*/
|
||||
static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr,
|
||||
bool msix, unsigned req_num)
|
||||
static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, bool msix,
|
||||
unsigned first_irq, unsigned req_num)
|
||||
{
|
||||
unsigned i;
|
||||
MSIMessage msg = { .address = addr, .data = 0 };
|
||||
MSIMessage msg = { .address = addr, .data = first_irq };
|
||||
|
||||
if (!msix) {
|
||||
msi_set_message(pdev, msg);
|
||||
@ -270,8 +262,7 @@ static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr,
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < req_num; ++i) {
|
||||
msg.address = addr | (i << 2);
|
||||
for (i = 0; i < req_num; ++i, ++msg.data) {
|
||||
msix_set_message(pdev, i, msg);
|
||||
trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
|
||||
}
|
||||
@ -351,7 +342,8 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
|
||||
/* There is no cached config, allocate MSIs */
|
||||
if (!phb->msi_table[ndev].nvec) {
|
||||
irq = spapr_allocate_irq_block(req_num, false);
|
||||
irq = spapr_allocate_irq_block(req_num, false,
|
||||
ret_intr_type == RTAS_TYPE_MSI);
|
||||
if (irq < 0) {
|
||||
fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
|
||||
rtas_st(rets, 0, -1); /* Hardware error */
|
||||
@ -363,8 +355,8 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
}
|
||||
|
||||
/* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
|
||||
spapr_msi_setmsg(pdev, phb->msi_win_addr | (ndev << 16),
|
||||
ret_intr_type == RTAS_TYPE_MSIX, req_num);
|
||||
spapr_msi_setmsg(pdev, spapr->msi_win_addr, ret_intr_type == RTAS_TYPE_MSIX,
|
||||
phb->msi_table[ndev].irq, req_num);
|
||||
|
||||
rtas_st(rets, 0, 0);
|
||||
rtas_st(rets, 1, req_num);
|
||||
@ -450,10 +442,7 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
|
||||
static void spapr_msi_write(void *opaque, hwaddr addr,
|
||||
uint64_t data, unsigned size)
|
||||
{
|
||||
sPAPRPHBState *phb = opaque;
|
||||
int ndev = addr >> 16;
|
||||
int vec = ((addr & 0xFFFF) >> 2) | data;
|
||||
uint32_t irq = phb->msi_table[ndev].irq + vec;
|
||||
uint32_t irq = data;
|
||||
|
||||
trace_spapr_pci_msi_write(addr, data, irq);
|
||||
|
||||
@ -467,6 +456,23 @@ static const MemoryRegionOps spapr_msi_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN
|
||||
};
|
||||
|
||||
void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
|
||||
{
|
||||
/*
|
||||
* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
|
||||
* we need to allocate some memory to catch those writes coming
|
||||
* from msi_notify()/msix_notify().
|
||||
* As MSIMessage:addr is going to be the same and MSIMessage:data
|
||||
* is going to be a VIRQ number, 4 bytes of the MSI MR will only
|
||||
* be used.
|
||||
*/
|
||||
spapr->msi_win_addr = addr;
|
||||
memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
|
||||
"msi", getpagesize());
|
||||
memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
|
||||
&spapr->msiwindow);
|
||||
}
|
||||
|
||||
/*
|
||||
* PHB PCI device
|
||||
*/
|
||||
@ -492,8 +498,7 @@ static int spapr_phb_init(SysBusDevice *s)
|
||||
|
||||
if ((sphb->buid != -1) || (sphb->dma_liobn != -1)
|
||||
|| (sphb->mem_win_addr != -1)
|
||||
|| (sphb->io_win_addr != -1)
|
||||
|| (sphb->msi_win_addr != -1)) {
|
||||
|| (sphb->io_win_addr != -1)) {
|
||||
fprintf(stderr, "Either \"index\" or other parameters must"
|
||||
" be specified for PAPR PHB, not both\n");
|
||||
return -1;
|
||||
@ -506,7 +511,6 @@ static int spapr_phb_init(SysBusDevice *s)
|
||||
+ sphb->index * SPAPR_PCI_WINDOW_SPACING;
|
||||
sphb->mem_win_addr = windows_base + SPAPR_PCI_MMIO_WIN_OFF;
|
||||
sphb->io_win_addr = windows_base + SPAPR_PCI_IO_WIN_OFF;
|
||||
sphb->msi_win_addr = windows_base + SPAPR_PCI_MSI_WIN_OFF;
|
||||
}
|
||||
|
||||
if (sphb->buid == -1) {
|
||||
@ -529,11 +533,6 @@ static int spapr_phb_init(SysBusDevice *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sphb->msi_win_addr == -1) {
|
||||
fprintf(stderr, "MSI window address not specified for PHB\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (find_phb(spapr, sphb->buid)) {
|
||||
fprintf(stderr, "PCI host bridges must have unique BUIDs\n");
|
||||
return -1;
|
||||
@ -573,18 +572,6 @@ static int spapr_phb_init(SysBusDevice *s)
|
||||
get_system_io(), 0, SPAPR_PCI_IO_WIN_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
|
||||
&sphb->iowindow);
|
||||
|
||||
/* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
|
||||
* we need to allocate some memory to catch those writes coming
|
||||
* from msi_notify()/msix_notify() */
|
||||
if (msi_supported) {
|
||||
sprintf(namebuf, "%s.msi", sphb->dtbusname);
|
||||
memory_region_init_io(&sphb->msiwindow, OBJECT(sphb), &spapr_msi_ops, sphb,
|
||||
namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000);
|
||||
memory_region_add_subregion(get_system_memory(), sphb->msi_win_addr,
|
||||
&sphb->msiwindow);
|
||||
}
|
||||
|
||||
/*
|
||||
* Selecting a busname is more complex than you'd think, due to
|
||||
* interacting constraints. If the user has specified an id
|
||||
@ -659,7 +646,6 @@ static Property spapr_phb_properties[] = {
|
||||
DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
|
||||
DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size,
|
||||
SPAPR_PCI_IO_WIN_SIZE),
|
||||
DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, -1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -701,7 +687,6 @@ static const VMStateDescription vmstate_spapr_pci = {
|
||||
VMSTATE_UINT64_EQUAL(mem_win_size, sPAPRPHBState),
|
||||
VMSTATE_UINT64_EQUAL(io_win_addr, sPAPRPHBState),
|
||||
VMSTATE_UINT64_EQUAL(io_win_size, sPAPRPHBState),
|
||||
VMSTATE_UINT64_EQUAL(msi_win_addr, sPAPRPHBState),
|
||||
VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
|
||||
vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
|
||||
VMSTATE_STRUCT_ARRAY(msi_table, sPAPRPHBState, SPAPR_MSIX_MAX_DEVS, 0,
|
||||
|
@ -202,6 +202,28 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
|
||||
rtas_st(rets, 0, -3);
|
||||
}
|
||||
|
||||
static void rtas_stop_self(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
uint32_t token, uint32_t nargs,
|
||||
target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
cs->halted = 1;
|
||||
cpu_exit(cs);
|
||||
/*
|
||||
* While stopping a CPU, the guest calls H_CPPR which
|
||||
* effectively disables interrupts on XICS level.
|
||||
* However decrementer interrupts in TCG can still
|
||||
* wake the CPU up so here we disable interrupts in MSR
|
||||
* as well.
|
||||
* As rtas_start_cpu() resets the whole MSR anyway, there is
|
||||
* no need to bother with specific bits, we just clear it.
|
||||
*/
|
||||
env->msr = 0;
|
||||
}
|
||||
|
||||
static struct rtas_call {
|
||||
const char *name;
|
||||
spapr_rtas_fn fn;
|
||||
@ -322,6 +344,7 @@ static void core_rtas_register_types(void)
|
||||
spapr_rtas_register("query-cpu-stopped-state",
|
||||
rtas_query_cpu_stopped_state);
|
||||
spapr_rtas_register("start-cpu", rtas_start_cpu);
|
||||
spapr_rtas_register("stop-self", rtas_stop_self);
|
||||
}
|
||||
|
||||
type_init(core_rtas_register_types)
|
||||
|
@ -141,9 +141,18 @@ static int xilinx_load_device_tree(hwaddr addr,
|
||||
{
|
||||
char *path;
|
||||
int fdt_size;
|
||||
void *fdt;
|
||||
void *fdt = NULL;
|
||||
int r;
|
||||
const char *dtb_filename;
|
||||
|
||||
dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
|
||||
if (dtb_filename) {
|
||||
fdt = load_device_tree(dtb_filename, &fdt_size);
|
||||
if (!fdt) {
|
||||
error_report("Error while loading device tree file '%s'",
|
||||
dtb_filename);
|
||||
}
|
||||
} else {
|
||||
/* Try the local "ppc.dtb" override. */
|
||||
fdt = load_device_tree("ppc.dtb", &fdt_size);
|
||||
if (!fdt) {
|
||||
@ -152,11 +161,11 @@ static int xilinx_load_device_tree(hwaddr addr,
|
||||
fdt = load_device_tree(path, &fdt_size);
|
||||
g_free(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fdt) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "couldn't set /chosen/bootargs\n");
|
||||
|
@ -43,8 +43,7 @@ typedef struct sPAPRPHBState {
|
||||
|
||||
MemoryRegion memspace, iospace;
|
||||
hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size;
|
||||
hwaddr msi_win_addr;
|
||||
MemoryRegion memwindow, iowindow, msiwindow;
|
||||
MemoryRegion memwindow, iowindow;
|
||||
|
||||
uint32_t dma_liobn;
|
||||
uint64_t dma_window_start;
|
||||
@ -73,7 +72,8 @@ typedef struct sPAPRPHBState {
|
||||
#define SPAPR_PCI_MMIO_WIN_SIZE 0x20000000
|
||||
#define SPAPR_PCI_IO_WIN_OFF 0x80000000
|
||||
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
|
||||
#define SPAPR_PCI_MSI_WIN_OFF 0x90000000
|
||||
|
||||
#define SPAPR_PCI_MSI_WINDOW 0x40000000000ULL
|
||||
|
||||
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
|
||||
|
||||
@ -88,6 +88,8 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
|
||||
uint32_t xics_phandle,
|
||||
void *fdt);
|
||||
|
||||
void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr);
|
||||
|
||||
void spapr_pci_rtas_init(void);
|
||||
|
||||
#endif /* __HW_SPAPR_PCI_H__ */
|
||||
|
@ -13,6 +13,8 @@ struct sPAPRNVRAM;
|
||||
typedef struct sPAPREnvironment {
|
||||
struct VIOsPAPRBus *vio_bus;
|
||||
QLIST_HEAD(, sPAPRPHBState) phbs;
|
||||
hwaddr msi_win_addr;
|
||||
MemoryRegion msiwindow;
|
||||
struct sPAPRNVRAM *nvram;
|
||||
XICSState *icp;
|
||||
|
||||
@ -109,6 +111,15 @@ typedef struct sPAPREnvironment {
|
||||
#define H_NOT_ENOUGH_RESOURCES -44
|
||||
#define H_R_STATE -45
|
||||
#define H_RESCINDEND -46
|
||||
#define H_P2 -55
|
||||
#define H_P3 -56
|
||||
#define H_P4 -57
|
||||
#define H_P5 -58
|
||||
#define H_P6 -59
|
||||
#define H_P7 -60
|
||||
#define H_P8 -61
|
||||
#define H_P9 -62
|
||||
#define H_UNSUPPORTED_FLAG -256
|
||||
#define H_MULTI_THREADS_ACTIVE -9005
|
||||
|
||||
|
||||
@ -143,6 +154,11 @@ typedef struct sPAPREnvironment {
|
||||
#define H_PP1 (1ULL<<(63-62))
|
||||
#define H_PP2 (1ULL<<(63-63))
|
||||
|
||||
/* H_SET_MODE flags */
|
||||
#define H_SET_MODE_ENDIAN 4
|
||||
#define H_SET_MODE_ENDIAN_BIG 0
|
||||
#define H_SET_MODE_ENDIAN_LITTLE 1
|
||||
|
||||
/* VASI States */
|
||||
#define H_VASI_INVALID 0
|
||||
#define H_VASI_ENABLED 1
|
||||
@ -267,7 +283,8 @@ typedef struct sPAPREnvironment {
|
||||
#define H_GET_EM_PARMS 0x2B8
|
||||
#define H_SET_MPP 0x2D0
|
||||
#define H_GET_MPP 0x2D4
|
||||
#define MAX_HCALL_OPCODE H_GET_MPP
|
||||
#define H_SET_MODE 0x31C
|
||||
#define MAX_HCALL_OPCODE H_SET_MODE
|
||||
|
||||
/* The hcalls above are standardized in PAPR and implemented by pHyp
|
||||
* as well.
|
||||
@ -303,7 +320,7 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
|
||||
target_ulong *args);
|
||||
|
||||
int spapr_allocate_irq(int hint, bool lsi);
|
||||
int spapr_allocate_irq_block(int num, bool lsi);
|
||||
int spapr_allocate_irq_block(int num, bool lsi, bool msi);
|
||||
|
||||
static inline int spapr_allocate_msi(int hint)
|
||||
{
|
||||
|
@ -453,6 +453,8 @@ struct ppc_slb_t {
|
||||
#define MSR_RI 1 /* Recoverable interrupt 1 */
|
||||
#define MSR_LE 0 /* Little-endian mode 1 hflags */
|
||||
|
||||
#define LPCR_ILE (1 << (63-38))
|
||||
|
||||
#define msr_sf ((env->msr >> MSR_SF) & 1)
|
||||
#define msr_isf ((env->msr >> MSR_ISF) & 1)
|
||||
#define msr_shv ((env->msr >> MSR_SHV) & 1)
|
||||
|
@ -611,9 +611,19 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
tlb_flush(env, 1);
|
||||
}
|
||||
|
||||
#ifdef TARGET_PPC64
|
||||
if (excp_model == POWERPC_EXCP_POWER7) {
|
||||
if (env->spr[SPR_LPCR] & LPCR_ILE) {
|
||||
new_msr |= (target_ulong)1 << MSR_LE;
|
||||
}
|
||||
} else if (msr_ile) {
|
||||
new_msr |= (target_ulong)1 << MSR_LE;
|
||||
}
|
||||
#else
|
||||
if (msr_ile) {
|
||||
new_msr |= (target_ulong)1 << MSR_LE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Jump to handler */
|
||||
vector = env->excp_vectors[excp];
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "qemu/timer.h"
|
||||
#include "kvm_ppc.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
||||
#define PROC_DEVTREE_PATH "/proc/device-tree"
|
||||
|
||||
|
@ -2061,7 +2061,7 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
|
||||
/* ESID = srnum */
|
||||
rb |= ((uint32_t)srnum & 0xf) << 28;
|
||||
/* Set the valid bit */
|
||||
rb |= 1 << 27;
|
||||
rb |= SLB_ESID_V;
|
||||
/* Index = ESID */
|
||||
rb |= (uint32_t)srnum;
|
||||
|
||||
|
@ -428,9 +428,9 @@ EXTRACT_HELPER(CRM, 12, 8);
|
||||
EXTRACT_HELPER(SR, 16, 4);
|
||||
|
||||
/* mtfsf/mtfsfi */
|
||||
EXTRACT_HELPER(FPBF, 19, 3);
|
||||
EXTRACT_HELPER(FPBF, 23, 3);
|
||||
EXTRACT_HELPER(FPIMM, 12, 4);
|
||||
EXTRACT_HELPER(FPL, 21, 1);
|
||||
EXTRACT_HELPER(FPL, 25, 1);
|
||||
EXTRACT_HELPER(FPFLM, 17, 8);
|
||||
EXTRACT_HELPER(FPW, 16, 1);
|
||||
|
||||
|
@ -7227,7 +7227,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
|
||||
PPC_SEGMENT_64B | PPC_SLBI |
|
||||
PPC_POPCNTB | PPC_POPCNTWD;
|
||||
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205;
|
||||
pcc->msr_mask = 0x800000000204FF36ULL;
|
||||
pcc->msr_mask = 0x800000000204FF37ULL;
|
||||
pcc->mmu_model = POWERPC_MMU_2_06;
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
|
||||
|
@ -1133,6 +1133,11 @@ xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_
|
||||
xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]"
|
||||
xics_ics_eoi(int nr) "ics_eoi: irq %#x"
|
||||
|
||||
# hw/ppc/spapr_iommu.c
|
||||
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
|
||||
spapr_iommu_xlate(uint64_t liobn, uint64_t ioba, uint64_t tce, unsigned perm, unsigned pgsize) "liobn=%"PRIx64" 0x%"PRIx64" -> 0x%"PRIx64" perm=%u mask=%x"
|
||||
spapr_iommu_new_table(uint64_t liobn, void *tcet, void *table, int fd) "liobn=%"PRIx64" tcet=%p table=%p fd=%d"
|
||||
|
||||
# util/hbitmap.c
|
||||
hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx"
|
||||
hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64
|
||||
|
Loading…
Reference in New Issue
Block a user