drivers/option/cfr: Add optional override table for default values
Add a mechanism for mainboards to override default values of CFR
objects defined in SoC or common code without duplicating object
metadata.
Mainboards can now declare a simple override table mapping option
names to new default values:
const struct cfr_default_override mb_cfr_overrides[] = {
CFR_OVERRIDE_BOOL("s0ix_enable", false),
CFR_OVERRIDE_ENUM("pciexp_aspm", ASPM_DISABLE),
CFR_OVERRIDE_END
};
The CFR backend checks this table when writing options and uses the
override value if one exists. All other metadata (name, help text,
enum values, flags) comes from the original object.
Change-Id: Ifb3da90d605f2799bf0207ff58d69bee3415ccc2
Signed-off-by: Matt DeVillier <matt.devillier@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/89933
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
ea84a29a27
commit
786ac14d48
3 changed files with 134 additions and 2 deletions
|
|
@ -23,6 +23,50 @@ In both cases you have to add `C` structs in ramstage to describe the
|
|||
option and group them together into a form. CFR objects should reside
|
||||
on the heap as they can be modified to match the current boot flow.
|
||||
|
||||
### Overriding default values
|
||||
|
||||
Mainboards often want to reuse CFR objects defined in SoC or common code
|
||||
but with different default values. Rather than duplicating the entire object
|
||||
definition, mainboards can declare an override table that maps option names
|
||||
to new default values.
|
||||
|
||||
**Example:** Override defaults for several SoC-defined options:
|
||||
|
||||
```
|
||||
#include <drivers/option/cfr_frontend.h>
|
||||
#include <intelblocks/pcie_rp.h>
|
||||
|
||||
const struct cfr_default_override mb_cfr_overrides[] = {
|
||||
CFR_OVERRIDE_BOOL("s0ix_enable", false),
|
||||
CFR_OVERRIDE_ENUM("pciexp_aspm", ASPM_DISABLE),
|
||||
CFR_OVERRIDE_NUMBER("igd_dvmt", 64),
|
||||
CFR_OVERRIDE_END
|
||||
};
|
||||
|
||||
void mb_cfr_setup_menu(struct lb_cfr *cfr_root)
|
||||
{
|
||||
/* Register overrides before writing menu */
|
||||
cfr_register_overrides(mb_cfr_overrides);
|
||||
cfr_write_setup_menu(cfr_root, sm_root);
|
||||
}
|
||||
```
|
||||
|
||||
When the CFR system writes the setup menu, it will check the override table
|
||||
for each option and use the override value if one exists. All other object
|
||||
metadata (name, help text, enum values, flags) comes from the original object.
|
||||
|
||||
The following helper macros are available to populate the table:
|
||||
|
||||
- `CFR_OVERRIDE_BOOL(name, value)`
|
||||
- `CFR_OVERRIDE_ENUM(name, value)`
|
||||
- `CFR_OVERRIDE_NUMBER(name, value)`
|
||||
- `CFR_OVERRIDE_VARCHAR(name, value)`
|
||||
- `CFR_OVERRIDE_END`
|
||||
|
||||
Each macro encodes the override type, and the CFR backend validates that the
|
||||
override type matches the original object's type. If the types do not match,
|
||||
the override is ignored and a warning is printed.
|
||||
|
||||
### Updating CFR options
|
||||
|
||||
The CFR options should be updated before tables are written.
|
||||
|
|
@ -143,4 +187,4 @@ static const __cfr_form struct sm_obj_form southbridge = {
|
|||
NULL
|
||||
},
|
||||
};
|
||||
```
|
||||
```
|
||||
|
|
|
|||
|
|
@ -10,6 +10,27 @@
|
|||
#include <string.h>
|
||||
#include <types.h>
|
||||
|
||||
/* Global override table registered by mainboard */
|
||||
static const struct cfr_default_override *mb_overrides = NULL;
|
||||
|
||||
void cfr_register_overrides(const struct cfr_default_override *overrides)
|
||||
{
|
||||
mb_overrides = overrides;
|
||||
}
|
||||
|
||||
/* Look up override for a given option name */
|
||||
static const struct cfr_default_override *find_override(const char *opt_name)
|
||||
{
|
||||
if (!mb_overrides || !opt_name)
|
||||
return NULL;
|
||||
|
||||
for (const struct cfr_default_override *ovr = mb_overrides; ovr->opt_name; ovr++) {
|
||||
if (strcmp(ovr->opt_name, opt_name) == 0)
|
||||
return ovr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint32_t cfr_record_size(const char *startp, const char *endp)
|
||||
{
|
||||
const uintptr_t start = (uintptr_t)startp;
|
||||
|
|
@ -111,6 +132,17 @@ static uint32_t write_numeric_option(char *current, uint32_t tag, const uint64_t
|
|||
struct lb_cfr_numeric_option *option = (struct lb_cfr_numeric_option *)current;
|
||||
size_t len;
|
||||
|
||||
/* Check for mainboard override of default value */
|
||||
const struct cfr_default_override *ovr = find_override(opt_name);
|
||||
if (ovr) {
|
||||
if (ovr->kind != tag)
|
||||
printk(BIOS_WARNING, "CFR: override for option '%s' has mismatched type; skipping.\n", opt_name);
|
||||
else if (tag == CFR_TAG_OPTION_BOOL)
|
||||
default_value = ovr->bool_value;
|
||||
else
|
||||
default_value = ovr->uint_value;
|
||||
}
|
||||
|
||||
option->tag = tag;
|
||||
option->object_id = object_id;
|
||||
option->dependency_id = dep_id;
|
||||
|
|
@ -187,6 +219,16 @@ static uint32_t sm_write_opt_varchar(char *current, const struct sm_obj_varchar
|
|||
{
|
||||
struct lb_cfr_varchar_option *option = (struct lb_cfr_varchar_option *)current;
|
||||
size_t len;
|
||||
const char *default_value = sm_varchar->default_value;
|
||||
|
||||
/* Check for mainboard override of default value */
|
||||
const struct cfr_default_override *ovr = find_override(sm_varchar->opt_name);
|
||||
if (ovr) {
|
||||
if (ovr->kind == SM_OBJ_VARCHAR)
|
||||
default_value = ovr->str_value;
|
||||
else
|
||||
printk(BIOS_WARNING, "CFR: override for option '%s' has mismatched type (not varchar); skipping.\n", sm_varchar->opt_name);
|
||||
}
|
||||
|
||||
option->tag = CFR_TAG_OPTION_VARCHAR;
|
||||
option->object_id = object_id;
|
||||
|
|
@ -197,7 +239,7 @@ static uint32_t sm_write_opt_varchar(char *current, const struct sm_obj_varchar
|
|||
option->size = sizeof(*option);
|
||||
|
||||
current += option->size;
|
||||
current += sm_write_string_default_value(current, sm_varchar->default_value);
|
||||
current += sm_write_string_default_value(current, default_value);
|
||||
len = sm_write_opt_name(current, sm_varchar->opt_name);
|
||||
if (!len)
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <commonlib/coreboot_tables.h>
|
||||
#include <commonlib/cfr.h>
|
||||
#include <string.h>
|
||||
#include <types.h>
|
||||
|
||||
/* Front-end */
|
||||
|
|
@ -119,6 +120,51 @@ struct sm_object {
|
|||
.dep_values = ((const uint32_t[]) { __VA_ARGS__ }), \
|
||||
.num_dep_values = sizeof((uint32_t[]) { __VA_ARGS__ }) / sizeof(uint32_t)
|
||||
|
||||
/*
|
||||
* CFR Default Value Override System
|
||||
*
|
||||
* Mainboards can override default values of CFR objects defined in SoC/common
|
||||
* code by declaring an override table. This avoids duplicating object metadata.
|
||||
*
|
||||
* Usage:
|
||||
* 1. Declare overrides in mainboard cfr.c:
|
||||
*
|
||||
* const struct cfr_default_override mb_cfr_overrides[] = {
|
||||
* CFR_OVERRIDE_BOOL("s0ix_enable", false),
|
||||
* CFR_OVERRIDE_ENUM("pciexp_aspm", ASPM_DISABLE),
|
||||
* CFR_OVERRIDE_END
|
||||
* };
|
||||
*
|
||||
* 2. Register the table in mb_cfr_setup_menu():
|
||||
*
|
||||
* void mb_cfr_setup_menu(struct lb_cfr *cfr_root)
|
||||
* {
|
||||
* cfr_register_overrides(mb_cfr_overrides);
|
||||
* cfr_write_setup_menu(cfr_root, sm_root);
|
||||
* }
|
||||
*/
|
||||
|
||||
/* Override table entry */
|
||||
struct cfr_default_override {
|
||||
const char *opt_name;
|
||||
enum sm_object_kind kind;
|
||||
union {
|
||||
bool bool_value;
|
||||
uint32_t uint_value;
|
||||
const char *str_value;
|
||||
};
|
||||
};
|
||||
|
||||
/* Helper macros for override table entries */
|
||||
#define CFR_OVERRIDE_BOOL(name, val) { .opt_name = (name), .kind = SM_OBJ_BOOL, .bool_value = (val) }
|
||||
#define CFR_OVERRIDE_ENUM(name, val) { .opt_name = (name), .kind = SM_OBJ_ENUM, .uint_value = (val) }
|
||||
#define CFR_OVERRIDE_NUMBER(name, val) { .opt_name = (name), .kind = SM_OBJ_NUMBER, .uint_value = (val) }
|
||||
#define CFR_OVERRIDE_VARCHAR(name, val) { .opt_name = (name), .kind = SM_OBJ_VARCHAR, .str_value = (val) }
|
||||
#define CFR_OVERRIDE_END { .opt_name = NULL }
|
||||
|
||||
/* Register mainboard override table (call before cfr_write_setup_menu) */
|
||||
void cfr_register_overrides(const struct cfr_default_override *overrides);
|
||||
|
||||
void cfr_write_setup_menu(struct lb_cfr *cfr_root, struct sm_obj_form *sm_root[]);
|
||||
|
||||
#if ENV_RAMSTAGE
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue