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

Commit e2392d4395 ("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: e2392d4395 ("ppc/pnv: Create BMC devices at machine init")
Reported-by: Nathan Chancellor <natechancellor@gmail.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20200404153655.166834-1-clg@kaod.org>
Tested-by: Nathan Chancellor <natechancellor@gmail.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Cédric Le Goater 2020-04-04 17:36:55 +02:00 committed by David Gibson
parent a872e4328b
commit 25f3170b06
3 changed files with 74 additions and 5 deletions

View file

@ -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 */
pnv_ipmi_bt_init(pnv->isa_bus, pnv->bmc, 10);
/*
* 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

View file

@ -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;
}

View file

@ -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