drivers/ocp/vpd: Overwrite Linux payload's kernel command via VPD

Add a new Kconfig LINUXPAYLOAD_CMDLINE_VPD_OVERWRITE that can overwrite
Linux payload's kernel command line from VPD. Currently only overwrite
Linux kernel command line 'loglevel' via VPD key 'kernel_log_level'.

TESTED=On OCP Delta Lake, with kernel_log_level set to 0, warm reboot
time can see about 10 seconds improvement comparing to kernel log level
7.

Change-Id: Idf06c7ab9958c940fc3b23d560bb9dade991a6da
Signed-off-by: Johnny Lin <johnny_lin@wiwynn.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/75510
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
This commit is contained in:
Johnny Lin 2023-05-29 16:23:02 +08:00 committed by Felix Held
parent ae81497cb6
commit 2bb5ecbcd6
4 changed files with 69 additions and 0 deletions

View File

@ -77,6 +77,9 @@ enum cxl_memory_mode {
/* Socket 1 core disable bitmask */
#define CORE_DIS_BITMSK1 "core_disable_bitmask1"
/* Linux payload kernel log level */
#define KERNEL_LOG_LEVEL "kernel_log_level"
/* Get VPD key with provided fallback value and min/max ranges */
int get_int_from_vpd_range(const char *const key, const int fallback, const int min,
const int max);

View File

@ -4,3 +4,12 @@ config OCP_VPD
depends on VPD
help
It implements functions that get common VPD variables for OCP projects.
config LINUXPAYLOAD_CMDLINE_VPD_OVERWRITE
bool
default n
depends on VPD
help
Overwrite Linux payload's kernel command line by using VPD. Currently only
overwrite the value of kernel command line 'loglevel'. The Linux kernel command
line data is detected in the last segment loaded in memory and overwritten.

View File

@ -1,5 +1,6 @@
romstage-$(CONFIG_OCP_VPD) += vpd_util.c
ramstage-$(CONFIG_OCP_VPD) += vpd_util.c
ramstage-$(CONFIG_LINUXPAYLOAD_CMDLINE_VPD_OVERWRITE) += vpd_cmdline.c
ifeq ($(CONFIG_VPD),y)
all-$(CONFIG_CONSOLE_OVERRIDE_LOGLEVEL) += loglevel_vpd.c
endif

View File

@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <drivers/vpd/vpd.h>
#include <drivers/ocp/include/vpd.h>
#include <string.h>
#include <program_loading.h>
#define CMDLINE_LOGLVL_STR "loglevel="
static void overwrite_kernel_loglevel(uintptr_t start)
{
int val;
if (!vpd_get_int(KERNEL_LOG_LEVEL, VPD_RW_THEN_RO, &val)) {
printk(BIOS_DEBUG, "%s: not able to get VPD %s\n", __func__, KERNEL_LOG_LEVEL);
return;
}
printk(BIOS_DEBUG, "%s: VPD %s, got %d\n", __func__, KERNEL_LOG_LEVEL, val);
if (val < 0 || val > 7) {
printk(BIOS_INFO, "Invalid VPD for Linux kernel log level\n");
return;
}
int loglevel;
char *loc = strstr((const char *)start, CMDLINE_LOGLVL_STR);
if (!loc) {
printk(BIOS_INFO, "%s is not found from LINUX_COMMAND_LINE\n",
CMDLINE_LOGLVL_STR);
return;
}
char *loc_bkup;
loc += strlen(CMDLINE_LOGLVL_STR);
loc_bkup = loc;
loglevel = skip_atoi(&loc);
printk(BIOS_DEBUG, "Original kernel log level is %d\n", loglevel);
/* Unlikely but don't overwrite with such an unexpected case. */
if (loglevel < 0 || loglevel > 7) {
printk(BIOS_DEBUG, "Invalid kernel log level, must be from 0 to 7.\n");
return;
}
char c = '0' + val;
printk(BIOS_INFO, "Overwrite kernel log level with %c from VPD.\n", c);
memcpy(loc_bkup, &c, 1);
}
void platform_segment_loaded(uintptr_t start, size_t size, int flags)
{
/* CONFIG_LINUX_COMMAND_LINE is in the final segment. */
if (flags != SEG_FINAL)
return;
overwrite_kernel_loglevel(start);
}