ppc patch queue 2018-03-06

This pull request supersedes ppc-for-2.12-20180302 which had compile
 problems with some gcc versions.  It also contains a few additional
 patches.
 
 Highlights are:
     * New Sam460ex machine type
     * Yet more fixes related to vcpu id allocation for spapr
     * Numerous macio cleanupsr
     * Some enhancements to the Spectre/Meltdown fixes for pseries,
       allowing use of a better mitigation for indirect branch based
       exploits
     * New pseries machine types with Spectre/Meltdown mitigations
       enabled (stop gap until libvirt and management understands the
       machine options)
     * A handful of other fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAlqeEnwACgkQbDjKyiDZ
 s5JdZw/+PtrngCvXVKQsPkLzL1cZVPqjrKObTeuQMHolmD/hvSD6nk1XfvLnkvyx
 kuixt4ARv9oEUdE7uy2WrbaBt9JDbrLsIrW+iKXlNCdMzn3ka4Bazd9v/fNiir+0
 IAhi4/KdHZiU6v/niXKSWgRzjtPbCDjDy+qCyo4rFv02UhWlCqr5UyTawN/C7iZO
 YsMEM4aSWOycMuY/kxxn1sBsr3O6apfU64nSVu98fESk6fgXCK0o53O1ajEdR960
 r+oJKv/lOJXCg6xto3qXS7UDbgUslhhxXnawNxOwpmthHu9u8EmyGSujF6UsO6t0
 piUc/VHcOP4LoozaNQbSvxhZe+k6jVOhPGsedhkgtAq2NoM4k9Q2+JbNipZqmW1V
 IkzGM5W8zqvhqw1/YzG/fNnRHKNsq/HPfHb6ZR+i0w+OkOROlt3aXvGwDfOXdrIG
 kkj6oGnFomtrnFSGBXn4p7Vz80+HhgykDuuT78Zx1ob2s4+ylgaDKoFippvJBr1Z
 LrJPVacxnsstXw0RFL3i2dKhHkyWwPxtA1wk4oBPOSIIYn87nB/i6tDgM6TO2aXu
 al48nisiVdlbE6raAQPIJC0euHaWgJjXnP4GK4SqnlFpZVEMI6gFt8B/rf8TqZJK
 ADYS1qT0fkq5cVaC981QldonB7ZE3gk1ee907hOPjnEY/q3pCc8=
 =Rtfm
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.12-20180306' into staging

ppc patch queue 2018-03-06

This pull request supersedes ppc-for-2.12-20180302 which had compile
problems with some gcc versions.  It also contains a few additional
patches.

Highlights are:
    * New Sam460ex machine type
    * Yet more fixes related to vcpu id allocation for spapr
    * Numerous macio cleanupsr
    * Some enhancements to the Spectre/Meltdown fixes for pseries,
      allowing use of a better mitigation for indirect branch based
      exploits
    * New pseries machine types with Spectre/Meltdown mitigations
      enabled (stop gap until libvirt and management understands the
      machine options)
    * A handful of other fixes

# gpg: Signature made Tue 06 Mar 2018 04:01:00 GMT
# gpg:                using RSA key 6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg:                 aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dgibson/tags/ppc-for-2.12-20180306: (30 commits)
  PowerPC: Add TS bits into msr_mask
  adb: add trace-events for monitoring keyboard/mouse during bus enumeration
  PPC: e500: Fix duplicate kernel load and device tree overlap
  hw/ppc/spapr,e500: Use new property "stdout-path" for boot console
  ppc/spapr-caps: Define the pseries-2.12-sxxm machine type
  ppc/spapr-caps: Convert cap-ibs to custom spapr-cap
  ppc/spapr-caps: Convert cap-sbbc to custom spapr-cap
  ppc/spapr-caps: Convert cap-cfpc to custom spapr-cap
  ppc/spapr-caps: Add support for custom spapr_capabilities
  target/ppc: Check mask when setting cap_ppc_safe_indirect_branch
  macio: remove macio_init() function
  macio: move setting of CUDA timebase frequency to macio_common_realize()
  mac_newworld: use object link to pass OpenPIC object to macio
  openpic: move OpenPIC state and related definitions to openpic.h
  openpic: move KVM-specific declarations into separate openpic_kvm.h file
  mac_oldworld: use object link to pass heathrow PIC object to macio
  macio: move macio related structures and defines into separate macio.h file
  heathrow: change heathrow_pic_init() to return the heathrow device
  heathrow: convert to trace-events
  heathrow: QOMify heathrow PIC
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-03-06 10:21:35 +00:00
commit e1ee9ee139
37 changed files with 2534 additions and 574 deletions

3
.gitmodules vendored
View File

@ -43,3 +43,6 @@
[submodule "roms/seabios-hppa"]
path = roms/seabios-hppa
url = git://github.com/hdeller/seabios-hppa.git
[submodule "roms/u-boot-sam460ex"]
path = roms/u-boot-sam460ex
url = git://github.com/zbalaton/u-boot-sam460ex

View File

@ -779,12 +779,12 @@ efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \
efi-e1000e.rom efi-vmxnet3.rom \
qemu-icon.bmp qemu_logo_no_text.svg \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin \
s390-ccw.img s390-netboot.img \
spapr-rtas.bin slof.bin skiboot.lid \
palcode-clipper \
u-boot.e500 \
u-boot.e500 u-boot-sam460-20100605.bin \
qemu_vga.ndrv \
hppa-firmware.img
else

View File

@ -21,6 +21,8 @@ CONFIG_E500=y
CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM))
CONFIG_PLATFORM_BUS=y
CONFIG_ETSEC=y
# For Sam460ex
CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y
CONFIG_IDE_SII3112=y
CONFIG_I2C=y

View File

@ -15,6 +15,7 @@ CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_XILINX_ETHLITE=y
CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y
CONFIG_IDE_SII3112=y
CONFIG_I2C=y

View File

@ -258,6 +258,7 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
trace_adb_kbd_request_change_addr(d->devaddr);
break;
default:
d->devaddr = buf[1] & 0xf;
@ -269,6 +270,9 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) {
d->handler = buf[2];
}
trace_adb_kbd_request_change_addr_and_handler(d->devaddr,
d->handler);
break;
}
}

View File

@ -118,6 +118,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
s->dx = 0;
s->dy = 0;
s->dz = 0;
trace_adb_mouse_flush();
return 0;
}
@ -138,6 +139,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
trace_adb_mouse_request_change_addr(d->devaddr);
break;
default:
d->devaddr = buf[1] & 0xf;
@ -155,6 +157,9 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
if (buf[2] == 1 || buf[2] == 2) {
d->handler = buf[2];
}
trace_adb_mouse_request_change_addr_and_handler(d->devaddr,
d->handler);
break;
}
}

View File

@ -4,10 +4,15 @@
adb_kbd_no_key(void) "Ignoring NO_KEY"
adb_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
adb_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
adb_kbd_request_change_addr(int devaddr) "change addr to 0x%x"
adb_kbd_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
# hw/input/adb-mouse.c
adb_mouse_flush(void) "flush"
adb_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
adb_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
adb_mouse_request_change_addr(int devaddr) "change addr to 0x%x"
adb_mouse_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
# hw/input/ps2.c
ps2_put_keycode(void *opaque, int keycode) "%p keycode 0x%02x"

View File

@ -25,78 +25,58 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/ppc/mac.h"
#include "hw/intc/heathrow_pic.h"
#include "trace.h"
/* debug PIC */
//#define DEBUG_PIC
#ifdef DEBUG_PIC
#define PIC_DPRINTF(fmt, ...) \
do { printf("PIC: " fmt , ## __VA_ARGS__); } while (0)
#else
#define PIC_DPRINTF(fmt, ...)
#endif
typedef struct HeathrowPIC {
uint32_t events;
uint32_t mask;
uint32_t levels;
uint32_t level_triggered;
} HeathrowPIC;
typedef struct HeathrowPICS {
MemoryRegion mem;
HeathrowPIC pics[2];
qemu_irq *irqs;
} HeathrowPICS;
static inline int check_irq(HeathrowPIC *pic)
static inline int heathrow_check_irq(HeathrowPICState *pic)
{
return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
}
/* update the CPU irq state */
static void heathrow_pic_update(HeathrowPICS *s)
static void heathrow_update_irq(HeathrowState *s)
{
if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
if (heathrow_check_irq(&s->pics[0]) ||
heathrow_check_irq(&s->pics[1])) {
qemu_irq_raise(s->irqs[0]);
} else {
qemu_irq_lower(s->irqs[0]);
}
}
static void pic_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
static void heathrow_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
HeathrowState *s = opaque;
HeathrowPICState *pic;
unsigned int n;
n = ((addr & 0xfff) - 0x10) >> 4;
PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
trace_heathrow_write(addr, n, value);
if (n >= 2)
return;
pic = &s->pics[n];
switch(addr & 0xf) {
case 0x04:
pic->mask = value;
heathrow_pic_update(s);
heathrow_update_irq(s);
break;
case 0x08:
/* do not reset level triggered IRQs */
value &= ~pic->level_triggered;
pic->events &= ~value;
heathrow_pic_update(s);
heathrow_update_irq(s);
break;
default:
break;
}
}
static uint64_t pic_read(void *opaque, hwaddr addr,
unsigned size)
static uint64_t heathrow_read(void *opaque, hwaddr addr,
unsigned size)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
HeathrowState *s = opaque;
HeathrowPICState *pic;
unsigned int n;
uint32_t value;
@ -120,40 +100,39 @@ static uint64_t pic_read(void *opaque, hwaddr addr,
break;
}
}
PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
trace_heathrow_read(addr, n, value);
return value;
}
static const MemoryRegionOps heathrow_pic_ops = {
.read = pic_read,
.write = pic_write,
static const MemoryRegionOps heathrow_ops = {
.read = heathrow_read,
.write = heathrow_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void heathrow_pic_set_irq(void *opaque, int num, int level)
static void heathrow_set_irq(void *opaque, int num, int level)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
HeathrowState *s = opaque;
HeathrowPICState *pic;
unsigned int irq_bit;
int last_level;
#if defined(DEBUG)
{
static int last_level[64];
if (last_level[num] != level) {
PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level);
last_level[num] = level;
}
}
#endif
pic = &s->pics[1 - (num >> 5)];
irq_bit = 1 << (num & 0x1f);
last_level = (pic->levels & irq_bit) ? 1 : 0;
if (level) {
pic->events |= irq_bit & ~pic->level_triggered;
pic->levels |= irq_bit;
} else {
pic->levels &= ~irq_bit;
}
heathrow_pic_update(s);
if (last_level != level) {
trace_heathrow_set_irq(num, level);
}
heathrow_update_irq(s);
}
static const VMStateDescription vmstate_heathrow_pic_one = {
@ -161,54 +140,81 @@ static const VMStateDescription vmstate_heathrow_pic_one = {
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_UINT32(events, HeathrowPIC),
VMSTATE_UINT32(mask, HeathrowPIC),
VMSTATE_UINT32(levels, HeathrowPIC),
VMSTATE_UINT32(level_triggered, HeathrowPIC),
VMSTATE_UINT32(events, HeathrowPICState),
VMSTATE_UINT32(mask, HeathrowPICState),
VMSTATE_UINT32(levels, HeathrowPICState),
VMSTATE_UINT32(level_triggered, HeathrowPICState),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_heathrow_pic = {
static const VMStateDescription vmstate_heathrow = {
.name = "heathrow_pic",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1,
vmstate_heathrow_pic_one, HeathrowPIC),
VMSTATE_STRUCT_ARRAY(pics, HeathrowState, 2, 1,
vmstate_heathrow_pic_one, HeathrowPICState),
VMSTATE_END_OF_LIST()
}
};
static void heathrow_pic_reset_one(HeathrowPIC *s)
static void heathrow_reset(DeviceState *d)
{
memset(s, '\0', sizeof(HeathrowPIC));
}
static void heathrow_pic_reset(void *opaque)
{
HeathrowPICS *s = opaque;
heathrow_pic_reset_one(&s->pics[0]);
heathrow_pic_reset_one(&s->pics[1]);
HeathrowState *s = HEATHROW(d);
s->pics[0].level_triggered = 0;
s->pics[1].level_triggered = 0x1ff00000;
}
qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
int nb_cpus, qemu_irq **irqs)
static void heathrow_init(Object *obj)
{
HeathrowPICS *s;
HeathrowState *s = HEATHROW(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
s = g_malloc0(sizeof(HeathrowPICS));
memory_region_init_io(&s->mem, OBJECT(s), &heathrow_ops, s,
"heathrow-pic", 0x1000);
sysbus_init_mmio(sbd, &s->mem);
}
DeviceState *heathrow_pic_init(int nb_cpus, qemu_irq **irqs,
qemu_irq **pic_irqs)
{
DeviceState *d;
HeathrowState *s;
d = qdev_create(NULL, TYPE_HEATHROW);
qdev_init_nofail(d);
s = HEATHROW(d);
/* only 1 CPU */
s->irqs = irqs[0];
memory_region_init_io(&s->mem, NULL, &heathrow_pic_ops, s,
"heathrow-pic", 0x1000);
*pmem = &s->mem;
vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
qemu_register_reset(heathrow_pic_reset, s);
return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
*pic_irqs = qemu_allocate_irqs(heathrow_set_irq, s, HEATHROW_NUM_IRQS);
return d;
}
static void heathrow_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->reset = heathrow_reset;
dc->vmsd = &vmstate_heathrow;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static const TypeInfo heathrow_type_info = {
.name = TYPE_HEATHROW,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(HeathrowState),
.instance_init = heathrow_init,
.class_init = heathrow_class_init,
};
static void heathrow_register_types(void)
{
type_register_static(&heathrow_type_info);
}
type_init(heathrow_register_types)

View File

@ -63,10 +63,6 @@ static int get_current_cpu(void);
} \
} while (0)
#define MAX_CPU 32
#define MAX_MSI 8
#define VID 0x03 /* MPIC version ID */
/* OpenPIC capability flags */
#define OPENPIC_FLAG_IDR_CRIT (1 << 0)
#define OPENPIC_FLAG_ILR (2 << 0)
@ -85,35 +81,6 @@ static int get_current_cpu(void);
#define OPENPIC_CPU_REG_START 0x20000
#define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
/* Raven */
#define RAVEN_MAX_CPU 2
#define RAVEN_MAX_EXT 48
#define RAVEN_MAX_IRQ 64
#define RAVEN_MAX_TMR OPENPIC_MAX_TMR
#define RAVEN_MAX_IPI OPENPIC_MAX_IPI
/* KeyLargo */
#define KEYLARGO_MAX_CPU 4
#define KEYLARGO_MAX_EXT 64
#define KEYLARGO_MAX_IPI 4
#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI)
#define KEYLARGO_MAX_TMR 0
#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */
/* Timers don't exist but this makes the code happy... */
#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI)
/* Interrupt definitions */
#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */
#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */
#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */
#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
/* First doorbell IRQ */
#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
typedef struct FslMpicInfo {
int max_ext;
} FslMpicInfo;
static FslMpicInfo fsl_mpic_20 = {
.max_ext = 12,
};
@ -211,55 +178,6 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
uint32_t val, int idx);
static void openpic_reset(DeviceState *d);
typedef enum IRQType {
IRQ_TYPE_NORMAL = 0,
IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */
IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
} IRQType;
/* Round up to the nearest 64 IRQs so that the queue length
* won't change when moving between 32 and 64 bit hosts.
*/
#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63)
typedef struct IRQQueue {
unsigned long *queue;
int32_t queue_size; /* Only used for VMSTATE_BITMAP */
int next;
int priority;
} IRQQueue;
typedef struct IRQSource {
uint32_t ivpr; /* IRQ vector/priority register */
uint32_t idr; /* IRQ destination register */
uint32_t destmask; /* bitmap of CPU destinations */
int last_cpu;
int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
int pending; /* TRUE if IRQ is pending */
IRQType type;
bool level:1; /* level-triggered */
bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */
} IRQSource;
#define IVPR_MASK_SHIFT 31
#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT)
#define IVPR_ACTIVITY_SHIFT 30
#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT)
#define IVPR_MODE_SHIFT 29
#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT)
#define IVPR_POLARITY_SHIFT 23
#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT)
#define IVPR_SENSE_SHIFT 22
#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT)
#define IVPR_PRIORITY_MASK (0xFU << 16)
#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
#define IDR_EP 0x80000000 /* external pin */
#define IDR_CI 0x40000000 /* critical interrupt */
/* Convert between openpic clock ticks and nanosecs. In the hardware the clock
frequency is driven by board inputs to the PIC which the PIC would then
divide by 4 or 8. For now hard code to 25MZ.
@ -275,81 +193,6 @@ static inline uint64_t ticks_to_ns(uint64_t ticks)
return ticks * OPENPIC_TIMER_NS_PER_TICK;
}
typedef struct OpenPICTimer {
uint32_t tccr; /* Global timer current count register */
uint32_t tbcr; /* Global timer base count register */
int n_IRQ;
bool qemu_timer_active; /* Is the qemu_timer is running? */
struct QEMUTimer *qemu_timer;
struct OpenPICState *opp; /* Device timer is part of. */
/* The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last
current_count written or read, only defined if qemu_timer_active. */
uint64_t origin_time;
} OpenPICTimer;
typedef struct OpenPICMSI {
uint32_t msir; /* Shared Message Signaled Interrupt Register */
} OpenPICMSI;
typedef struct IRQDest {
int32_t ctpr; /* CPU current task priority */
IRQQueue raised;
IRQQueue servicing;
qemu_irq *irqs;
/* Count of IRQ sources asserting on non-INT outputs */
uint32_t outputs_active[OPENPIC_OUTPUT_NB];
} IRQDest;
#define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC)
typedef struct OpenPICState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion mem;
/* Behavior control */
FslMpicInfo *fsl;
uint32_t model;
uint32_t flags;
uint32_t nb_irqs;
uint32_t vid;
uint32_t vir; /* Vendor identification register */
uint32_t vector_mask;
uint32_t tfrr_reset;
uint32_t ivpr_reset;
uint32_t idr_reset;
uint32_t brr1;
uint32_t mpic_mode_mask;
/* Sub-regions */
MemoryRegion sub_io_mem[6];
/* Global registers */
uint32_t frr; /* Feature reporting register */
uint32_t gcr; /* Global configuration register */
uint32_t pir; /* Processor initialization register */
uint32_t spve; /* Spurious vector register */
uint32_t tfrr; /* Timer frequency reporting register */
/* Source registers */
IRQSource src[OPENPIC_MAX_IRQ];
/* Local registers per output pin */
IRQDest dst[MAX_CPU];
uint32_t nb_cpus;
/* Timer registers */
OpenPICTimer timers[OPENPIC_MAX_TMR];
uint32_t max_tmr;
/* Shared MSI registers */
OpenPICMSI msi[MAX_MSI];
uint32_t max_irq;
uint32_t irq_ipi0;
uint32_t irq_tim0;
uint32_t irq_msi;
} OpenPICState;
static inline void IRQ_setbit(IRQQueue *q, int n_IRQ)
{
set_bit(n_IRQ, q->queue);

View File

@ -30,6 +30,7 @@
#include "exec/address-spaces.h"
#include "hw/hw.h"
#include "hw/ppc/openpic.h"
#include "hw/ppc/openpic_kvm.h"
#include "hw/pci/msi.h"
#include "hw/sysbus.h"
#include "sysemu/kvm.h"

View File

@ -186,3 +186,8 @@ nvic_complete_irq(int irq, bool secure) "NVIC complete IRQ %d (secure %d)"
nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to %d"
nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
# hw/intc/heathrow_pic.c
heathrow_write(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
heathrow_read(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
heathrow_set_irq(int num, int level) "set_irq: num=0x%02x level=%d"

View File

@ -30,48 +30,11 @@
#include "hw/pci/pci.h"
#include "hw/ppc/mac_dbdma.h"
#include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
#include "hw/intc/heathrow_pic.h"
#define TYPE_MACIO "macio"
#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
typedef struct MacIOState
{
/*< private >*/
PCIDevice parent;
/*< public >*/
MemoryRegion bar;
CUDAState cuda;
DBDMAState *dbdma;
MemoryRegion *pic_mem;
MemoryRegion *escc_mem;
uint64_t frequency;
} MacIOState;
#define OLDWORLD_MACIO(obj) \
OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
typedef struct OldWorldMacIOState {
/*< private >*/
MacIOState parent_obj;
/*< public >*/
qemu_irq irqs[5];
MacIONVRAMState nvram;
MACIOIDEState ide[2];
} OldWorldMacIOState;
#define NEWWORLD_MACIO(obj) \
OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
typedef struct NewWorldMacIOState {
/*< private >*/
MacIOState parent_obj;
/*< public >*/
qemu_irq irqs[5];
MACIOIDEState ide[2];
} NewWorldMacIOState;
/* Note: this code is strongly inspirated from the corresponding code
* in PearPC */
/*
* The mac-io has two interfaces to the ESCC. One is called "escc-legacy",
@ -84,10 +47,12 @@ typedef struct NewWorldMacIOState {
*
* Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf
*/
static void macio_escc_legacy_setup(MacIOState *macio_state)
static void macio_escc_legacy_setup(MacIOState *s)
{
ESCCState *escc = ESCC(&s->escc);
SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
MemoryRegion *escc_legacy = g_new(MemoryRegion, 1);
MemoryRegion *bar = &macio_state->bar;
MemoryRegion *bar = &s->bar;
int i;
static const int maps[] = {
0x00, 0x00, /* Command B */
@ -102,25 +67,26 @@ static void macio_escc_legacy_setup(MacIOState *macio_state)
0xb0, 0xb0, /* Detect AB */
};
memory_region_init(escc_legacy, OBJECT(macio_state), "escc-legacy", 256);
memory_region_init(escc_legacy, OBJECT(s), "escc-legacy", 256);
for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
MemoryRegion *port = g_new(MemoryRegion, 1);
memory_region_init_alias(port, OBJECT(macio_state), "escc-legacy-port",
macio_state->escc_mem, maps[i+1], 0x2);
memory_region_init_alias(port, OBJECT(s), "escc-legacy-port",
sysbus_mmio_get_region(sbd, 0),
maps[i + 1], 0x2);
memory_region_add_subregion(escc_legacy, maps[i], port);
}
memory_region_add_subregion(bar, 0x12000, escc_legacy);
}
static void macio_bar_setup(MacIOState *macio_state)
static void macio_bar_setup(MacIOState *s)
{
MemoryRegion *bar = &macio_state->bar;
ESCCState *escc = ESCC(&s->escc);
SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
MemoryRegion *bar = &s->bar;
if (macio_state->escc_mem) {
memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
macio_escc_legacy_setup(macio_state);
}
memory_region_add_subregion(bar, 0x13000, sysbus_mmio_get_region(sbd, 0));
macio_escc_legacy_setup(s);
}
static void macio_common_realize(PCIDevice *d, Error **errp)
@ -129,15 +95,17 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
SysBusDevice *sysbus_dev;
Error *err = NULL;
object_property_set_bool(OBJECT(s->dbdma), true, "realized", &err);
object_property_set_bool(OBJECT(&s->dbdma), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_dev = SYS_BUS_DEVICE(s->dbdma);
sysbus_dev = SYS_BUS_DEVICE(&s->dbdma);
memory_region_add_subregion(&s->bar, 0x08000,
sysbus_mmio_get_region(sysbus_dev, 0));
qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency",
s->frequency);
object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@ -147,6 +115,12 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
memory_region_add_subregion(&s->bar, 0x16000,
sysbus_mmio_get_region(sysbus_dev, 0));
object_property_set_bool(OBJECT(&s->escc), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
macio_bar_setup(s);
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
}
@ -161,7 +135,7 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide,
sysbus_connect_irq(sysbus_dev, 0, irq0);
sysbus_connect_irq(sysbus_dev, 1, irq1);
qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid);
object_property_set_link(OBJECT(ide), OBJECT(s->dbdma), "dbdma", errp);
object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", errp);
macio_ide_register_dma(ide);
object_property_set_bool(OBJECT(ide), true, "realized", errp);
@ -185,6 +159,10 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp)
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
sysbus_dev = SYS_BUS_DEVICE(&s->escc);
sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
sysbus_connect_irq(sysbus_dev, 1, os->irqs[cur_irq++]);
object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@ -195,10 +173,10 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp)
sysbus_mmio_get_region(sysbus_dev, 0));
pmac_format_nvram_partition(&os->nvram, os->nvram.size);
if (s->pic_mem) {
/* Heathrow PIC */
memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem);
}
/* Heathrow PIC */
sysbus_dev = SYS_BUS_DEVICE(os->pic);
memory_region_add_subregion(&s->bar, 0x0,
sysbus_mmio_get_region(sysbus_dev, 0));
/* IDE buses */
for (i = 0; i < ARRAY_SIZE(os->ide); i++) {
@ -236,6 +214,11 @@ static void macio_oldworld_init(Object *obj)
qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
object_property_add_link(obj, "pic", TYPE_HEATHROW,
(Object **) &os->pic,
qdev_prop_allow_set_link_before_realize,
0, NULL);
object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM);
dev = DEVICE(&os->nvram);
qdev_prop_set_uint32(dev, "size", 0x2000);
@ -297,10 +280,14 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
if (s->pic_mem) {
/* OpenPIC */
memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem);
}
sysbus_dev = SYS_BUS_DEVICE(&s->escc);
sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
sysbus_connect_irq(sysbus_dev, 1, ns->irqs[cur_irq++]);
/* OpenPIC */
sysbus_dev = SYS_BUS_DEVICE(ns->pic);
memory_region_add_subregion(&s->bar, 0x40000,
sysbus_mmio_get_region(sysbus_dev, 0));
/* IDE buses */
for (i = 0; i < ARRAY_SIZE(ns->ide); i++) {
@ -329,6 +316,11 @@ static void macio_newworld_init(Object *obj)
qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
object_property_add_link(obj, "pic", TYPE_OPENPIC,
(Object **) &ns->pic,
qdev_prop_allow_set_link_before_realize,
0, NULL);
for (i = 0; i < 2; i++) {
macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
}
@ -344,8 +336,20 @@ static void macio_instance_init(Object *obj)
qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
s->dbdma = MAC_DBDMA(object_new(TYPE_MAC_DBDMA));
object_property_add_child(obj, "dbdma", OBJECT(s->dbdma), NULL);
object_initialize(&s->dbdma, sizeof(s->dbdma), TYPE_MAC_DBDMA);
qdev_set_parent_bus(DEVICE(&s->dbdma), sysbus_get_default());
object_property_add_child(obj, "dbdma", OBJECT(&s->dbdma), NULL);
object_initialize(&s->escc, sizeof(s->escc), TYPE_ESCC);
qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0);
qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK);
qdev_prop_set_uint32(DEVICE(&s->escc), "it_shift", 4);
qdev_prop_set_chr(DEVICE(&s->escc), "chrA", serial_hds[0]);
qdev_prop_set_chr(DEVICE(&s->escc), "chrB", serial_hds[1]);
qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial);
qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial);
qdev_set_parent_bus(DEVICE(&s->escc), sysbus_get_default());
object_property_add_child(obj, "escc", OBJECT(&s->escc), NULL);
}
static const VMStateDescription vmstate_macio_oldworld = {
@ -441,19 +445,3 @@ static void macio_register_types(void)
}
type_init(macio_register_types)
void macio_init(PCIDevice *d,
MemoryRegion *pic_mem,
MemoryRegion *escc_mem)
{
MacIOState *macio_state = MACIO(d);
macio_state->pic_mem = pic_mem;
macio_state->escc_mem = escc_mem;
/* Note: this code is strongly inspirated from the corresponding code
in PearPC */
qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "timebase-frequency",
macio_state->frequency);
qdev_init_nofail(DEVICE(d));
}

View File

@ -13,7 +13,8 @@ endif
obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o
# PowerPC 4xx boards
obj-y += ppc4xx_devs.o ppc405_uc.o
obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o ppc440_bamboo.o
obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o
obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o sam460ex.o
# PReP
obj-$(CONFIG_PREP) += prep.o
obj-$(CONFIG_PREP) += prep_systemio.o

View File

@ -29,6 +29,7 @@
#include "kvm_ppc.h"
#include "sysemu/device_tree.h"
#include "hw/ppc/openpic.h"
#include "hw/ppc/openpic_kvm.h"
#include "hw/ppc/ppc.h"
#include "hw/loader.h"
#include "elf.h"
@ -119,7 +120,14 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
if (defcon) {
/*
* "linux,stdout-path" and "stdout" properties are deprecated by linux
* kernel. New platforms should only use the "stdout-path" property. Set
* the new property and continue using older property to remain
* compatible with the existing firmware.
*/
qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser);
}
}
@ -784,8 +792,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
int initrd_size = 0;
hwaddr cur_base = 0;
char *filename;
const char *payload_name;
bool kernel_as_payload;
hwaddr bios_entry = 0;
target_long bios_size;
target_long payload_size;
struct boot_info *boot_info;
int dt_size;
int i;
@ -913,11 +923,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
/* Register spinning region */
sysbus_create_simple("e500-spin", params->spin_base, NULL);
if (cur_base < (32 * 1024 * 1024)) {
/* u-boot occupies memory up to 32MB, so load blobs above */
cur_base = (32 * 1024 * 1024);
}
if (params->has_mpc8xxx_gpio) {
qemu_irq poweroff_irq;
@ -952,8 +957,61 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
sysbus_mmio_get_region(s, 0));
}
/* Load kernel. */
if (machine->kernel_filename) {
/*
* Smart firmware defaults ahead!
*
* We follow the following table to select which payload we execute.
*
* -kernel | -bios | payload
* ---------+-------+---------
* N | Y | u-boot
* N | N | u-boot
* Y | Y | u-boot
* Y | N | kernel
*
* This ensures backwards compatibility with how we used to expose
* -kernel to users but allows them to run through u-boot as well.
*/
kernel_as_payload = false;
if (bios_name == NULL) {
if (machine->kernel_filename) {
payload_name = machine->kernel_filename;
kernel_as_payload = true;
} else {
payload_name = "u-boot.e500";
}
} else {
payload_name = bios_name;
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
1, PPC_ELF_MACHINE, 0, 0);
if (payload_size < 0) {
/*
* Hrm. No ELF image? Try a uImage, maybe someone is giving us an
* ePAPR compliant kernel
*/
payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
NULL, NULL);
if (payload_size < 0) {
error_report("qemu: could not load firmware '%s'", filename);
exit(1);
}
}
g_free(filename);
if (kernel_as_payload) {
kernel_base = loadaddr;
kernel_size = payload_size;
}
cur_base = loadaddr + payload_size;
/* Load bare kernel only if no bios/u-boot has been provided */
if (machine->kernel_filename && !kernel_as_payload) {
kernel_base = cur_base;
kernel_size = load_image_targphys(machine->kernel_filename,
cur_base,
@ -967,6 +1025,11 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
cur_base += kernel_size;
}
if (cur_base < (32 * 1024 * 1024)) {
/* u-boot occupies memory up to 32MB, so load blobs above */
cur_base = (32 * 1024 * 1024);
}
/* Load initrd. */
if (machine->initrd_filename) {
initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
@ -983,47 +1046,16 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
}
/*
* Smart firmware defaults ahead!
*
* We follow the following table to select which payload we execute.
*
* -kernel | -bios | payload
* ---------+-------+---------
* N | Y | u-boot
* N | N | u-boot
* Y | Y | u-boot
* Y | N | kernel
*
* This ensures backwards compatibility with how we used to expose
* -kernel to users but allows them to run through u-boot as well.
* Reserve space for dtb behind the kernel image because Linux has a bug
* where it can only handle the dtb if it's within the first 64MB of where
* <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
* ensures enough space between kernel and initrd.
*/
if (bios_name == NULL) {
if (machine->kernel_filename) {
bios_name = machine->kernel_filename;
} else {
bios_name = "u-boot.e500";
}
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
1, PPC_ELF_MACHINE, 0, 0);
if (bios_size < 0) {
/*
* Hrm. No ELF image? Try a uImage, maybe someone is giving us an
* ePAPR compliant kernel
*/
kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
NULL, NULL);
if (kernel_size < 0) {
error_report("could not load firmware '%s'", filename);
dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
if (dt_base + DTB_MAX_SIZE > ram_size) {
error_report("qemu: not enough memory for device tree");
exit(1);
}
}
g_free(filename);
/* Reserve space for dtb */
dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
dt_size = ppce500_prep_device_tree(machine, params, dt_base,
initrd_base, initrd_size,

View File

@ -47,9 +47,6 @@
/* MacIO */
#define TYPE_OLDWORLD_MACIO "macio-oldworld"
#define TYPE_NEWWORLD_MACIO "macio-newworld"
#define TYPE_MACIO_IDE "macio-ide"
#define MACIO_IDE(obj) OBJECT_CHECK(MACIOIDEState, (obj), TYPE_MACIO_IDE)
@ -76,12 +73,11 @@ void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table);
void macio_ide_register_dma(MACIOIDEState *ide);
void macio_init(PCIDevice *dev,
MemoryRegion *pic_mem,
MemoryRegion *escc_mem);
MemoryRegion *pic_mem);
/* Heathrow PIC */
qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
int nb_cpus, qemu_irq **irqs);
DeviceState *heathrow_pic_init(int nb_cpus, qemu_irq **irqs,
qemu_irq **pic_irqs);
/* Grackle PCI */
#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost"

View File

@ -60,6 +60,7 @@
#include "hw/boards.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
#include "hw/ppc/openpic.h"
#include "hw/ide.h"
#include "hw/loader.h"
@ -153,20 +154,18 @@ static void ppc_core99_init(MachineState *machine)
hwaddr kernel_base, initrd_base, cmdline_base = 0;
long kernel_size, initrd_size;
PCIBus *pci_bus;
PCIDevice *macio;
NewWorldMacIOState *macio;
MACIOIDEState *macio_ide;
BusState *adb_bus;
MacIONVRAMState *nvr;
int bios_size, ndrv_size;
uint8_t *ndrv_file;
MemoryRegion *pic_mem, *escc_mem;
MemoryRegion *escc_bar = g_new(MemoryRegion, 1);
int ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
int machine_arch;
SysBusDevice *s;
DeviceState *dev;
DeviceState *dev, *pic_dev;
int *token = g_new(int, 1);
hwaddr nvram_addr = 0xFFF04000;
uint64_t tbfreq;
@ -333,11 +332,10 @@ static void ppc_core99_init(MachineState *machine)
pic = g_new0(qemu_irq, 64);
dev = qdev_create(NULL, TYPE_OPENPIC);
qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_KEYLARGO);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
pic_mem = s->mmio[0].memory;
pic_dev = qdev_create(NULL, TYPE_OPENPIC);
qdev_prop_set_uint32(pic_dev, "model", OPENPIC_MODEL_KEYLARGO);
qdev_init_nofail(pic_dev);
s = SYS_BUS_DEVICE(pic_dev);
k = 0;
for (i = 0; i < smp_cpus; i++) {
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
@ -346,7 +344,7 @@ static void ppc_core99_init(MachineState *machine)
}
for (i = 0; i < 64; i++) {
pic[i] = qdev_get_gpio_in(dev, i);
pic[i] = qdev_get_gpio_in(pic_dev, i);
}
if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
@ -368,36 +366,20 @@ static void ppc_core99_init(MachineState *machine)
tbfreq = TBFREQ;
}
/* init basic PC hardware */
dev = qdev_create(NULL, TYPE_ESCC);
qdev_prop_set_uint32(dev, "disabled", 0);
qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK);
qdev_prop_set_uint32(dev, "it_shift", 4);
qdev_prop_set_chr(dev, "chrA", serial_hds[0]);
qdev_prop_set_chr(dev, "chrB", serial_hds[1]);
qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(s, 0, pic[0x24]);
sysbus_connect_irq(s, 1, pic[0x25]);
escc_mem = &ESCC(s)->mmio;
memory_region_init_alias(escc_bar, NULL, "escc-bar",
escc_mem, 0, memory_region_size(escc_mem));
macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO);
/* MacIO */
macio = NEWWORLD_MACIO(pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO));
dev = DEVICE(macio);
qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */
qdev_connect_gpio_out(dev, 1, pic[0x0d]); /* IDE */
qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */
qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */
qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */
qdev_connect_gpio_out(dev, 1, pic[0x24]); /* ESCC-B */
qdev_connect_gpio_out(dev, 2, pic[0x25]); /* ESCC-A */
qdev_connect_gpio_out(dev, 3, pic[0x0d]); /* IDE */
qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */
qdev_connect_gpio_out(dev, 5, pic[0x0e]); /* IDE */
qdev_connect_gpio_out(dev, 6, pic[0x03]); /* IDE DMA */
qdev_prop_set_uint64(dev, "frequency", tbfreq);
macio_init(macio, pic_mem, escc_bar);
object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
&error_abort);
qdev_init_nofail(dev);
/* We only emulate 2 out of 3 IDE controllers for now */
ide_drive_get(hd, ARRAY_SIZE(hd));

View File

@ -37,6 +37,7 @@
#include "hw/boards.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
#include "hw/ide.h"
#include "hw/loader.h"
#include "elf.h"
@ -92,19 +93,16 @@ static void ppc_heathrow_init(MachineState *machine)
uint32_t kernel_base, initrd_base, cmdline_base = 0;
int32_t kernel_size, initrd_size;
PCIBus *pci_bus;
PCIDevice *macio;
OldWorldMacIOState *macio;
MACIOIDEState *macio_ide;
DeviceState *dev;
DeviceState *dev, *pic_dev;
BusState *adb_bus;
int bios_size, ndrv_size;
uint8_t *ndrv_file;
MemoryRegion *pic_mem;
MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1);
uint16_t ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
uint64_t tbfreq;
SysBusDevice *s;
linux_boot = (kernel_filename != NULL);
@ -259,46 +257,32 @@ static void ppc_heathrow_init(MachineState *machine)
error_report("Only 6xx bus is supported on heathrow machine");
exit(1);
}
pic = heathrow_pic_init(&pic_mem, 1, heathrow_irqs);
pic_dev = heathrow_pic_init(1, heathrow_irqs, &pic);
pci_bus = pci_grackle_init(0xfec00000, pic,
get_system_memory(),
get_system_io());
pci_vga_init(pci_bus);
dev = qdev_create(NULL, TYPE_ESCC);
qdev_prop_set_uint32(dev, "disabled", 0);
qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK);
qdev_prop_set_uint32(dev, "it_shift", 4);
qdev_prop_set_chr(dev, "chrA", serial_hds[0]);
qdev_prop_set_chr(dev, "chrB", serial_hds[1]);
qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(s, 0, pic[0x10]);
sysbus_connect_irq(s, 1, pic[0x0f]);
escc_mem = &ESCC(s)->mmio;
memory_region_init_alias(escc_bar, NULL, "escc-bar",
escc_mem, 0, memory_region_size(escc_mem));
for(i = 0; i < nb_nics; i++)
for (i = 0; i < nb_nics; i++) {
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
}
ide_drive_get(hd, ARRAY_SIZE(hd));
macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO);
/* MacIO */
macio = OLDWORLD_MACIO(pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO));
dev = DEVICE(macio);
qdev_connect_gpio_out(dev, 0, pic[0x12]); /* CUDA */
qdev_connect_gpio_out(dev, 1, pic[0x0D]); /* IDE-0 */
qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE-0 DMA */
qdev_connect_gpio_out(dev, 3, pic[0x0E]); /* IDE-1 */
qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE-1 DMA */
qdev_connect_gpio_out(dev, 1, pic[0x10]); /* ESCC-B */
qdev_connect_gpio_out(dev, 2, pic[0x0F]); /* ESCC-A */
qdev_connect_gpio_out(dev, 3, pic[0x0D]); /* IDE-0 */
qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE-0 DMA */
qdev_connect_gpio_out(dev, 5, pic[0x0E]); /* IDE-1 */
qdev_connect_gpio_out(dev, 6, pic[0x03]); /* IDE-1 DMA */
qdev_prop_set_uint64(dev, "frequency", tbfreq);
macio_init(macio, pic_mem, escc_bar);
object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
&error_abort);
qdev_init_nofail(dev);
macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
"ide[0]"));

528
hw/ppc/ppc440_pcix.c Normal file
View File

@ -0,0 +1,528 @@
/*
* Emulation of the ibm,plb-pcix PCI controller
* This is found in some 440 SoCs e.g. the 460EX.
*
* Copyright (c) 2016-2018 BALATON Zoltan
*
* Derived from ppc4xx_pci.c and pci-host/ppce500.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "hw/hw.h"
#include "hw/ppc/ppc.h"
#include "hw/ppc/ppc4xx.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
#include "exec/address-spaces.h"
#include "trace.h"
struct PLBOutMap {
uint64_t la;
uint64_t pcia;
uint32_t sa;
MemoryRegion mr;
};
struct PLBInMap {
uint64_t sa;
uint64_t la;
MemoryRegion mr;
};
#define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host"
#define PPC440_PCIX_HOST_BRIDGE(obj) \
OBJECT_CHECK(PPC440PCIXState, (obj), TYPE_PPC440_PCIX_HOST_BRIDGE)
#define PPC440_PCIX_NR_POMS 3
#define PPC440_PCIX_NR_PIMS 3
typedef struct PPC440PCIXState {
PCIHostState parent_obj;
PCIDevice *dev;
struct PLBOutMap pom[PPC440_PCIX_NR_POMS];
struct PLBInMap pim[PPC440_PCIX_NR_PIMS];
uint32_t sts;
qemu_irq irq[PCI_NUM_PINS];
AddressSpace bm_as;
MemoryRegion bm;
MemoryRegion container;
MemoryRegion iomem;
MemoryRegion busmem;
} PPC440PCIXState;
#define PPC440_REG_BASE 0x80000
#define PPC440_REG_SIZE 0xff
#define PCIC0_CFGADDR 0x0
#define PCIC0_CFGDATA 0x4
#define PCIX0_POM0LAL 0x68
#define PCIX0_POM0LAH 0x6c
#define PCIX0_POM0SA 0x70
#define PCIX0_POM0PCIAL 0x74
#define PCIX0_POM0PCIAH 0x78
#define PCIX0_POM1LAL 0x7c
#define PCIX0_POM1LAH 0x80
#define PCIX0_POM1SA 0x84
#define PCIX0_POM1PCIAL 0x88
#define PCIX0_POM1PCIAH 0x8c
#define PCIX0_POM2SA 0x90
#define PCIX0_PIM0SAL 0x98
#define PCIX0_PIM0LAL 0x9c
#define PCIX0_PIM0LAH 0xa0
#define PCIX0_PIM1SA 0xa4
#define PCIX0_PIM1LAL 0xa8
#define PCIX0_PIM1LAH 0xac
#define PCIX0_PIM2SAL 0xb0
#define PCIX0_PIM2LAL 0xb4
#define PCIX0_PIM2LAH 0xb8
#define PCIX0_PIM0SAH 0xf8
#define PCIX0_PIM2SAH 0xfc
#define PCIX0_STS 0xe0
#define PCI_ALL_SIZE (PPC440_REG_BASE + PPC440_REG_SIZE)
static void ppc440_pcix_clear_region(MemoryRegion *parent,
MemoryRegion *mem)
{
if (memory_region_is_mapped(mem)) {
memory_region_del_subregion(parent, mem);
object_unparent(OBJECT(mem));
}
}
/* DMA mapping */
static void ppc440_pcix_update_pim(PPC440PCIXState *s, int idx)
{
MemoryRegion *mem = &s->pim[idx].mr;
char *name;
uint64_t size;
/* Before we modify anything, unmap and destroy the region */
ppc440_pcix_clear_region(&s->bm, mem);
if (!(s->pim[idx].sa & 1)) {
/* Not enabled, nothing to do */
return;
}
name = g_strdup_printf("PCI Inbound Window %d", idx);
size = ~(s->pim[idx].sa & ~7ULL) + 1;
memory_region_init_alias(mem, OBJECT(s), name, get_system_memory(),
s->pim[idx].la, size);
memory_region_add_subregion_overlap(&s->bm, 0, mem, -1);
g_free(name);
trace_ppc440_pcix_update_pim(idx, size, s->pim[idx].la);
}
/* BAR mapping */
static void ppc440_pcix_update_pom(PPC440PCIXState *s, int idx)
{
MemoryRegion *mem = &s->pom[idx].mr;
MemoryRegion *address_space_mem = get_system_memory();
char *name;
uint32_t size;
/* Before we modify anything, unmap and destroy the region */
ppc440_pcix_clear_region(address_space_mem, mem);
if (!(s->pom[idx].sa & 1)) {
/* Not enabled, nothing to do */
return;
}
name = g_strdup_printf("PCI Outbound Window %d", idx);
size = ~(s->pom[idx].sa & 0xfffffffe) + 1;
if (!size) {
size = 0xffffffff;
}
memory_region_init_alias(mem, OBJECT(s), name, &s->busmem,
s->pom[idx].pcia, size);
memory_region_add_subregion(address_space_mem, s->pom[idx].la, mem);
g_free(name);
trace_ppc440_pcix_update_pom(idx, size, s->pom[idx].la, s->pom[idx].pcia);
}
static void ppc440_pcix_reg_write4(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
struct PPC440PCIXState *s = opaque;
trace_ppc440_pcix_reg_read(addr, val);
switch (addr) {
case PCI_VENDOR_ID ... PCI_MAX_LAT:
stl_le_p(s->dev->config + addr, val);
break;
case PCIX0_POM0LAL:
s->pom[0].la &= 0xffffffff00000000ULL;
s->pom[0].la |= val;
ppc440_pcix_update_pom(s, 0);
break;
case PCIX0_POM0LAH:
s->pom[0].la &= 0xffffffffULL;
s->pom[0].la |= val << 32;
ppc440_pcix_update_pom(s, 0);
break;
case PCIX0_POM0SA:
s->pom[0].sa = val;
ppc440_pcix_update_pom(s, 0);
break;
case PCIX0_POM0PCIAL:
s->pom[0].pcia &= 0xffffffff00000000ULL;
s->pom[0].pcia |= val;
ppc440_pcix_update_pom(s, 0);
break;
case PCIX0_POM0PCIAH:
s->pom[0].pcia &= 0xffffffffULL;
s->pom[0].pcia |= val << 32;
ppc440_pcix_update_pom(s, 0);
break;
case PCIX0_POM1LAL:
s->pom[1].la &= 0xffffffff00000000ULL;
s->pom[1].la |= val;
ppc440_pcix_update_pom(s, 1);
break;
case PCIX0_POM1LAH:
s->pom[1].la &= 0xffffffffULL;
s->pom[1].la |= val << 32;
ppc440_pcix_update_pom(s, 1);
break;
case PCIX0_POM1SA:
s->pom[1].sa = val;
ppc440_pcix_update_pom(s, 1);
break;
case PCIX0_POM1PCIAL:
s->pom[1].pcia &= 0xffffffff00000000ULL;
s->pom[1].pcia |= val;
ppc440_pcix_update_pom(s, 1);
break;
case PCIX0_POM1PCIAH:
s->pom[1].pcia &= 0xffffffffULL;
s->pom[1].pcia |= val << 32;
ppc440_pcix_update_pom(s, 1);
break;
case PCIX0_POM2SA:
s->pom[2].sa = val;
break;
case PCIX0_PIM0SAL:
s->pim[0].sa &= 0xffffffff00000000ULL;
s->pim[0].sa |= val;
ppc440_pcix_update_pim(s, 0);
break;
case PCIX0_PIM0LAL:
s->pim[0].la &= 0xffffffff00000000ULL;
s->pim[0].la |= val;
ppc440_pcix_update_pim(s, 0);
break;
case PCIX0_PIM0LAH:
s->pim[0].la &= 0xffffffffULL;
s->pim[0].la |= val << 32;
ppc440_pcix_update_pim(s, 0);
break;
case PCIX0_PIM1SA:
s->pim[1].sa = val;
ppc440_pcix_update_pim(s, 1);
break;
case PCIX0_PIM1LAL:
s->pim[1].la &= 0xffffffff00000000ULL;
s->pim[1].la |= val;
ppc440_pcix_update_pim(s, 1);
break;
case PCIX0_PIM1LAH:
s->pim[1].la &= 0xffffffffULL;
s->pim[1].la |= val << 32;
ppc440_pcix_update_pim(s, 1);
break;
case PCIX0_PIM2SAL:
s->pim[2].sa &= 0xffffffff00000000ULL;
s->pim[2].sa = val;
ppc440_pcix_update_pim(s, 2);
break;
case PCIX0_PIM2LAL:
s->pim[2].la &= 0xffffffff00000000ULL;
s->pim[2].la |= val;
ppc440_pcix_update_pim(s, 2);
break;
case PCIX0_PIM2LAH:
s->pim[2].la &= 0xffffffffULL;
s->pim[2].la |= val << 32;
ppc440_pcix_update_pim(s, 2);
break;
case PCIX0_STS:
s->sts = val;
break;
case PCIX0_PIM0SAH:
s->pim[0].sa &= 0xffffffffULL;
s->pim[0].sa |= val << 32;
ppc440_pcix_update_pim(s, 0);
break;
case PCIX0_PIM2SAH:
s->pim[2].sa &= 0xffffffffULL;
s->pim[2].sa |= val << 32;
ppc440_pcix_update_pim(s, 2);
break;
default:
error_report("%s: unhandled PCI internal register 0x%lx", __func__,
(unsigned long)addr);
break;
}
}
static uint64_t ppc440_pcix_reg_read4(void *opaque, hwaddr addr,
unsigned size)
{
struct PPC440PCIXState *s = opaque;
uint32_t val;
switch (addr) {
case PCI_VENDOR_ID ... PCI_MAX_LAT:
val = ldl_le_p(s->dev->config + addr);
break;
case PCIX0_POM0LAL:
val = s->pom[0].la;
break;
case PCIX0_POM0LAH:
val = s->pom[0].la >> 32;
break;
case PCIX0_POM0SA:
val = s->pom[0].sa;
break;
case PCIX0_POM0PCIAL:
val = s->pom[0].pcia;
break;
case PCIX0_POM0PCIAH:
val = s->pom[0].pcia >> 32;
break;
case PCIX0_POM1LAL:
val = s->pom[1].la;
break;
case PCIX0_POM1LAH:
val = s->pom[1].la >> 32;
break;
case PCIX0_POM1SA:
val = s->pom[1].sa;
break;
case PCIX0_POM1PCIAL:
val = s->pom[1].pcia;
break;
case PCIX0_POM1PCIAH:
val = s->pom[1].pcia >> 32;
break;
case PCIX0_POM2SA:
val = s->pom[2].sa;
break;
case PCIX0_PIM0SAL:
val = s->pim[0].sa;
break;
case PCIX0_PIM0LAL:
val = s->pim[0].la;
break;
case PCIX0_PIM0LAH:
val = s->pim[0].la >> 32;
break;
case PCIX0_PIM1SA:
val = s->pim[1].sa;
break;
case PCIX0_PIM1LAL:
val = s->pim[1].la;
break;
case PCIX0_PIM1LAH:
val = s->pim[1].la >> 32;
break;
case PCIX0_PIM2SAL:
val = s->pim[2].sa;
break;
case PCIX0_PIM2LAL:
val = s->pim[2].la;
break;
case PCIX0_PIM2LAH:
val = s->pim[2].la >> 32;
break;
case PCIX0_STS:
val = s->sts;
break;
case PCIX0_PIM0SAH:
val = s->pim[0].sa >> 32;
break;
case PCIX0_PIM2SAH:
val = s->pim[2].sa >> 32;
break;
default:
error_report("%s: invalid PCI internal register 0x%lx", __func__,
(unsigned long)addr);
val = 0;
}
trace_ppc440_pcix_reg_read(addr, val);
return val;
}
static const MemoryRegionOps pci_reg_ops = {
.read = ppc440_pcix_reg_read4,
.write = ppc440_pcix_reg_write4,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void ppc440_pcix_reset(DeviceState *dev)
{
struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev);
int i;
for (i = 0; i < PPC440_PCIX_NR_POMS; i++) {
ppc440_pcix_clear_region(get_system_memory(), &s->pom[i].mr);
}
for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
ppc440_pcix_clear_region(&s->bm, &s->pim[i].mr);
}
memset(s->pom, 0, sizeof(s->pom));
memset(s->pim, 0, sizeof(s->pim));
for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
s->pim[i].sa = 0xffffffff00000000ULL;
}
s->sts = 0;
}
/* All pins from each slot are tied to a single board IRQ.
* This may need further refactoring for other boards. */
static int ppc440_pcix_map_irq(PCIDevice *pci_dev, int irq_num)
{
int slot = pci_dev->devfn >> 3;
trace_ppc440_pcix_map_irq(pci_dev->devfn, irq_num, slot);
return slot - 1;
}
static void ppc440_pcix_set_irq(void *opaque, int irq_num, int level)
{
qemu_irq *pci_irqs = opaque;
trace_ppc440_pcix_set_irq(irq_num);
if (irq_num < 0) {
error_report("%s: PCI irq %d", __func__, irq_num);
return;
}
qemu_set_irq(pci_irqs[irq_num], level);
}
static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn)
{
PPC440PCIXState *s = opaque;
return &s->bm_as;
}
/* The default pci_host_data_{read,write} functions in pci/pci_host.c
* deny access to registers without bit 31 set but our clients want
* this to work so we have to override these here */
static void pci_host_data_write(void *opaque, hwaddr addr,
uint64_t val, unsigned len)
{
PCIHostState *s = opaque;
pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
}
static uint64_t pci_host_data_read(void *opaque,
hwaddr addr, unsigned len)
{
PCIHostState *s = opaque;
uint32_t val;
val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
return val;
}
const MemoryRegionOps ppc440_pcix_host_data_ops = {
.read = pci_host_data_read,
.write = pci_host_data_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static int ppc440_pcix_initfn(SysBusDevice *dev)
{
PPC440PCIXState *s;
PCIHostState *h;
int i;
h = PCI_HOST_BRIDGE(dev);
s = PPC440_PCIX_HOST_BRIDGE(dev);
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
sysbus_init_irq(dev, &s->irq[i]);
}
memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX);
h->bus = pci_register_root_bus(DEVICE(dev), NULL, ppc440_pcix_set_irq,
ppc440_pcix_map_irq, s->irq, &s->busmem,
get_system_io(), PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge");
memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX);
memory_region_add_subregion(&s->bm, 0x0, &s->busmem);
address_space_init(&s->bm_as, &s->bm, "pci-bm");
pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s);
memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE);
memory_region_init_io(&h->conf_mem, OBJECT(s), &pci_host_conf_le_ops,
h, "pci-conf-idx", 4);
memory_region_init_io(&h->data_mem, OBJECT(s), &ppc440_pcix_host_data_ops,
h, "pci-conf-data", 4);
memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s,
"pci.reg", PPC440_REG_SIZE);
memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem);
sysbus_init_mmio(dev, &s->container);
return 0;
}
static void ppc440_pcix_class_init(ObjectClass *klass, void *data)
{
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
k->init = ppc440_pcix_initfn;
dc->reset = ppc440_pcix_reset;
}
static const TypeInfo ppc440_pcix_info = {
.name = TYPE_PPC440_PCIX_HOST_BRIDGE,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PPC440PCIXState),
.class_init = ppc440_pcix_class_init,
};
static void ppc440_pcix_register_types(void)
{
type_register_static(&ppc440_pcix_info);
}
type_init(ppc440_pcix_register_types)

View File

@ -1050,6 +1050,9 @@ static void ppc460ex_pcie_realize(DeviceState *dev, Error **errp)
case DCRN_PCIE1_BASE:
id = 1;
break;
default:
error_setg(errp, "invalid PCIe DCRN base");
return;
}
snprintf(buf, sizeof(buf), "pcie%d-io", id);
memory_region_init(&s->iomem, OBJECT(s), buf, UINT64_MAX);

603
hw/ppc/sam460ex.c Normal file
View File

@ -0,0 +1,603 @@
/*
* QEMU aCube Sam460ex board emulation
*
* Copyright (c) 2012 François Revol
* Copyright (c) 2016-2018 BALATON Zoltan
*
* This file is derived from hw/ppc440_bamboo.c,
* the copyright for that material belongs to the original owners.
*
* This work is licensed under the GNU GPL license version 2 or later.
*
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "sysemu/blockdev.h"
#include "hw/boards.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "sysemu/device_tree.h"
#include "sysemu/block-backend.h"
#include "hw/loader.h"
#include "elf.h"
#include "exec/address-spaces.h"
#include "exec/memory.h"
#include "hw/ppc/ppc440.h"
#include "hw/ppc/ppc405.h"
#include "hw/block/flash.h"
#include "sysemu/sysemu.h"
#include "sysemu/qtest.h"
#include "hw/sysbus.h"
#include "hw/char/serial.h"
#include "hw/i2c/ppc4xx_i2c.h"
#include "hw/i2c/smbus.h"
#include "hw/usb/hcd-ehci.h"
#define BINARY_DEVICE_TREE_FILE "canyonlands.dtb"
#define UBOOT_FILENAME "u-boot-sam460-20100605.bin"
/* to extract the official U-Boot bin from the updater: */
/* dd bs=1 skip=$(($(stat -c '%s' updater/updater-460) - 0x80000)) \
if=updater/updater-460 of=u-boot-sam460-20100605.bin */
/* from Sam460 U-Boot include/configs/Sam460ex.h */
#define FLASH_BASE 0xfff00000
#define FLASH_BASE_H 0x4
#define FLASH_SIZE (1 << 20)
#define UBOOT_LOAD_BASE 0xfff80000
#define UBOOT_SIZE 0x00080000
#define UBOOT_ENTRY 0xfffffffc
/* from U-Boot */
#define EPAPR_MAGIC (0x45504150)
#define KERNEL_ADDR 0x1000000
#define FDT_ADDR 0x1800000
#define RAMDISK_ADDR 0x1900000
/* Sam460ex IRQ MAP:
IRQ0 = ETH_INT
IRQ1 = FPGA_INT
IRQ2 = PCI_INT (PCIA, PCIB, PCIC, PCIB)
IRQ3 = FPGA_INT2
IRQ11 = RTC_INT
IRQ12 = SM502_INT
*/
#define SDRAM_NR_BANKS 4
/* FIXME: See u-boot.git 8ac41e, also fix in ppc440_uc.c */
static const unsigned int ppc460ex_sdram_bank_sizes[] = {
1024 << 20, 512 << 20, 256 << 20, 128 << 20, 64 << 20, 32 << 20, 0
};
struct boot_info {
uint32_t dt_base;
uint32_t dt_size;
uint32_t entry;
};
/*****************************************************************************/
/* SPD eeprom content from mips_malta.c */
struct _eeprom24c0x_t {
uint8_t tick;
uint8_t address;
uint8_t command;
uint8_t ack;
uint8_t scl;
uint8_t sda;
uint8_t data;
uint8_t contents[256];
};
typedef struct _eeprom24c0x_t eeprom24c0x_t;
static eeprom24c0x_t spd_eeprom = {
.contents = {
/* 00000000: */ 0x80, 0x08, 0xFF, 0x0D, 0x0A, 0xFF, 0x40, 0x00,
/* 00000008: */ 0x04, 0x75, 0x54, 0x00, 0x82, 0x08, 0x00, 0x01,
/* 00000010: */ 0x8F, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
/* 00000018: */ 0x00, 0x00, 0x00, 0x14, 0x0F, 0x14, 0x2D, 0xFF,
/* 00000020: */ 0x15, 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00,
/* 00000028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xD0,
/* 00000040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 00000078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xF4,
},
};
static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
{
enum { SDR = 0x4, DDR1 = 0x7, DDR2 = 0x8 } type;
uint8_t *spd = spd_eeprom.contents;
uint8_t nbanks = 0;
uint16_t density = 0;
int i;
/* work in terms of MB */
ram_size >>= 20;
while ((ram_size >= 4) && (nbanks <= 2)) {
int sz_log2 = MIN(31 - clz32(ram_size), 14);
nbanks++;
density |= 1 << (sz_log2 - 2);
ram_size -= 1 << sz_log2;
}
/* split to 2 banks if possible */
if ((nbanks == 1) && (density > 1)) {
nbanks++;
density >>= 1;
}
if (density & 0xff00) {
density = (density & 0xe0) | ((density >> 8) & 0x1f);
type = DDR2;
} else if (!(density & 0x1f)) {
type = DDR2;
} else {
type = SDR;
}
if (ram_size) {
warn_report("SPD cannot represent final " RAM_ADDR_FMT "MB"
" of SDRAM", ram_size);
}
/* fill in SPD memory information */
spd[2] = type;
spd[5] = nbanks;
spd[31] = density;
/* XXX: this is totally random */
spd[9] = 0x10; /* CAS tcyc */
spd[18] = 0x20; /* CAS bit */
spd[23] = 0x10; /* CAS tcyc */
spd[25] = 0x10; /* CAS tcyc */
/* checksum */
spd[63] = 0;
for (i = 0; i < 63; i++) {
spd[63] += spd[i];
}
/* copy for SMBUS */
memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
}
static void generate_eeprom_serial(uint8_t *eeprom)
{
int i, pos = 0;
uint8_t mac[6] = { 0x00 };
uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
/* version */
eeprom[pos++] = 0x01;
/* count */
eeprom[pos++] = 0x02;
/* MAC address */
eeprom[pos++] = 0x01; /* MAC */
eeprom[pos++] = 0x06; /* length */
memcpy(&eeprom[pos], mac, sizeof(mac));
pos += sizeof(mac);
/* serial number */
eeprom[pos++] = 0x02; /* serial */
eeprom[pos++] = 0x05; /* length */
memcpy(&eeprom[pos], sn, sizeof(sn));
pos += sizeof(sn);
/* checksum */
eeprom[pos] = 0;
for (i = 0; i < pos; i++) {
eeprom[pos] += eeprom[i];
}
}
/*****************************************************************************/
static int sam460ex_load_uboot(void)
{
DriveInfo *dinfo;
BlockBackend *blk = NULL;
hwaddr base = FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32);
long bios_size = FLASH_SIZE;
int fl_sectors;
dinfo = drive_get(IF_PFLASH, 0, 0);
if (dinfo) {
blk = blk_by_legacy_dinfo(dinfo);
bios_size = blk_getlength(blk);
}
fl_sectors = (bios_size + 65535) >> 16;
if (!pflash_cfi01_register(base, NULL, "sam460ex.flash", bios_size,
blk, (64 * 1024), fl_sectors,
1, 0x89, 0x18, 0x0000, 0x0, 1)) {
error_report("qemu: Error registering flash memory.");
/* XXX: return an error instead? */
exit(1);
}
if (!blk) {
/*error_report("No flash image given with the 'pflash' parameter,"
" using default u-boot image");*/
base = UBOOT_LOAD_BASE | ((hwaddr)FLASH_BASE_H << 32);
rom_add_file_fixed(UBOOT_FILENAME, base, -1);
}
return 0;
}
static int sam460ex_load_device_tree(hwaddr addr,
uint32_t ramsize,
hwaddr initrd_base,
hwaddr initrd_size,
const char *kernel_cmdline)
{
int ret = -1;
uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
char *filename;
int fdt_size;
void *fdt;
uint32_t tb_freq = 50000000;
uint32_t clock_freq = 50000000;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (!filename) {
goto out;
}
fdt = load_device_tree(filename, &fdt_size);
g_free(filename);
if (fdt == NULL) {
goto out;
}
/* Manipulate device tree in memory. */
ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
sizeof(mem_reg_property));
if (ret < 0) {
error_report("couldn't set /memory/reg");
}
/* default FDT doesn't have a /chosen node... */
qemu_fdt_add_subnode(fdt, "/chosen");
ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
initrd_base);
if (ret < 0) {
error_report("couldn't set /chosen/linux,initrd-start");
}
ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
(initrd_base + initrd_size));
if (ret < 0) {
error_report("couldn't set /chosen/linux,initrd-end");
}
ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
kernel_cmdline);
if (ret < 0) {
error_report("couldn't set /chosen/bootargs");
}
/* Copy data from the host device tree into the guest. Since the guest can
* directly access the timebase without host involvement, we must expose
* the correct frequencies. */
if (kvm_enabled()) {
tb_freq = kvmppc_get_tbfreq();
clock_freq = kvmppc_get_clockfreq();
}
qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
clock_freq);
qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
tb_freq);
rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
g_free(fdt);
ret = fdt_size;
out:
return ret;
}
/* Create reset TLB entries for BookE, mapping only the flash memory. */
static void mmubooke_create_initial_mapping_uboot(CPUPPCState *env)
{
ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
/* on reset the flash is mapped by a shadow TLB,
* but since we don't implement them we need to use
* the same values U-Boot will use to avoid a fault.
*/
tlb->attr = 0;
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
tlb->size = 0x10000000; /* up to 0xffffffff */
tlb->EPN = 0xf0000000 & TARGET_PAGE_MASK;
tlb->RPN = (0xf0000000 & TARGET_PAGE_MASK) | 0x4;
tlb->PID = 0;
}
/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
static void mmubooke_create_initial_mapping(CPUPPCState *env,
target_ulong va,
hwaddr pa)
{
ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
tlb->attr = 0;
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
tlb->size = 1 << 31; /* up to 0x80000000 */
tlb->EPN = va & TARGET_PAGE_MASK;
tlb->RPN = pa & TARGET_PAGE_MASK;
tlb->PID = 0;
}
static void main_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
struct boot_info *bi = env->load_info;
cpu_reset(CPU(cpu));
/* either we have a kernel to boot or we jump to U-Boot */
if (bi->entry != UBOOT_ENTRY) {
env->gpr[1] = (16 << 20) - 8;
env->gpr[3] = FDT_ADDR;
env->nip = bi->entry;
/* Create a mapping for the kernel. */
mmubooke_create_initial_mapping(env, 0, 0);
env->gpr[6] = tswap32(EPAPR_MAGIC);
env->gpr[7] = (16 << 20) - 8; /*bi->ima_size;*/
} else {
env->nip = UBOOT_ENTRY;
mmubooke_create_initial_mapping_uboot(env);
}
}
static void sam460ex_init(MachineState *machine)
{
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *isa = g_new(MemoryRegion, 1);
MemoryRegion *ram_memories = g_new(MemoryRegion, SDRAM_NR_BANKS);
hwaddr ram_bases[SDRAM_NR_BANKS];
hwaddr ram_sizes[SDRAM_NR_BANKS];
MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
qemu_irq *irqs, *uic[4];
PCIBus *pci_bus;
PowerPCCPU *cpu;
CPUPPCState *env;
PPC4xxI2CState *i2c[2];
hwaddr entry = UBOOT_ENTRY;
hwaddr loadaddr = 0;
target_long initrd_size = 0;
DeviceState *dev;
SysBusDevice *sbdev;
int success;
int i;
struct boot_info *boot_info;
const size_t smbus_eeprom_size = 8 * 256;
uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
env = &cpu->env;
if (env->mmu_model != POWERPC_MMU_BOOKE) {
error_report("Only MMU model BookE is supported by this machine.");
exit(1);
}
#ifdef TARGET_PPCEMB
if (!qtest_enabled()) {
warn_report("qemu-system-ppcemb is deprecated, "
"please use qemu-system-ppc instead.");
}
#endif
qemu_register_reset(main_cpu_reset, cpu);
boot_info = g_malloc0(sizeof(*boot_info));
env->load_info = boot_info;
ppc_booke_timers_init(cpu, 50000000, 0);
ppc_dcr_init(env, NULL, NULL);
/* PLB arbitrer */
ppc4xx_plb_init(env);
/* interrupt controllers */
irqs = g_malloc0(sizeof(*irqs) * PPCUIC_OUTPUT_NB);
irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
/* SDRAM controller */
memset(ram_bases, 0, sizeof(ram_bases));
memset(ram_sizes, 0, sizeof(ram_sizes));
/* put all RAM on first bank because board has one slot
* and firmware only checks that */
machine->ram_size = ppc4xx_sdram_adjust(machine->ram_size, 1,
ram_memories, ram_bases, ram_sizes,
ppc460ex_sdram_bank_sizes);
/* FIXME: does 460EX have ECC interrupts? */
ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories,
ram_bases, ram_sizes, 1);
/* generate SPD EEPROM data */
for (i = 0; i < SDRAM_NR_BANKS; i++) {
generate_eeprom_spd(&smbus_eeprom_buf[i * 256], ram_sizes[i]);
}
generate_eeprom_serial(&smbus_eeprom_buf[4 * 256]);
generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
/* IIC controllers */
dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]);
i2c[0] = PPC4xx_I2C(dev);
object_property_set_bool(OBJECT(dev), true, "realized", NULL);
smbus_eeprom_init(i2c[0]->bus, 8, smbus_eeprom_buf, smbus_eeprom_size);
g_free(smbus_eeprom_buf);
dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
i2c[1] = PPC4xx_I2C(dev);
/* External bus controller */
ppc405_ebc_init(env);
/* CPR */
ppc4xx_cpr_init(env);
/* PLB to AHB bridge */
ppc4xx_ahb_init(env);
/* System DCRs */
ppc4xx_sdr_init(env);
/* MAL */
ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
/* 256K of L2 cache as memory */
ppc4xx_l2sram_init(env);
/* FIXME: remove this after fixing l2sram mapping in ppc440_uc.c? */
memory_region_init_ram(l2cache_ram, NULL, "ppc440.l2cache_ram", 256 << 10,
&error_abort);
memory_region_add_subregion(address_space_mem, 0x400000000LL, l2cache_ram);
/* USB */
sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400, uic[2][29]);
dev = qdev_create(NULL, "sysbus-ohci");
qdev_prop_set_string(dev, "masterbus", "usb-bus.0");
qdev_prop_set_uint32(dev, "num-ports", 6);
qdev_init_nofail(dev);
sbdev = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(sbdev, 0, 0x4bffd0000);
sysbus_connect_irq(sbdev, 0, uic[2][30]);
usb_create_simple(usb_bus_find(-1), "usb-kbd");
usb_create_simple(usb_bus_find(-1), "usb-mouse");
/* PCI bus */
ppc460ex_pcie_init(env);
/* FIXME: is this correct? */
dev = sysbus_create_varargs("ppc440-pcix-host", 0xc0ec00000,
uic[1][0], uic[1][20], uic[1][21], uic[1][22],
NULL);
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
if (!pci_bus) {
error_report("couldn't create PCI controller!");
exit(1);
}
memory_region_init_alias(isa, NULL, "isa_mmio", get_system_io(),
0, 0x10000);
memory_region_add_subregion(get_system_memory(), 0xc08000000, isa);
/* PCI devices */
pci_create_simple(pci_bus, PCI_DEVFN(6, 0), "sm501");
/* SoC has a single SATA port but we don't emulate that yet
* However, firmware and usual clients have driver for SiI311x
* so add one for convenience by default */
if (defaults_enabled()) {
pci_create_simple(pci_bus, -1, "sii3112");
}
/* SoC has 4 UARTs
* but board has only one wired and two are present in fdt */
if (serial_hds[0] != NULL) {
serial_mm_init(address_space_mem, 0x4ef600300, 0, uic[1][1],
PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
DEVICE_BIG_ENDIAN);
}
if (serial_hds[1] != NULL) {
serial_mm_init(address_space_mem, 0x4ef600400, 0, uic[0][1],
PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
DEVICE_BIG_ENDIAN);
}
/* Load U-Boot image. */
if (!machine->kernel_filename) {
success = sam460ex_load_uboot();
if (success < 0) {
error_report("qemu: could not load firmware");
exit(1);
}
}
/* Load kernel. */
if (machine->kernel_filename) {
success = load_uimage(machine->kernel_filename, &entry, &loadaddr,
NULL, NULL, NULL);
if (success < 0) {
uint64_t elf_entry, elf_lowaddr;
success = load_elf(machine->kernel_filename, NULL, NULL, &elf_entry,
&elf_lowaddr, NULL, 1, PPC_ELF_MACHINE, 0, 0);
entry = elf_entry;
loadaddr = elf_lowaddr;
}
/* XXX try again as binary */
if (success < 0) {
error_report("qemu: could not load kernel '%s'",
machine->kernel_filename);
exit(1);
}
}
/* Load initrd. */
if (machine->initrd_filename) {
initrd_size = load_image_targphys(machine->initrd_filename,
RAMDISK_ADDR,
machine->ram_size - RAMDISK_ADDR);
if (initrd_size < 0) {
error_report("qemu: could not load ram disk '%s' at %x",
machine->initrd_filename, RAMDISK_ADDR);
exit(1);
}
}
/* If we're loading a kernel directly, we must load the device tree too. */
if (machine->kernel_filename) {
int dt_size;
dt_size = sam460ex_load_device_tree(FDT_ADDR, machine->ram_size,
RAMDISK_ADDR, initrd_size,
machine->kernel_cmdline);
if (dt_size < 0) {
error_report("couldn't load device tree");
exit(1);
}
boot_info->dt_base = FDT_ADDR;
boot_info->dt_size = dt_size;
}
boot_info->entry = entry;
}
static void sam460ex_machine_init(MachineClass *mc)
{
mc->desc = "aCube Sam460ex";
mc->init = sam460ex_init;
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("460exb");
mc->default_ram_size = 512 * M_BYTE;
}
DEFINE_MACHINE("sam460ex", sam460ex_machine_init)

View File

@ -105,12 +105,14 @@
*/
static int spapr_vcpu_id(sPAPRMachineState *spapr, int cpu_index)
{
assert(spapr->vsmt);
return
(cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
}
static bool spapr_is_thread0_in_vcore(sPAPRMachineState *spapr,
PowerPCCPU *cpu)
{
assert(spapr->vsmt);
return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
}
@ -177,13 +179,13 @@ static void pre_2_10_vmstate_unregister_dummy_icp(int i)
static int xics_max_server_number(sPAPRMachineState *spapr)
{
assert(spapr->vsmt);
return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
}
static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
if (kvm_enabled()) {
if (machine_kernel_irqchip_allowed(machine) &&
@ -205,17 +207,6 @@ static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
return;
}
}
if (smc->pre_2_10_has_unused_icps) {
int i;
for (i = 0; i < xics_max_server_number(spapr); i++) {
/* Dummy entries get deregistered when real ICPState objects
* are registered during CPU core hotplug.
*/
pre_2_10_vmstate_register_dummy_icp(i);
}
}
}
static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
@ -1062,7 +1053,14 @@ static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)
}
if (!spapr->has_graphics && stdout_path) {
/*
* "linux,stdout-path" and "stdout" properties are deprecated by linux
* kernel. New platforms should only use the "stdout-path" property. Set
* the new property and continue using older property to remain
* compatible with the existing firmware.
*/
_FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
_FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
}
spapr_dt_ov5_platform_support(fdt, chosen);
@ -2232,61 +2230,6 @@ static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
return &ms->possible_cpus->cpus[index];
}
static void spapr_init_cpus(sPAPRMachineState *spapr)
{
MachineState *machine = MACHINE(spapr);
MachineClass *mc = MACHINE_GET_CLASS(machine);
const char *type = spapr_get_cpu_core_type(machine->cpu_type);
const CPUArchIdList *possible_cpus;
int boot_cores_nr = smp_cpus / smp_threads;
int i;
possible_cpus = mc->possible_cpu_arch_ids(machine);
if (mc->has_hotpluggable_cpus) {
if (smp_cpus % smp_threads) {
error_report("smp_cpus (%u) must be multiple of threads (%u)",
smp_cpus, smp_threads);
exit(1);
}
if (max_cpus % smp_threads) {
error_report("max_cpus (%u) must be multiple of threads (%u)",
max_cpus, smp_threads);
exit(1);
}
} else {
if (max_cpus != smp_cpus) {
error_report("This machine version does not support CPU hotplug");
exit(1);
}
boot_cores_nr = possible_cpus->len;
}
for (i = 0; i < possible_cpus->len; i++) {
int core_id = i * smp_threads;
if (mc->has_hotpluggable_cpus) {
spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
spapr_vcpu_id(spapr, core_id));
}
if (i < boot_cores_nr) {
Object *core = object_new(type);
int nr_threads = smp_threads;
/* Handle the partially filled core for older machine types */
if ((i + 1) * smp_threads >= smp_cpus) {
nr_threads = smp_cpus - i * smp_threads;
}
object_property_set_int(core, nr_threads, "nr-threads",
&error_fatal);
object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
&error_fatal);
object_property_set_bool(core, true, "realized", &error_fatal);
}
}
}
static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp)
{
Error *local_err = NULL;
@ -2359,6 +2302,78 @@ out:
error_propagate(errp, local_err);
}
static void spapr_init_cpus(sPAPRMachineState *spapr)
{
MachineState *machine = MACHINE(spapr);
MachineClass *mc = MACHINE_GET_CLASS(machine);
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
const char *type = spapr_get_cpu_core_type(machine->cpu_type);
const CPUArchIdList *possible_cpus;
int boot_cores_nr = smp_cpus / smp_threads;
int i;
possible_cpus = mc->possible_cpu_arch_ids(machine);
if (mc->has_hotpluggable_cpus) {
if (smp_cpus % smp_threads) {
error_report("smp_cpus (%u) must be multiple of threads (%u)",
smp_cpus, smp_threads);
exit(1);
}
if (max_cpus % smp_threads) {
error_report("max_cpus (%u) must be multiple of threads (%u)",
max_cpus, smp_threads);
exit(1);
}
} else {
if (max_cpus != smp_cpus) {
error_report("This machine version does not support CPU hotplug");
exit(1);
}
boot_cores_nr = possible_cpus->len;
}
/* VSMT must be set in order to be able to compute VCPU ids, ie to
* call xics_max_server_number() or spapr_vcpu_id().
*/
spapr_set_vsmt_mode(spapr, &error_fatal);
if (smc->pre_2_10_has_unused_icps) {
int i;
for (i = 0; i < xics_max_server_number(spapr); i++) {
/* Dummy entries get deregistered when real ICPState objects
* are registered during CPU core hotplug.
*/
pre_2_10_vmstate_register_dummy_icp(i);
}
}
for (i = 0; i < possible_cpus->len; i++) {
int core_id = i * smp_threads;
if (mc->has_hotpluggable_cpus) {
spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
spapr_vcpu_id(spapr, core_id));
}
if (i < boot_cores_nr) {
Object *core = object_new(type);
int nr_threads = smp_threads;
/* Handle the partially filled core for older machine types */
if ((i + 1) * smp_threads >= smp_cpus) {
nr_threads = smp_cpus - i * smp_threads;
}
object_property_set_int(core, nr_threads, "nr-threads",
&error_fatal);
object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
&error_fatal);
object_property_set_bool(core, true, "realized", &error_fatal);
}
}
}
/* pSeries LPAR / sPAPR hardware init */
static void spapr_machine_init(MachineState *machine)
{
@ -2486,8 +2501,6 @@ static void spapr_machine_init(MachineState *machine)
}
/* init CPUs */
spapr_set_vsmt_mode(spapr, &error_fatal);
spapr_init_cpus(spapr);
if (kvm_enabled()) {
@ -3810,13 +3823,7 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj,
int spapr_get_vcpu_id(PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
if (kvm_enabled()) {
return kvm_arch_vcpu_id(cs);
} else {
return cs->cpu_index;
}
return cpu->vcpu_id;
}
void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
@ -3983,6 +3990,23 @@ static void spapr_machine_2_12_class_options(MachineClass *mc)
DEFINE_SPAPR_MACHINE(2_12, "2.12", true);
static void spapr_machine_2_12_sxxm_instance_options(MachineState *machine)
{
spapr_machine_2_12_instance_options(machine);
}
static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
spapr_machine_2_12_class_options(mc);
smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
}
DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
/*
* pseries-2.11
*/

View File

@ -32,6 +32,20 @@
#include "hw/ppc/spapr.h"
typedef struct sPAPRCapPossible {
int num; /* size of vals array below */
const char *help; /* help text for vals */
/*
* Note:
* - because of the way compatibility is determined vals MUST be ordered
* such that later options are a superset of all preceding options.
* - the order of vals must be preserved, that is their index is important,
* however vals may be added to the end of the list so long as the above
* point is observed
*/
const char *vals[];
} sPAPRCapPossible;
typedef struct sPAPRCapabilityInfo {
const char *name;
const char *description;
@ -41,6 +55,8 @@ typedef struct sPAPRCapabilityInfo {
ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set;
const char *type;
/* Possible values if this is a custom string type */
sPAPRCapPossible *possible;
/* Make sure the virtual hardware can support this capability */
void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
} sPAPRCapabilityInfo;
@ -73,41 +89,34 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
}
static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
sPAPRCapabilityInfo *cap = opaque;
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
char *val = NULL;
uint8_t value = spapr_get_cap(spapr, cap->index);
switch (value) {
case SPAPR_CAP_BROKEN:
val = g_strdup("broken");
break;
case SPAPR_CAP_WORKAROUND:
val = g_strdup("workaround");
break;
case SPAPR_CAP_FIXED:
val = g_strdup("fixed");
break;
default:
if (value >= cap->possible->num) {
error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name);
return;
}
val = g_strdup(cap->possible->vals[value]);
visit_type_str(v, name, &val, errp);
g_free(val);
}
static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
sPAPRCapabilityInfo *cap = opaque;
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
char *val;
Error *local_err = NULL;
uint8_t value;
uint8_t i;
char *val;
visit_type_str(v, name, &val, &local_err);
if (local_err) {
@ -115,20 +124,20 @@ static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
return;
}
if (!strcasecmp(val, "broken")) {
value = SPAPR_CAP_BROKEN;
} else if (!strcasecmp(val, "workaround")) {
value = SPAPR_CAP_WORKAROUND;
} else if (!strcasecmp(val, "fixed")) {
value = SPAPR_CAP_FIXED;
} else {
error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
cap->name);
if (!strcmp(val, "?")) {
error_setg(errp, "%s", cap->possible->help);
goto out;
}
for (i = 0; i < cap->possible->num; i++) {
if (!strcasecmp(val, cap->possible->vals[i])) {
spapr->cmd_line_caps[cap->index] = true;
spapr->eff.caps[cap->index] = i;
goto out;
}
}
spapr->cmd_line_caps[cap->index] = true;
spapr->eff.caps[cap->index] = value;
error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
cap->name);
out:
g_free(val);
}
@ -180,38 +189,77 @@ static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
}
}
sPAPRCapPossible cap_cfpc_possible = {
.num = 3,
.vals = {"broken", "workaround", "fixed"},
.help = "broken - no protection, workaround - workaround available,"
" fixed - fixed in hardware",
};
static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val,
Error **errp)
{
uint8_t kvm_val = kvmppc_get_cap_safe_cache();
if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
error_setg(errp, "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
} else if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) {
error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc");
error_setg(errp,
"Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
"Requested safe cache capability level not supported by kvm, try cap-cfpc=%s",
cap_cfpc_possible.vals[kvm_val]);
}
}
sPAPRCapPossible cap_sbbc_possible = {
.num = 3,
.vals = {"broken", "workaround", "fixed"},
.help = "broken - no protection, workaround - workaround available,"
" fixed - fixed in hardware",
};
static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val,
Error **errp)
{
uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check();
if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
error_setg(errp, "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
} else if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) {
error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc");
error_setg(errp,
"Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
"Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s",
cap_sbbc_possible.vals[kvm_val]);
}
}
sPAPRCapPossible cap_ibs_possible = {
.num = 4,
/* Note workaround only maintained for compatibility */
.vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd"},
.help = "broken - no protection, fixed-ibs - indirect branch serialisation,"
" fixed-ccd - cache count disabled",
};
static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr,
uint8_t val, Error **errp)
{
uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch();
if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */
error_setg(errp, "Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=fixed");
error_setg(errp,
"Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=%s",
cap_ibs_possible.vals[kvm_val]);
} else if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
} else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) {
error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs");
error_setg(errp,
"Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
} else if (kvm_enabled() && val && (val != kvm_val)) {
error_setg(errp,
"Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s",
cap_ibs_possible.vals[kvm_val]);
}
}
@ -249,27 +297,31 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
.name = "cfpc",
.description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE,
.index = SPAPR_CAP_CFPC,
.get = spapr_cap_get_tristate,
.set = spapr_cap_set_tristate,
.get = spapr_cap_get_string,
.set = spapr_cap_set_string,
.type = "string",
.possible = &cap_cfpc_possible,
.apply = cap_safe_cache_apply,
},
[SPAPR_CAP_SBBC] = {
.name = "sbbc",
.description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE,
.index = SPAPR_CAP_SBBC,
.get = spapr_cap_get_tristate,
.set = spapr_cap_set_tristate,
.get = spapr_cap_get_string,
.set = spapr_cap_set_string,
.type = "string",
.possible = &cap_sbbc_possible,
.apply = cap_safe_bounds_check_apply,
},
[SPAPR_CAP_IBS] = {
.name = "ibs",
.description = "Indirect Branch Serialisation (broken, fixed)",
.description =
"Indirect Branch Speculation (broken, fixed-ibs, fixed-ccd)",
.index = SPAPR_CAP_IBS,
.get = spapr_cap_get_tristate,
.set = spapr_cap_set_tristate,
.get = spapr_cap_get_string,
.set = spapr_cap_set_string,
.type = "string",
.possible = &cap_ibs_possible,
.apply = cap_safe_indirect_branch_apply,
},
};
@ -283,15 +335,26 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
caps = smc->default_caps;
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
}
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
}
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06_PLUS,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
}
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
}
return caps;

View File

@ -1705,7 +1705,10 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
}
switch (safe_indirect_branch) {
case SPAPR_CAP_FIXED:
case SPAPR_CAP_FIXED_CCD:
characteristics |= H_CPU_CHAR_CACHE_COUNT_DIS;
break;
case SPAPR_CAP_FIXED_IBS:
characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED;
break;
default: /* broken */

View File

@ -99,3 +99,11 @@ mac99_uninorth_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"P
# hw/ppc/ppc4xx_pci.c
ppc4xx_pci_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
ppc4xx_pci_set_irq(int irq_num) "PCI irq %d"
# hw/ppc/ppc440_pcix.c
ppc440_pcix_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
ppc440_pcix_set_irq(int irq_num) "PCI irq %d"
ppc440_pcix_update_pim(int idx, uint64_t size, uint64_t la) "Added window %d of size=0x%" PRIx64 " to CPU=0x%" PRIx64
ppc440_pcix_update_pom(int idx, uint32_t size, uint64_t la, uint64_t pcia) "Added window %d of size=0x%x from CPU=0x%" PRIx64 " to PCI=0x%" PRIx64
ppc440_pcix_reg_read(uint64_t addr, uint32_t val) "addr 0x%" PRIx64 " = 0x%" PRIx32
ppc440_pcix_reg_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " = 0x%" PRIx64

View File

@ -0,0 +1,49 @@
/*
* Heathrow PIC support (OldWorld PowerMac)
*
* Copyright (c) 2005-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* 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.
*/
#ifndef HEATHROW_H
#define HEATHROW_H
#define TYPE_HEATHROW "heathrow"
#define HEATHROW(obj) OBJECT_CHECK(HeathrowState, (obj), TYPE_HEATHROW)
typedef struct HeathrowPICState {
uint32_t events;
uint32_t mask;
uint32_t levels;
uint32_t level_triggered;
} HeathrowPICState;
typedef struct HeathrowState {
SysBusDevice parent_obj;
MemoryRegion mem;
HeathrowPICState pics[2];
qemu_irq *irqs;
} HeathrowState;
#define HEATHROW_NUM_IRQS 64
#endif /* HEATHROW_H */

View File

@ -0,0 +1,79 @@
/*
* PowerMac MacIO device emulation
*
* Copyright (c) 2005-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
*
* 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.
*/
#ifndef MACIO_H
#define MACIO_H
#include "hw/intc/heathrow_pic.h"
#include "hw/misc/macio/cuda.h"
#include "hw/ppc/mac_dbdma.h"
#include "hw/ppc/openpic.h"
#define TYPE_MACIO "macio"
#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
typedef struct MacIOState {
/*< private >*/
PCIDevice parent;
/*< public >*/
MemoryRegion bar;
CUDAState cuda;
DBDMAState dbdma;
ESCCState escc;
uint64_t frequency;
} MacIOState;
#define TYPE_OLDWORLD_MACIO "macio-oldworld"
#define OLDWORLD_MACIO(obj) \
OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
typedef struct OldWorldMacIOState {
/*< private >*/
MacIOState parent_obj;
/*< public >*/
HeathrowState *pic;
qemu_irq irqs[7];
MacIONVRAMState nvram;
MACIOIDEState ide[2];
} OldWorldMacIOState;
#define TYPE_NEWWORLD_MACIO "macio-newworld"
#define NEWWORLD_MACIO(obj) \
OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
typedef struct NewWorldMacIOState {
/*< private >*/
MacIOState parent_obj;
/*< public >*/
OpenPICState *pic;
qemu_irq irqs[7];
MACIOIDEState ide[2];
} NewWorldMacIOState;
#endif /* MACIO_H */

View File

@ -2,10 +2,13 @@
#define OPENPIC_H
#include "qemu-common.h"
#include "hw/sysbus.h"
#include "hw/qdev-core.h"
#include "qom/cpu.h"
#define TYPE_OPENPIC "openpic"
#define MAX_CPU 32
#define MAX_MSI 8
#define VID 0x03 /* MPIC version ID */
/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
enum {
@ -28,7 +31,158 @@ enum {
#define OPENPIC_MAX_IRQ (OPENPIC_MAX_SRC + OPENPIC_MAX_IPI + \
OPENPIC_MAX_TMR)
#define TYPE_KVM_OPENPIC "kvm-openpic"
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs);
/* Raven */
#define RAVEN_MAX_CPU 2
#define RAVEN_MAX_EXT 48
#define RAVEN_MAX_IRQ 64
#define RAVEN_MAX_TMR OPENPIC_MAX_TMR
#define RAVEN_MAX_IPI OPENPIC_MAX_IPI
/* KeyLargo */
#define KEYLARGO_MAX_CPU 4
#define KEYLARGO_MAX_EXT 64
#define KEYLARGO_MAX_IPI 4
#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI)
#define KEYLARGO_MAX_TMR 0
#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */
/* Timers don't exist but this makes the code happy... */
#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI)
/* Interrupt definitions */
#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */
#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */
#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */
#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
/* First doorbell IRQ */
#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
typedef struct FslMpicInfo {
int max_ext;
} FslMpicInfo;
typedef enum IRQType {
IRQ_TYPE_NORMAL = 0,
IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */
IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
} IRQType;
/* Round up to the nearest 64 IRQs so that the queue length
* won't change when moving between 32 and 64 bit hosts.
*/
#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63)
typedef struct IRQQueue {
unsigned long *queue;
int32_t queue_size; /* Only used for VMSTATE_BITMAP */
int next;
int priority;
} IRQQueue;
typedef struct IRQSource {
uint32_t ivpr; /* IRQ vector/priority register */
uint32_t idr; /* IRQ destination register */
uint32_t destmask; /* bitmap of CPU destinations */
int last_cpu;
int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
int pending; /* TRUE if IRQ is pending */
IRQType type;
bool level:1; /* level-triggered */
bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */
} IRQSource;
#define IVPR_MASK_SHIFT 31
#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT)
#define IVPR_ACTIVITY_SHIFT 30
#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT)
#define IVPR_MODE_SHIFT 29
#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT)
#define IVPR_POLARITY_SHIFT 23
#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT)
#define IVPR_SENSE_SHIFT 22
#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT)
#define IVPR_PRIORITY_MASK (0xFU << 16)
#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
#define IDR_EP 0x80000000 /* external pin */
#define IDR_CI 0x40000000 /* critical interrupt */
typedef struct OpenPICTimer {
uint32_t tccr; /* Global timer current count register */
uint32_t tbcr; /* Global timer base count register */
int n_IRQ;
bool qemu_timer_active; /* Is the qemu_timer is running? */
struct QEMUTimer *qemu_timer;
struct OpenPICState *opp; /* Device timer is part of. */
/* The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last
current_count written or read, only defined if qemu_timer_active. */
uint64_t origin_time;
} OpenPICTimer;
typedef struct OpenPICMSI {
uint32_t msir; /* Shared Message Signaled Interrupt Register */
} OpenPICMSI;
typedef struct IRQDest {
int32_t ctpr; /* CPU current task priority */
IRQQueue raised;
IRQQueue servicing;
qemu_irq *irqs;
/* Count of IRQ sources asserting on non-INT outputs */
uint32_t outputs_active[OPENPIC_OUTPUT_NB];
} IRQDest;
#define TYPE_OPENPIC "openpic"
#define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC)
typedef struct OpenPICState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion mem;
/* Behavior control */
FslMpicInfo *fsl;
uint32_t model;
uint32_t flags;
uint32_t nb_irqs;
uint32_t vid;
uint32_t vir; /* Vendor identification register */
uint32_t vector_mask;
uint32_t tfrr_reset;
uint32_t ivpr_reset;
uint32_t idr_reset;
uint32_t brr1;
uint32_t mpic_mode_mask;
/* Sub-regions */
MemoryRegion sub_io_mem[6];
/* Global registers */
uint32_t frr; /* Feature reporting register */
uint32_t gcr; /* Global configuration register */
uint32_t pir; /* Processor initialization register */
uint32_t spve; /* Spurious vector register */
uint32_t tfrr; /* Timer frequency reporting register */
/* Source registers */
IRQSource src[OPENPIC_MAX_IRQ];
/* Local registers per output pin */
IRQDest dst[MAX_CPU];
uint32_t nb_cpus;
/* Timer registers */
OpenPICTimer timers[OPENPIC_MAX_TMR];
uint32_t max_tmr;
/* Shared MSI registers */
OpenPICMSI msi[MAX_MSI];
uint32_t max_irq;
uint32_t irq_ipi0;
uint32_t irq_tim0;
uint32_t irq_msi;
} OpenPICState;
#endif /* OPENPIC_H */

View File

@ -0,0 +1,7 @@
#ifndef OPENPIC_KVM_H
#define OPENPIC_KVM_H
#define TYPE_KVM_OPENPIC "kvm-openpic"
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs);
#endif /* OPENPIC_KVM_H */

View File

@ -75,10 +75,12 @@ typedef enum {
/* Bool Caps */
#define SPAPR_CAP_OFF 0x00
#define SPAPR_CAP_ON 0x01
/* Broken | Workaround | Fixed Caps */
/* Custom Caps */
#define SPAPR_CAP_BROKEN 0x00
#define SPAPR_CAP_WORKAROUND 0x01
#define SPAPR_CAP_FIXED 0x02
#define SPAPR_CAP_FIXED_IBS 0x02
#define SPAPR_CAP_FIXED_CCD 0x03
typedef struct sPAPRCapabilities sPAPRCapabilities;
struct sPAPRCapabilities {
@ -313,6 +315,7 @@ struct sPAPRMachineState {
#define H_CPU_CHAR_L1D_THREAD_PRIV PPC_BIT(4)
#define H_CPU_CHAR_HON_BRANCH_HINTS PPC_BIT(5)
#define H_CPU_CHAR_THR_RECONF_TRIG PPC_BIT(6)
#define H_CPU_CHAR_CACHE_COUNT_DIS PPC_BIT(7)
#define H_CPU_BEHAV_FAVOUR_SECURITY PPC_BIT(0)
#define H_CPU_BEHAV_L1D_FLUSH_PR PPC_BIT(1)
#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR PPC_BIT(2)

BIN
pc-bios/canyonlands.dtb Normal file

Binary file not shown.

566
pc-bios/canyonlands.dts Normal file
View File

@ -0,0 +1,566 @@
/*
* Device Tree Source for AMCC Canyonlands (460EX)
*
* Copyright 2008-2009 DENX Software Engineering, Stefan Roese <sr@denx.de>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without
* any warranty of any kind, whether express or implied.
*/
/dts-v1/;
/ {
#address-cells = <2>;
#size-cells = <1>;
model = "amcc,canyonlands";
compatible = "amcc,canyonlands";
dcr-parent = <&{/cpus/cpu@0}>;
aliases {
ethernet0 = &EMAC0;
ethernet1 = &EMAC1;
serial0 = &UART0;
serial1 = &UART1;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
model = "PowerPC,460EX";
reg = <0x00000000>;
clock-frequency = <0>; /* Filled in by U-Boot */
timebase-frequency = <0>; /* Filled in by U-Boot */
i-cache-line-size = <32>;
d-cache-line-size = <32>;
i-cache-size = <32768>;
d-cache-size = <32768>;
dcr-controller;
dcr-access-method = "native";
next-level-cache = <&L2C0>;
};
};
memory {
device_type = "memory";
reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by U-Boot */
};
UIC0: interrupt-controller0 {
compatible = "ibm,uic-460ex","ibm,uic";
interrupt-controller;
cell-index = <0>;
dcr-reg = <0x0c0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
};
UIC1: interrupt-controller1 {
compatible = "ibm,uic-460ex","ibm,uic";
interrupt-controller;
cell-index = <1>;
dcr-reg = <0x0d0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
interrupt-parent = <&UIC0>;
};
UIC2: interrupt-controller2 {
compatible = "ibm,uic-460ex","ibm,uic";
interrupt-controller;
cell-index = <2>;
dcr-reg = <0x0e0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
interrupt-parent = <&UIC0>;
};
UIC3: interrupt-controller3 {
compatible = "ibm,uic-460ex","ibm,uic";
interrupt-controller;
cell-index = <3>;
dcr-reg = <0x0f0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
interrupt-parent = <&UIC0>;
};
SDR0: sdr {
compatible = "ibm,sdr-460ex";
dcr-reg = <0x00e 0x002>;
};
CPR0: cpr {
compatible = "ibm,cpr-460ex";
dcr-reg = <0x00c 0x002>;
};
CPM0: cpm {
compatible = "ibm,cpm";
dcr-access-method = "native";
dcr-reg = <0x160 0x003>;
unused-units = <0x00000100>;
idle-doze = <0x02000000>;
standby = <0xfeff791d>;
};
L2C0: l2c {
compatible = "ibm,l2-cache-460ex", "ibm,l2-cache";
dcr-reg = <0x020 0x008 /* Internal SRAM DCR's */
0x030 0x008>; /* L2 cache DCR's */
cache-line-size = <32>; /* 32 bytes */
cache-size = <262144>; /* L2, 256K */
interrupt-parent = <&UIC1>;
interrupts = <11 1>;
};
plb {
compatible = "ibm,plb-460ex", "ibm,plb4";
#address-cells = <2>;
#size-cells = <1>;
ranges;
clock-frequency = <0>; /* Filled in by U-Boot */
SDRAM0: sdram {
compatible = "ibm,sdram-460ex", "ibm,sdram-405gp";
dcr-reg = <0x010 0x002>;
};
CRYPTO: crypto@180000 {
compatible = "amcc,ppc460ex-crypto", "amcc,ppc4xx-crypto";
reg = <4 0x00180000 0x80400>;
interrupt-parent = <&UIC0>;
interrupts = <0x1d 0x4>;
};
HWRNG: hwrng@110000 {
compatible = "amcc,ppc460ex-rng", "ppc4xx-rng";
reg = <4 0x00110000 0x50>;
};
MAL0: mcmal {
compatible = "ibm,mcmal-460ex", "ibm,mcmal2";
dcr-reg = <0x180 0x062>;
num-tx-chans = <2>;
num-rx-chans = <16>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-parent = <&UIC2>;
interrupts = < /*TXEOB*/ 0x6 0x4
/*RXEOB*/ 0x7 0x4
/*SERR*/ 0x3 0x4
/*TXDE*/ 0x4 0x4
/*RXDE*/ 0x5 0x4>;
};
USB0: ehci@bffd0400 {
compatible = "ibm,usb-ehci-460ex", "usb-ehci";
interrupt-parent = <&UIC2>;
interrupts = <0x1d 4>;
reg = <4 0xbffd0400 0x90 4 0xbffd0490 0x70>;
};
USB1: usb@bffd0000 {
compatible = "ohci-le";
reg = <4 0xbffd0000 0x60>;
interrupt-parent = <&UIC2>;
interrupts = <0x1e 4>;
};
USBOTG0: usbotg@bff80000 {
compatible = "amcc,dwc-otg";
reg = <0x4 0xbff80000 0x10000>;
interrupt-parent = <&USBOTG0>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupts = <0x0 0x1 0x2>;
interrupt-map = </* USB-OTG */ 0x0 &UIC2 0x1c 0x4
/* HIGH-POWER */ 0x1 &UIC1 0x1a 0x8
/* DMA */ 0x2 &UIC0 0xc 0x4>;
};
AHBDMA: dma@bffd0800 {
compatible = "snps,dma-spear1340";
reg = <4 0xbffd0800 0x400>;
interrupt-parent = <&UIC3>;
interrupts = <0x5 0x4>;
#dma-cells = <3>;
};
SATA0: sata@bffd1000 {
compatible = "amcc,sata-460ex";
reg = <4 0xbffd1000 0x800>;
interrupt-parent = <&UIC3>;
interrupts = <0x0 0x4>;
dmas = <&AHBDMA 0 1 0>;
dma-names = "sata-dma";
};
POB0: opb {
compatible = "ibm,opb-460ex", "ibm,opb";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0xb0000000 0x00000004 0xb0000000 0x50000000>;
clock-frequency = <0>; /* Filled in by U-Boot */
EBC0: ebc {
compatible = "ibm,ebc-460ex", "ibm,ebc";
dcr-reg = <0x012 0x002>;
#address-cells = <2>;
#size-cells = <1>;
clock-frequency = <0>; /* Filled in by U-Boot */
/* ranges property is supplied by U-Boot */
interrupts = <0x6 0x4>;
interrupt-parent = <&UIC1>;
nor_flash@0,0 {
compatible = "amd,s29gl512n", "cfi-flash";
bank-width = <2>;
reg = <0x00000000 0x00000000 0x04000000>;
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "kernel";
reg = <0x00000000 0x001e0000>;
};
partition@1e0000 {
label = "dtb";
reg = <0x001e0000 0x00020000>;
};
partition@200000 {
label = "ramdisk";
reg = <0x00200000 0x01400000>;
};
partition@1600000 {
label = "jffs2";
reg = <0x01600000 0x00400000>;
};
partition@1a00000 {
label = "user";
reg = <0x01a00000 0x02560000>;
};
partition@3f60000 {
label = "env";
reg = <0x03f60000 0x00040000>;
};
partition@3fa0000 {
label = "u-boot";
reg = <0x03fa0000 0x00060000>;
};
};
cpld@2,0 {
compatible = "amcc,ppc460ex-bcsr";
reg = <2 0x0 0x9>;
};
ndfc@3,0 {
compatible = "ibm,ndfc";
reg = <0x00000003 0x00000000 0x00002000>;
ccr = <0x00001000>;
bank-settings = <0x80002222>;
#address-cells = <1>;
#size-cells = <1>;
nand {
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x00000000 0x00100000>;
};
partition@100000 {
label = "user";
reg = <0x00000000 0x03f00000>;
};
};
};
};
UART0: serial@ef600300 {
device_type = "serial";
compatible = "ns16550";
reg = <0xef600300 0x00000008>;
virtual-reg = <0xef600300>;
clock-frequency = <0>; /* Filled in by U-Boot */
current-speed = <0>; /* Filled in by U-Boot */
interrupt-parent = <&UIC1>;
interrupts = <0x1 0x4>;
};
UART1: serial@ef600400 {
device_type = "serial";
compatible = "ns16550";
reg = <0xef600400 0x00000008>;
virtual-reg = <0xef600400>;
clock-frequency = <0>; /* Filled in by U-Boot */
current-speed = <0>; /* Filled in by U-Boot */
interrupt-parent = <&UIC0>;
interrupts = <0x1 0x4>;
};
IIC0: i2c@ef600700 {
compatible = "ibm,iic-460ex", "ibm,iic";
reg = <0xef600700 0x00000014>;
interrupt-parent = <&UIC0>;
interrupts = <0x2 0x4>;
#address-cells = <1>;
#size-cells = <0>;
rtc@68 {
compatible = "st,m41t80";
reg = <0x68>;
interrupt-parent = <&UIC2>;
interrupts = <0x19 0x8>;
};
sttm@48 {
compatible = "ad,ad7414";
reg = <0x48>;
interrupt-parent = <&UIC1>;
interrupts = <0x14 0x8>;
};
};
IIC1: i2c@ef600800 {
compatible = "ibm,iic-460ex", "ibm,iic";
reg = <0xef600800 0x00000014>;
interrupt-parent = <&UIC0>;
interrupts = <0x3 0x4>;
};
GPIO0: gpio@ef600b00 {
compatible = "ibm,ppc4xx-gpio";
reg = <0xef600b00 0x00000048>;
gpio-controller;
};
ZMII0: emac-zmii@ef600d00 {
compatible = "ibm,zmii-460ex", "ibm,zmii";
reg = <0xef600d00 0x0000000c>;
};
RGMII0: emac-rgmii@ef601500 {
compatible = "ibm,rgmii-460ex", "ibm,rgmii";
reg = <0xef601500 0x00000008>;
has-mdio;
};
TAH0: emac-tah@ef601350 {
compatible = "ibm,tah-460ex", "ibm,tah";
reg = <0xef601350 0x00000030>;
};
TAH1: emac-tah@ef601450 {
compatible = "ibm,tah-460ex", "ibm,tah";
reg = <0xef601450 0x00000030>;
};
EMAC0: ethernet@ef600e00 {
device_type = "network";
compatible = "ibm,emac-460ex", "ibm,emac4sync";
interrupt-parent = <&EMAC0>;
interrupts = <0x0 0x1>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
/*Wake*/ 0x1 &UIC2 0x14 0x4>;
reg = <0xef600e00 0x000000c4>;
local-mac-address = [000000000000]; /* Filled in by U-Boot */
mal-device = <&MAL0>;
mal-tx-channel = <0>;
mal-rx-channel = <0>;
cell-index = <0>;
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;
rgmii-channel = <0>;
tah-device = <&TAH0>;
tah-channel = <0>;
has-inverted-stacr-oc;
has-new-stacr-staopc;
};
EMAC1: ethernet@ef600f00 {
device_type = "network";
compatible = "ibm,emac-460ex", "ibm,emac4sync";
interrupt-parent = <&EMAC1>;
interrupts = <0x0 0x1>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = </*Status*/ 0x0 &UIC2 0x11 0x4
/*Wake*/ 0x1 &UIC2 0x15 0x4>;
reg = <0xef600f00 0x000000c4>;
local-mac-address = [000000000000]; /* Filled in by U-Boot */
mal-device = <&MAL0>;
mal-tx-channel = <1>;
mal-rx-channel = <8>;
cell-index = <1>;
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;
rgmii-channel = <1>;
tah-device = <&TAH1>;
tah-channel = <1>;
has-inverted-stacr-oc;
has-new-stacr-staopc;
mdio-device = <&EMAC0>;
};
};
PCIX0: pci@c0ec00000 {
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
compatible = "ibm,plb-pcix-460ex", "ibm,plb-pcix";
primary;
large-inbound-windows;
enable-msi-hole;
reg = <0x0000000c 0x0ec00000 0x00000008 /* Config space access */
0x00000000 0x00000000 0x00000000 /* no IACK cycles */
0x0000000c 0x0ed00000 0x00000004 /* Special cycles */
0x0000000c 0x0ec80000 0x00000100 /* Internal registers */
0x0000000c 0x0ec80100 0x000000fc>; /* Internal messaging registers */
/* Outbound ranges, one memory and one IO,
* later cannot be changed
*/
ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000
0x02000000 0x00000000 0x00000000 0x0000000c 0x0ee00000 0x00000000 0x00100000
0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* This drives busses 0 to 0x3f */
bus-range = <0x0 0x3f>;
/* All PCI interrupts are routed to ext IRQ 2 -> UIC1-0 */
interrupt-map-mask = <0x0 0x0 0x0 0x0>;
interrupt-map = < 0x0 0x0 0x0 0x0 &UIC1 0x0 0x8 >;
};
PCIE0: pciex@d00000000 {
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
compatible = "ibm,plb-pciex-460ex", "ibm,plb-pciex";
primary;
port = <0x0>; /* port number */
reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */
0x0000000c 0x08010000 0x00001000>; /* Registers */
dcr-reg = <0x100 0x020>;
sdr-base = <0x300>;
/* Outbound ranges, one memory and one IO,
* later cannot be changed
*/
ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000
0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* This drives busses 40 to 0x7f */
bus-range = <0x40 0x7f>;
/* Legacy interrupts (note the weird polarity, the bridge seems
* to invert PCIe legacy interrupts).
* We are de-swizzling here because the numbers are actually for
* port of the root complex virtual P2P bridge. But I want
* to avoid putting a node for it in the tree, so the numbers
* below are basically de-swizzled numbers.
* The real slot is on idsel 0, so the swizzling is 1:1
*/
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <
0x0 0x0 0x0 0x1 &UIC3 0xc 0x4 /* swizzled int A */
0x0 0x0 0x0 0x2 &UIC3 0xd 0x4 /* swizzled int B */
0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */
0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>;
};
PCIE1: pciex@d20000000 {
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
compatible = "ibm,plb-pciex-460ex", "ibm,plb-pciex";
primary;
port = <0x1>; /* port number */
reg = <0x0000000d 0x20000000 0x20000000 /* Config space access */
0x0000000c 0x08011000 0x00001000>; /* Registers */
dcr-reg = <0x120 0x020>;
sdr-base = <0x340>;
/* Outbound ranges, one memory and one IO,
* later cannot be changed
*/
ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000
0x02000000 0x00000000 0x00000000 0x0000000f 0x00100000 0x00000000 0x00100000
0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* This drives busses 80 to 0xbf */
bus-range = <0x80 0xbf>;
/* Legacy interrupts (note the weird polarity, the bridge seems
* to invert PCIe legacy interrupts).
* We are de-swizzling here because the numbers are actually for
* port of the root complex virtual P2P bridge. But I want
* to avoid putting a node for it in the tree, so the numbers
* below are basically de-swizzled numbers.
* The real slot is on idsel 0, so the swizzling is 1:1
*/
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <
0x0 0x0 0x0 0x1 &UIC3 0x10 0x4 /* swizzled int A */
0x0 0x0 0x0 0x2 &UIC3 0x11 0x4 /* swizzled int B */
0x0 0x0 0x0 0x3 &UIC3 0x12 0x4 /* swizzled int C */
0x0 0x0 0x0 0x4 &UIC3 0x13 0x4 /* swizzled int D */>;
};
MSI: ppc4xx-msi@C10000000 {
compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
reg = < 0xC 0x10000000 0x100>;
sdr-base = <0x36C>;
msi-data = <0x00000000>;
msi-mask = <0x44440000>;
interrupt-count = <3>;
interrupts = <0 1 2 3>;
interrupt-parent = <&UIC3>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = <0 &UIC3 0x18 1
1 &UIC3 0x19 1
2 &UIC3 0x1A 1
3 &UIC3 0x1B 1>;
};
};
};

Binary file not shown.

View File

@ -65,6 +65,7 @@ default:
@echo " slof -- update slof.bin"
@echo " skiboot -- update skiboot.lid"
@echo " u-boot.e500 -- update u-boot.e500"
@echo " u-boot.sam460 -- update u-boot.sam460"
bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k
cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin
@ -147,6 +148,11 @@ u-boot.e500:
$(powerpc_cross_prefix)strip u-boot/build.e500/u-boot -o \
../pc-bios/u-boot.e500
u-boot.sam460:
$(MAKE) -C u-boot-sam460ex Sam460ex_config
$(MAKE) -C u-boot-sam460ex CROSS_COMPILE=$(powerpc_cross_prefix)
cp u-boot-sam460ex/u-boot.bin ../pc-bios/u-boot-sam460-20100605.bin
skiboot:
$(MAKE) -C skiboot CROSS=$(powerpc64_cross_prefix)
cp skiboot/skiboot.lid ../pc-bios/skiboot.lid
@ -160,4 +166,5 @@ clean:
$(MAKE) -C ipxe/src veryclean
$(MAKE) -C SLOF clean
rm -rf u-boot/build.e500
$(MAKE) -C u-boot-sam460ex distclean
$(MAKE) -C skiboot clean

1
roms/u-boot-sam460ex Submodule

@ -0,0 +1 @@
Subproject commit 119aa277f74a4a2d3f7ab6c9471292308eba14e4

View File

@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
#include "hw/ppc/openpic.h"
#include "hw/ppc/openpic_kvm.h"
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
{

View File

@ -2494,8 +2494,10 @@ static void kvmppc_get_cpu_characteristics(KVMState *s)
cap_ppc_safe_bounds_check = 1;
}
/* Parse and set cap_ppc_safe_indirect_branch */
if (c.character & H_CPU_CHAR_BCCTRL_SERIALISED) {
cap_ppc_safe_indirect_branch = 2;
if (c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) {
cap_ppc_safe_indirect_branch = SPAPR_CAP_FIXED_CCD;
} else if (c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED) {
cap_ppc_safe_indirect_branch = SPAPR_CAP_FIXED_IBS;
}
}

View File

@ -8692,6 +8692,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
(1ull << MSR_DR) |
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_TS0) |
(1ull << MSR_TS1) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_2_07;
#if defined(CONFIG_SOFTMMU)