[Skiboot] [PATCH] plat/qemu: use the common OpenPOWER routines to initialize

Joel Stanley joel at jms.id.au
Tue Dec 4 08:54:44 AEDT 2018


On Mon, 3 Dec 2018 at 23:08, Cédric Le Goater <clg at kaod.org> wrote:
>
> Back in 2016, we did not have a large support of the PowerNV devices
> under QEMU and we were using our own custom ones. This has changed and
> we can now use all the common init routines of the OpenPOWER
> platforms.
>
> Signed-off-by: Cédric Le Goater <clg at kaod.org>

Reviewed-by: Joel Stanley <joel at jms.id.au>

This fixes the bt device when running with a power9 powernv machine
type, which in turn fixes shutting down the guest.

qemu-system-ppc64 -M powernv -m 3G -device ipmi-bmc-sim,id=bmc0
-device isa-ipmi-bt,bmc=bmc0,irq=10 \
 -nographic -kernel arch/powerpc/boot/zImage.epapr  ~/rootfs.cpio.xz
-L /scratch/joel/skiboot -cpu power9

I gave this a spin on Qemu 2.12 (which ships with Ubuntu and Debian)
and it successfully loads a kernel on a p8 powernv machine. Given that
is the oldest version that is practical for skiboot powernv testing,
we can safely apply this to skiboot and not regress.

I suggest we merge this one to master and the stable tree.

Cheers,

Joel

> ---
>  platforms/qemu/qemu.c | 236 ++----------------------------------------
>  1 file changed, 6 insertions(+), 230 deletions(-)
>
> diff --git a/platforms/qemu/qemu.c b/platforms/qemu/qemu.c
> index 2e9884d2cb2e..316231314b14 100644
> --- a/platforms/qemu/qemu.c
> +++ b/platforms/qemu/qemu.c
> @@ -14,243 +14,19 @@
>   * limitations under the License.
>   */
>
> -
>  #include <skiboot.h>
>  #include <device.h>
> -#include <lpc.h>
> -#include <console.h>
> -#include <opal.h>
> -#include <psi.h>
> -#include <bt.h>
> -#include <errorlog.h>
>  #include <ipmi.h>
> -#include <ast.h>
> -#include <platforms/astbmc/astbmc.h>
> -
> -/* BT config */
> -#define BT_IO_BASE     0xe4
> -#define BT_IO_COUNT    3
> -#define BT_LPC_IRQ     10
> -
> -static bool bt_device_present;
> -
> -static void qemu_ipmi_error(struct ipmi_msg *msg)
> -{
> -       prlog(PR_DEBUG, "QEMU: error sending msg. cc = %02x\n", msg->cc);
> -
> -       ipmi_free_msg(msg);
> -}
> -
> -static void qemu_ipmi_setenables(void)
> -{
> -       struct ipmi_msg *msg;
> -
> -       struct {
> -               uint8_t oem2_en : 1;
> -               uint8_t oem1_en : 1;
> -               uint8_t oem0_en : 1;
> -               uint8_t reserved : 1;
> -               uint8_t sel_en : 1;
> -               uint8_t msgbuf_en : 1;
> -               uint8_t msgbuf_full_int_en : 1;
> -               uint8_t rxmsg_queue_int_en : 1;
> -       } data;
> -
> -       memset(&data, 0, sizeof(data));
> -
> -       /* The spec says we need to read-modify-write to not clobber
> -        * the state of the other flags. These are set on by the bmc */
> -       data.rxmsg_queue_int_en = 1;
> -       data.sel_en = 1;
> -
> -       /* These are the ones we want to set on */
> -       data.msgbuf_en = 1;
> -
> -       msg = ipmi_mkmsg_simple(IPMI_SET_ENABLES, &data, sizeof(data));
> -       if (!msg) {
> -               prlog(PR_ERR, "QEMU: failed to set enables\n");
> -               return;
> -       }
> -
> -       msg->error = qemu_ipmi_error;
> -
> -       ipmi_queue_msg(msg);
> -
> -}
> -
> -static void qemu_init(void)
> -{
> -       /* Initialize PNOR/NVRAM */
> -       pnor_init();
> -
> -       /* Setup UART console for use by Linux via OPAL API */
> -       set_opal_console(&uart_opal_con);
> -
> -       /* Setup LPC RTC and use it as time source. Call after
> -        * chiptod_init()
> -        */
> -       lpc_rtc_init();
> -
> -       if (!bt_device_present)
> -               return;
> -
> -       /* Register the BT interface with the IPMI layer */
> -       bt_init();
> -       /* Initialize elog */
> -       elog_init();
> -       ipmi_sel_init();
> -       ipmi_wdt_init();
> -       ipmi_opal_init();
> -       ipmi_fru_init(0);
> -       ipmi_sensor_init();
> -
> -       /* As soon as IPMI is up, inform BMC we are in "S0" */
> -       ipmi_set_power_state(IPMI_PWR_SYS_S0_WORKING, IPMI_PWR_NOCHANGE);
> -
> -       /* Enable IPMI OEM message interrupts */
> -       qemu_ipmi_setenables();
> -
> -       ipmi_set_fw_progress_sensor(IPMI_FW_MOTHERBOARD_INIT);
> -}
> -
> -static void qemu_dt_fixup_uart(struct dt_node *lpc)
> -{
> -       /*
> -        * The official OF ISA/LPC binding is a bit odd, it prefixes
> -        * the unit address for IO with "i". It uses 2 cells, the first
> -        * one indicating IO vs. Memory space (along with bits to
> -        * represent aliasing).
> -        *
> -        * We pickup that binding and add to it "2" as a indication
> -        * of FW space.
> -        *
> -        * TODO: Probe the UART instead if the LPC bus allows for it
> -        */
> -       struct dt_node *uart;
> -       char namebuf[32];
> -#define UART_IO_BASE   0x3f8
> -#define UART_IO_COUNT  8
> -#define UART_LPC_IRQ   4
>
> -       /* check if the UART device was defined by qemu */
> -       dt_for_each_child(lpc, uart) {
> -               if (dt_node_is_compatible(uart, "pnpPNP,501")) {
> -                       prlog(PR_DEBUG, "QEMU: uart device already here\n");
> -                       return;
> -               }
> -       }
> -
> -       snprintf(namebuf, sizeof(namebuf), "serial at i%x", UART_IO_BASE);
> -       uart = dt_new(lpc, namebuf);
> -
> -       dt_add_property_cells(uart, "reg",
> -                             1, /* IO space */
> -                             UART_IO_BASE, UART_IO_COUNT);
> -       dt_add_property_strings(uart, "compatible",
> -                               "ns16550",
> -                               "pnpPNP,501");
> -       dt_add_property_cells(uart, "clock-frequency", 1843200);
> -       dt_add_property_cells(uart, "current-speed", 115200);
> -       dt_add_property_cells(uart, "interrupts", UART_LPC_IRQ);
> -       dt_add_property_cells(uart, "interrupt-parent", lpc->phandle);
> -
> -       /*
> -        * This is needed by Linux for some obscure reasons,
> -        * we'll eventually need to sanitize it but in the meantime
> -        * let's make sure it's there
> -        */
> -       dt_add_property_strings(uart, "device_type", "serial");
> -}
> -
> -/*
> - * This adds the legacy RTC device to the device-tree
> - * for Linux to use
> - */
> -static void qemu_dt_fixup_rtc(struct dt_node *lpc)
> -{
> -       struct dt_node *rtc;
> -       char namebuf[32];
> -
> -       /* check if the RTC device was defined by qemu */
> -       dt_for_each_child(lpc, rtc) {
> -               if (dt_node_is_compatible(rtc, "pnpPNP,b00")) {
> -                       prlog(PR_DEBUG, "QEMU: rtc device already here\n");
> -                       return;
> -               }
> -       }
> -
> -       /*
> -        * Follows the structure expected by the kernel file
> -        * arch/powerpc/sysdev/rtc_cmos_setup.c
> -        */
> -       snprintf(namebuf, sizeof(namebuf), "rtc at i%x", 0x70);
> -       rtc = dt_new(lpc, namebuf);
> -       dt_add_property_string(rtc, "compatible", "pnpPNP,b00");
> -       dt_add_property_cells(rtc, "reg",
> -                             1, /* IO space */
> -                             0x70, 2);
> -}
> -
> -static void qemu_dt_fixup(void)
> -{
> -       struct dt_node *n, *primary_lpc = NULL;
> -
> -       /* Find the primary LPC bus */
> -       dt_for_each_compatible(dt_root, n, "ibm,power8-lpc") {
> -               if (!primary_lpc || dt_has_node_property(n, "primary", NULL))
> -                       primary_lpc = n;
> -               if (dt_has_node_property(n, "#address-cells", NULL))
> -                       break;
> -       }
> -
> -       if (!primary_lpc)
> -               return;
> -
> -       qemu_dt_fixup_rtc(primary_lpc);
> -       qemu_dt_fixup_uart(primary_lpc);
> -
> -       /* check if the BT device was defined by qemu */
> -       dt_for_each_child(primary_lpc, n) {
> -               if (dt_node_is_compatible(n, "bt"))
> -                       bt_device_present = true;
> -       }
> -}
> -
> -static void qemu_ext_irq_serirq_cpld(unsigned int chip_id)
> -{
> -       lpc_all_interrupts(chip_id);
> -}
> -
> -static int64_t qemu_ipmi_power_down(uint64_t request)
> -{
> -       if (request != IPMI_CHASSIS_PWR_DOWN) {
> -               prlog(PR_WARNING, "PLAT: unexpected shutdown request %llx\n",
> -                                  request);
> -       }
> -
> -       return ipmi_chassis_control(request);
> -}
> +#include <platforms/astbmc/astbmc.h>
>
> -static int64_t qemu_ipmi_reboot(void)
> -{
> -       return ipmi_chassis_control(IPMI_CHASSIS_HARD_RESET);
> -}
>
>  static bool qemu_probe(void)
>  {
>         if (!dt_node_is_compatible(dt_root, "qemu,powernv"))
>                 return false;
>
> -       /* Add missing bits of device-tree such as the UART */
> -       qemu_dt_fixup();
> -
> -       psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT);
> -
> -       if (!ast_sio_init())
> -               prerror("PLAT: AST SIO initialisation failed!\n");
> -
> -       /* Setup UART and use it as console */
> -       uart_init();
> +        astbmc_early_init();
>
>         return true;
>  }
> @@ -258,10 +34,10 @@ static bool qemu_probe(void)
>  DECLARE_PLATFORM(qemu) = {
>         .name           = "Qemu",
>         .probe          = qemu_probe,
> -       .init           = qemu_init,
> -       .external_irq   = qemu_ext_irq_serirq_cpld,
> -       .cec_power_down = qemu_ipmi_power_down,
> -       .cec_reboot     = qemu_ipmi_reboot,
> +       .init           = astbmc_init,
> +       .external_irq   = astbmc_ext_irq_serirq_cpld,
> +       .cec_power_down = astbmc_ipmi_power_down,
> +       .cec_reboot     = astbmc_ipmi_reboot,
>         .start_preload_resource = flash_start_preload_resource,
>         .resource_loaded        = flash_resource_loaded,
>         .terminate      = ipmi_terminate,
> --
> 2.17.2
>


More information about the Skiboot mailing list