diff --git a/sys/arm64/arm64/cpu_feat.c b/sys/arm64/arm64/cpu_feat.c index 986d5079e980..6aec0fdf8a78 100644 --- a/sys/arm64/arm64/cpu_feat.c +++ b/sys/arm64/arm64/cpu_feat.c @@ -1,142 +1,143 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2024 Arm Ltd * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include SYSCTL_NODE(_hw, OID_AUTO, feat, CTLFLAG_RD, 0, "CPU features/errata"); /* TODO: Make this a list if we ever grow a callback other than smccc_errata */ static cpu_feat_errata_check_fn cpu_feat_check_cb = NULL; void enable_cpu_feat(uint32_t stage) { char tunable[32]; struct cpu_feat **featp, *feat; uint32_t midr; u_int errata_count, *errata_list; cpu_feat_errata errata_status; cpu_feat_en check_status; bool val; MPASS((stage & ~CPU_FEAT_STAGE_MASK) == 0); midr = get_midr(); SET_FOREACH(featp, cpu_feat_set) { feat = *featp; /* Run the enablement code at the correct stage of boot */ if ((feat->feat_flags & CPU_FEAT_STAGE_MASK) != stage) continue; /* If the feature is system wide run on a single CPU */ if ((feat->feat_flags & CPU_FEAT_SCOPE_MASK)==CPU_FEAT_SYSTEM && PCPU_GET(cpuid) != 0) continue; - if (feat->feat_check != NULL) - continue; - - check_status = feat->feat_check(feat, midr); + if (feat->feat_check != NULL) { + check_status = feat->feat_check(feat, midr); + } else { + check_status = FEAT_DEFAULT_ENABLE; + } /* Ignore features that are not present */ if (check_status == FEAT_ALWAYS_DISABLE) continue; snprintf(tunable, sizeof(tunable), "hw.feat.%s", feat->feat_name); if (TUNABLE_BOOL_FETCH(tunable, &val)) { /* Is the feature disabled by the tunable? */ if (!val) continue; /* If enabled by the tunable then enable it */ } else if (check_status == FEAT_DEFAULT_DISABLE) { /* No tunable set and disabled by default */ continue; } /* * Check if the feature has any errata that may need a * workaround applied (or it is to install the workaround for * known errata. */ errata_status = ERRATA_NONE; errata_list = NULL; errata_count = 0; if (feat->feat_has_errata != NULL) { if (feat->feat_has_errata(feat, midr, &errata_list, &errata_count)) { /* Assume we are affected */ errata_status = ERRATA_AFFECTED; } } if (errata_status == ERRATA_AFFECTED && cpu_feat_check_cb != NULL) { for (int i = 0; i < errata_count; i++) { cpu_feat_errata new_status; /* Check if affected by this erratum */ new_status = cpu_feat_check_cb(feat, errata_list[i]); if (new_status != ERRATA_UNKNOWN) { errata_status = new_status; errata_list = &errata_list[i]; errata_count = 1; break; } } } /* Shouldn't be possible */ MPASS(errata_status != ERRATA_UNKNOWN); if (feat->feat_enable(feat, errata_status, errata_list, errata_count)) feat->feat_enabled = true; } } static void enable_cpu_feat_after_dev(void *dummy __unused) { MPASS(PCPU_GET(cpuid) == 0); enable_cpu_feat(CPU_FEAT_AFTER_DEV); } SYSINIT(enable_cpu_feat_after_dev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, enable_cpu_feat_after_dev, NULL); void cpu_feat_register_errata_check(cpu_feat_errata_check_fn cb) { MPASS(cpu_feat_check_cb == NULL); cpu_feat_check_cb = cb; }