diff options
-rw-r--r-- | core/Makefile.inc | 2 | ||||
-rw-r--r-- | core/init.c | 4 | ||||
-rw-r--r-- | core/opal-dump.c | 144 | ||||
-rw-r--r-- | include/opal-dump.h | 4 |
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 */ |