diff mbox

plat/qemu: add BT and IPMI support

Message ID 1470131965-16510-1-git-send-email-clg@kaod.org
State Accepted
Headers show

Commit Message

Cédric Le Goater Aug. 2, 2016, 9:59 a.m. UTC
This brings the qemu platform to the level of an Open Power platform.
It adds the BT device used to communicate with the BMC using IPMI
messaging, power_downs and reboots the way OpenPower systems operate.

The device tree is also checked for UART and RTC device nodes and
updated if qemu has not defined them already. The initialization of
the BT and IPMI interfaces depends on the availability of the BT
device which needs to be explicitly defined by qemu. These tests
enable skiboot to maintain compatibility with previous versions of
qemu which did not update the device tree with enabled devices.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---

 The only significant difference now with the ast platform is on the
 RTC device which lives under the LPC bus on qemu.

 Tested with the latest qemu powernv+ipmi patchset :

	https://github.com/legoater/qemu/tree/powernv-ipmi-2.7

 which is now based on a v2.7.0-rc1.

 Also tested with Ben's qemu for compatibility. 

 Cheers,


 platforms/qemu/qemu.c |  115 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)

Comments

Cédric Le Goater Aug. 2, 2016, 5:54 p.m. UTC | #1
On 08/02/2016 12:59 PM, Stewart Smith wrote:
> Cédric Le Goater <clg@kaod.org> writes:
>> This brings the qemu platform to the level of an Open Power platform.
>> It adds the BT device used to communicate with the BMC using IPMI
>> messaging, power_downs and reboots the way OpenPower systems operate.
>>
>> The device tree is also checked for UART and RTC device nodes and
>> updated if qemu has not defined them already. The initialization of
>> the BT and IPMI interfaces depends on the availability of the BT
>> device which needs to be explicitly defined by qemu. These tests
>> enable skiboot to maintain compatibility with previous versions of
>> qemu which did not update the device tree with enabled devices.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>
>>  The only significant difference now with the ast platform is on the
>>  RTC device which lives under the LPC bus on qemu.
>>
>>  Tested with the latest qemu powernv+ipmi patchset :
>>
>> 	https://github.com/legoater/qemu/tree/powernv-ipmi-2.7
>>
>>  which is now based on a v2.7.0-rc1.
> 
> Awesome!
> 
> I'm strongly inclined to make this tree the new one that's run in the
> travis-ci qemu build (opal-ci/build-qemu.sh or whatever it's called
> that's run from .travis.yml).
> 

FYI, I have added a quick patch on powernv-ipmi-2.7 to support old 
skiboots not having the proposed patch in this email. So the current 
skiboot non-regression tests should work with it. Well, that's the 
plan.

I should start a 2.8 branch based on David Gibson 'for 2.8' when I 
have more PowerNV material to commit. 

As for IPMI support, you will need some extra files to define the 
sensors and the FRUs which are needed at run time. The device tree is 
built in qemu using these files. Here is a quick howto : 

	https://legoater.github.io/

Cheers,

C.
diff mbox

Patch

Index: skiboot.git/platforms/qemu/qemu.c
===================================================================
--- skiboot.git.orig/platforms/qemu/qemu.c
+++ skiboot.git/platforms/qemu/qemu.c
@@ -21,6 +21,60 @@ 
 #include <console.h>
 #include <opal.h>
 #include <psi.h>
+#include <bt.h>
+#include <errorlog.h>
+#include <ipmi.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)
 {
@@ -32,6 +86,27 @@  static void qemu_init(void)
 	 * 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)
@@ -53,6 +128,14 @@  static void qemu_dt_fixup_uart(struct dt
 #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_WARNING, "QEMU: uart device already here\n");
+			return;
+		}
+	}
+
 	snprintf(namebuf, sizeof(namebuf), "serial@i%x", UART_IO_BASE);
 	uart = dt_new(lpc, namebuf);
 
@@ -84,6 +167,14 @@  static void qemu_dt_fixup_rtc(struct dt_
 	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_WARNING, "QEMU: rtc device already here\n");
+			return;
+		}
+	}
+
 	/*
 	 * Follows the structure expected by the kernel file
 	 * arch/powerpc/sysdev/rtc_cmos_setup.c
@@ -113,6 +204,12 @@  static void qemu_dt_fixup(void)
 
 	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)
@@ -120,6 +217,21 @@  static void qemu_ext_irq_serirq_cpld(uns
 	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);
+}
+
+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"))
@@ -145,4 +257,7 @@  DECLARE_PLATFORM(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,
+	.terminate	= ipmi_terminate,
 };