Commit 36f87b45 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.10-20170630' into staging



ppc patch queue 2017-06-30

  * More DRC cleanups, these now actually fix a few bugs
  * Properly implements the openpic timers (they now count and
    generate interrupts)
  * Fixes for XICS migration
  * Fixes for migration of POWER9 RPT guests
  * The last of the compatibility mode rework

# gpg: Signature made Fri 30 Jun 2017 10:52:25 BST
# gpg:                using RSA key 0x6C38CACA20D9B392
# 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.10-20170630: (21 commits)
  spapr: Clean up DRC set_isolation_state() path
  spapr: Clean up DRC set_allocation_state path
  spapr: Make DRC reset force DRC into known state
  spapr: Split DRC release from DRC detach
  spapr: Eliminate DRC 'signalled' state variable
  spapr: Start hotplugged PCI devices in ISOLATED state
  target-ppc: Enable open-pic timers to count and generate interrupts
  hw/ppc/spapr.c: consecutive 'spapr->patb_entry = 0' statements
  spapr: prevent QEMU crash when CPU realization fails
  target/ppc: Proper cleanup when ppc_cpu_realizefn fails
  spapr: fix migration of ICPState objects from/to older QEMU
  xics: directly register ICPState objects to vmstate
  target/ppc: Fix return value in tcg radix mmu fault handler
  target/ppc/excp_helper: Take BQL before calling cpu_interrupt()
  spapr: Fix migration of Radix guests
  spapr: Add a "no HPT" encoding to HTAB migration stream
  ppc: Rework CPU compatibility testing across migration
  pseries: Reset CPU compatibility mode
  pseries: Move CPU compatibility property to machine
  qapi: add explicit null to string input and output visitors
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents c5eb5846 0dfabd39
Loading
Loading
Loading
Loading
+111 −6
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include "qemu/bitops.h"
#include "qapi/qmp/qerror.h"
#include "qemu/log.h"
#include "qemu/timer.h"

//#define DEBUG_OPENPIC

@@ -54,8 +55,10 @@ static const int debug_openpic = 1;
static const int debug_openpic = 0;
#endif

static int get_current_cpu(void);
#define DPRINTF(fmt, ...) do { \
        if (debug_openpic) { \
            printf("Core%d: ", get_current_cpu()); \
            printf(fmt , ## __VA_ARGS__); \
        } \
    } while (0)
@@ -246,9 +249,31 @@ typedef struct IRQSource {
#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.
*/
#define OPENPIC_TIMER_FREQ_MHZ 25
#define OPENPIC_TIMER_NS_PER_TICK (1000 / OPENPIC_TIMER_FREQ_MHZ)
static inline uint64_t ns_to_ticks(uint64_t ns)
{
    return ns    / OPENPIC_TIMER_NS_PER_TICK;
}
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 {
@@ -795,6 +820,65 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
    return retval;
}

static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enabled);

static void qemu_timer_cb(void *opaque)
{
    OpenPICTimer *tmr = opaque;
    OpenPICState *opp = tmr->opp;
    uint32_t    n_IRQ = tmr->n_IRQ;
    uint32_t val =   tmr->tbcr & ~TBCR_CI;
    uint32_t tog = ((tmr->tccr & TCCR_TOG) ^ TCCR_TOG);  /* invert toggle. */

    DPRINTF("%s n_IRQ=%d\n", __func__, n_IRQ);
    /* Reload current count from base count and setup timer. */
    tmr->tccr = val | tog;
    openpic_tmr_set_tmr(tmr, val, /*enabled=*/true);
    /* Raise the interrupt. */
    opp->src[n_IRQ].destmask = read_IRQreg_idr(opp, n_IRQ);
    openpic_set_irq(opp, n_IRQ, 1);
    openpic_set_irq(opp, n_IRQ, 0);
}

/* If enabled is true, arranges for an interrupt to be raised val clocks into
   the future, if enabled is false cancels the timer. */
static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enabled)
{
    uint64_t ns = ticks_to_ns(val & ~TCCR_TOG);
    /* A count of zero causes a timer to be set to expire immediately.  This
       effectively stops the simulation since the timer is constantly expiring
       which prevents guest code execution, so we don't honor that
       configuration.  On real hardware, this situation would generate an
       interrupt on every clock cycle if the interrupt was unmasked. */
    if ((ns == 0) || !enabled) {
        tmr->qemu_timer_active = false;
        tmr->tccr = tmr->tccr & TCCR_TOG;
        timer_del(tmr->qemu_timer); /* set timer to never expire. */
    } else {
        tmr->qemu_timer_active = true;
        uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
        tmr->origin_time = now;
        timer_mod(tmr->qemu_timer, now + ns);     /* set timer expiration. */
    }
}

/* Returns the currrent tccr value, i.e., timer value (in clocks) with
   appropriate TOG. */
static uint64_t openpic_tmr_get_timer(OpenPICTimer *tmr)
{
    uint64_t retval;
    if (!tmr->qemu_timer_active) {
        retval = tmr->tccr;
    } else {
        uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
        uint64_t used = now - tmr->origin_time;  /* nsecs */
        uint32_t used_ticks = (uint32_t)ns_to_ticks(used);
        uint32_t count = (tmr->tccr & ~TCCR_TOG) - used_ticks;
        retval = (uint32_t)((tmr->tccr & TCCR_TOG) | (count & ~TCCR_TOG));
    }
    return retval;
}

static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
                              unsigned len)
{
@@ -819,10 +903,15 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
    case 0x00: /* TCCR */
        break;
    case 0x10: /* TBCR */
        if ((opp->timers[idx].tccr & TCCR_TOG) != 0 &&
            (val & TBCR_CI) == 0 &&
            (opp->timers[idx].tbcr & TBCR_CI) != 0) {
            opp->timers[idx].tccr &= ~TCCR_TOG;
        /* Did the enable status change? */
        if ((opp->timers[idx].tbcr & TBCR_CI) != (val & TBCR_CI)) {
            /* Did "Count Inhibit" transition from 1 to 0? */
            if ((val & TBCR_CI) == 0) {
                opp->timers[idx].tccr = val & ~TCCR_TOG;
            }
            openpic_tmr_set_tmr(&opp->timers[idx],
                                (val & ~TBCR_CI),
                                /*enabled=*/((val & TBCR_CI) == 0));
        }
        opp->timers[idx].tbcr = val;
        break;
@@ -854,7 +943,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
    idx = (addr >> 6) & 0x3;
    switch (addr & 0x30) {
    case 0x00: /* TCCR */
        retval = opp->timers[idx].tccr;
        retval = openpic_tmr_get_timer(&opp->timers[idx]);
        break;
    case 0x10: /* TBCR */
        retval = opp->timers[idx].tbcr;
@@ -1136,7 +1225,10 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
        IRQ_resetbit(&dst->raised, irq);
    }

    if ((irq >= opp->irq_ipi0) &&  (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) {
    /* Timers and IPIs support multicast. */
    if (((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) ||
        ((irq >= opp->irq_tim0) && (irq < (opp->irq_tim0 + OPENPIC_MAX_TMR)))) {
        DPRINTF("irq is IPI or TMR\n");
        src->destmask &= ~(1 << cpu);
        if (src->destmask && !src->level) {
            /* trigger on CPUs that didn't know about it yet */
@@ -1341,6 +1433,10 @@ static void openpic_reset(DeviceState *d)
    for (i = 0; i < OPENPIC_MAX_TMR; i++) {
        opp->timers[i].tccr = 0;
        opp->timers[i].tbcr = TBCR_CI;
        if (opp->timers[i].qemu_timer_active) {
            timer_del(opp->timers[i].qemu_timer);  /* Inhibit timer */
            opp->timers[i].qemu_timer_active = false;
        }
    }
    /* Go out of RESET state */
    opp->gcr = 0;
@@ -1391,6 +1487,15 @@ static void fsl_common_init(OpenPICState *opp)
        opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
        opp->src[i].level = false;
    }

    for (i = 0; i < OPENPIC_MAX_TMR; i++) {
        opp->timers[i].n_IRQ = opp->irq_tim0 + i;
        opp->timers[i].qemu_timer_active = false;
        opp->timers[i].qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                                 &qemu_timer_cb,
                                                 &opp->timers[i]);
        opp->timers[i].opp = opp;
    }
}

static void map_list(OpenPICState *opp, const MemReg *list, int *count)
+4 −1
Original line number Diff line number Diff line
@@ -344,10 +344,14 @@ static void icp_realize(DeviceState *dev, Error **errp)
    }

    qemu_register_reset(icp_reset, dev);
    vmstate_register(NULL, icp->cs->cpu_index, &vmstate_icp_server, icp);
}

static void icp_unrealize(DeviceState *dev, Error **errp)
{
    ICPState *icp = ICP(dev);

    vmstate_unregister(NULL, &vmstate_icp_server, icp);
    qemu_unregister_reset(icp_reset, dev);
}

@@ -355,7 +359,6 @@ static void icp_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);

    dc->vmsd = &vmstate_icp_server;
    dc->realize = icp_realize;
    dc->unrealize = icp_unrealize;
}
+0 −4
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@
#include "hw/pci/pci_host.h"
#include "hw/ppc/ppc.h"
#include "hw/boards.h"
#include "hw/audio/soundhw.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "hw/ide.h"
@@ -782,9 +781,6 @@ static void ibm_40p_init(MachineState *machine)
    qbus_walk_children(BUS(isa_bus), prep_set_cmos_checksum, NULL, NULL, NULL,
                       &cmos_checksum);

    /* initialize audio subsystem */
    soundhw_init();

    /* add some more devices */
    if (defaults_enabled()) {
        isa_create_simple(isa_bus, "i8042");
+136 −24
Original line number Diff line number Diff line
@@ -127,9 +127,49 @@ error:
    return NULL;
}

static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
{
    /* Dummy entries correspond to unused ICPState objects in older QEMUs,
     * and newer QEMUs don't even have them. In both cases, we don't want
     * to send anything on the wire.
     */
    return false;
}

static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
    .name = "icp/server",
    .version_id = 1,
    .minimum_version_id = 1,
    .needed = pre_2_10_vmstate_dummy_icp_needed,
    .fields = (VMStateField[]) {
        VMSTATE_UNUSED(4), /* uint32_t xirr */
        VMSTATE_UNUSED(1), /* uint8_t pending_priority */
        VMSTATE_UNUSED(1), /* uint8_t mfrr */
        VMSTATE_END_OF_LIST()
    },
};

static void pre_2_10_vmstate_register_dummy_icp(int i)
{
    vmstate_register(NULL, i, &pre_2_10_vmstate_dummy_icp,
                     (void *)(uintptr_t) i);
}

static void pre_2_10_vmstate_unregister_dummy_icp(int i)
{
    vmstate_unregister(NULL, &pre_2_10_vmstate_dummy_icp,
                       (void *)(uintptr_t) i);
}

static inline int xics_max_server_number(void)
{
    return DIV_ROUND_UP(max_cpus * kvmppc_smt_threads(), 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) &&
@@ -151,6 +191,17 @@ 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(); 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,
@@ -979,7 +1030,6 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
    void *fdt;
    sPAPRPHBState *phb;
    char *buf;
    int smt = kvmppc_smt_threads();

    fdt = g_malloc0(FDT_MAX_SIZE);
    _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
@@ -1019,7 +1069,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
    _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));

    /* /interrupt controller */
    spapr_dt_xics(DIV_ROUND_UP(max_cpus * smt, smp_threads), fdt, PHANDLE_XICP);
    spapr_dt_xics(xics_max_server_number(), fdt, PHANDLE_XICP);

    ret = spapr_populate_memory(spapr, fdt);
    if (ret < 0) {
@@ -1326,7 +1376,6 @@ static void ppc_spapr_reset(void)
         * Set the GR bit in PATB so that we know there is no HPT. */
        spapr->patb_entry = PATBE1_GR;
    } else {
        spapr->patb_entry = 0;
        spapr_setup_hpt_and_vrma(spapr);
    }

@@ -1346,6 +1395,8 @@ static void ppc_spapr_reset(void)
    if (!spapr->cas_reboot) {
        spapr_ovec_cleanup(spapr->ov5_cas);
        spapr->ov5_cas = spapr_ovec_new();

        ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
    }

    fdt = spapr_build_fdt(spapr, rtas_addr, spapr->rtas_size);
@@ -1443,6 +1494,18 @@ static int spapr_post_load(void *opaque, int version_id)
        err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
    }

    if (spapr->patb_entry) {
        PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
        bool radix = !!(spapr->patb_entry & PATBE1_GR);
        bool gtse = !!(cpu->env.spr[SPR_LPCR] & LPCR_GTSE);

        err = kvmppc_configure_v3_mmu(cpu, radix, gtse, spapr->patb_entry);
        if (err) {
            error_report("Process table config unsupported by the host");
            return -EINVAL;
        }
    }

    return err;
}

@@ -1558,14 +1621,20 @@ static int htab_save_setup(QEMUFile *f, void *opaque)
    sPAPRMachineState *spapr = opaque;

    /* "Iteration" header */
    if (!spapr->htab_shift) {
        qemu_put_be32(f, -1);
    } else {
        qemu_put_be32(f, spapr->htab_shift);
    }

    if (spapr->htab) {
        spapr->htab_save_index = 0;
        spapr->htab_first_pass = true;
    } else {
        if (spapr->htab_shift) {
            assert(kvm_enabled());
        }
    }


    return 0;
@@ -1710,7 +1779,12 @@ static int htab_save_iterate(QEMUFile *f, void *opaque)
    int rc = 0;

    /* Iteration header */
    if (!spapr->htab_shift) {
        qemu_put_be32(f, -1);
        return 0;
    } else {
        qemu_put_be32(f, 0);
    }

    if (!spapr->htab) {
        assert(kvm_enabled());
@@ -1744,7 +1818,12 @@ static int htab_save_complete(QEMUFile *f, void *opaque)
    int fd;

    /* Iteration header */
    if (!spapr->htab_shift) {
        qemu_put_be32(f, -1);
        return 0;
    } else {
        qemu_put_be32(f, 0);
    }

    if (!spapr->htab) {
        int rc;
@@ -1788,6 +1867,11 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id)

    section_hdr = qemu_get_be32(f);

    if (section_hdr == -1) {
        spapr_free_hpt(spapr);
        return 0;
    }

    if (section_hdr) {
        Error *local_err = NULL;

@@ -2131,7 +2215,7 @@ static void ppc_spapr_init(MachineState *machine)
        machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu;
    }

    ppc_cpu_parse_features(machine->cpu_model);
    spapr_cpu_parse_features(spapr);

    spapr_init_cpus(spapr);

@@ -2503,6 +2587,10 @@ static void spapr_machine_initfn(Object *obj)
                                    " place of standard EPOW events when possible"
                                    " (required for memory hot-unplug support)",
                                    NULL);

    ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr,
                            "Maximum permitted CPU compatibility mode",
                            &error_fatal);
}

static void spapr_machine_finalizefn(Object *obj)
@@ -2548,12 +2636,6 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,

        spapr_drc_attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp);
        addr += SPAPR_MEMORY_BLOCK_SIZE;
        if (!dev->hotplugged) {
            sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
            /* guests expect coldplugged LMBs to be pre-allocated */
            drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
            drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
        }
    }
    /* send hotplug notification to the
     * guest only in case of hotplugged memory
@@ -2806,9 +2888,24 @@ static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
                              Error **errp)
{
    MachineState *ms = MACHINE(qdev_get_machine());
    sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
    CPUCore *cc = CPU_CORE(dev);
    CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);

    if (smc->pre_2_10_has_unused_icps) {
        sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
        sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(cc));
        const char *typename = object_class_get_name(scc->cpu_class);
        size_t size = object_type_get_instance_size(typename);
        int i;

        for (i = 0; i < cc->nr_threads; i++) {
            CPUState *cs = CPU(sc->threads + i * size);

            pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
        }
    }

    assert(core_slot);
    core_slot->cpu = NULL;
    object_unparent(OBJECT(dev));
@@ -2860,6 +2957,7 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
{
    sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
    MachineClass *mc = MACHINE_GET_CLASS(spapr);
    sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
    sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
    CPUCore *cc = CPU_CORE(dev);
    CPUState *cs = CPU(core->threads);
@@ -2905,17 +3003,23 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
         * of hotplugged CPUs.
         */
        spapr_hotplug_req_add_by_index(drc);
    } else {
        /*
         * Set the right DRC states for cold plugged CPU.
         */
        if (drc) {
            sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
            drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
            drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
        }
    }
    core_slot->cpu = OBJECT(dev);

    if (smc->pre_2_10_has_unused_icps) {
        sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(cc));
        const char *typename = object_class_get_name(scc->cpu_class);
        size_t size = object_type_get_instance_size(typename);
        int i;

        for (i = 0; i < cc->nr_threads; i++) {
            sPAPRCPUCore *sc = SPAPR_CPU_CORE(dev);
            void *obj = sc->threads + i * size;

            cs = CPU(obj);
            pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
        }
    }
}

static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
@@ -3356,7 +3460,12 @@ DEFINE_SPAPR_MACHINE(2_10, "2.10", true);
 * pseries-2.9
 */
#define SPAPR_COMPAT_2_9                                               \
    HW_COMPAT_2_9
    HW_COMPAT_2_9                                                      \
    {                                                                  \
        .driver = TYPE_POWERPC_CPU,                                    \
        .property = "pre-2.10-migration",                              \
        .value    = "on",                                              \
    },                                                                 \

static void spapr_machine_2_9_instance_options(MachineState *machine)
{
@@ -3365,9 +3474,12 @@ static void spapr_machine_2_9_instance_options(MachineState *machine)

static void spapr_machine_2_9_class_options(MachineClass *mc)
{
    sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);

    spapr_machine_2_10_class_options(mc);
    SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_9);
    mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
    smc->pre_2_10_has_unused_icps = true;
}

DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
+55 −13
Original line number Diff line number Diff line
@@ -20,6 +20,57 @@
#include "sysemu/numa.h"
#include "qemu/error-report.h"

void spapr_cpu_parse_features(sPAPRMachineState *spapr)
{
    /*
     * Backwards compatibility hack:
     *
     *   CPUs had a "compat=" property which didn't make sense for
     *   anything except pseries.  It was replaced by "max-cpu-compat"
     *   machine option.  This supports old command lines like
     *       -cpu POWER8,compat=power7
     *   By stripping the compat option and applying it to the machine
     *   before passing it on to the cpu level parser.
     */
    gchar **inpieces;
    int i, j;
    gchar *compat_str = NULL;

    inpieces = g_strsplit(MACHINE(spapr)->cpu_model, ",", 0);

    /* inpieces[0] is the actual model string */
    i = 1;
    j = 1;
    while (inpieces[i]) {
        if (g_str_has_prefix(inpieces[i], "compat=")) {
            /* in case of multiple compat= options */
            g_free(compat_str);
            compat_str = inpieces[i];
        } else {
            j++;
        }

        i++;
        /* Excise compat options from list */
        inpieces[j] = inpieces[i];
    }

    if (compat_str) {
        char *val = compat_str + strlen("compat=");
        gchar *newprops = g_strjoinv(",", inpieces);

        object_property_set_str(OBJECT(spapr), val, "max-cpu-compat",
                                &error_fatal);

        ppc_cpu_parse_features(newprops);
        g_free(newprops);
    } else {
        ppc_cpu_parse_features(MACHINE(spapr)->cpu_model);
    }

    g_strfreev(inpieces);
}

static void spapr_cpu_reset(void *opaque)
{
    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
@@ -67,16 +118,6 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
    /* Enable PAPR mode in TCG or KVM */
    cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));

    if (cpu->max_compat) {
        Error *local_err = NULL;

        ppc_set_compat(cpu, cpu->max_compat, &local_err);
        if (local_err) {
            error_propagate(errp, local_err);
            return;
        }
    }

    qemu_register_reset(spapr_cpu_reset, cpu);
    spapr_cpu_reset(cpu);
}
@@ -137,7 +178,7 @@ static void spapr_cpu_core_realize_child(Object *child, Error **errp)
    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
    CPUState *cs = CPU(child);
    PowerPCCPU *cpu = POWERPC_CPU(cs);
    Object *obj = NULL;
    Object *obj;

    object_property_set_bool(child, true, "realized", &local_err);
    if (local_err) {
@@ -157,13 +198,14 @@ static void spapr_cpu_core_realize_child(Object *child, Error **errp)
    object_property_add_const_link(obj, ICP_PROP_CPU, child, &error_abort);
    object_property_set_bool(obj, true, "realized", &local_err);
    if (local_err) {
        goto error;
        goto free_icp;
    }

    return;

error:
free_icp:
    object_unparent(obj);
error:
    error_propagate(errp, local_err);
}

Loading