summaryrefslogtreecommitdiff
path: root/arch/arm64/kernel/idreg-override.c
diff options
context:
space:
mode:
authorMarc Zyngier <maz@kernel.org>2022-06-30 19:04:56 +0300
committerWill Deacon <will@kernel.org>2022-07-01 17:22:51 +0300
commit6b7ec18c09763f72dcd3d87e194860f9e9db8968 (patch)
tree7a4d1980a525a38cca8431ff0219e4aebe2c99b2 /arch/arm64/kernel/idreg-override.c
parentfa8aa59ae6454b7a6a670acb2097e7800992cba1 (diff)
downloadlinux-6b7ec18c09763f72dcd3d87e194860f9e9db8968.tar.xz
arm64: Allow the idreg override to deal with variable field width
Currently, the override mechanism can only deal with 4bit fields, which is the most common case. However, we now have a bunch of ID registers that have more diverse field widths, such as ID_AA64SMFR0_EL1, which has fields that are a single bit wide. Add the support for variable width, and a macro that encodes a feature width of 4 for all existing override. No functional change. Signed-off-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20220630160500.1536744-6-maz@kernel.org Signed-off-by: Will Deacon <will@kernel.org>
Diffstat (limited to 'arch/arm64/kernel/idreg-override.c')
-rw-r--r--arch/arm64/kernel/idreg-override.c28
1 files changed, 16 insertions, 12 deletions
diff --git a/arch/arm64/kernel/idreg-override.c b/arch/arm64/kernel/idreg-override.c
index 03185bc46d69..1e5f3dba3f01 100644
--- a/arch/arm64/kernel/idreg-override.c
+++ b/arch/arm64/kernel/idreg-override.c
@@ -27,10 +27,13 @@ struct ftr_set_desc {
struct {
char name[FTR_DESC_FIELD_LEN];
u8 shift;
+ u8 width;
bool (*filter)(u64 val);
} fields[];
};
+#define FIELD(n, s, f) { .name = n, .shift = s, .width = 4, .filter = f }
+
static bool __init mmfr1_vh_filter(u64 val)
{
/*
@@ -47,7 +50,7 @@ static const struct ftr_set_desc mmfr1 __initconst = {
.name = "id_aa64mmfr1",
.override = &id_aa64mmfr1_override,
.fields = {
- { "vh", ID_AA64MMFR1_VHE_SHIFT, mmfr1_vh_filter },
+ FIELD("vh", ID_AA64MMFR1_VHE_SHIFT, mmfr1_vh_filter),
{}
},
};
@@ -56,8 +59,8 @@ static const struct ftr_set_desc pfr1 __initconst = {
.name = "id_aa64pfr1",
.override = &id_aa64pfr1_override,
.fields = {
- { "bt", ID_AA64PFR1_BT_SHIFT },
- { "mte", ID_AA64PFR1_MTE_SHIFT},
+ FIELD("bt", ID_AA64PFR1_BT_SHIFT, NULL),
+ FIELD("mte", ID_AA64PFR1_MTE_SHIFT, NULL),
{}
},
};
@@ -66,10 +69,10 @@ static const struct ftr_set_desc isar1 __initconst = {
.name = "id_aa64isar1",
.override = &id_aa64isar1_override,
.fields = {
- { "gpi", ID_AA64ISAR1_GPI_SHIFT },
- { "gpa", ID_AA64ISAR1_GPA_SHIFT },
- { "api", ID_AA64ISAR1_API_SHIFT },
- { "apa", ID_AA64ISAR1_APA_SHIFT },
+ FIELD("gpi", ID_AA64ISAR1_GPI_SHIFT, NULL),
+ FIELD("gpa", ID_AA64ISAR1_GPA_SHIFT, NULL),
+ FIELD("api", ID_AA64ISAR1_API_SHIFT, NULL),
+ FIELD("apa", ID_AA64ISAR1_APA_SHIFT, NULL),
{}
},
};
@@ -78,8 +81,8 @@ static const struct ftr_set_desc isar2 __initconst = {
.name = "id_aa64isar2",
.override = &id_aa64isar2_override,
.fields = {
- { "gpa3", ID_AA64ISAR2_GPA3_SHIFT },
- { "apa3", ID_AA64ISAR2_APA3_SHIFT },
+ FIELD("gpa3", ID_AA64ISAR2_GPA3_SHIFT, NULL),
+ FIELD("apa3", ID_AA64ISAR2_APA3_SHIFT, NULL),
{}
},
};
@@ -92,7 +95,7 @@ static const struct ftr_set_desc kaslr __initconst = {
.override = &kaslr_feature_override,
#endif
.fields = {
- { "disabled", 0 },
+ FIELD("disabled", 0, NULL),
{}
},
};
@@ -147,7 +150,8 @@ static void __init match_options(const char *cmdline)
for (f = 0; strlen(regs[i]->fields[f].name); f++) {
u64 shift = regs[i]->fields[f].shift;
- u64 mask = 0xfUL << shift;
+ u64 width = regs[i]->fields[f].width ?: 4;
+ u64 mask = GENMASK_ULL(shift + width - 1, shift);
u64 v;
if (find_field(cmdline, regs[i], f, &v))
@@ -155,7 +159,7 @@ static void __init match_options(const char *cmdline)
/*
* If an override gets filtered out, advertise
- * it by setting the value to 0xf, but
+ * it by setting the value to the all-ones while
* clearing the mask... Yes, this is fragile.
*/
if (regs[i]->fields[f].filter &&