arm64: arch_timer: Allow erratum matching with ACPI OEM information
authorMarc Zyngier <marc.zyngier@arm.com>
Tue, 21 Feb 2017 14:37:30 +0000 (14:37 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Fri, 7 Apr 2017 10:22:10 +0000 (11:22 +0100)
Just as we're able to identify a broken platform using some DT
information, let's enable a way to spot the offenders with ACPI.

The difference is that we can only match on some OEM info instead
of implementation-specific properties. So in order to avoid the
insane multiplication of errata structures, we allow an array
of OEM descriptions to be attached to an erratum structure.

Acked-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: dann frazier <dann.frazier@canonical.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm64/include/asm/arch_timer.h
drivers/clocksource/arm_arch_timer.c

index 6bd1a9a1573a5df34def4aedbdb3f029c2795a9c..74d08e44a651b9e58de7d8a6075f6101083f5262 100644 (file)
@@ -41,6 +41,7 @@ extern struct static_key_false arch_timer_read_ool_enabled;
 enum arch_timer_erratum_match_type {
        ate_match_dt,
        ate_match_local_cap_id,
+       ate_match_acpi_oem_info,
 };
 
 struct clock_event_device;
index 8459d19a84f5ac1dc1319105e6bd2bb199be2c8e..887f6d00a71d897cbc7c489eba82d6e8bb0b6be5 100644 (file)
@@ -190,6 +190,12 @@ static struct cyclecounter cyclecounter __ro_after_init = {
        .mask   = CLOCKSOURCE_MASK(56),
 };
 
+struct ate_acpi_oem_info {
+       char oem_id[ACPI_OEM_ID_SIZE + 1];
+       char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
+       u32 oem_revision;
+};
+
 #ifdef CONFIG_FSL_ERRATUM_A008585
 /*
  * The number of retries is an arbitrary value well beyond the highest number
@@ -371,6 +377,28 @@ bool arch_timer_check_local_cap_erratum(const struct arch_timer_erratum_workarou
        return this_cpu_has_cap((uintptr_t)wa->id);
 }
 
+
+static
+bool arch_timer_check_acpi_oem_erratum(const struct arch_timer_erratum_workaround *wa,
+                                      const void *arg)
+{
+       static const struct ate_acpi_oem_info empty_oem_info = {};
+       const struct ate_acpi_oem_info *info = wa->id;
+       const struct acpi_table_header *table = arg;
+
+       /* Iterate over the ACPI OEM info array, looking for a match */
+       while (memcmp(info, &empty_oem_info, sizeof(*info))) {
+               if (!memcmp(info->oem_id, table->oem_id, ACPI_OEM_ID_SIZE) &&
+                   !memcmp(info->oem_table_id, table->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) &&
+                   info->oem_revision == table->oem_revision)
+                       return true;
+
+               info++;
+       }
+
+       return false;
+}
+
 static const struct arch_timer_erratum_workaround *
 arch_timer_iterate_errata(enum arch_timer_erratum_match_type type,
                          ate_match_fn_t match_fn,
@@ -431,6 +459,9 @@ static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type t
                match_fn = arch_timer_check_local_cap_erratum;
                local = true;
                break;
+       case ate_match_acpi_oem_info:
+               match_fn = arch_timer_check_acpi_oem_erratum;
+               break;
        default:
                WARN_ON(1);
                return;
@@ -1277,6 +1308,9 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
        /* Always-on capability */
        arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
 
+       /* Check for globally applicable workarounds */
+       arch_timer_check_ool_workaround(ate_match_acpi_oem_info, table);
+
        arch_timer_init();
        return 0;
 }