diff mbox series

platforms/astbmc/vesnin: Send list of PCI devices to BMC through IPMI

Message ID 20181019113751.GB15617@yadro.com
State Accepted
Headers show
Series platforms/astbmc/vesnin: Send list of PCI devices to BMC through IPMI | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success master/apply_patch Successfully applied
snowpatch_ozlabs/make_check success Test make_check on branch master

Commit Message

Artem Senichev Oct. 19, 2018, 11:37 a.m. UTC
Implements sending a list of installed PCI devices through IPMI protocol.
Each PCI device description is sent as a standalone IPMI message.
A list of devices can be gathered from separate messages using the
session identifier. The session Id is an incremental counter that is
updated at the start of synchronization session.

Signed-off-by: Artem Senichev <a.senichev@yadro.com>
---
 platforms/astbmc/vesnin.c | 103 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 101 insertions(+), 2 deletions(-)

Comments

Stewart Smith Oct. 25, 2018, 11:14 p.m. UTC | #1
Artem Senichev <a.senichev@yadro.com> writes:
> Implements sending a list of installed PCI devices through IPMI protocol.
> Each PCI device description is sent as a standalone IPMI message.
> A list of devices can be gathered from separate messages using the
> session identifier. The session Id is an incremental counter that is
> updated at the start of synchronization session.
>
> Signed-off-by: Artem Senichev <a.senichev@yadro.com>
> ---
>  platforms/astbmc/vesnin.c | 103 +++++++++++++++++++++++++++++++++++++-
>  1 file changed, 101 insertions(+), 2 deletions(-)

Great!

Merged to master as of 6ea075edd7af49c06fe758fb4014105de9cedac2

I wonder if any other platforms would want this functionality, I have
heard that in the x86 world it's relatively common to have BMCs know PCI
inventory.
Artem Senichev Oct. 26, 2018, 7:21 a.m. UTC | #2
On Fri, Oct 26, 2018 at 10:14:02AM +1100, Stewart Smith wrote:
> Artem Senichev <a.senichev@yadro.com> writes:
> > Implements sending a list of installed PCI devices through IPMI protocol.
> > Each PCI device description is sent as a standalone IPMI message.
> > A list of devices can be gathered from separate messages using the
> > session identifier. The session Id is an incremental counter that is
> > updated at the start of synchronization session.
> 
> I wonder if any other platforms would want this functionality, I have
> heard that in the x86 world it's relatively common to have BMCs know PCI
> inventory.

I have already tried ;)
https://lists.ozlabs.org/pipermail/skiboot/2018-May/011261.html
diff mbox series

Patch

diff --git a/platforms/astbmc/vesnin.c b/platforms/astbmc/vesnin.c
index 62eb3403..fb3425f8 100644
--- a/platforms/astbmc/vesnin.c
+++ b/platforms/astbmc/vesnin.c
@@ -1,5 +1,5 @@ 
 /**
- * Copyright (c) 2018 YADRO (KNS Group LLC)
+ * Copyright (c) 2018 YADRO
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@ 
 #include <console.h>
 #include <chip.h>
 #include <ipmi.h>
+#include <pci.h>
+#include <pci-cfg.h>
 
 #include "astbmc.h"
 
@@ -27,6 +29,51 @@ 
 #define CHIP_ID_CPU2 0x10
 #define CHIP_ID_CPU3 0x18
 
+/* Current version of the PCI inventory synchronization packet. */
+#define PCI_INV_VERSION 1
+
+/* IPMI message identifier (IBM OEM) for PCI inventory. */
+#define IPMI_PCI_INV IPMI_CODE(0x3a, 0x2a)
+
+/* Id of the current PCI inventory synchronization session. */
+static uint8_t pci_inv_session_id;
+
+/**
+ * struct pciinv_device - PCI device inventory description.
+ * @domain_num: Domain number.
+ * @bus_num: Bus number.
+ * @device_num: Device number.
+ * @func_num: Function number.
+ * @vendor_id: Vendor Id.
+ * @device_id: Device Id.
+ * @class_code: Device class code.
+ * @revision: Revision number.
+ *
+ * All fields have Big Endian byte order.
+ */
+struct pciinv_device {
+	uint16_t	domain_num;
+	uint8_t		bus_num;
+	uint8_t		device_num;
+	uint8_t		func_num;
+	uint16_t	vendor_id;
+	uint16_t	device_id;
+	uint32_t	class_code;
+	uint8_t		revision;
+} __packed;
+
+/**
+ * struct pciinv_packet - IPMI message packet data.
+ * @version: Packet version, must be set to %PCI_INVENTORY_VERSION.
+ * @session: Sync session Id.
+ * @device: PCI device description.
+ */
+struct pciinv_packet {
+	uint8_t		version;
+	uint8_t		session;
+	struct pciinv_device device;
+} __packed;
+
 
 static const struct slot_table_entry vesnin_phb0_0_slot[] = {
 	{
@@ -233,6 +280,58 @@  static const struct slot_table_entry vesnin_phb_table[] = {
 	{ .etype = st_end }
 };
 
+/**
+ * pciinv_walk() - Callback from PCI enumerator, see :c:func:`pci_walk_dev`.
+ */
+static int pciinv_walk(struct phb *phb, struct pci_device *pd, void *data __unused)
+{
+	struct ipmi_msg *msg;
+	struct pciinv_packet pack = {
+		.version = PCI_INV_VERSION,
+		.session = pci_inv_session_id
+	};
+
+	/* PCI device filter: Skip non-EP devices */
+	if (pci_has_cap(pd, PCI_CFG_CAP_ID_EXP, false)) {
+		if (pd->dev_type != PCIE_TYPE_ENDPOINT)
+			return OPAL_SUCCESS;
+	}
+	else if (pd->is_bridge)
+		return OPAL_SUCCESS;
+
+	/* Fill the PCI device inventory description */
+	pack.device.domain_num = cpu_to_be16(phb->opal_id & 0xffff);
+	pack.device.bus_num = (pd->bdfn >> 8) & 0xff;
+	pack.device.device_num = (pd->bdfn >> 3) & 0x1f;
+	pack.device.func_num = pd->bdfn & 0x7;
+	pack.device.vendor_id = cpu_to_be16(PCI_VENDOR_ID(pd->vdid));
+	pack.device.device_id = cpu_to_be16(PCI_DEVICE_ID(pd->vdid));
+	pack.device.class_code = cpu_to_be32(pd->class & 0xffffff);
+	pci_cfg_read8(phb, pd->bdfn, PCI_CFG_REV_ID, &pack.device.revision);
+
+	msg = ipmi_mkmsg_simple(IPMI_PCI_INV, &pack, sizeof(pack));
+	if (!msg)
+		return OPAL_HARDWARE;
+
+	/* Synchronously send the IPMI message, the queue is too small */
+	ipmi_queue_msg_sync(msg);
+
+	return OPAL_SUCCESS;
+}
+
+static void vesnin_pci_probe_complete(void)
+{
+	struct phb *phb;
+
+	check_all_slot_table();
+
+	/* Send PCI device list to the BMC */
+	++pci_inv_session_id;
+	for_each_phb(phb) {
+		pci_walk_dev(phb, NULL, &pciinv_walk, NULL);
+	}
+}
+
 static bool vesnin_probe(void)
 {
 	if (!dt_node_is_compatible(dt_root, "YADRO,vesnin"))
@@ -251,7 +350,7 @@  DECLARE_PLATFORM(vesnin) = {
 	.probe			= vesnin_probe,
 	.init			= astbmc_init,
 	.pci_get_slot_info	= slot_table_get_slot_info,
-	.pci_probe_complete	= check_all_slot_table,
+	.pci_probe_complete	= vesnin_pci_probe_complete,
 	.external_irq		= astbmc_ext_irq_serirq_cpld,
 	.cec_power_down		= astbmc_ipmi_power_down,
 	.cec_reboot		= astbmc_ipmi_reboot,