Commit 25f3170b authored by Cédric Le Goater's avatar Cédric Le Goater Committed by David Gibson
Browse files

ppc/pnv: Create BMC devices only when defaults are enabled



Commit e2392d43 ("ppc/pnv: Create BMC devices at machine init")
introduced default BMC devices which can be a problem when the same
devices are defined on the command line with :

  -device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10

QEMU fails with :

  qemu-system-ppc64: error creating device tree: node: FDT_ERR_EXISTS

Use defaults_enabled() when creating the default BMC devices to let
the user provide its own BMC devices using '-nodefaults'. If no BMC
device are provided, output a warning but let QEMU run as this is a
supported configuration. However, when multiple BMC devices are
defined, stop QEMU with a clear error as the results are unexpected.

Fixes: e2392d43 ("ppc/pnv: Create BMC devices at machine init")
Reported-by: default avatarNathan Chancellor <natechancellor@gmail.com>
Signed-off-by: default avatarCédric Le Goater <clg@kaod.org>
Message-Id: <20200404153655.166834-1-clg@kaod.org>
Tested-by: default avatarNathan Chancellor <natechancellor@gmail.com>
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent a872e432
Loading
Loading
Loading
Loading
+27 −5
Original line number Diff line number Diff line
@@ -571,10 +571,29 @@ static void pnv_powerdown_notify(Notifier *n, void *opaque)

static void pnv_reset(MachineState *machine)
{
    PnvMachineState *pnv = PNV_MACHINE(machine);
    IPMIBmc *bmc;
    void *fdt;

    qemu_devices_reset();

    /*
     * The machine should provide by default an internal BMC simulator.
     * If not, try to use the BMC device that was provided on the command
     * line.
     */
    bmc = pnv_bmc_find(&error_fatal);
    if (!pnv->bmc) {
        if (!bmc) {
            warn_report("machine has no BMC device. Use '-device "
                        "ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10' "
                        "to define one");
        } else {
            pnv_bmc_set_pnor(bmc, pnv->pnor);
            pnv->bmc = bmc;
        }
    }

    fdt = pnv_dt_create(machine);

    /* Pack resulting tree */
@@ -833,9 +852,6 @@ static void pnv_init(MachineState *machine)
    }
    g_free(chip_typename);

    /* Create the machine BMC simulator */
    pnv->bmc = pnv_bmc_create(pnv->pnor);

    /* Instantiate ISA bus on chip 0 */
    pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal);

@@ -845,8 +861,14 @@ static void pnv_init(MachineState *machine)
    /* Create an RTC ISA device too */
    mc146818_rtc_init(pnv->isa_bus, 2000, NULL);

    /* Create the IPMI BT device for communication with the BMC */
    /*
     * Create the machine BMC simulator and the IPMI BT device for
     * communication with the BMC
     */
    if (defaults_enabled()) {
        pnv->bmc = pnv_bmc_create(pnv->pnor);
        pnv_ipmi_bt_init(pnv->isa_bus, pnv->bmc, 10);
    }

    /*
     * OpenPOWER systems use a IPMI SEL Event message to notify the
+45 −0
Original line number Diff line number Diff line
@@ -213,6 +213,18 @@ static const IPMINetfn hiomap_netfn = {
    .cmd_handlers = hiomap_cmds
};


void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor)
{
    object_ref(OBJECT(pnor));
    object_property_add_const_link(OBJECT(bmc), "pnor", OBJECT(pnor),
                                   &error_abort);

    /* Install the HIOMAP protocol handlers to access the PNOR */
    ipmi_sim_register_netfn(IPMI_BMC_SIMULATOR(bmc), IPMI_NETFN_OEM,
                            &hiomap_netfn);
}

/*
 * Instantiate the machine BMC. PowerNV uses the QEMU internal
 * simulator but it could also be external.
@@ -232,3 +244,36 @@ IPMIBmc *pnv_bmc_create(PnvPnor *pnor)

    return IPMI_BMC(obj);
}

typedef struct ForeachArgs {
    const char *name;
    Object *obj;
} ForeachArgs;

static int bmc_find(Object *child, void *opaque)
{
    ForeachArgs *args = opaque;

    if (object_dynamic_cast(child, args->name)) {
        if (args->obj) {
            return 1;
        }
        args->obj = child;
    }
    return 0;
}

IPMIBmc *pnv_bmc_find(Error **errp)
{
    ForeachArgs args = { TYPE_IPMI_BMC_SIMULATOR, NULL };
    int ret;

    ret = object_child_foreach_recursive(object_get_root(), bmc_find, &args);
    if (ret) {
        error_setg(errp, "machine should have only one BMC device. "
                   "Use '-nodefaults'");
        return NULL;
    }

    return args.obj ? IPMI_BMC(args.obj) : NULL;
}
+2 −0
Original line number Diff line number Diff line
@@ -241,6 +241,8 @@ struct PnvMachineState {
void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt);
void pnv_bmc_powerdown(IPMIBmc *bmc);
IPMIBmc *pnv_bmc_create(PnvPnor *pnor);
IPMIBmc *pnv_bmc_find(Error **errp);
void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor);

/*
 * POWER8 MMIO base addresses