aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/Makefile.inc2
-rw-r--r--core/init.c4
-rw-r--r--core/opal-dump.c144
-rw-r--r--include/opal-dump.h4
4 files changed, 153 insertions, 1 deletions
diff --git a/core/Makefile.inc b/core/Makefile.inc
index f8bfa7d..fddff50 100644
--- a/core/Makefile.inc
+++ b/core/Makefile.inc
@@ -12,7 +12,7 @@ CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o pool.o errorlog.o
CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o ipmi-opal.o
CORE_OBJS += flash-subpartition.o bitmap.o buddy.o pci-quirk.o powercap.o psr.o
CORE_OBJS += pci-dt-slot.o direct-controls.o cpufeatures.o
-CORE_OBJS += flash-firmware-versions.o
+CORE_OBJS += flash-firmware-versions.o opal-dump.o
ifeq ($(SKIBOOT_GCOV),1)
CORE_OBJS += gcov-profiling.o
diff --git a/core/init.c b/core/init.c
index 25d827f..e9509e7 100644
--- a/core/init.c
+++ b/core/init.c
@@ -44,6 +44,7 @@
#include <sbe-p9.h>
#include <debug_descriptor.h>
#include <occ.h>
+#include <opal-dump.h>
enum proc_gen proc_gen;
unsigned int pcie_max_link_speed;
@@ -1255,6 +1256,9 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
/* Create the LPC bus interrupt-map on P9 */
lpc_finalize_interrupts();
+ /* init opal dump */
+ opal_mpipl_init();
+
/* Add the list of interrupts going to OPAL */
add_opal_interrupts();
diff --git a/core/opal-dump.c b/core/opal-dump.c
new file mode 100644
index 0000000..3d61f50
--- /dev/null
+++ b/core/opal-dump.c
@@ -0,0 +1,144 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define pr_fmt(fmt) "DUMP: " fmt
+
+#include <device.h>
+#include <mem-map.h>
+#include <mem_region.h>
+#include <mem_region-malloc.h>
+#include <opal.h>
+#include <opal-dump.h>
+#include <opal-internal.h>
+#include <skiboot.h>
+
+#include <ccan/endian/endian.h>
+
+#include "hdata/spira.h"
+
+/* Actual address of MDST and MDDT table */
+#define MDST_TABLE_BASE (SKIBOOT_BASE + MDST_TABLE_OFF)
+#define MDDT_TABLE_BASE (SKIBOOT_BASE + MDDT_TABLE_OFF)
+
+static struct spira_ntuple *ntuple_mdst;
+static struct spira_ntuple *ntuple_mddt;
+static struct spira_ntuple *ntuple_mdrt;
+
+static int opal_mpipl_add_entry(u8 region, u64 src, u64 dest, u64 size)
+{
+ int i, max_cnt;
+ struct mdst_table *mdst;
+ struct mddt_table *mddt;
+
+ max_cnt = MDST_TABLE_SIZE / sizeof(struct mdst_table);
+ if (ntuple_mdst->act_cnt >= max_cnt) {
+ prlog(PR_DEBUG, "MDST table is full\n");
+ return OPAL_RESOURCE;
+ }
+
+ max_cnt = MDDT_TABLE_SIZE / sizeof(struct mddt_table);
+ if (ntuple_mdst->act_cnt >= max_cnt) {
+ prlog(PR_DEBUG, "MDDT table is full\n");
+ return OPAL_RESOURCE;
+ }
+
+ /* Use relocated memory address */
+ mdst = (void *)(MDST_TABLE_BASE);
+ mddt = (void *)(MDDT_TABLE_BASE);
+
+ /* Check for duplicate entry */
+ for (i = 0; i < ntuple_mdst->act_cnt; i++) {
+ if (mdst->addr == (src | HRMOR_BIT)) {
+ prlog(PR_DEBUG,
+ "Duplicate source address : 0x%llx", src);
+ return OPAL_PARAMETER;
+ }
+ mdst++;
+ }
+ for (i = 0; i < ntuple_mddt->act_cnt; i++) {
+ if (mddt->addr == (dest | HRMOR_BIT)) {
+ prlog(PR_DEBUG,
+ "Duplicate destination address : 0x%llx", dest);
+ return OPAL_PARAMETER;
+ }
+ mddt++;
+ }
+
+ /* Add OPAL source address to MDST entry */
+ mdst->addr = src | HRMOR_BIT;
+ mdst->data_region = region;
+ mdst->size = size;
+ ntuple_mdst->act_cnt++;
+
+ /* Add OPAL destination address to MDDT entry */
+ mddt->addr = dest | HRMOR_BIT;
+ mddt->data_region = region;
+ mddt->size = size;
+ ntuple_mddt->act_cnt++;
+
+ prlog(PR_TRACE, "Added new entry. src : 0x%llx, dest : 0x%llx,"
+ " size : 0x%llx\n", src, dest, size);
+ return OPAL_SUCCESS;
+}
+
+/* Register for OPAL dump. */
+static void opal_mpipl_register(void)
+{
+ u64 opal_dest, opal_size;
+
+ /* Get OPAL runtime size */
+ if (!dt_find_property(opal_node, "opal-runtime-size")) {
+ prlog(PR_DEBUG, "Could not get OPAL runtime size\n");
+ return;
+ }
+ opal_size = dt_prop_get_u64(opal_node, "opal-runtime-size");
+ if (!opal_size) {
+ prlog(PR_DEBUG, "OPAL runtime size is zero\n");
+ return;
+ }
+
+ /* Calculate and reserve OPAL dump destination memory */
+ opal_dest = SKIBOOT_BASE + opal_size;
+ mem_reserve_fw("ibm,firmware-dump", opal_dest, opal_size);
+
+ /* Add OPAL reservation detail to MDST/MDDT table */
+ opal_mpipl_add_entry(DUMP_REGION_OPAL_MEMORY,
+ SKIBOOT_BASE, opal_dest, opal_size);
+}
+
+void opal_mpipl_init(void)
+{
+ void *mdst_base = (void *)MDST_TABLE_BASE;
+ void *mddt_base = (void *)MDDT_TABLE_BASE;
+ struct dt_node *dump_node;
+
+ dump_node = dt_find_by_path(opal_node, "dump");
+ if (!dump_node)
+ return;
+
+ /* Get MDST and MDDT ntuple from SPIRAH */
+ ntuple_mdst = &(spirah.ntuples.mdump_src);
+ ntuple_mddt = &(spirah.ntuples.mdump_dst);
+ ntuple_mdrt = &(spirah.ntuples.mdump_res);
+
+ /* Clear MDST and MDDT table */
+ memset(mdst_base, 0, MDST_TABLE_SIZE);
+ ntuple_mdst->act_cnt = 0;
+ memset(mddt_base, 0, MDDT_TABLE_SIZE);
+ ntuple_mddt->act_cnt = 0;
+
+ opal_mpipl_register();
+}
diff --git a/include/opal-dump.h b/include/opal-dump.h
index e7c0ad5..c05e810 100644
--- a/include/opal-dump.h
+++ b/include/opal-dump.h
@@ -19,6 +19,7 @@
#define DUMP_REGION_CONSOLE 0x01
#define DUMP_REGION_HBRT_LOG 0x02
+#define DUMP_REGION_OPAL_MEMORY 0x03
/* Mainstore memory to be captured by FSP SYSDUMP */
#define DUMP_TYPE_SYSDUMP 0xF5
@@ -106,4 +107,7 @@ struct proc_reg_data {
uint64_t reg_val;
} __packed;
+/* init opal dump */
+extern void opal_mpipl_init(void);
+
#endif /* __OPAL_DUMP_H */