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

Cédric Le Goater posted 1 patch 4 years, 1 month ago
Test docker-mingw@fedora passed
Test docker-quick@centos7 passed
Test checkpatch passed
Test FreeBSD passed
Test asan passed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20200404153655.166834-1-clg@kaod.org
Maintainers: "Cédric Le Goater" <clg@kaod.org>, David Gibson <david@gibson.dropbear.id.au>
include/hw/ppc/pnv.h |  2 ++
hw/ppc/pnv.c         | 32 ++++++++++++++++++++++++++-----
hw/ppc/pnv_bmc.c     | 45 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+), 5 deletions(-)
[PATCH] ppc/pnv: Create BMC devices only when defaults are enabled
Posted by Cédric Le Goater 4 years, 1 month ago
Commit e2392d4395dd ("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: e2392d4395dd ("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>
---
 include/hw/ppc/pnv.h |  2 ++
 hw/ppc/pnv.c         | 32 ++++++++++++++++++++++++++-----
 hw/ppc/pnv_bmc.c     | 45 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 74 insertions(+), 5 deletions(-)

diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index fb4d0c0234b3..d4b0b0e2ff71 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -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
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index ac83b8698b8e..a3b7a8d0ff32 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -573,10 +573,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 */
@@ -835,9 +854,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);
 
@@ -847,8 +863,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
diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c
index 8863354c1c08..4e018b8b70e4 100644
--- a/hw/ppc/pnv_bmc.c
+++ b/hw/ppc/pnv_bmc.c
@@ -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.25.1


Re: [PATCH] ppc/pnv: Create BMC devices only when defaults are enabled
Posted by Nathan Chancellor 4 years, 1 month ago
Hi Cédric,

On Sat, Apr 04, 2020 at 05:36:55PM +0200, Cédric Le Goater wrote:
> Commit e2392d4395dd ("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: e2392d4395dd ("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>

This fixes my issue when -nodefaults is passed and that does not regress
QEMU 3.1.0 or 4.2.0. Thank you for the quick fix!

Tested-by: Nathan Chancellor <natechancellor@gmail.com>

A few comments inline.

> ---
>  include/hw/ppc/pnv.h |  2 ++
>  hw/ppc/pnv.c         | 32 ++++++++++++++++++++++++++-----
>  hw/ppc/pnv_bmc.c     | 45 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 74 insertions(+), 5 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index fb4d0c0234b3..d4b0b0e2ff71 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -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
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index ac83b8698b8e..a3b7a8d0ff32 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -573,10 +573,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");

If I pass no -device flags + -nodefaults, I don't see this message. Is
that expected?

> +        } else {
> +            pnv_bmc_set_pnor(bmc, pnv->pnor);
> +            pnv->bmc = bmc;
> +        }
> +    }
> +
>      fdt = pnv_dt_create(machine);
>  
>      /* Pack resulting tree */
> @@ -835,9 +854,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);
>  
> @@ -847,8 +863,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
> diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c
> index 8863354c1c08..4e018b8b70e4 100644
> --- a/hw/ppc/pnv_bmc.c
> +++ b/hw/ppc/pnv_bmc.c
> @@ -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'");

When passing the -device flags in the commit message as I did in my
original command without -nodefaults, I still see the

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

message. Is that expected?

> +        return NULL;
> +    }
> +
> +    return args.obj ? IPMI_BMC(args.obj) : NULL;
> +}
> -- 
> 2.25.1
> 

Re: [PATCH] ppc/pnv: Create BMC devices only when defaults are enabled
Posted by Cédric Le Goater 4 years, 1 month ago
On 4/4/20 11:44 PM, Nathan Chancellor wrote:
> Hi Cédric,
> 
> On Sat, Apr 04, 2020 at 05:36:55PM +0200, Cédric Le Goater wrote:
>> Commit e2392d4395dd ("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: e2392d4395dd ("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>
> 
> This fixes my issue when -nodefaults is passed and that does not regress
> QEMU 3.1.0 or 4.2.0. Thank you for the quick fix!
> 
> Tested-by: Nathan Chancellor <natechancellor@gmail.com>
> 
> A few comments inline.
> 
>> ---
>>  include/hw/ppc/pnv.h |  2 ++
>>  hw/ppc/pnv.c         | 32 ++++++++++++++++++++++++++-----
>>  hw/ppc/pnv_bmc.c     | 45 ++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 74 insertions(+), 5 deletions(-)
>>
>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>> index fb4d0c0234b3..d4b0b0e2ff71 100644
>> --- a/include/hw/ppc/pnv.h
>> +++ b/include/hw/ppc/pnv.h
>> @@ -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
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index ac83b8698b8e..a3b7a8d0ff32 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -573,10 +573,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");
> 
> If I pass no -device flags + -nodefaults, I don't see this message. Is
> that expected?

yes. Because the machine instantiates the default BMC devices.

> 
>> +        } else {
>> +            pnv_bmc_set_pnor(bmc, pnv->pnor);
>> +            pnv->bmc = bmc;
>> +        }
>> +    }
>> +
>>      fdt = pnv_dt_create(machine);
>>  
>>      /* Pack resulting tree */
>> @@ -835,9 +854,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);
>>  
>> @@ -847,8 +863,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
>> diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c
>> index 8863354c1c08..4e018b8b70e4 100644
>> --- a/hw/ppc/pnv_bmc.c
>> +++ b/hw/ppc/pnv_bmc.c
>> @@ -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'");
> 
> When passing the -device flags in the commit message as I did in my
> original command without -nodefaults, I still see the
> 
> qemu-system-ppc64: error creating device tree: node: FDT_ERR_EXISTS
> 
> message. Is that expected?
object_child_foreach_recursive() is broken. Here is the fix :

   http://patchwork.ozlabs.org/patch/1266419/

Sorry. I should have copied you.

But there are other ways to find multiple instances of the same type. 
May be we will need to rework that part a bit.

Thanks,

C.

> 
>> +        return NULL;
>> +    }
>> +
>> +    return args.obj ? IPMI_BMC(args.obj) : NULL;
>> +}
>> -- 
>> 2.25.1
>>


Re: [PATCH] ppc/pnv: Create BMC devices only when defaults are enabled
Posted by David Gibson 4 years, 1 month ago
On Sat, Apr 04, 2020 at 05:36:55PM +0200, Cédric Le Goater wrote:
> Commit e2392d4395dd ("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: e2392d4395dd ("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>

As a regression fix, applied to ppc-for-5.0.

> ---
>  include/hw/ppc/pnv.h |  2 ++
>  hw/ppc/pnv.c         | 32 ++++++++++++++++++++++++++-----
>  hw/ppc/pnv_bmc.c     | 45 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 74 insertions(+), 5 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index fb4d0c0234b3..d4b0b0e2ff71 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -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
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index ac83b8698b8e..a3b7a8d0ff32 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -573,10 +573,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 */
> @@ -835,9 +854,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);
>  
> @@ -847,8 +863,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
> diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c
> index 8863354c1c08..4e018b8b70e4 100644
> --- a/hw/ppc/pnv_bmc.c
> +++ b/hw/ppc/pnv_bmc.c
> @@ -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;
> +}

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson