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:
parent
ae81497cb6
commit
2bb5ecbcd6
|
@ -77,6 +77,9 @@ enum cxl_memory_mode {
|
||||||
/* Socket 1 core disable bitmask */
|
/* Socket 1 core disable bitmask */
|
||||||
#define CORE_DIS_BITMSK1 "core_disable_bitmask1"
|
#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 */
|
/* 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,
|
int get_int_from_vpd_range(const char *const key, const int fallback, const int min,
|
||||||
const int max);
|
const int max);
|
||||||
|
|
|
@ -4,3 +4,12 @@ config OCP_VPD
|
||||||
depends on VPD
|
depends on VPD
|
||||||
help
|
help
|
||||||
It implements functions that get common VPD variables for OCP projects.
|
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.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
romstage-$(CONFIG_OCP_VPD) += vpd_util.c
|
romstage-$(CONFIG_OCP_VPD) += vpd_util.c
|
||||||
ramstage-$(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)
|
ifeq ($(CONFIG_VPD),y)
|
||||||
all-$(CONFIG_CONSOLE_OVERRIDE_LOGLEVEL) += loglevel_vpd.c
|
all-$(CONFIG_CONSOLE_OVERRIDE_LOGLEVEL) += loglevel_vpd.c
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue