mirror of
https://github.com/qemu/qemu.git
synced 2025-08-15 05:04:03 +00:00
Merge remote branch 'agraf/ppc-next' into staging
This commit is contained in:
commit
53462f4aeb
@ -14,7 +14,7 @@ x86 Fabrice Bellard
|
|||||||
ARM Paul Brook
|
ARM Paul Brook
|
||||||
SPARC Blue Swirl
|
SPARC Blue Swirl
|
||||||
MIPS ?
|
MIPS ?
|
||||||
PowerPC ?
|
PowerPC Alexander Graf
|
||||||
M68K Paul Brook
|
M68K Paul Brook
|
||||||
SH4 ?
|
SH4 ?
|
||||||
CRIS Edgar E. Iglesias
|
CRIS Edgar E. Iglesias
|
||||||
@ -48,9 +48,9 @@ MIPS
|
|||||||
mips_mipssim.c ?
|
mips_mipssim.c ?
|
||||||
PowerPC
|
PowerPC
|
||||||
ppc_prep.c ?
|
ppc_prep.c ?
|
||||||
ppc_oldworld.c Fabrice Bellard
|
ppc_oldworld.c Alexander Graf
|
||||||
ppc_chrp.c Fabrice Bellard
|
ppc_newworld.c Alexander Graf
|
||||||
ppc405_boards.c ?
|
ppc405_boards.c Alexander Graf
|
||||||
M86K
|
M86K
|
||||||
mcf5208.c Paul Brook
|
mcf5208.c Paul Brook
|
||||||
an5206.c Paul Brook
|
an5206.c Paul Brook
|
||||||
|
11
hw/ppc.c
11
hw/ppc.c
@ -28,6 +28,8 @@
|
|||||||
#include "nvram.h"
|
#include "nvram.h"
|
||||||
#include "qemu-log.h"
|
#include "qemu-log.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
|
#include "kvm.h"
|
||||||
|
#include "kvm_ppc.h"
|
||||||
|
|
||||||
//#define PPC_DEBUG_IRQ
|
//#define PPC_DEBUG_IRQ
|
||||||
//#define PPC_DEBUG_TB
|
//#define PPC_DEBUG_TB
|
||||||
@ -50,6 +52,8 @@ static void cpu_ppc_tb_start (CPUState *env);
|
|||||||
|
|
||||||
static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
|
static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
|
||||||
{
|
{
|
||||||
|
unsigned int old_pending = env->pending_interrupts;
|
||||||
|
|
||||||
if (level) {
|
if (level) {
|
||||||
env->pending_interrupts |= 1 << n_IRQ;
|
env->pending_interrupts |= 1 << n_IRQ;
|
||||||
cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
||||||
@ -58,6 +62,13 @@ static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
|
|||||||
if (env->pending_interrupts == 0)
|
if (env->pending_interrupts == 0)
|
||||||
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
|
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (old_pending != env->pending_interrupts) {
|
||||||
|
#ifdef CONFIG_KVM
|
||||||
|
kvmppc_set_interrupt(env, n_IRQ, level);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
|
LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
|
||||||
"req %08x\n", __func__, env, n_IRQ, level,
|
"req %08x\n", __func__, env, n_IRQ, level,
|
||||||
env->pending_interrupts, env->interrupt_request);
|
env->pending_interrupts, env->interrupt_request);
|
||||||
|
132
hw/ppce500_pci.c
132
hw/ppce500_pci.c
@ -73,11 +73,11 @@ struct pci_inbound {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct PPCE500PCIState {
|
struct PPCE500PCIState {
|
||||||
|
PCIHostState pci_state;
|
||||||
struct pci_outbound pob[PPCE500_PCI_NR_POBS];
|
struct pci_outbound pob[PPCE500_PCI_NR_POBS];
|
||||||
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
|
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
|
||||||
uint32_t gasket_time;
|
uint32_t gasket_time;
|
||||||
PCIHostState pci_state;
|
uint64_t base_addr;
|
||||||
PCIDevice *pci_dev;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct PPCE500PCIState PPCE500PCIState;
|
typedef struct PPCE500PCIState PPCE500PCIState;
|
||||||
@ -221,7 +221,7 @@ static void ppce500_pci_save(QEMUFile *f, void *opaque)
|
|||||||
PPCE500PCIState *controller = opaque;
|
PPCE500PCIState *controller = opaque;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
pci_device_save(controller->pci_dev, f);
|
/* pci_device_save(controller->pci_dev, f); */
|
||||||
|
|
||||||
for (i = 0; i < PPCE500_PCI_NR_POBS; i++) {
|
for (i = 0; i < PPCE500_PCI_NR_POBS; i++) {
|
||||||
qemu_put_be32s(f, &controller->pob[i].potar);
|
qemu_put_be32s(f, &controller->pob[i].potar);
|
||||||
@ -247,7 +247,7 @@ static int ppce500_pci_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
if (version_id != 1)
|
if (version_id != 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
pci_device_load(controller->pci_dev, f);
|
/* pci_device_load(controller->pci_dev, f); */
|
||||||
|
|
||||||
for (i = 0; i < PPCE500_PCI_NR_POBS; i++) {
|
for (i = 0; i < PPCE500_PCI_NR_POBS; i++) {
|
||||||
qemu_get_be32s(f, &controller->pob[i].potar);
|
qemu_get_be32s(f, &controller->pob[i].potar);
|
||||||
@ -269,55 +269,95 @@ static int ppce500_pci_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
|
|
||||||
PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
|
PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
|
||||||
{
|
{
|
||||||
PPCE500PCIState *controller;
|
DeviceState *dev;
|
||||||
|
PCIBus *b;
|
||||||
|
PCIHostState *h;
|
||||||
|
PPCE500PCIState *s;
|
||||||
PCIDevice *d;
|
PCIDevice *d;
|
||||||
int index;
|
|
||||||
static int ppce500_pci_id;
|
static int ppce500_pci_id;
|
||||||
|
|
||||||
controller = qemu_mallocz(sizeof(PPCE500PCIState));
|
dev = qdev_create(NULL, "e500-pcihost");
|
||||||
|
h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
|
||||||
|
s = DO_UPCAST(PPCE500PCIState, pci_state, h);
|
||||||
|
|
||||||
controller->pci_state.bus = pci_register_bus(NULL, "pci",
|
qdev_prop_set_uint64(dev, "base_addr", registers);
|
||||||
mpc85xx_pci_set_irq,
|
b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq,
|
||||||
mpc85xx_pci_map_irq,
|
mpc85xx_pci_map_irq, pci_irqs, PCI_DEVFN(0x11, 0), 4);
|
||||||
pci_irqs, PCI_DEVFN(0x11, 0),
|
|
||||||
4);
|
|
||||||
d = pci_register_device(controller->pci_state.bus,
|
|
||||||
"host bridge", sizeof(PCIDevice),
|
|
||||||
0, NULL, NULL);
|
|
||||||
|
|
||||||
pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_FREESCALE);
|
s->pci_state.bus = b;
|
||||||
pci_config_set_device_id(d->config, PCI_DEVICE_ID_MPC8533E);
|
qdev_init_nofail(dev);
|
||||||
pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_POWERPC);
|
d = pci_create_simple(b, 0, "e500-host-bridge");
|
||||||
|
|
||||||
controller->pci_dev = d;
|
|
||||||
|
|
||||||
/* CFGADDR */
|
|
||||||
index = pci_host_conf_register_mmio(&controller->pci_state, 0);
|
|
||||||
if (index < 0)
|
|
||||||
goto free;
|
|
||||||
cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index);
|
|
||||||
|
|
||||||
/* CFGDATA */
|
|
||||||
index = pci_host_data_register_mmio(&controller->pci_state, 0);
|
|
||||||
if (index < 0)
|
|
||||||
goto free;
|
|
||||||
cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index);
|
|
||||||
|
|
||||||
index = cpu_register_io_memory(e500_pci_reg_read,
|
|
||||||
e500_pci_reg_write, controller);
|
|
||||||
if (index < 0)
|
|
||||||
goto free;
|
|
||||||
cpu_register_physical_memory(registers + PCIE500_REG_BASE,
|
|
||||||
PCIE500_REG_SIZE, index);
|
|
||||||
|
|
||||||
/* XXX load/save code not tested. */
|
/* XXX load/save code not tested. */
|
||||||
register_savevm(&d->qdev, "ppce500_pci", ppce500_pci_id++,
|
register_savevm(&d->qdev, "ppce500_pci", ppce500_pci_id++,
|
||||||
1, ppce500_pci_save, ppce500_pci_load, controller);
|
1, ppce500_pci_save, ppce500_pci_load, s);
|
||||||
|
|
||||||
return controller->pci_state.bus;
|
return b;
|
||||||
|
|
||||||
free:
|
|
||||||
printf("%s error\n", __func__);
|
|
||||||
qemu_free(controller);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int e500_pcihost_initfn(SysBusDevice *dev)
|
||||||
|
{
|
||||||
|
PCIHostState *h;
|
||||||
|
PPCE500PCIState *s;
|
||||||
|
target_phys_addr_t registers;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
|
||||||
|
s = DO_UPCAST(PPCE500PCIState, pci_state, h);
|
||||||
|
registers = (target_phys_addr_t)s->base_addr;
|
||||||
|
|
||||||
|
/* CFGADDR */
|
||||||
|
index = pci_host_conf_register_mmio(&s->pci_state, 0);
|
||||||
|
if (index < 0)
|
||||||
|
return -1;
|
||||||
|
cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index);
|
||||||
|
|
||||||
|
/* CFGDATA */
|
||||||
|
index = pci_host_data_register_mmio(&s->pci_state, 1);
|
||||||
|
if (index < 0)
|
||||||
|
return -1;
|
||||||
|
cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index);
|
||||||
|
|
||||||
|
index = cpu_register_io_memory(e500_pci_reg_read,
|
||||||
|
e500_pci_reg_write, s);
|
||||||
|
if (index < 0)
|
||||||
|
return -1;
|
||||||
|
cpu_register_physical_memory(registers + PCIE500_REG_BASE,
|
||||||
|
PCIE500_REG_SIZE, index);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int e500_host_bridge_initfn(PCIDevice *dev)
|
||||||
|
{
|
||||||
|
pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_FREESCALE);
|
||||||
|
pci_config_set_device_id(dev->config, PCI_DEVICE_ID_MPC8533E);
|
||||||
|
pci_config_set_class(dev->config, PCI_CLASS_PROCESSOR_POWERPC);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PCIDeviceInfo e500_host_bridge_info = {
|
||||||
|
.qdev.name = "e500-host-bridge",
|
||||||
|
.qdev.desc = "Host bridge",
|
||||||
|
.qdev.size = sizeof(PCIDevice),
|
||||||
|
.qdev.no_user = 1,
|
||||||
|
.init = e500_host_bridge_initfn,
|
||||||
|
};
|
||||||
|
|
||||||
|
static SysBusDeviceInfo e500_pcihost_info = {
|
||||||
|
.init = e500_pcihost_initfn,
|
||||||
|
.qdev.name = "e500-pcihost",
|
||||||
|
.qdev.size = sizeof(PPCE500PCIState),
|
||||||
|
.qdev.no_user = 1,
|
||||||
|
.qdev.props = (Property[]) {
|
||||||
|
DEFINE_PROP_UINT64("base_addr", PPCE500PCIState, base_addr, 0),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void e500_pci_register(void)
|
||||||
|
{
|
||||||
|
sysbus_register_withprop(&e500_pcihost_info);
|
||||||
|
pci_qdev_register(&e500_host_bridge_info);
|
||||||
|
}
|
||||||
|
device_init(e500_pci_register);
|
||||||
|
@ -37,6 +37,9 @@
|
|||||||
do { } while (0)
|
do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int cap_interrupt_unset = false;
|
||||||
|
static int cap_interrupt_level = false;
|
||||||
|
|
||||||
/* XXX We have a race condition where we actually have a level triggered
|
/* XXX We have a race condition where we actually have a level triggered
|
||||||
* interrupt, but the infrastructure can't expose that yet, so the guest
|
* interrupt, but the infrastructure can't expose that yet, so the guest
|
||||||
* takes but ignores it, goes to sleep and never gets notified that there's
|
* takes but ignores it, goes to sleep and never gets notified that there's
|
||||||
@ -55,6 +58,18 @@ static void kvm_kick_env(void *env)
|
|||||||
|
|
||||||
int kvm_arch_init(KVMState *s, int smp_cpus)
|
int kvm_arch_init(KVMState *s, int smp_cpus)
|
||||||
{
|
{
|
||||||
|
#ifdef KVM_CAP_PPC_UNSET_IRQ
|
||||||
|
cap_interrupt_unset = kvm_check_extension(s, KVM_CAP_PPC_UNSET_IRQ);
|
||||||
|
#endif
|
||||||
|
#ifdef KVM_CAP_PPC_IRQ_LEVEL
|
||||||
|
cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!cap_interrupt_level) {
|
||||||
|
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
|
||||||
|
"VM to stall at times!\n");
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,6 +193,23 @@ int kvm_arch_get_registers(CPUState *env)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int kvmppc_set_interrupt(CPUState *env, int irq, int level)
|
||||||
|
{
|
||||||
|
unsigned virq = level ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET;
|
||||||
|
|
||||||
|
if (irq != PPC_INTERRUPT_EXT) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!kvm_enabled() || !cap_interrupt_unset || !cap_interrupt_level) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kvm_vcpu_ioctl(env, KVM_INTERRUPT, &virq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(TARGET_PPCEMB)
|
#if defined(TARGET_PPCEMB)
|
||||||
#define PPC_INPUT_INT PPC40x_INPUT_INT
|
#define PPC_INPUT_INT PPC40x_INPUT_INT
|
||||||
#elif defined(TARGET_PPC64)
|
#elif defined(TARGET_PPC64)
|
||||||
@ -193,7 +225,8 @@ int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
|
|||||||
|
|
||||||
/* PowerPC Qemu tracks the various core input pins (interrupt, critical
|
/* PowerPC Qemu tracks the various core input pins (interrupt, critical
|
||||||
* interrupt, reset, etc) in PPC-specific env->irq_input_state. */
|
* interrupt, reset, etc) in PPC-specific env->irq_input_state. */
|
||||||
if (run->ready_for_interrupt_injection &&
|
if (!cap_interrupt_level &&
|
||||||
|
run->ready_for_interrupt_injection &&
|
||||||
(env->interrupt_request & CPU_INTERRUPT_HARD) &&
|
(env->interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||||
(env->irq_input_state & (1<<PPC_INPUT_INT)))
|
(env->irq_input_state & (1<<PPC_INPUT_INT)))
|
||||||
{
|
{
|
||||||
@ -201,7 +234,7 @@ int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
|
|||||||
* future KVM could cache it in-kernel to avoid a heavyweight exit
|
* future KVM could cache it in-kernel to avoid a heavyweight exit
|
||||||
* when reading the UIC.
|
* when reading the UIC.
|
||||||
*/
|
*/
|
||||||
irq = -1U;
|
irq = KVM_INTERRUPT_SET;
|
||||||
|
|
||||||
dprintf("injected interrupt %d\n", irq);
|
dprintf("injected interrupt %d\n", irq);
|
||||||
r = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &irq);
|
r = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &irq);
|
||||||
|
@ -16,5 +16,18 @@ int kvmppc_read_host_property(const char *node_path, const char *prop,
|
|||||||
|
|
||||||
uint32_t kvmppc_get_tbfreq(void);
|
uint32_t kvmppc_get_tbfreq(void);
|
||||||
int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
|
int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
|
||||||
|
int kvmppc_set_interrupt(CPUState *env, int irq, int level);
|
||||||
|
|
||||||
|
#ifndef KVM_INTERRUPT_SET
|
||||||
|
#define KVM_INTERRUPT_SET -1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KVM_INTERRUPT_UNSET
|
||||||
|
#define KVM_INTERRUPT_UNSET -2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KVM_INTERRUPT_SET_LEVEL
|
||||||
|
#define KVM_INTERRUPT_SET_LEVEL -3
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __KVM_PPC_H__ */
|
#endif /* __KVM_PPC_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user