summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/drivers/ipmi/Makefile.inc1
-rw-r--r--src/drivers/ipmi/ocp/Kconfig14
-rw-r--r--src/drivers/ipmi/ocp/Makefile.inc1
-rw-r--r--src/drivers/ipmi/ocp/ipmi_ocp.h132
-rw-r--r--src/drivers/ipmi/ocp/ipmi_sel.c81
5 files changed, 229 insertions, 0 deletions
diff --git a/src/drivers/ipmi/Makefile.inc b/src/drivers/ipmi/Makefile.inc
index 85f3dde437..28ff78c085 100644
--- a/src/drivers/ipmi/Makefile.inc
+++ b/src/drivers/ipmi/Makefile.inc
@@ -8,3 +8,4 @@ romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_if.c
romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_ops_premem.c
romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_kcs.c
romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_ops.c
+smm-$(CONFIG_SOC_RAS_BMC_SEL) += ipmi_kcs.c
diff --git a/src/drivers/ipmi/ocp/Kconfig b/src/drivers/ipmi/ocp/Kconfig
index 7899e69588..c048e20efb 100644
--- a/src/drivers/ipmi/ocp/Kconfig
+++ b/src/drivers/ipmi/ocp/Kconfig
@@ -3,3 +3,17 @@ config IPMI_OCP
default n
help
This implements OCP specific IPMI command
+
+config IPMI_BMC_SEL
+ bool
+ depends on IPMI_OCP
+ default n
+ help
+ This implements OCP specific command to generate/send SEL record
+
+config RAS_SEL_VENDOR_ID
+ hex
+ depends on IPMI_BMC_SEL
+ default 0xff
+ help
+ This option specifies a vendor ID for BMC SEL messages
diff --git a/src/drivers/ipmi/ocp/Makefile.inc b/src/drivers/ipmi/ocp/Makefile.inc
index c77ee4a964..fc56364170 100644
--- a/src/drivers/ipmi/ocp/Makefile.inc
+++ b/src/drivers/ipmi/ocp/Makefile.inc
@@ -1,4 +1,5 @@
ramstage-$(CONFIG_IPMI_OCP) += ipmi_ocp.c
ifeq ($(CONFIG_IPMI_OCP),y)
romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_ocp_romstage.c
+smm-$(CONFIG_IPMI_BMC_SEL) += ipmi_sel.c
endif
diff --git a/src/drivers/ipmi/ocp/ipmi_ocp.h b/src/drivers/ipmi/ocp/ipmi_ocp.h
index bd15aa3ef5..c479e520a4 100644
--- a/src/drivers/ipmi/ocp/ipmi_ocp.h
+++ b/src/drivers/ipmi/ocp/ipmi_ocp.h
@@ -4,6 +4,7 @@
#define __IPMI_OCP_H
#include <commonlib/bsd/cb_err.h>
+#include <device/pci_type.h>
#define IPMI_NETFN_OEM 0x30
#define IPMI_OEM_SET_PPIN 0x77
@@ -33,6 +34,137 @@ struct boot_order {
uint8_t boot_dev4;
} __packed;
+struct pci_dev_fn {
+ u32 func:15;
+ u32 dev:5;
+ u32 bus:12;
+};
+
+struct ipmi_pci_dev_fn {
+ uint16_t func:3;
+ uint16_t dev:5;
+ uint16_t bus:8;
+};
+
+struct ipmi_sel_pcie_dev_err {
+ uint16_t record_id;
+ uint8_t record_type;
+ uint8_t general_info;
+ uint32_t timestamp;
+ uint16_t aux_loc;
+ struct ipmi_pci_dev_fn bdf;
+ uint16_t primary_err_count;
+ uint8_t secondary_id;
+ uint8_t primary_id;
+} __packed;
+
+struct iio_port_location {
+ uint8_t socket:4;
+ uint8_t sled:2;
+ uint8_t rsvd:2;
+};
+
+struct ipmi_sel_iio_err {
+ uint16_t record_id;
+ uint8_t record_type;
+ uint8_t general_info;
+ uint32_t timestamp;
+ struct iio_port_location loc;
+ uint8_t iio_stack_num;
+ uint8_t rsvd0;
+ uint8_t rsvd1;
+ uint8_t iio_err_id;
+ uint8_t rsvd2;
+ uint8_t rsvd3;
+ uint8_t rsvd4;
+} __packed;
+
+enum fail_type {
+ PCIE_DPC_EVNT = 0,
+ PCIE_LER_EVNT = 1,
+ PCIE_LRTRN_REC = 2,
+ PCIE_CRC_RETRY = 3,
+ PCIE_CRPT_DATA_CONTMT = 4,
+ PCIE_ECRC_EVNT = 5,
+};
+
+struct ipmi_sel_pcie_dev_fail {
+ uint16_t record_id;
+ uint8_t record_type;
+ uint8_t general_info;
+ uint32_t timestamp;
+ enum fail_type type;
+ uint8_t rsvd0;
+ uint16_t failure_details1; /* if DPC, DPC sts reg of root port */
+ uint16_t failure_details2; /* if DPC, source ID of root port */
+ uint8_t rsvd1;
+ uint8_t rsvd2;
+} __packed;
+
+#define SEL_RECORD_ID 0x01
+#define SEL_PCIE_DEV_ERR 0x20
+#define SEL_PCIE_IIO_ERR 0x23
+#define SEL_PCIE_DEV_FAIL_ID 0x29
+
+/* PCIE Unified Messages */
+
+/* PCIE CE */
+#define RECEIVER_ERROR 0x00
+#define BAD_TLP 0x01
+#define BAD_DLLP 0x02
+#define REPLAY_TIME_OUT 0x03
+#define REPLAY_NUMBER_ROLLOVER 0x04
+#define ADVISORY_NONFATAL_ERROR_STATUS 0x05
+#define CORRECTED_INTERNAL_ERROR_STATUS 0x06
+#define HEADER_LOG_OVERFLOW_STATUS 0x07
+
+/* PCIE UCE */
+#define PCI_EXPRESS_DATA_LINK_PROTOCOL_ERROR 0x20
+#define SURPRISE_DOWN_ERROR 0x21
+#define RECEIVED_PCI_EXPRESS_POISONED_TLP 0x22
+#define PCI_EXPRESS_FLOW_CONTROL_PROTOCOL_ERROR 0x23
+#define COMPLETION_TIMEOUT_ON_NP_TRANSACTIONS_OUTSTANDING_ON_PCI_EXPRESS_DMI 0x24
+#define RECEIVED_A_REQUEST_FROM_A_DOWNSTREAM_COMPONENT_THAT_IS_TO_BE_COMPLETER_ABORTED 0x25
+#define RECEIVED_PCI_EXPRESS_UNEXPECTED_COMPLETION 0x26
+#define PCI_EXPRESS_RECEIVER_OVERFLOW 0x27
+#define PCI_EXPRESS_MALFORMED_TLP 0x28
+#define ECRC_ERROR_STATUS 0x29
+#define RECEIVED_A_REQUEST_FROM_A_DOWNSTREAM_COMPONENT_THAT_IS_UNSUPPORTED 0x2A
+#define ACS_VIOLATION 0x2B
+#define UNCORRECTABLE_INTERNAL_ERROR_STATUS 0x2C
+#define MC_BLOCKED_TLP 0x2D
+#define ATOMICOP_EGRESS_BLOCKED_STATUS 0x2E
+#define TLP_PREFIX_BLOCKED_ERROR_STATUS 0x2F
+#define POISONED_TLP_EGRESS_BLOCKED 0x30
+
+/* Root error status (from PCIE spec) */
+#define RECEIVED_ERR_COR_MESSAGE_FROM_DOWNSTREAM_DEVICE 0x50
+#define RECEIVED_ERR_NONFATAL_MESSAGE_FROM_DOWNSTREAM_DEVICE 0x51
+#define RECEIVED_ERR_FATAL_MESSAGE_FROM_DOWNSTREAM_DEVICE 0x52
+
+/* DPC Trigger Reason */
+#define DPC_WAS_TRIGGERED_DUE_TO_AN_UNMASKED_UNCORRECTABLE_ERROR 0x53
+#define DPC_WAS_TRIGGERED_DUE_TO_RECEIVING_AN_ERR_NONFATAL 0x54
+#define DPC_WAS_TRIGGERED_DUE_TO_RECEIVING_AN_ERR_FATAL 0x55
+#define DPC_WAS_TRIGGERED_DUE_TO_RP_PIO_ERROR 0x56
+#define DPC_WAS_TRIGGERED_DUE_TO_THE_DPC_SOFTWARE_TRIGGER_BIT 0x57
+
+#define OUTBOUND_SWITCH_FIFO_DATA_PARITY_ERROR_DETECTED 0x80
+#define SENT_A_PCI_EXPRESS_COMPLETER_ABORT 0x81
+#define SENT_A_PCI_EXPRESS_UNSUPPORTED_REQUEST 0x82
+#define RECEIVED_COMPLETER_ABORT 0x83
+#define RECEIVED_UNSUPPORTED_REQUEST_COMPLETION_STATUS_FROM_DOWNSTREAM_DEVICE 0x84
+#define RECEIVED_MSI_WRITES_GREATER_THAN_A_DWORD 0x85
+#define OUTBOUND_POISONED_DATA 0x86
+#define PERR_NON_AER 0xA0
+#define SERR_NON_AER 0xA1
+
enum cb_err ipmi_set_post_start(const int port);
enum cb_err ipmi_set_cmos_clear(void);
+
+void ipmi_send_to_bmc(unsigned char *data, size_t size);
+void ipmi_send_sel_pcie_dev_err(pci_devfn_t bdf, uint16_t prmry_cnt, uint8_t sec_id,
+ uint8_t prmry_id);
+void ipmi_send_sel_pcie_dev_fail(uint16_t sts_reg, uint16_t src_id, enum fail_type code);
+void ipmi_send_sel_iio_err(uint8_t iio_stack_num, uint8_t err_id);
#endif
diff --git a/src/drivers/ipmi/ocp/ipmi_sel.c b/src/drivers/ipmi/ocp/ipmi_sel.c
new file mode 100644
index 0000000000..55c0c3e3d9
--- /dev/null
+++ b/src/drivers/ipmi/ocp/ipmi_sel.c
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <console/console.h>
+#include <drivers/ipmi/ipmi_if.h>
+#include <string.h>
+
+#include "ipmi_ocp.h"
+
+static int ipmi_add_sel_entry(int port, unsigned char *data, int size)
+{
+ return ipmi_message(port, IPMI_NETFN_STORAGE, 0, IPMI_ADD_SEL_ENTRY, data, size,
+ NULL, 0);
+}
+
+void ipmi_send_to_bmc(unsigned char *data, size_t size)
+{
+ if (CONFIG(IPMI_KCS)) {
+ _Static_assert(CONFIG_BMC_KCS_BASE != 0,
+ "\tBMC_ERROR: Unable to send record: Port #:0\n");
+
+ ipmi_add_sel_entry(CONFIG_BMC_KCS_BASE, data, size);
+ }
+}
+
+void ipmi_send_sel_iio_err(uint8_t iio_stack_num, uint8_t err_id)
+{
+ struct ipmi_sel_iio_err ubslp = {
+ .record_id = SEL_RECORD_ID,
+ .record_type = CONFIG_RAS_SEL_VENDOR_ID,
+ .general_info = SEL_PCIE_IIO_ERR,
+ .iio_stack_num = iio_stack_num,
+ .iio_err_id = err_id,
+ };
+
+ ipmi_send_to_bmc((unsigned char *)&ubslp, sizeof(ubslp));
+ printk(BIOS_DEBUG, "\tsending PCIE IIO device error record to BMC\n");
+ printk(BIOS_DEBUG, "\tstack # = %x\n", ubslp.iio_stack_num);
+}
+
+void ipmi_send_sel_pcie_dev_err(pci_devfn_t bdf, uint16_t prmry_cnt, uint8_t sec_id,
+ uint8_t prmry_id)
+{
+ struct pci_dev_fn *inbdf = (struct pci_dev_fn *)&bdf;
+ struct ipmi_sel_pcie_dev_err ubslp = {
+ .record_id = SEL_RECORD_ID,
+ .record_type = CONFIG_RAS_SEL_VENDOR_ID,
+ .general_info = SEL_PCIE_DEV_ERR,
+ .timestamp = 0, /* BMC will apply timestamp */
+ .aux_loc = 0,
+ .bdf.bus = inbdf->bus,
+ .bdf.dev = inbdf->dev,
+ .bdf.func = inbdf->func >> 12,
+ .primary_err_count = prmry_cnt,
+ .primary_id = prmry_id,
+ .secondary_id = sec_id,
+ };
+
+ ipmi_send_to_bmc((unsigned char *)&ubslp, sizeof(ubslp));
+ printk(BIOS_DEBUG, "\tsending PCIE device error record to BMC\n");
+ printk(BIOS_DEBUG, "\tbdf = %x:%x:%x\n", ubslp.bdf.bus, ubslp.bdf.dev, ubslp.bdf.func);
+ printk(BIOS_DEBUG, "\tubslp.primary_id = %x\n", ubslp.primary_id);
+ printk(BIOS_DEBUG, "\tsecondary_id = %x\n", ubslp.secondary_id);
+}
+
+void ipmi_send_sel_pcie_dev_fail(uint16_t sts_reg, uint16_t src_id, enum fail_type code)
+{
+ struct ipmi_sel_pcie_dev_fail ubslp = {
+ .record_id = SEL_RECORD_ID,
+ .record_type = CONFIG_RAS_SEL_VENDOR_ID,
+ .general_info = SEL_PCIE_DEV_FAIL_ID,
+ .timestamp = 0, /* BMC will apply timestamp */
+ .type = code,
+ .failure_details1 = sts_reg,
+ .failure_details2 = src_id,
+ };
+
+ ipmi_send_to_bmc((unsigned char *)&ubslp, sizeof(ubslp));
+ printk(BIOS_DEBUG, "\tsending PCI device FAILURE record to BMC\n");
+ printk(BIOS_DEBUG, "\terror_code = %x, src_id = %x\n", ubslp.type,
+ ubslp.failure_details2);
+}