Patch queue for ppc - 2015-03-09

This is my current patch queue for 2.3. Highlights include:
 
   * pseries: 2.3 machine
   * pseries: Export RTC via QOM
   * pseries: EEH support
   * mac: save/restore support
   * fix POWER5 hosts
   * random bug fixes
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iQIcBAABAgAGBQJU/aeVAAoJECszeR4D/txgvckP/RuGGwTAEjxeR0ejGez8e2PP
 Ph/ZOgAXpvHN1LuKhqiMhkk5mPc9g4j4YlcgjLqlWjk3G+DPtb7pR0V+gZ0LP2k0
 TIOAU9Pyepkswry4FHBlBdPlWpL/RYx4Y9073+TmZvf7C3JXPkxbFPPY8xqIdrZ+
 pIS2C/NeMkva9c8LC9Z16u8Nhv8d09SZhp0hjKV1lthceVakcjwFcn57K/YQhpQJ
 XTSH4XwrjrdGrQF8hGWUxqhqMd3jG21XRo678wXuyEwhU+hvn3tHzrImuvtObGIn
 cJ0xwA2h+yu2T5q/Y9BRHbHjRtIZ5OwuZ8/xl7JY1lyKozzF3AfrqXg6lety3tNK
 F7T/xDAPX364vng4mKSxbdCqJ+3U7pThClF7juWluXWAywF3oeuXBvSm6YTTl1pK
 4t5v1p9tIvMHxNmEYPof0l4yU5qnP8E6msAyGef5IG7J3K8p1Gxt2mvXazKbSC+Y
 HWL+lSJ8TMW/ALH6XfUYwxdail0dgby2HubWT1yIVvzLTzgVQoLvYculb7fitKv6
 huDBOgMUrCx4Lr8ZFsH11aPvWzbAQjxBsKolOO8MpCKzg99bq3OQHWgyxDQ/6JFo
 UZmCZSF4PPHSYBQOAuxfIkbjMZ6dHQ6SMYG+WLfM3LzfDYCjexRgYVsB7LjAKMBT
 5Vzmqw3lAgI949rzA6d+
 =Erps
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging

Patch queue for ppc - 2015-03-09

This is my current patch queue for 2.3. Highlights include:

  * pseries: 2.3 machine
  * pseries: Export RTC via QOM
  * pseries: EEH support
  * mac: save/restore support
  * fix POWER5 hosts
  * random bug fixes

# gpg: Signature made Mon Mar  9 14:00:53 2015 GMT using RSA key ID 03FEDC60
# gpg: Good signature from "Alexander Graf <agraf@suse.de>"
# gpg:                 aka "Alexander Graf <alex@csgraf.de>"

* remotes/agraf/tags/signed-ppc-for-upstream: (38 commits)
  target-ppc: Fix warnings from Sparse
  sPAPR: Implement sPAPRPHBClass EEH callbacks
  sPAPR: Implement EEH RTAS calls
  target-ppc: Add versions to server CPU descriptions
  PPC: Introduce the Virtual Time Base (VTB) SPR register
  PPC: Remove duplicate OPENPIC defines in default-configs
  ppc64-softmmu: Remove duplicated OPENPIC from config
  Revert "default-configs/ppc64: add all components of i82378 SuperIO chip used by prep"
  spapr_vio: Convert to realize()
  openpic: convert to vmstate
  openpic: switch IRQQueue queue from inline to bitmap
  openpic: fix up loadvm under -M mac99
  openpic: fix segfault on -M mac99 savevm
  target-ppc: force update of msr bits in cpu_post_load
  target-ppc: move sdr1 value change detection logic to helper_store_sdr1()
  cuda.c: include adb_poll_timer in VMStateDescription
  adb.c: include ADBDevice parent state in KBDState and MouseState
  macio.c: include parent PCIDevice state in VMStateDescription
  display cpu id dump state
  Openpic: check that cpu id is within the number of cpus
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-03-09 14:04:14 +00:00
commit 277263e1b3
41 changed files with 1284 additions and 383 deletions

View File

@ -38,7 +38,6 @@ CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_XILINX_ETHLITE=y
CONFIG_OPENPIC=y
CONFIG_PREP=y
CONFIG_MAC=y
CONFIG_E500=y

View File

@ -38,7 +38,6 @@ CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_XILINX_ETHLITE=y
CONFIG_OPENPIC=y
CONFIG_PSERIES=y
CONFIG_PREP=y
CONFIG_MAC=y
@ -51,11 +50,5 @@ CONFIG_LIBDECNUMBER=y
CONFIG_XICS=$(CONFIG_PSERIES)
CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
# For PReP
CONFIG_I82378=y
CONFIG_I8259=y
CONFIG_I8254=y
CONFIG_PCSPK=y
CONFIG_I82374=y
CONFIG_I8257=y
CONFIG_MC146818RTC=y
CONFIG_ISA_TESTDEV=y

View File

@ -13,5 +13,4 @@ CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_XILINX_ETHLITE=y
CONFIG_OPENPIC=y
CONFIG_LIBDECNUMBER=y

View File

@ -60,19 +60,17 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
qemu_chr_fe_write(dev->chardev, buf, len);
}
static int spapr_vty_init(VIOsPAPRDevice *sdev)
static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
{
VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
if (!dev->chardev) {
fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
exit(1);
error_setg(errp, "chardev property not set");
return;
}
qemu_chr_add_handlers(dev->chardev, vty_can_receive,
vty_receive, NULL, dev);
return 0;
}
/* Forward declaration */
@ -163,7 +161,7 @@ static void spapr_vty_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->init = spapr_vty_init;
k->realize = spapr_vty_realize;
k->dt_name = "vty";
k->dt_type = "serial";
k->dt_compatible = "hvterm1";

View File

@ -181,6 +181,20 @@ static void pci_vga_qext_write(void *ptr, hwaddr addr,
}
}
static bool vga_get_big_endian_fb(Object *obj, Error **errp)
{
PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, PCI_DEVICE(obj));
return d->vga.big_endian_fb;
}
static void vga_set_big_endian_fb(Object *obj, bool value, Error **errp)
{
PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, PCI_DEVICE(obj));
d->vga.big_endian_fb = value;
}
static const MemoryRegionOps pci_vga_qext_ops = {
.read = pci_vga_qext_read,
.write = pci_vga_qext_write,
@ -234,6 +248,13 @@ static void pci_std_vga_realize(PCIDevice *dev, Error **errp)
}
}
static void pci_std_vga_init(Object *obj)
{
/* Expose framebuffer byteorder via QOM */
object_property_add_bool(obj, "big-endian-framebuffer",
vga_get_big_endian_fb, vga_set_big_endian_fb, NULL);
}
static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp)
{
PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
@ -265,7 +286,13 @@ static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp)
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
}
static void pci_secondary_vga_init(Object *obj)
{
/* Expose framebuffer byteorder via QOM */
object_property_add_bool(obj, "big-endian-framebuffer",
vga_get_big_endian_fb, vga_set_big_endian_fb, NULL);
}
static void pci_secondary_vga_reset(DeviceState *dev)
@ -324,6 +351,7 @@ static void secondary_class_init(ObjectClass *klass, void *data)
static const TypeInfo vga_info = {
.name = "VGA",
.parent = TYPE_PCI_DEVICE,
.instance_init = pci_std_vga_init,
.instance_size = sizeof(PCIVGAState),
.class_init = vga_class_init,
};
@ -331,6 +359,7 @@ static const TypeInfo vga_info = {
static const TypeInfo secondary_info = {
.name = "secondary-vga",
.parent = TYPE_PCI_DEVICE,
.instance_init = pci_secondary_vga_init,
.instance_size = sizeof(PCIVGAState),
.class_init = secondary_class_init,
};

View File

@ -118,6 +118,17 @@ static const TypeInfo adb_bus_type_info = {
.instance_size = sizeof(ADBBusState),
};
static const VMStateDescription vmstate_adb_device = {
.name = "adb_device",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_INT32(devaddr, ADBDevice),
VMSTATE_INT32(handler, ADBDevice),
VMSTATE_END_OF_LIST()
}
};
static void adb_device_realizefn(DeviceState *dev, Error **errp)
{
ADBDevice *d = ADB_DEVICE(dev);
@ -301,9 +312,10 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
static const VMStateDescription vmstate_adb_kbd = {
.name = "adb_kbd",
.version_id = 1,
.minimum_version_id = 1,
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(parent_obj, KBDState, 0, vmstate_adb_device, ADBDevice),
VMSTATE_BUFFER(data, KBDState),
VMSTATE_INT32(rptr, KBDState),
VMSTATE_INT32(wptr, KBDState),
@ -515,9 +527,11 @@ static void adb_mouse_reset(DeviceState *dev)
static const VMStateDescription vmstate_adb_mouse = {
.name = "adb_mouse",
.version_id = 1,
.minimum_version_id = 1,
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device,
ADBDevice),
VMSTATE_INT32(buttons_state, MouseState),
VMSTATE_INT32(last_buttons_state, MouseState),
VMSTATE_INT32(dx, MouseState),

View File

@ -200,11 +200,14 @@ typedef enum IRQType {
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 {
/* Round up to the nearest 64 IRQs so that the queue length
* won't change when moving between 32 and 64 bit hosts.
*/
unsigned long queue[BITS_TO_LONGS((OPENPIC_MAX_IRQ + 63) & ~63)];
unsigned long *queue;
int32_t queue_size; /* Only used for VMSTATE_BITMAP */
int next;
int priority;
} IRQQueue;
@ -240,6 +243,15 @@ typedef struct IRQSource {
#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 */
} 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;
@ -288,14 +300,9 @@ typedef struct OpenPICState {
IRQDest dst[MAX_CPU];
uint32_t nb_cpus;
/* Timer registers */
struct {
uint32_t tccr; /* Global timer current count register */
uint32_t tbcr; /* Global timer base count register */
} timers[OPENPIC_MAX_TMR];
OpenPICTimer timers[OPENPIC_MAX_TMR];
/* Shared MSI registers */
struct {
uint32_t msir; /* Shared Message Signaled Interrupt Register */
} msi[MAX_MSI];
OpenPICMSI msi[MAX_MSI];
uint32_t max_irq;
uint32_t irq_ipi0;
uint32_t irq_tim0;
@ -1013,7 +1020,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx,
addr, val);
if (idx < 0) {
if (idx < 0 || idx >= opp->nb_cpus) {
return;
}
@ -1152,7 +1159,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr);
retval = 0xFFFFFFFF;
if (idx < 0) {
if (idx < 0 || idx >= opp->nb_cpus) {
return retval;
}
@ -1287,132 +1294,6 @@ static const MemoryRegionOps openpic_summary_ops_be = {
},
};
static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
/* Always put the lower half of a 64-bit long first, in case we
* restore on a 32-bit host. The least significant bits correspond
* to lower IRQ numbers in the bitmap.
*/
qemu_put_be32(f, (uint32_t)q->queue[i]);
#if LONG_MAX > 0x7FFFFFFF
qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32));
#endif
}
qemu_put_sbe32s(f, &q->next);
qemu_put_sbe32s(f, &q->priority);
}
static void openpic_save(QEMUFile* f, void *opaque)
{
OpenPICState *opp = (OpenPICState *)opaque;
unsigned int i;
qemu_put_be32s(f, &opp->gcr);
qemu_put_be32s(f, &opp->vir);
qemu_put_be32s(f, &opp->pir);
qemu_put_be32s(f, &opp->spve);
qemu_put_be32s(f, &opp->tfrr);
qemu_put_be32s(f, &opp->nb_cpus);
for (i = 0; i < opp->nb_cpus; i++) {
qemu_put_sbe32s(f, &opp->dst[i].ctpr);
openpic_save_IRQ_queue(f, &opp->dst[i].raised);
openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
sizeof(opp->dst[i].outputs_active));
}
for (i = 0; i < OPENPIC_MAX_TMR; i++) {
qemu_put_be32s(f, &opp->timers[i].tccr);
qemu_put_be32s(f, &opp->timers[i].tbcr);
}
for (i = 0; i < opp->max_irq; i++) {
qemu_put_be32s(f, &opp->src[i].ivpr);
qemu_put_be32s(f, &opp->src[i].idr);
qemu_get_be32s(f, &opp->src[i].destmask);
qemu_put_sbe32s(f, &opp->src[i].last_cpu);
qemu_put_sbe32s(f, &opp->src[i].pending);
}
}
static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
unsigned long val;
val = qemu_get_be32(f);
#if LONG_MAX > 0x7FFFFFFF
val <<= 32;
val |= qemu_get_be32(f);
#endif
q->queue[i] = val;
}
qemu_get_sbe32s(f, &q->next);
qemu_get_sbe32s(f, &q->priority);
}
static int openpic_load(QEMUFile* f, void *opaque, int version_id)
{
OpenPICState *opp = (OpenPICState *)opaque;
unsigned int i, nb_cpus;
if (version_id != 1) {
return -EINVAL;
}
qemu_get_be32s(f, &opp->gcr);
qemu_get_be32s(f, &opp->vir);
qemu_get_be32s(f, &opp->pir);
qemu_get_be32s(f, &opp->spve);
qemu_get_be32s(f, &opp->tfrr);
qemu_get_be32s(f, &nb_cpus);
if (opp->nb_cpus != nb_cpus) {
return -EINVAL;
}
assert(nb_cpus > 0 && nb_cpus <= MAX_CPU);
for (i = 0; i < opp->nb_cpus; i++) {
qemu_get_sbe32s(f, &opp->dst[i].ctpr);
openpic_load_IRQ_queue(f, &opp->dst[i].raised);
openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
sizeof(opp->dst[i].outputs_active));
}
for (i = 0; i < OPENPIC_MAX_TMR; i++) {
qemu_get_be32s(f, &opp->timers[i].tccr);
qemu_get_be32s(f, &opp->timers[i].tbcr);
}
for (i = 0; i < opp->max_irq; i++) {
uint32_t val;
val = qemu_get_be32(f);
write_IRQreg_idr(opp, i, val);
val = qemu_get_be32(f);
write_IRQreg_ivpr(opp, i, val);
qemu_get_be32s(f, &opp->src[i].ivpr);
qemu_get_be32s(f, &opp->src[i].idr);
qemu_get_be32s(f, &opp->src[i].destmask);
qemu_get_sbe32s(f, &opp->src[i].last_cpu);
qemu_get_sbe32s(f, &opp->src[i].pending);
}
return 0;
}
static void openpic_reset(DeviceState *d)
{
OpenPICState *opp = OPENPIC(d);
@ -1446,12 +1327,14 @@ static void openpic_reset(DeviceState *d)
write_IRQreg_idr(opp, i, opp->idr_reset);
}
/* Initialise IRQ destinations */
for (i = 0; i < MAX_CPU; i++) {
for (i = 0; i < opp->nb_cpus; i++) {
opp->dst[i].ctpr = 15;
memset(&opp->dst[i].raised, 0, sizeof(IRQQueue));
opp->dst[i].raised.next = -1;
memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue));
opp->dst[i].raised.priority = 0;
bitmap_clear(opp->dst[i].raised.queue, 0, IRQQUEUE_SIZE_BITS);
opp->dst[i].servicing.next = -1;
opp->dst[i].servicing.priority = 0;
bitmap_clear(opp->dst[i].servicing.queue, 0, IRQQUEUE_SIZE_BITS);
}
/* Initialise timers */
for (i = 0; i < OPENPIC_MAX_TMR; i++) {
@ -1525,6 +1408,110 @@ static void map_list(OpenPICState *opp, const MemReg *list, int *count)
}
}
static const VMStateDescription vmstate_openpic_irq_queue = {
.name = "openpic_irq_queue",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_BITMAP(queue, IRQQueue, 0, queue_size),
VMSTATE_INT32(next, IRQQueue),
VMSTATE_INT32(priority, IRQQueue),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_openpic_irqdest = {
.name = "openpic_irqdest",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_INT32(ctpr, IRQDest),
VMSTATE_STRUCT(raised, IRQDest, 0, vmstate_openpic_irq_queue,
IRQQueue),
VMSTATE_STRUCT(servicing, IRQDest, 0, vmstate_openpic_irq_queue,
IRQQueue),
VMSTATE_UINT32_ARRAY(outputs_active, IRQDest, OPENPIC_OUTPUT_NB),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_openpic_irqsource = {
.name = "openpic_irqsource",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_UINT32(ivpr, IRQSource),
VMSTATE_UINT32(idr, IRQSource),
VMSTATE_UINT32(destmask, IRQSource),
VMSTATE_INT32(last_cpu, IRQSource),
VMSTATE_INT32(pending, IRQSource),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_openpic_timer = {
.name = "openpic_timer",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_UINT32(tccr, OpenPICTimer),
VMSTATE_UINT32(tbcr, OpenPICTimer),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_openpic_msi = {
.name = "openpic_msi",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_UINT32(msir, OpenPICMSI),
VMSTATE_END_OF_LIST()
}
};
static int openpic_post_load(void *opaque, int version_id)
{
OpenPICState *opp = (OpenPICState *)opaque;
int i;
/* Update internal ivpr and idr variables */
for (i = 0; i < opp->max_irq; i++) {
write_IRQreg_idr(opp, i, opp->src[i].idr);
write_IRQreg_ivpr(opp, i, opp->src[i].ivpr);
}
return 0;
}
static const VMStateDescription vmstate_openpic = {
.name = "openpic",
.version_id = 3,
.minimum_version_id = 3,
.post_load = openpic_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32(gcr, OpenPICState),
VMSTATE_UINT32(vir, OpenPICState),
VMSTATE_UINT32(pir, OpenPICState),
VMSTATE_UINT32(spve, OpenPICState),
VMSTATE_UINT32(tfrr, OpenPICState),
VMSTATE_UINT32(max_irq, OpenPICState),
VMSTATE_STRUCT_VARRAY_UINT32(src, OpenPICState, max_irq, 0,
vmstate_openpic_irqsource, IRQSource),
VMSTATE_UINT32_EQUAL(nb_cpus, OpenPICState),
VMSTATE_STRUCT_VARRAY_UINT32(dst, OpenPICState, nb_cpus, 0,
vmstate_openpic_irqdest, IRQDest),
VMSTATE_STRUCT_ARRAY(timers, OpenPICState, OPENPIC_MAX_TMR, 0,
vmstate_openpic_timer, OpenPICTimer),
VMSTATE_STRUCT_ARRAY(msi, OpenPICState, MAX_MSI, 0,
vmstate_openpic_msi, OpenPICMSI),
VMSTATE_UINT32(irq_ipi0, OpenPICState),
VMSTATE_UINT32(irq_tim0, OpenPICState),
VMSTATE_UINT32(irq_msi, OpenPICState),
VMSTATE_END_OF_LIST()
}
};
static void openpic_init(Object *obj)
{
OpenPICState *opp = OPENPIC(obj);
@ -1631,10 +1618,12 @@ static void openpic_realize(DeviceState *dev, Error **errp)
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
sysbus_init_irq(d, &opp->dst[i].irqs[j]);
}
}
register_savevm(dev, "openpic", 0, 2,
openpic_save, openpic_load, opp);
opp->dst[i].raised.queue_size = IRQQUEUE_SIZE_BITS;
opp->dst[i].raised.queue = bitmap_new(IRQQUEUE_SIZE_BITS);
opp->dst[i].servicing.queue_size = IRQQUEUE_SIZE_BITS;
opp->dst[i].servicing.queue = bitmap_new(IRQQUEUE_SIZE_BITS);
}
sysbus_init_mmio(d, &opp->mem);
qdev_init_gpio_in(dev, openpic_set_irq, opp->max_irq);
@ -1653,6 +1642,7 @@ static void openpic_class_init(ObjectClass *oc, void *data)
dc->realize = openpic_realize;
dc->props = openpic_properties;
dc->reset = openpic_reset;
dc->vmsd = &vmstate_openpic;
}
static const TypeInfo openpic_info = {

View File

@ -638,8 +638,8 @@ static const VMStateDescription vmstate_cuda_timer = {
static const VMStateDescription vmstate_cuda = {
.name = "cuda",
.version_id = 1,
.minimum_version_id = 1,
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT8(a, CUDAState),
VMSTATE_UINT8(b, CUDAState),
@ -660,6 +660,7 @@ static const VMStateDescription vmstate_cuda = {
VMSTATE_UINT32(tick_offset, CUDAState),
VMSTATE_STRUCT_ARRAY(timers, CUDAState, 2, 1,
vmstate_cuda_timer, CUDATimer),
VMSTATE_TIMER_PTR(adb_poll_timer, CUDAState),
VMSTATE_END_OF_LIST()
}
};

View File

@ -336,20 +336,44 @@ static void macio_instance_init(Object *obj)
memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
}
static const VMStateDescription vmstate_macio_oldworld = {
.name = "macio-oldworld",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj.parent, OldWorldMacIOState),
VMSTATE_END_OF_LIST()
}
};
static void macio_oldworld_class_init(ObjectClass *oc, void *data)
{
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
pdc->init = macio_oldworld_initfn;
pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
dc->vmsd = &vmstate_macio_oldworld;
}
static const VMStateDescription vmstate_macio_newworld = {
.name = "macio-newworld",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj.parent, NewWorldMacIOState),
VMSTATE_END_OF_LIST()
}
};
static void macio_newworld_class_init(ObjectClass *oc, void *data)
{
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
pdc->init = macio_newworld_initfn;
pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
dc->vmsd = &vmstate_macio_newworld;
}
static Property macio_properties[] = {

View File

@ -203,7 +203,7 @@ static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
dev->isopen = 0;
}
static int spapr_vlan_init(VIOsPAPRDevice *sdev)
static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
{
VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
@ -212,8 +212,6 @@ static int spapr_vlan_init(VIOsPAPRDevice *sdev)
dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
return 0;
}
static void spapr_vlan_instance_init(Object *obj)
@ -534,7 +532,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->init = spapr_vlan_init;
k->realize = spapr_vlan_realize;
k->reset = spapr_vlan_reset;
k->devnode = spapr_vlan_devnode;
k->dt_name = "l-lan";

View File

@ -132,7 +132,7 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
rtas_st(rets, 1, (alen < 0) ? 0 : alen);
}
static int spapr_nvram_init(VIOsPAPRDevice *dev)
static void spapr_nvram_realize(VIOsPAPRDevice *dev, Error **errp)
{
sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
@ -145,23 +145,22 @@ static int spapr_nvram_init(VIOsPAPRDevice *dev)
nvram->buf = g_malloc0(nvram->size);
if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {
fprintf(stderr, "spapr-nvram must be between %d and %d bytes in size\n",
MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
return -1;
error_setg(errp, "spapr-nvram must be between %d and %d bytes in size",
MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
return;
}
if (nvram->blk) {
int alen = blk_pread(nvram->blk, 0, nvram->buf, nvram->size);
if (alen != nvram->size) {
return -1;
error_setg(errp, "can't read spapr-nvram contents");
return;
}
}
spapr_rtas_register(RTAS_NVRAM_FETCH, "nvram-fetch", rtas_nvram_fetch);
spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store);
return 0;
}
static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
@ -224,7 +223,7 @@ static void spapr_nvram_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->init = spapr_nvram_init;
k->realize = spapr_nvram_realize;
k->devnode = spapr_nvram_devnode;
k->dt_name = "nvram";
k->dt_type = "nvram";

View File

@ -3,7 +3,7 @@ obj-y += ppc.o ppc_booke.o
# IBM pSeries (sPAPR)
obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o
obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
obj-$(CONFIG_PSERIES) += spapr_pci.o
obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
obj-y += spapr_pci_vfio.o
endif

View File

@ -706,17 +706,19 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
}
static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
qemu_irq **irqs)
qemu_irq **irqs, Error **errp)
{
Error *err = NULL;
DeviceState *dev;
CPUState *cs;
int r;
dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
qdev_prop_set_uint32(dev, "model", params->mpic_version);
r = qdev_init(dev);
if (r) {
object_property_set_bool(OBJECT(dev), true, "realized", &err);
if (err) {
error_propagate(errp, err);
object_unparent(OBJECT(dev));
return NULL;
}
@ -747,15 +749,15 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
"kernel_irqchip", true);
bool irqchip_required = qemu_opt_get_bool(machine_opts,
"kernel_irqchip", false);
Error *err = NULL;
if (irqchip_allowed) {
dev = ppce500_init_mpic_kvm(params, irqs);
dev = ppce500_init_mpic_kvm(params, irqs, &err);
}
if (irqchip_required && !dev) {
fprintf(stderr, "%s: irqchip requested but unavailable\n",
__func__);
abort();
error_report("kernel_irqchip requested but unavailable: %s",
error_get_pretty(err));
exit(1);
}
}

View File

@ -110,17 +110,20 @@ struct sPAPRMachineState {
sPAPREnvironment *spapr;
static XICSState *try_create_xics(const char *type, int nr_servers,
int nr_irqs)
int nr_irqs, Error **errp)
{
Error *err = NULL;
DeviceState *dev;
dev = qdev_create(NULL, type);
qdev_prop_set_uint32(dev, "nr_servers", nr_servers);
qdev_prop_set_uint32(dev, "nr_irqs", nr_irqs);
if (qdev_init(dev) < 0) {
object_property_set_bool(OBJECT(dev), true, "realized", &err);
if (err) {
error_propagate(errp, err);
object_unparent(OBJECT(dev));
return NULL;
}
return XICS_COMMON(dev);
}
@ -134,23 +137,19 @@ static XICSState *xics_system_init(int nr_servers, int nr_irqs)
"kernel_irqchip", true);
bool irqchip_required = qemu_opt_get_bool(machine_opts,
"kernel_irqchip", false);
Error *err = NULL;
if (irqchip_allowed) {
icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs);
icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs, &err);
}
if (irqchip_required && !icp) {
perror("Failed to create in-kernel XICS\n");
abort();
error_report("kernel_irqchip requested but unavailable: %s",
error_get_pretty(err));
}
}
if (!icp) {
icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs);
}
if (!icp) {
perror("Failed to create XICS\n");
abort();
icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs, &error_abort);
}
return icp;
@ -994,6 +993,17 @@ static void spapr_create_nvram(sPAPREnvironment *spapr)
spapr->nvram = (struct sPAPRNVRAM *)dev;
}
static void spapr_rtc_create(sPAPREnvironment *spapr)
{
DeviceState *dev = qdev_create(NULL, TYPE_SPAPR_RTC);
qdev_init_nofail(dev);
spapr->rtc = dev;
object_property_add_alias(qdev_get_machine(), "rtc-time",
OBJECT(spapr->rtc), "date", NULL);
}
/* Returns whether we want to use VGA or not */
static int spapr_vga_init(PCIBus *pci_bus)
{
@ -1011,15 +1021,39 @@ static int spapr_vga_init(PCIBus *pci_bus)
}
}
static int spapr_post_load(void *opaque, int version_id)
{
sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
int err = 0;
/* In earlier versions, there was no seperate qdev for the PAPR
* RTC, so the RTC offset was stored directly in sPAPREnvironment.
* So when migrating from those versions, poke the incoming offset
* value into the RTC device */
if (version_id < 3) {
err = spapr_rtc_import_offset(spapr->rtc, spapr->rtc_offset);
}
return err;
}
static bool version_before_3(void *opaque, int version_id)
{
return version_id < 3;
}
static const VMStateDescription vmstate_spapr = {
.name = "spapr",
.version_id = 2,
.version_id = 3,
.minimum_version_id = 1,
.post_load = spapr_post_load,
.fields = (VMStateField[]) {
VMSTATE_UNUSED(4), /* used to be @next_irq */
/* used to be @next_irq */
VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
/* RTC offset */
VMSTATE_UINT64(rtc_offset, sPAPREnvironment),
VMSTATE_UINT64_TEST(rtc_offset, sPAPREnvironment, version_before_3),
VMSTATE_PPC_TIMEBASE_V(tb, sPAPREnvironment, 2),
VMSTATE_END_OF_LIST()
},
@ -1491,6 +1525,9 @@ static void ppc_spapr_init(MachineState *machine)
/* Set up EPOW events infrastructure */
spapr_events_init(spapr);
/* Set up the RTC RTAS interfaces */
spapr_rtc_create(spapr);
/* Set up VIO bus */
spapr->vio_bus = spapr_vio_bus_init();
@ -1759,11 +1796,22 @@ static const TypeInfo spapr_machine_info = {
},
};
#define SPAPR_COMPAT_2_2 \
{\
.driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\
.property = "mem_win_size",\
.value = "0x20000000",\
}
#define SPAPR_COMPAT_2_1 \
SPAPR_COMPAT_2_2
static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
static GlobalProperty compat_props[] = {
HW_COMPAT_2_1,
SPAPR_COMPAT_2_1,
{ /* end of list */ }
};
@ -1780,12 +1828,15 @@ static const TypeInfo spapr_machine_2_1_info = {
static void spapr_machine_2_2_class_init(ObjectClass *oc, void *data)
{
static GlobalProperty compat_props[] = {
SPAPR_COMPAT_2_2,
{ /* end of list */ }
};
MachineClass *mc = MACHINE_CLASS(oc);
mc->name = "pseries-2.2";
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.2";
mc->alias = "pseries";
mc->is_default = 1;
mc->compat_props = compat_props;
}
static const TypeInfo spapr_machine_2_2_info = {
@ -1794,11 +1845,28 @@ static const TypeInfo spapr_machine_2_2_info = {
.class_init = spapr_machine_2_2_class_init,
};
static void spapr_machine_2_3_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->name = "pseries-2.3";
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.3";
mc->alias = "pseries";
mc->is_default = 1;
}
static const TypeInfo spapr_machine_2_3_info = {
.name = TYPE_SPAPR_MACHINE "2.3",
.parent = TYPE_SPAPR_MACHINE,
.class_init = spapr_machine_2_3_class_init,
};
static void spapr_machine_register_types(void)
{
type_register_static(&spapr_machine_info);
type_register_static(&spapr_machine_2_1_info);
type_register_static(&spapr_machine_2_2_info);
type_register_static(&spapr_machine_2_3_info);
}
type_init(spapr_machine_register_types)

View File

@ -246,7 +246,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque)
maina->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINA);
maina->hdr.section_length = cpu_to_be16(sizeof(*maina));
/* FIXME: section version, subtype and creator id? */
qemu_get_timedate(&tm, spapr->rtc_offset);
spapr_rtc_read(spapr->rtc, &tm, NULL);
year = tm.tm_year + 1900;
maina->creation_date = cpu_to_be32((to_bcd(year / 100) << 24)
| (to_bcd(year % 100) << 16)

View File

@ -731,12 +731,14 @@ static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu,
CPU_FOREACH(cs) {
set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
}
spapr_pci_switch_vga(true);
return H_SUCCESS;
case H_SET_MODE_ENDIAN_LITTLE:
CPU_FOREACH(cs) {
set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
}
spapr_pci_switch_vga(false);
return H_SUCCESS;
}

View File

@ -25,6 +25,7 @@
#include "trace.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
#include <libfdt.h>
@ -73,9 +74,7 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr,
.perm = IOMMU_NONE,
};
if (tcet->bypass) {
ret.perm = IOMMU_RW;
} else if ((addr >> tcet->page_shift) < tcet->nb_table) {
if ((addr >> tcet->page_shift) < tcet->nb_table) {
/* Check if we are in bound */
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
@ -91,10 +90,22 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr,
return ret;
}
static int spapr_tce_table_post_load(void *opaque, int version_id)
{
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque);
if (tcet->vdev) {
spapr_vio_set_bypass(tcet->vdev, tcet->bypass);
}
return 0;
}
static const VMStateDescription vmstate_spapr_tce_table = {
.name = "spapr_iommu",
.version_id = 2,
.minimum_version_id = 2,
.post_load = spapr_tce_table_post_load,
.fields = (VMStateField []) {
/* Sanity check */
VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable),
@ -132,7 +143,8 @@ static int spapr_tce_table_realize(DeviceState *dev)
trace_spapr_iommu_new_table(tcet->liobn, tcet, tcet->table, tcet->fd);
memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops,
"iommu-spapr", ram_size);
"iommu-spapr",
(uint64_t)tcet->nb_table << tcet->page_shift);
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
@ -192,17 +204,11 @@ MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet)
return &tcet->iommu;
}
void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass)
{
tcet->bypass = bypass;
}
static void spapr_tce_reset(DeviceState *dev)
{
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
size_t table_size = tcet->nb_table * sizeof(uint64_t);
tcet->bypass = false;
memset(tcet->table, 0, table_size);
}

View File

@ -406,6 +406,258 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
}
static void rtas_ibm_set_eeh_option(PowerPCCPU *cpu,
sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
sPAPRPHBState *sphb;
sPAPRPHBClass *spc;
uint32_t addr, option;
uint64_t buid;
int ret;
if ((nargs != 4) || (nret != 1)) {
goto param_error_exit;
}
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
addr = rtas_ld(args, 0);
option = rtas_ld(args, 3);
sphb = find_phb(spapr, buid);
if (!sphb) {
goto param_error_exit;
}
spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb);
if (!spc->eeh_set_option) {
goto param_error_exit;
}
ret = spc->eeh_set_option(sphb, addr, option);
rtas_st(rets, 0, ret);
return;
param_error_exit:
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
}
static void rtas_ibm_get_config_addr_info2(PowerPCCPU *cpu,
sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
sPAPRPHBState *sphb;
sPAPRPHBClass *spc;
PCIDevice *pdev;
uint32_t addr, option;
uint64_t buid;
if ((nargs != 4) || (nret != 2)) {
goto param_error_exit;
}
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
sphb = find_phb(spapr, buid);
if (!sphb) {
goto param_error_exit;
}
spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb);
if (!spc->eeh_set_option) {
goto param_error_exit;
}
/*
* We always have PE address of form "00BB0001". "BB"
* represents the bus number of PE's primary bus.
*/
option = rtas_ld(args, 3);
switch (option) {
case RTAS_GET_PE_ADDR:
addr = rtas_ld(args, 0);
pdev = find_dev(spapr, buid, addr);
if (!pdev) {
goto param_error_exit;
}
rtas_st(rets, 1, (pci_bus_num(pdev->bus) << 16) + 1);
break;
case RTAS_GET_PE_MODE:
rtas_st(rets, 1, RTAS_PE_MODE_SHARED);
break;
default:
goto param_error_exit;
}
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
return;
param_error_exit:
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
}
static void rtas_ibm_read_slot_reset_state2(PowerPCCPU *cpu,
sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
sPAPRPHBState *sphb;
sPAPRPHBClass *spc;
uint64_t buid;
int state, ret;
if ((nargs != 3) || (nret != 4 && nret != 5)) {
goto param_error_exit;
}
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
sphb = find_phb(spapr, buid);
if (!sphb) {
goto param_error_exit;
}
spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb);
if (!spc->eeh_get_state) {
goto param_error_exit;
}
ret = spc->eeh_get_state(sphb, &state);
rtas_st(rets, 0, ret);
if (ret != RTAS_OUT_SUCCESS) {
return;
}
rtas_st(rets, 1, state);
rtas_st(rets, 2, RTAS_EEH_SUPPORT);
rtas_st(rets, 3, RTAS_EEH_PE_UNAVAIL_INFO);
if (nret >= 5) {
rtas_st(rets, 4, RTAS_EEH_PE_RECOVER_INFO);
}
return;
param_error_exit:
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
}
static void rtas_ibm_set_slot_reset(PowerPCCPU *cpu,
sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
sPAPRPHBState *sphb;
sPAPRPHBClass *spc;
uint32_t option;
uint64_t buid;
int ret;
if ((nargs != 4) || (nret != 1)) {
goto param_error_exit;
}
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
option = rtas_ld(args, 3);
sphb = find_phb(spapr, buid);
if (!sphb) {
goto param_error_exit;
}
spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb);
if (!spc->eeh_reset) {
goto param_error_exit;
}
ret = spc->eeh_reset(sphb, option);
rtas_st(rets, 0, ret);
return;
param_error_exit:
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
}
static void rtas_ibm_configure_pe(PowerPCCPU *cpu,
sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
sPAPRPHBState *sphb;
sPAPRPHBClass *spc;
uint64_t buid;
int ret;
if ((nargs != 3) || (nret != 1)) {
goto param_error_exit;
}
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
sphb = find_phb(spapr, buid);
if (!sphb) {
goto param_error_exit;
}
spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb);
if (!spc->eeh_configure) {
goto param_error_exit;
}
ret = spc->eeh_configure(sphb);
rtas_st(rets, 0, ret);
return;
param_error_exit:
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
}
/* To support it later */
static void rtas_ibm_slot_error_detail(PowerPCCPU *cpu,
sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args, uint32_t nret,
target_ulong rets)
{
sPAPRPHBState *sphb;
sPAPRPHBClass *spc;
int option;
uint64_t buid;
if ((nargs != 8) || (nret != 1)) {
goto param_error_exit;
}
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
sphb = find_phb(spapr, buid);
if (!sphb) {
goto param_error_exit;
}
spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb);
if (!spc->eeh_set_option) {
goto param_error_exit;
}
option = rtas_ld(args, 7);
switch (option) {
case RTAS_SLOT_TEMP_ERR_LOG:
case RTAS_SLOT_PERM_ERR_LOG:
break;
default:
goto param_error_exit;
}
/* We don't have error log yet */
rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
return;
param_error_exit:
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
}
static int pci_spapr_swizzle(int slot, int pin)
{
return (slot + pin) % PCI_NUM_PINS;
@ -501,6 +753,12 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
return;
}
if (sphb->index > SPAPR_PCI_MAX_INDEX) {
error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
SPAPR_PCI_MAX_INDEX);
return;
}
sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index;
sphb->dma_liobn = SPAPR_PCI_BASE_LIOBN + sphb->index;
@ -669,7 +927,7 @@ static void spapr_phb_reset(DeviceState *qdev)
}
static Property spapr_phb_properties[] = {
DEFINE_PROP_INT32("index", sPAPRPHBState, index, -1),
DEFINE_PROP_UINT32("index", sPAPRPHBState, index, -1),
DEFINE_PROP_UINT64("buid", sPAPRPHBState, buid, -1),
DEFINE_PROP_UINT32("liobn", sPAPRPHBState, dma_liobn, -1),
DEFINE_PROP_UINT64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1),
@ -862,6 +1120,10 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
int bus_off, i, j;
char nodename[256];
uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
const uint64_t mmiosize = memory_region_size(&phb->memwindow);
const uint64_t w32max = (1ULL << 32) - SPAPR_PCI_MEM_WIN_BUS_OFFSET;
const uint64_t w32size = MIN(w32max, mmiosize);
const uint64_t w64size = (mmiosize > w32size) ? (mmiosize - w32size) : 0;
struct {
uint32_t hi;
uint64_t child;
@ -876,9 +1138,15 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
{
cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET),
cpu_to_be64(phb->mem_win_addr),
cpu_to_be64(memory_region_size(&phb->memwindow)),
cpu_to_be64(w32size),
},
{
cpu_to_be32(b_ss(3)), cpu_to_be64(1ULL << 32),
cpu_to_be64(phb->mem_win_addr + w32size),
cpu_to_be64(w64size)
},
};
const unsigned sizeof_ranges = (w64size ? 3 : 2) * sizeof(ranges[0]);
uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 };
uint32_t interrupt_map_mask[] = {
cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)};
@ -907,7 +1175,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
_FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
_FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
_FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof_ranges));
_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS));
@ -958,6 +1226,25 @@ void spapr_pci_rtas_init(void)
spapr_rtas_register(RTAS_IBM_CHANGE_MSI, "ibm,change-msi",
rtas_ibm_change_msi);
}
spapr_rtas_register(RTAS_IBM_SET_EEH_OPTION,
"ibm,set-eeh-option",
rtas_ibm_set_eeh_option);
spapr_rtas_register(RTAS_IBM_GET_CONFIG_ADDR_INFO2,
"ibm,get-config-addr-info2",
rtas_ibm_get_config_addr_info2);
spapr_rtas_register(RTAS_IBM_READ_SLOT_RESET_STATE2,
"ibm,read-slot-reset-state2",
rtas_ibm_read_slot_reset_state2);
spapr_rtas_register(RTAS_IBM_SET_SLOT_RESET,
"ibm,set-slot-reset",
rtas_ibm_set_slot_reset);
spapr_rtas_register(RTAS_IBM_CONFIGURE_PE,
"ibm,configure-pe",
rtas_ibm_configure_pe);
spapr_rtas_register(RTAS_IBM_SLOT_ERROR_DETAIL,
"ibm,slot-error-detail",
rtas_ibm_slot_error_detail);
}
static void spapr_pci_register_types(void)
@ -966,3 +1253,31 @@ static void spapr_pci_register_types(void)
}
type_init(spapr_pci_register_types)
static int spapr_switch_one_vga(DeviceState *dev, void *opaque)
{
bool be = *(bool *)opaque;
if (object_dynamic_cast(OBJECT(dev), "VGA")
|| object_dynamic_cast(OBJECT(dev), "secondary-vga")) {
object_property_set_bool(OBJECT(dev), be, "big-endian-framebuffer",
&error_abort);
}
return 0;
}
void spapr_pci_switch_vga(bool big_endian)
{
sPAPRPHBState *sphb;
/*
* For backward compatibility with existing guests, we switch
* the endianness of the VGA controller when changing the guest
* interrupt mode
*/
QLIST_FOREACH(sphb, &spapr->phbs, list) {
BusState *bus = &PCI_HOST_BRIDGE(sphb)->bus->qbus;
qbus_walk_children(bus, spapr_switch_one_vga, NULL, NULL, NULL,
&big_endian);
}
}

View File

@ -76,6 +76,117 @@ static void spapr_phb_vfio_reset(DeviceState *qdev)
/* Do nothing */
}
static int spapr_phb_vfio_eeh_set_option(sPAPRPHBState *sphb,
unsigned int addr, int option)
{
sPAPRPHBVFIOState *svphb = SPAPR_PCI_VFIO_HOST_BRIDGE(sphb);
struct vfio_eeh_pe_op op = { .argsz = sizeof(op) };
int ret;
switch (option) {
case RTAS_EEH_DISABLE:
op.op = VFIO_EEH_PE_DISABLE;
break;
case RTAS_EEH_ENABLE: {
PCIHostState *phb;
PCIDevice *pdev;
/*
* The EEH functionality is enabled on basis of PCI device,
* instead of PE. We need check the validity of the PCI
* device address.
*/
phb = PCI_HOST_BRIDGE(sphb);
pdev = pci_find_device(phb->bus,
(addr >> 16) & 0xFF, (addr >> 8) & 0xFF);
if (!pdev) {
return RTAS_OUT_PARAM_ERROR;
}
op.op = VFIO_EEH_PE_ENABLE;
break;
}
case RTAS_EEH_THAW_IO:
op.op = VFIO_EEH_PE_UNFREEZE_IO;
break;
case RTAS_EEH_THAW_DMA:
op.op = VFIO_EEH_PE_UNFREEZE_DMA;
break;
default:
return RTAS_OUT_PARAM_ERROR;
}
ret = vfio_container_ioctl(&svphb->phb.iommu_as, svphb->iommugroupid,
VFIO_EEH_PE_OP, &op);
if (ret < 0) {
return RTAS_OUT_HW_ERROR;
}
return RTAS_OUT_SUCCESS;
}
static int spapr_phb_vfio_eeh_get_state(sPAPRPHBState *sphb, int *state)
{
sPAPRPHBVFIOState *svphb = SPAPR_PCI_VFIO_HOST_BRIDGE(sphb);
struct vfio_eeh_pe_op op = { .argsz = sizeof(op) };
int ret;
op.op = VFIO_EEH_PE_GET_STATE;
ret = vfio_container_ioctl(&svphb->phb.iommu_as, svphb->iommugroupid,
VFIO_EEH_PE_OP, &op);
if (ret < 0) {
return RTAS_OUT_PARAM_ERROR;
}
*state = ret;
return RTAS_OUT_SUCCESS;
}
static int spapr_phb_vfio_eeh_reset(sPAPRPHBState *sphb, int option)
{
sPAPRPHBVFIOState *svphb = SPAPR_PCI_VFIO_HOST_BRIDGE(sphb);
struct vfio_eeh_pe_op op = { .argsz = sizeof(op) };
int ret;
switch (option) {
case RTAS_SLOT_RESET_DEACTIVATE:
op.op = VFIO_EEH_PE_RESET_DEACTIVATE;
break;
case RTAS_SLOT_RESET_HOT:
op.op = VFIO_EEH_PE_RESET_HOT;
break;
case RTAS_SLOT_RESET_FUNDAMENTAL:
op.op = VFIO_EEH_PE_RESET_FUNDAMENTAL;
break;
default:
return RTAS_OUT_PARAM_ERROR;
}
ret = vfio_container_ioctl(&svphb->phb.iommu_as, svphb->iommugroupid,
VFIO_EEH_PE_OP, &op);
if (ret < 0) {
return RTAS_OUT_HW_ERROR;
}
return RTAS_OUT_SUCCESS;
}
static int spapr_phb_vfio_eeh_configure(sPAPRPHBState *sphb)
{
sPAPRPHBVFIOState *svphb = SPAPR_PCI_VFIO_HOST_BRIDGE(sphb);
struct vfio_eeh_pe_op op = { .argsz = sizeof(op) };
int ret;
op.op = VFIO_EEH_PE_CONFIGURE;
ret = vfio_container_ioctl(&svphb->phb.iommu_as, svphb->iommugroupid,
VFIO_EEH_PE_OP, &op);
if (ret < 0) {
return RTAS_OUT_PARAM_ERROR;
}
return RTAS_OUT_SUCCESS;
}
static void spapr_phb_vfio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@ -84,6 +195,10 @@ static void spapr_phb_vfio_class_init(ObjectClass *klass, void *data)
dc->props = spapr_phb_vfio_properties;
dc->reset = spapr_phb_vfio_reset;
spc->finish_realize = spapr_phb_vfio_finish_realize;
spc->eeh_set_option = spapr_phb_vfio_eeh_set_option;
spc->eeh_get_state = spapr_phb_vfio_eeh_get_state;
spc->eeh_reset = spapr_phb_vfio_eeh_reset;
spc->eeh_configure = spapr_phb_vfio_eeh_configure;
}
static const TypeInfo spapr_phb_vfio_info = {

View File

@ -52,51 +52,6 @@ static void rtas_display_character(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
}
static void rtas_get_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
struct tm tm;
if (nret != 8) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
qemu_get_timedate(&tm, spapr->rtc_offset);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, tm.tm_year + 1900);
rtas_st(rets, 2, tm.tm_mon + 1);
rtas_st(rets, 3, tm.tm_mday);
rtas_st(rets, 4, tm.tm_hour);
rtas_st(rets, 5, tm.tm_min);
rtas_st(rets, 6, tm.tm_sec);
rtas_st(rets, 7, 0); /* we don't do nanoseconds */
}
static void rtas_set_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
struct tm tm;
tm.tm_year = rtas_ld(args, 0) - 1900;
tm.tm_mon = rtas_ld(args, 1) - 1;
tm.tm_mday = rtas_ld(args, 2);
tm.tm_hour = rtas_ld(args, 3);
tm.tm_min = rtas_ld(args, 4);
tm.tm_sec = rtas_ld(args, 5);
/* Just generate a monitor event for the change */
qapi_event_send_rtc_change(qemu_timedate_diff(&tm), &error_abort);
spapr->rtc_offset = qemu_timedate_diff(&tm);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
static void rtas_power_off(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
@ -400,10 +355,6 @@ static void core_rtas_register_types(void)
{
spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character",
rtas_display_character);
spapr_rtas_register(RTAS_GET_TIME_OF_DAY, "get-time-of-day",
rtas_get_time_of_day);
spapr_rtas_register(RTAS_SET_TIME_OF_DAY, "set-time-of-day",
rtas_set_time_of_day);
spapr_rtas_register(RTAS_POWER_OFF, "power-off", rtas_power_off);
spapr_rtas_register(RTAS_SYSTEM_REBOOT, "system-reboot",
rtas_system_reboot);

212
hw/ppc/spapr_rtc.c Normal file
View File

@ -0,0 +1,212 @@
/*
* QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
*
* RTAS Real Time Clock
*
* Copyright (c) 2010-2011 David Gibson, IBM Corporation.
* Copyright 2014 David Gibson, Red Hat.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "cpu.h"
#include "sysemu/sysemu.h"
#include "hw/ppc/spapr.h"
#include "qapi-event.h"
#define SPAPR_RTC(obj) \
OBJECT_CHECK(sPAPRRTCState, (obj), TYPE_SPAPR_RTC)
typedef struct sPAPRRTCState sPAPRRTCState;
struct sPAPRRTCState {
/*< private >*/
SysBusDevice parent_obj;
int64_t ns_offset;
};
#define NSEC_PER_SEC 1000000000LL
void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns)
{
sPAPRRTCState *rtc = SPAPR_RTC(dev);
int64_t host_ns = qemu_clock_get_ns(rtc_clock);
int64_t guest_ns;
time_t guest_s;
assert(rtc);
guest_ns = host_ns + rtc->ns_offset;
guest_s = guest_ns / NSEC_PER_SEC;
if (tm) {
gmtime_r(&guest_s, tm);
}
if (ns) {
*ns = guest_ns;
}
}
int spapr_rtc_import_offset(DeviceState *dev, int64_t legacy_offset)
{
sPAPRRTCState *rtc;
if (!dev) {
return -ENODEV;
}
rtc = SPAPR_RTC(dev);
rtc->ns_offset = legacy_offset * NSEC_PER_SEC;
return 0;
}
static void rtas_get_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
struct tm tm;
uint32_t ns;
if ((nargs != 0) || (nret != 8)) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
if (!spapr->rtc) {
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
spapr_rtc_read(spapr->rtc, &tm, &ns);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, tm.tm_year + 1900);
rtas_st(rets, 2, tm.tm_mon + 1);
rtas_st(rets, 3, tm.tm_mday);
rtas_st(rets, 4, tm.tm_hour);
rtas_st(rets, 5, tm.tm_min);
rtas_st(rets, 6, tm.tm_sec);
rtas_st(rets, 7, ns);
}
static void rtas_set_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
sPAPRRTCState *rtc;
struct tm tm;
time_t new_s;
int64_t host_ns;
if ((nargs != 7) || (nret != 1)) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
if (!spapr->rtc) {
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
tm.tm_year = rtas_ld(args, 0) - 1900;
tm.tm_mon = rtas_ld(args, 1) - 1;
tm.tm_mday = rtas_ld(args, 2);
tm.tm_hour = rtas_ld(args, 3);
tm.tm_min = rtas_ld(args, 4);
tm.tm_sec = rtas_ld(args, 5);
new_s = mktimegm(&tm);
if (new_s == -1) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
/* Generate a monitor event for the change */
qapi_event_send_rtc_change(qemu_timedate_diff(&tm), &error_abort);
rtc = SPAPR_RTC(spapr->rtc);
host_ns = qemu_clock_get_ns(rtc_clock);
rtc->ns_offset = (new_s * NSEC_PER_SEC) - host_ns;
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
static void spapr_rtc_qom_date(Object *obj, struct tm *current_tm, Error **errp)
{
spapr_rtc_read(DEVICE(obj), current_tm, NULL);
}
static void spapr_rtc_realize(DeviceState *dev, Error **errp)
{
sPAPRRTCState *rtc = SPAPR_RTC(dev);
struct tm tm;
time_t host_s;
int64_t rtc_ns;
/* Initialize the RTAS RTC from host time */
qemu_get_timedate(&tm, 0);
host_s = mktimegm(&tm);
rtc_ns = qemu_clock_get_ns(rtc_clock);
rtc->ns_offset = host_s * NSEC_PER_SEC - rtc_ns;
object_property_add_tm(OBJECT(rtc), "date", spapr_rtc_qom_date, NULL);
}
static const VMStateDescription vmstate_spapr_rtc = {
.name = "spapr/rtc",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT64(ns_offset, sPAPRRTCState),
VMSTATE_END_OF_LIST()
},
};
static void spapr_rtc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = spapr_rtc_realize;
dc->vmsd = &vmstate_spapr_rtc;
spapr_rtas_register(RTAS_GET_TIME_OF_DAY, "get-time-of-day",
rtas_get_time_of_day);
spapr_rtas_register(RTAS_SET_TIME_OF_DAY, "set-time-of-day",
rtas_set_time_of_day);
}
static const TypeInfo spapr_rtc_info = {
.name = TYPE_SPAPR_RTC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(sPAPRRTCState),
.class_size = sizeof(XICSStateClass),
.class_init = spapr_rtc_class_init,
};
static void spapr_rtc_register_types(void)
{
type_register_static(&spapr_rtc_info);
}
type_init(spapr_rtc_register_types)

View File

@ -322,6 +322,18 @@ static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
free_crq(dev);
}
void spapr_vio_set_bypass(VIOsPAPRDevice *dev, bool bypass)
{
if (!dev->tcet) {
return;
}
memory_region_set_enabled(&dev->mrbypass, bypass);
memory_region_set_enabled(spapr_tce_get_iommu(dev->tcet), !bypass);
dev->tcet->bypass = bypass;
}
static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
@ -348,7 +360,7 @@ static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return;
}
spapr_tce_set_bypass(dev->tcet, !!enable);
spapr_vio_set_bypass(dev, !!enable);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
@ -407,12 +419,13 @@ static void spapr_vio_busdev_reset(DeviceState *qdev)
dev->signal_state = 0;
spapr_vio_set_bypass(dev, false);
if (pc->reset) {
pc->reset(dev);
}
}
static int spapr_vio_busdev_init(DeviceState *qdev)
static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
{
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
@ -428,11 +441,11 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
VIOsPAPRDevice *other = reg_conflict(dev);
if (other) {
fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n",
object_get_typename(OBJECT(qdev)),
object_get_typename(OBJECT(&other->qdev)),
dev->reg);
return -1;
error_setg(errp, "%s and %s devices conflict at address %#x",
object_get_typename(OBJECT(qdev)),
object_get_typename(OBJECT(&other->qdev)),
dev->reg);
return;
}
} else {
/* Need to assign an address */
@ -451,20 +464,32 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
dev->irq = xics_alloc(spapr->icp, 0, dev->irq, false);
if (!dev->irq) {
return -1;
error_setg(errp, "can't allocate IRQ");
return;
}
if (pc->rtce_window_size) {
uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg;
memory_region_init(&dev->mrroot, OBJECT(dev), "iommu-spapr-root",
ram_size);
memory_region_init_alias(&dev->mrbypass, OBJECT(dev),
"iommu-spapr-bypass", get_system_memory(),
0, ram_size);
memory_region_add_subregion_overlap(&dev->mrroot, 0, &dev->mrbypass, 1);
address_space_init(&dev->as, &dev->mrroot, qdev->id);
dev->tcet = spapr_tce_new_table(qdev, liobn,
0,
SPAPR_TCE_PAGE_SHIFT,
pc->rtce_window_size >>
SPAPR_TCE_PAGE_SHIFT, false);
address_space_init(&dev->as, spapr_tce_get_iommu(dev->tcet), qdev->id);
dev->tcet->vdev = dev;
memory_region_add_subregion_overlap(&dev->mrroot, 0,
spapr_tce_get_iommu(dev->tcet), 2);
}
return pc->init(dev);
pc->realize(dev, errp);
}
static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPREnvironment *spapr,
@ -570,7 +595,7 @@ const VMStateDescription vmstate_spapr_vio = {
static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->init = spapr_vio_busdev_init;
k->realize = spapr_vio_busdev_realize;
k->reset = spapr_vio_busdev_reset;
k->bus_type = TYPE_SPAPR_VIO_BUS;
k->props = spapr_vio_props;

View File

@ -1212,24 +1212,17 @@ static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
}
}
static int spapr_vscsi_init(VIOsPAPRDevice *dev)
static void spapr_vscsi_realize(VIOsPAPRDevice *dev, Error **errp)
{
VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
Error *err = NULL;
dev->crq.SendFunc = vscsi_do_crq;
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
&vscsi_scsi_info, NULL);
if (!dev->qdev.hotplugged) {
scsi_bus_legacy_handle_cmdline(&s->bus, &err);
if (err != NULL) {
error_free(err);
return -1;
}
scsi_bus_legacy_handle_cmdline(&s->bus, errp);
}
return 0;
}
void spapr_vscsi_create(VIOsPAPRBus *bus)
@ -1281,7 +1274,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->init = spapr_vscsi_init;
k->realize = spapr_vscsi_realize;
k->reset = spapr_vscsi_reset;
k->devnode = spapr_vscsi_devnode;
k->dt_name = "v-scsi";

View File

@ -831,49 +831,12 @@ static const MemoryRegionOps cmos_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
static void rtc_get_date(Object *obj, struct tm *current_tm, Error **errp)
{
Error *err = NULL;
RTCState *s = MC146818_RTC(obj);
struct tm current_tm;
rtc_update_time(s);
rtc_get_time(s, &current_tm);
visit_start_struct(v, NULL, "struct tm", name, 0, &err);
if (err) {
goto out;
}
visit_type_int32(v, &current_tm.tm_year, "tm_year", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_mon, "tm_mon", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_mday, "tm_mday", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_hour, "tm_hour", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_min, "tm_min", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_sec, "tm_sec", &err);
if (err) {
goto out_end;
}
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, errp);
out:
error_propagate(errp, err);
rtc_get_time(s, current_tm);
}
static void rtc_realizefn(DeviceState *dev, Error **errp)
@ -932,8 +895,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
qdev_set_legacy_instance_id(dev, base, 3);
qemu_register_reset(rtc_reset, s);
object_property_add(OBJECT(s), "date", "struct tm",
rtc_get_date, NULL, NULL, s, NULL);
object_property_add_tm(OBJECT(s), "date", rtc_get_date, NULL);
object_property_add_alias(qdev_get_machine(), "rtc-time",
OBJECT(s), "date", NULL);

View File

@ -949,6 +949,7 @@ int vfio_container_ioctl(AddressSpace *as, int32_t groupid,
switch (req) {
case VFIO_CHECK_EXTENSION:
case VFIO_IOMMU_SPAPR_TCE_GET_INFO:
case VFIO_EEH_PE_OP:
break;
default:
/* Return an error on unknown requests */

View File

@ -49,6 +49,10 @@ struct sPAPRPHBClass {
PCIHostBridgeClass parent_class;
void (*finish_realize)(sPAPRPHBState *sphb, Error **errp);
int (*eeh_set_option)(sPAPRPHBState *sphb, unsigned int addr, int option);
int (*eeh_get_state)(sPAPRPHBState *sphb, int *state);
int (*eeh_reset)(sPAPRPHBState *sphb, int option);
int (*eeh_configure)(sPAPRPHBState *sphb);
};
typedef struct spapr_pci_msi {
@ -64,7 +68,7 @@ typedef struct spapr_pci_msi_mig {
struct sPAPRPHBState {
PCIHostState parent_obj;
int32_t index;
uint32_t index;
uint64_t buid;
char *dtbusname;
@ -94,19 +98,22 @@ struct sPAPRPHBVFIOState {
int32_t iommugroupid;
};
#define SPAPR_PCI_MAX_INDEX 255
#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL
#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL
#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000
#define SPAPR_PCI_MMIO_WIN_SIZE 0x20000000
#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \
SPAPR_PCI_MEM_WIN_BUS_OFFSET)
#define SPAPR_PCI_IO_WIN_OFF 0x80000000
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
#define SPAPR_PCI_MSI_WINDOW 0x40000000000ULL
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
{
return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);

View File

@ -15,6 +15,7 @@ typedef struct sPAPREnvironment {
QLIST_HEAD(, sPAPRPHBState) phbs;
struct sPAPRNVRAM *nvram;
XICSState *icp;
DeviceState *rtc;
hwaddr ram_limit;
void *htab;
@ -26,7 +27,7 @@ typedef struct sPAPREnvironment {
void *rtas_blob;
void *fdt_skel;
target_ulong entry_point;
uint64_t rtc_offset;
uint64_t rtc_offset; /* Now used only during incoming migration */
struct PPCTimebase tb;
bool has_graphics;
@ -338,6 +339,39 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
int spapr_allocate_irq(int hint, bool lsi);
int spapr_allocate_irq_block(int num, bool lsi, bool msi);
/* ibm,set-eeh-option */
#define RTAS_EEH_DISABLE 0
#define RTAS_EEH_ENABLE 1
#define RTAS_EEH_THAW_IO 2
#define RTAS_EEH_THAW_DMA 3
/* ibm,get-config-addr-info2 */
#define RTAS_GET_PE_ADDR 0
#define RTAS_GET_PE_MODE 1
#define RTAS_PE_MODE_NONE 0
#define RTAS_PE_MODE_NOT_SHARED 1
#define RTAS_PE_MODE_SHARED 2
/* ibm,read-slot-reset-state2 */
#define RTAS_EEH_PE_STATE_NORMAL 0
#define RTAS_EEH_PE_STATE_RESET 1
#define RTAS_EEH_PE_STATE_STOPPED_IO_DMA 2
#define RTAS_EEH_PE_STATE_STOPPED_DMA 4
#define RTAS_EEH_PE_STATE_UNAVAIL 5
#define RTAS_EEH_NOT_SUPPORT 0
#define RTAS_EEH_SUPPORT 1
#define RTAS_EEH_PE_UNAVAIL_INFO 1000
#define RTAS_EEH_PE_RECOVER_INFO 0
/* ibm,set-slot-reset */
#define RTAS_SLOT_RESET_DEACTIVATE 0
#define RTAS_SLOT_RESET_HOT 1
#define RTAS_SLOT_RESET_FUNDAMENTAL 3
/* ibm,slot-error-detail */
#define RTAS_SLOT_TEMP_ERR_LOG 1
#define RTAS_SLOT_PERM_ERR_LOG 2
/* RTAS return codes */
#define RTAS_OUT_SUCCESS 0
#define RTAS_OUT_NO_ERRORS_FOUND 1
@ -382,8 +416,14 @@ int spapr_allocate_irq_block(int num, bool lsi, bool msi);
#define RTAS_GET_SENSOR_STATE (RTAS_TOKEN_BASE + 0x1D)
#define RTAS_IBM_CONFIGURE_CONNECTOR (RTAS_TOKEN_BASE + 0x1E)
#define RTAS_IBM_OS_TERM (RTAS_TOKEN_BASE + 0x1F)
#define RTAS_IBM_SET_EEH_OPTION (RTAS_TOKEN_BASE + 0x20)
#define RTAS_IBM_GET_CONFIG_ADDR_INFO2 (RTAS_TOKEN_BASE + 0x21)
#define RTAS_IBM_READ_SLOT_RESET_STATE2 (RTAS_TOKEN_BASE + 0x22)
#define RTAS_IBM_SET_SLOT_RESET (RTAS_TOKEN_BASE + 0x23)
#define RTAS_IBM_CONFIGURE_PE (RTAS_TOKEN_BASE + 0x24)
#define RTAS_IBM_SLOT_ERROR_DETAIL (RTAS_TOKEN_BASE + 0x25)
#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x20)
#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x26)
/* RTAS ibm,get-system-parameter token values */
#define RTAS_SYSPARM_SPLPAR_CHARACTERISTICS 20
@ -463,6 +503,7 @@ struct sPAPRTCETable {
bool vfio_accel;
int fd;
MemoryRegion iommu;
struct VIOsPAPRDevice *vdev; /* for @bypass migration compatibility only */
QLIST_ENTRY(sPAPRTCETable) list;
};
@ -475,10 +516,15 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
uint32_t nb_table,
bool vfio_accel);
MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet);
void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass);
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
uint32_t liobn, uint64_t window, uint32_t size);
int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
sPAPRTCETable *tcet);
void spapr_pci_switch_vga(bool big_endian);
#define TYPE_SPAPR_RTC "spapr-rtc"
void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns);
int spapr_rtc_import_offset(DeviceState *dev, int64_t legacy_offset);
#endif /* !defined (__HW_SPAPR_H__) */

View File

@ -52,7 +52,7 @@ typedef struct VIOsPAPRDeviceClass {
const char *dt_name, *dt_type, *dt_compatible;
target_ulong signal_mask;
uint32_t rtce_window_size;
int (*init)(VIOsPAPRDevice *dev);
void (*realize)(VIOsPAPRDevice *dev, Error **errp);
void (*reset)(VIOsPAPRDevice *dev);
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
} VIOsPAPRDeviceClass;
@ -64,6 +64,8 @@ struct VIOsPAPRDevice {
target_ulong signal_state;
VIOsPAPR_CRQ crq;
AddressSpace as;
MemoryRegion mrroot;
MemoryRegion mrbypass;
sPAPRTCETable *tcet;
};
@ -139,4 +141,6 @@ extern const VMStateDescription vmstate_spapr_vio;
#define VMSTATE_SPAPR_VIO(_f, _s) \
VMSTATE_STRUCT(_f, _s, 0, vmstate_spapr_vio, VIOsPAPRDevice)
void spapr_vio_set_bypass(VIOsPAPRDevice *dev, bool bypass);
#endif /* _HW_SPAPR_VIO_H */

View File

@ -635,6 +635,18 @@ extern const VMStateInfo vmstate_info_bitmap;
#define VMSTATE_INT32_POSITIVE_LE(_f, _s) \
VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
#define VMSTATE_INT8_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int8, int8_t)
#define VMSTATE_INT16_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int16, int16_t)
#define VMSTATE_INT32_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int32, int32_t)
#define VMSTATE_INT64_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int64, int64_t)
#define VMSTATE_UINT8_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
@ -644,6 +656,9 @@ extern const VMStateInfo vmstate_info_bitmap;
#define VMSTATE_UINT32_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t)
#define VMSTATE_UINT64_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint64, uint64_t)
#define VMSTATE_FLOAT64_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, vmstate_info_float64, float64)

View File

@ -1203,6 +1203,20 @@ void object_property_add_bool(Object *obj, const char *name,
void (*set)(Object *, bool, Error **),
Error **errp);
/**
* object_property_add_tm:
* @obj: the object to add a property to
* @name: the name of the property
* @get: the getter or NULL if the property is write-only.
* @errp: if an error occurs, a pointer to an area to store the error
*
* Add a read-only struct tm valued property using a getter function.
* This function will add a property of type 'struct tm'.
*/
void object_property_add_tm(Object *obj, const char *name,
void (*get)(Object *, struct tm *, Error **),
Error **errp);
/**
* object_property_add_uint8_ptr:
* @obj: the object to add a property to

View File

@ -1543,6 +1543,85 @@ void object_property_add_bool(Object *obj, const char *name,
}
}
typedef struct TMProperty {
void (*get)(Object *, struct tm *, Error **);
} TMProperty;
static void property_get_tm(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
TMProperty *prop = opaque;
Error *err = NULL;
struct tm value;
prop->get(obj, &value, &err);
if (err) {
goto out;
}
visit_start_struct(v, NULL, "struct tm", name, 0, &err);
if (err) {
goto out;
}
visit_type_int32(v, &value.tm_year, "tm_year", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &value.tm_mon, "tm_mon", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &value.tm_mday, "tm_mday", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &value.tm_hour, "tm_hour", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &value.tm_min, "tm_min", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &value.tm_sec, "tm_sec", &err);
if (err) {
goto out_end;
}
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, errp);
out:
error_propagate(errp, err);
}
static void property_release_tm(Object *obj, const char *name,
void *opaque)
{
TMProperty *prop = opaque;
g_free(prop);
}
void object_property_add_tm(Object *obj, const char *name,
void (*get)(Object *, struct tm *, Error **),
Error **errp)
{
Error *local_err = NULL;
TMProperty *prop = g_malloc0(sizeof(*prop));
prop->get = get;
object_property_add(obj, name, "struct tm",
get ? property_get_tm : NULL, NULL,
property_release_tm,
prop, &local_err);
if (local_err) {
error_propagate(errp, local_err);
g_free(prop);
}
}
static char *qdev_get_type(Object *obj, Error **errp)
{
return g_strdup(object_get_typename(obj));

View File

@ -1124,8 +1124,8 @@
POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5,
"POWER5")
#endif
POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P,
"POWER5+")
POWERPC_DEF("POWER5+_v0.0", CPU_POWERPC_POWER5P_v00, POWER5P,
"POWER5+ v0.0")
POWERPC_DEF("POWER5+_v2.1", CPU_POWERPC_POWER5P_v21, POWER5P,
"POWER5+ v2.1")
#if defined(TODO)
@ -1144,8 +1144,8 @@
"POWER8E v1.0")
POWERPC_DEF("POWER8_v1.0", CPU_POWERPC_POWER8_v10, POWER8,
"POWER8 v1.0")
POWERPC_DEF("970", CPU_POWERPC_970, 970,
"PowerPC 970")
POWERPC_DEF("970_v2.2", CPU_POWERPC_970_v22, 970,
"PowerPC 970 v2.2")
POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970,
"PowerPC 970FX v1.0 (G5)")
POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970,
@ -1387,11 +1387,13 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
{ "Dino", "POWER3" },
{ "POWER3+", "631" },
{ "POWER5gr", "POWER5" },
{ "POWER5gs", "POWER5+" },
{ "POWER5+", "POWER5+_v0.0" },
{ "POWER5gs", "POWER5+_v0.0" },
{ "POWER7", "POWER7_v2.3" },
{ "POWER7+", "POWER7+_v2.1" },
{ "POWER8E", "POWER8E_v1.0" },
{ "POWER8", "POWER8_v1.0" },
{ "970", "970_v2.2" },
{ "970fx", "970fx_v3.1" },
{ "970mp", "970mp_v1.1" },
{ "Apache", "RS64" },

View File

@ -547,7 +547,7 @@ enum {
CPU_POWERPC_POWER4P = 0x00380000,
/* XXX: missing 0x003A0201 */
CPU_POWERPC_POWER5 = 0x003A0203,
CPU_POWERPC_POWER5P = 0x003B0000,
CPU_POWERPC_POWER5P_v00 = 0x003B0000,
CPU_POWERPC_POWER5P_v21 = 0x003B0201,
CPU_POWERPC_POWER6 = 0x003E0000,
CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */
@ -561,7 +561,7 @@ enum {
CPU_POWERPC_POWER8E_v10 = 0x004B0100,
CPU_POWERPC_POWER8_BASE = 0x004D0000,
CPU_POWERPC_POWER8_v10 = 0x004D0100,
CPU_POWERPC_970 = 0x00390202,
CPU_POWERPC_970_v22 = 0x00390202,
CPU_POWERPC_970FX_v10 = 0x00391100,
CPU_POWERPC_970FX_v20 = 0x003C0200,
CPU_POWERPC_970FX_v21 = 0x003C0201,

View File

@ -45,6 +45,7 @@
# define TARGET_VIRT_ADDR_SPACE_BITS 64
#endif
#define TARGET_PAGE_BITS_64K 16
#define TARGET_PAGE_BITS_16M 24
#else /* defined (TARGET_PPC64) */
@ -1623,6 +1624,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
#define SPR_MPC_MD_DBRAM1 (0x32A)
#define SPR_RCPU_L2U_RA3 (0x32B)
#define SPR_TAR (0x32F)
#define SPR_VTB (0x351)
#define SPR_440_INV0 (0x370)
#define SPR_440_INV1 (0x371)
#define SPR_440_INV2 (0x372)

View File

@ -159,6 +159,7 @@ static int cpu_post_load(void *opaque, int version_id)
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
int i;
target_ulong msr;
/*
* We always ignore the source PVR. The user or management
@ -190,7 +191,12 @@ static int cpu_post_load(void *opaque, int version_id)
/* Restore htab_base and htab_mask variables */
ppc_store_sdr1(env, env->spr[SPR_SDR1]);
}
hreg_compute_hflags(env);
/* Mark msr bits except MSR_TGPR invalid before restoring */
msr = env->msr;
env->msr ^= ~(1ULL << MSR_TGPR);
ppc_store_msr(env, msr);
hreg_compute_mem_idx(env);
return 0;

View File

@ -77,8 +77,13 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
void helper_store_sdr1(CPUPPCState *env, target_ulong val)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
if (!env->external_htab) {
ppc_store_sdr1(env, val);
if (env->spr[SPR_SDR1] != val) {
ppc_store_sdr1(env, val);
tlb_flush(CPU(cpu), 1);
}
}
}

View File

@ -350,7 +350,7 @@ uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index)
void ppc_hash64_stop_access(uint64_t token)
{
if (kvmppc_kern_htab) {
return kvmppc_hash64_free_pteg(token);
kvmppc_hash64_free_pteg(token);
}
}
@ -388,6 +388,24 @@ static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr hash,
return -1;
}
static uint64_t ppc_hash64_page_shift(ppc_slb_t *slb)
{
uint64_t epnshift;
/* Page size according to the SLB, which we use to generate the
* EPN for hash table lookup.. When we implement more recent MMU
* extensions this might be different from the actual page size
* encoded in the PTE */
if ((slb->vsid & SLB_VSID_LLP_MASK) == SLB_VSID_4K) {
epnshift = TARGET_PAGE_BITS;
} else if ((slb->vsid & SLB_VSID_LLP_MASK) == SLB_VSID_64K) {
epnshift = TARGET_PAGE_BITS_64K;
} else {
epnshift = TARGET_PAGE_BITS_16M;
}
return epnshift;
}
static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
ppc_slb_t *slb, target_ulong eaddr,
ppc_hash_pte64_t *pte)
@ -396,12 +414,7 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
hwaddr hash;
uint64_t vsid, epnshift, epnmask, epn, ptem;
/* Page size according to the SLB, which we use to generate the
* EPN for hash table lookup.. When we implement more recent MMU
* extensions this might be different from the actual page size
* encoded in the PTE */
epnshift = (slb->vsid & SLB_VSID_L)
? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
epnshift = ppc_hash64_page_shift(slb);
epnmask = ~((1ULL << epnshift) - 1);
if (slb->vsid & SLB_VSID_B) {
@ -448,12 +461,14 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
static hwaddr ppc_hash64_pte_raddr(ppc_slb_t *slb, ppc_hash_pte64_t pte,
target_ulong eaddr)
{
hwaddr mask;
int target_page_bits;
hwaddr rpn = pte.pte1 & HPTE64_R_RPN;
/* FIXME: Add support for SLLP extended page sizes */
int target_page_bits = (slb->vsid & SLB_VSID_L)
? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
hwaddr mask = (1ULL << target_page_bits) - 1;
/*
* We support 4K, 64K and 16M now
*/
target_page_bits = ppc_hash64_page_shift(slb);
mask = (1ULL << target_page_bits) - 1;
return (rpn & ~mask) | (eaddr & mask);
}
@ -617,7 +632,8 @@ void ppc_hash64_store_hpte(CPUPPCState *env,
CPUState *cs = CPU(ppc_env_get_cpu(env));
if (kvmppc_kern_htab) {
return kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
return;
}
pte_index *= HASH_PTE_SIZE_64;

View File

@ -37,6 +37,9 @@ void ppc_hash64_store_hpte(CPUPPCState *env, target_ulong index,
#define SLB_VSID_C 0x0000000000000080ULL /* class */
#define SLB_VSID_LP 0x0000000000000030ULL
#define SLB_VSID_ATTR 0x0000000000000FFFULL
#define SLB_VSID_LLP_MASK (SLB_VSID_L | SLB_VSID_LP)
#define SLB_VSID_4K 0x0000000000000000ULL
#define SLB_VSID_64K 0x0000000000000110ULL
/*
* Hash page table definitions

View File

@ -2036,31 +2036,26 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
/* Special registers manipulation */
void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
assert(!env->external_htab);
if (env->spr[SPR_SDR1] != value) {
env->spr[SPR_SDR1] = value;
env->spr[SPR_SDR1] = value;
#if defined(TARGET_PPC64)
if (env->mmu_model & POWERPC_MMU_64) {
target_ulong htabsize = value & SDR_64_HTABSIZE;
if (env->mmu_model & POWERPC_MMU_64) {
target_ulong htabsize = value & SDR_64_HTABSIZE;
if (htabsize > 28) {
fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
" stored in SDR1\n", htabsize);
htabsize = 28;
}
env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
env->htab_base = value & SDR_64_HTABORG;
} else
#endif /* defined(TARGET_PPC64) */
{
/* FIXME: Should check for valid HTABMASK values */
env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
env->htab_base = value & SDR_32_HTABORG;
if (htabsize > 28) {
fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
" stored in SDR1\n", htabsize);
htabsize = 28;
}
tlb_flush(CPU(cpu), 1);
env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
env->htab_base = value & SDR_64_HTABORG;
} else
#endif /* defined(TARGET_PPC64) */
{
/* FIXME: Should check for valid HTABMASK values */
env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
env->htab_base = value & SDR_32_HTABORG;
}
}

View File

@ -11214,8 +11214,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
int i;
cpu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR "
TARGET_FMT_lx " XER " TARGET_FMT_lx "\n",
env->nip, env->lr, env->ctr, cpu_read_xer(env));
TARGET_FMT_lx " XER " TARGET_FMT_lx " CPU#%d\n",
env->nip, env->lr, env->ctr, cpu_read_xer(env),
cs->cpu_index);
cpu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF "
TARGET_FMT_lx " idx %d\n", env->msr, env->spr[SPR_HID0],
env->hflags, env->mmu_idx);

View File

@ -7819,6 +7819,15 @@ static void gen_spr_power8_ebb(CPUPPCState *env)
KVM_REG_PPC_BESCR, 0x00000000);
}
/* Virtual Time Base */
static void gen_spr_vtb(CPUPPCState *env)
{
spr_register(env, SPR_VTB, "VTB",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_tbl, SPR_NOACCESS,
0x00000000);
}
static void gen_spr_power8_fscr(CPUPPCState *env)
{
#if defined(CONFIG_USER_ONLY)
@ -7881,6 +7890,7 @@ static void init_proc_book3s_64(CPUPPCState *env, int version)
gen_spr_power8_pmu_sup(env);
gen_spr_power8_pmu_user(env);
gen_spr_power8_tm(env);
gen_spr_vtb(env);
}
if (version < BOOK3S_CPU_POWER8) {
gen_spr_book3s_dbg(env);