[PATCH 02/30] acpi: re-orgainise HPET tests #1
Colin King
colin.king at canonical.com
Thu Jun 18 08:49:14 UTC 2015
From: Colin Ian King <colin.king at canonical.com>
Remove HPET test from acpitables. Move hpet/hpet_check to acpi/hpet, the
old name and location came from the old Intel firmware tests and is just
a legacy name. It makes more sense to be in the src/acpi directory nowadays.
Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
src/acpi/acpitables/acpitables.c | 18 --
src/acpi/hpet/hpet.c | 443 +++++++++++++++++++++++++++++++++++++++
src/hpet/hpet_check/hpet_check.c | 443 ---------------------------------------
3 files changed, 443 insertions(+), 461 deletions(-)
create mode 100644 src/acpi/hpet/hpet.c
delete mode 100644 src/hpet/hpet_check/hpet_check.c
diff --git a/src/acpi/acpitables/acpitables.c b/src/acpi/acpitables/acpitables.c
index 63c3605..c0b4895 100644
--- a/src/acpi/acpitables/acpitables.c
+++ b/src/acpi/acpitables/acpitables.c
@@ -25,23 +25,6 @@
#include "fwts.h"
-static void acpi_table_check_hpet(fwts_framework *fw, fwts_acpi_table_info *table)
-{
- fwts_acpi_table_hpet *hpet = (fwts_acpi_table_hpet*)table->data;
-
- if (hpet->base_address.address == 0)
- fwts_failed(fw, LOG_LEVEL_MEDIUM, "HPETBaseZero", "HPET base is 0x000000000000, which is invalid.");
-
- if (((hpet->event_timer_block_id >> 16) & 0xffff) == 0) {
- fwts_failed(fw, LOG_LEVEL_MEDIUM, "HPETVendorIdZero", "HPET PCI Vendor ID is 0x0000, which is invalid.");
- fwts_advice(fw, "The HPET specification (http://www.intel.com/hardwaredesign/hpetspec_1.pdf) describes "
- "the HPET table in section 3.2.4 'The ACPI 2.0 HPET Description Table (HPET)'. The top "
- "16 bits of the Event Timer Block ID specify the Vendor ID and this should not be zero. "
- "This won't affect the kernel behaviour, but should be fixed as it is an undefined ID value.");
- }
-
-}
-
static void acpi_table_check_fadt_firmware_control(fwts_framework *fw, fwts_acpi_table_fadt *fadt)
{
if (fadt->firmware_control == 0) {
@@ -695,7 +678,6 @@ static acpi_table_check_table check_table[] = {
{ "APIC", acpi_table_check_madt },
{ "FACP", acpi_table_check_fadt },
{ "GTDT", acpi_table_check_gtdt },
- { "HPET", acpi_table_check_hpet },
{ "MCFG", acpi_table_check_mcfg },
{ "RSDT", acpi_table_check_rsdt },
{ "RSDP", acpi_table_check_rsdp },
diff --git a/src/acpi/hpet/hpet.c b/src/acpi/hpet/hpet.c
new file mode 100644
index 0000000..6ccd3b0
--- /dev/null
+++ b/src/acpi/hpet/hpet.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2006, Intel Corporation
+ * Copyright (C) 2010-2015 Canonical
+ *
+ * This code was originally part of the Linux-ready Firmware Developer Kit
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#include <string.h>
+#include <inttypes.h>
+
+#include "fwts.h"
+
+#ifdef FWTS_ARCH_INTEL
+
+static fwts_list *klog;
+
+#define HPET_REG_SIZE (0x400)
+#define MAX_CLK_PERIOD (100000000)
+
+static uint64_t hpet_base_p = 0;
+static void *hpet_base_v = 0;
+
+static void hpet_parse_check_base(fwts_framework *fw,
+ const char *table, fwts_list_link *item)
+{
+ char *val;
+
+ if ((val = strstr(fwts_text_list_text(item), "0x")) != NULL) {
+ uint64_t address_base;
+ char *idx = index(val, ',');
+ if (idx)
+ *idx = '\0';
+
+ address_base = strtoul(val, NULL, 0x10);
+
+ if (hpet_base_p != 0) {
+ if (hpet_base_p != address_base)
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "HPETBaseMismatch",
+ "Mismatched HPET base between %s (%" PRIx64 ") "
+ "and the kernel (0x%" PRIx64 ").",
+ table,
+ hpet_base_p,
+ address_base);
+ else
+ fwts_passed(fw,
+ "HPET base matches that between %s and "
+ "the kernel (0x%" PRIx64 ").",
+ table,
+ hpet_base_p);
+ }
+ }
+}
+
+static void hpet_parse_device_hpet(fwts_framework *fw,
+ const char *table, fwts_list_link *item)
+{
+ for (;item != NULL; item = item->next) {
+ const char *str = fwts_text_list_text(item);
+
+ if ((strstr(str, "Name") != NULL) &&
+ (strstr(str, "ResourceTemplate") != NULL)) {
+ fwts_list_link *tmp_item = item->next;
+ for (; tmp_item != NULL; tmp_item = tmp_item->next) {
+ const char *tmpstr = fwts_text_list_text(tmp_item);
+
+ if (strstr(tmpstr, "Memory32Fixed") != NULL) {
+ /* Next line contains base address */
+ if (tmp_item->next != NULL) {
+ hpet_parse_check_base(fw, table, tmp_item->next);
+ return;
+ }
+ } else if (strstr(tmpstr, "DWordMemory") != NULL) {
+ if (tmp_item->next != NULL && /* Granularity */
+ tmp_item->next->next != NULL) { /* Base address */
+ hpet_parse_check_base(fw, table, tmp_item->next->next);
+ return;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * check_hpet_base_dsdt()
+ * used to parse the DSDT for HPET base info
+ */
+static void hpet_check_base_acpi_table(fwts_framework *fw,
+ const char *table, const int which)
+{
+ fwts_list *output;
+ fwts_list_link *item;
+
+ if (fwts_iasl_disassemble(fw, table, which, &output) != FWTS_OK) {
+ fwts_iasl_deinit();
+ return;
+ }
+ if (output == NULL)
+ return;
+
+ fwts_list_foreach(item, output)
+ if (strstr(fwts_text_list_text(item), "Device (HPET)") != NULL)
+ hpet_parse_device_hpet(fw, table, item);
+
+ fwts_text_list_free(output);
+}
+
+
+static int hpet_check_init(fwts_framework *fw)
+{
+ if ((klog = fwts_klog_read()) == NULL) {
+ fwts_log_error(fw, "Cannot read kernel log.");
+ return FWTS_ERROR;
+ }
+ return FWTS_OK;
+}
+
+static int hpet_check_deinit(fwts_framework *fw)
+{
+ FWTS_UNUSED(fw);
+
+ if (klog)
+ fwts_text_list_free(klog);
+
+ return FWTS_OK;
+}
+
+static int hpet_check_test1(fwts_framework *fw)
+{
+ fwts_list_link *item;
+
+ if (klog == NULL)
+ return FWTS_ERROR;
+
+ fwts_log_info(fw,
+ "This test checks the HPET PCI BAR for each timer block "
+ "in the timer. The base address is passed by the firmware "
+ "via an ACPI table. IRQ routing and initialization is also "
+ "verified by the test.");
+
+ fwts_list_foreach(item, klog) {
+ char *text = fwts_text_list_text(item);
+ /* Old format */
+ if (strstr(text, "ACPI: HPET id:") != NULL) {
+ char *str = strstr(text, "base: ");
+ if (str) {
+ hpet_base_p = strtoul(str+6, NULL, 0x10);
+ fwts_passed(fw,
+ "Found HPET base 0x%" PRIx64 " in kernel log.",
+ hpet_base_p);
+ break;
+ }
+ }
+ /* New format */
+ /* [ 0.277934] hpet0: at MMIO 0xfed00000, IRQs 2, 8, 0 */
+ if ((strstr(text, "hpet") != NULL) &&
+ (strstr(text, "IRQs") != NULL)) {
+ char *str = strstr(text, "at MMIO ");
+ if (str) {
+ hpet_base_p = strtoul(str+8, NULL, 0x10);
+ fwts_passed(fw,
+ "Found HPET base 0x%" PRIx64 " in kernel log.",
+ hpet_base_p);
+ break;
+ }
+ }
+ }
+
+ if (hpet_base_p == 0) {
+ fwts_log_info(fw, "No base address found for HPET in the kernel log.");
+ return FWTS_ERROR;
+ }
+
+ return FWTS_OK;
+}
+
+/*
+ * Sanity check HPET table, see:
+ * http://www.intel.co.uk/content/www/uk/en/software-developers/software-developers-hpet-spec-1-0a.html
+ */
+static int hpet_check_test2(fwts_framework *fw)
+{
+ fwts_acpi_table_info *table;
+ fwts_acpi_table_hpet *hpet;
+ bool passed = true;
+ char *page_prot;
+
+ if (fwts_acpi_find_table(fw, "HPET", 0, &table) != FWTS_OK) {
+ fwts_log_error(fw, "Cannot read ACPI table HPET.");
+ return FWTS_ERROR;
+ }
+
+ if (table == NULL) {
+ fwts_log_error(fw, "ACPI table HPET does not exist!");
+ return FWTS_ERROR;
+ }
+
+ if (table->length < sizeof(fwts_acpi_table_hpet)) {
+ fwts_failed(fw, LOG_LEVEL_HIGH, "HPETAcpiTableTooSmall",
+ "HPET ACPI table is %zd bytes long which is smaller "
+ "than the expected size of %zd bytes.",
+ table->length, sizeof(fwts_acpi_table_hpet));
+ return FWTS_ERROR;
+ }
+
+ hpet = (fwts_acpi_table_hpet *)table->data;
+
+ if (hpet->base_address.address == 0) {
+ fwts_failed(fw, LOG_LEVEL_HIGH, "HPETAcpiBaseAddressNull",
+ "HPET base address in ACPI HPET table is null.");
+ passed = false;
+ }
+
+ /*
+ * If we've already figured out the HPET base address then
+ * sanity check it against HPET. This should never happen.
+ */
+ if ((hpet_base_p != 0) &&
+ (hpet_base_p != hpet->base_address.address)) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM,
+ "HPETAcpiBaseAddressDifferFromKernel",
+ "HPET base address in ACPI HPET table "
+ "is 0x%" PRIx64 " which is different from "
+ "the kernel HPET base address of "
+ "0x%" PRIx64 ".",
+ hpet->base_address.address, hpet_base_p);
+ passed = false;
+ }
+
+#if 0
+ /*
+ * The Intel spec states that the address space ID
+ * must be memory or I/O space.
+ */
+ if ((hpet->base_address.address_space_id != 0) &&
+ (hpet->base_address.address_space_id != 1)) {
+ fwts_failed(fw, LOG_LEVEL_HIGH,
+ "HPETAcpiBaseAddressSpaceId",
+ "The HPET base address space ID was 0x%" PRIx8
+ ", was expecting 0 (System Memory) or "
+ "1 (System I/O).",
+ hpet->base_address.address_space_id);
+ passed = false;
+ }
+#endif
+ /*
+ * The kernel expects the HPET address space ID
+ * to be memory.
+ */
+ if (hpet->base_address.address_space_id != 0) {
+ fwts_failed(fw, LOG_LEVEL_HIGH,
+ "HPETAcpiBaseAddressSpaceIdNotMemory",
+ "The HPET base address space ID was 0x%" PRIx8
+ ", however, the Kernel expects the HPET address "
+ "space ID to be 0 (System Memory). The kernel "
+ "will not parse this and the HPET configuration "
+ "will be ignored.",
+ hpet->base_address.address_space_id);
+ }
+
+ /*
+ * Some broken firmware advertises the HPET at
+ * 0xfed0000000000000 instead of 0xfed00000. The kernel
+ * detects this and fixes it, but even so, it is wrong
+ * so lets check for this.
+ */
+ if ((hpet->base_address.address >> 32) != 0) {
+ fwts_failed(fw, LOG_LEVEL_CRITICAL,
+ "HPETAcpiBaseAddressBogus",
+ "The HPET base address is bogus: 0x%" PRIx64 ".",
+ hpet->base_address.address);
+ fwts_advice(fw,
+ "Bogus HPET base address can be worked around "
+ "by using the kernel parameter 'hpet=force' if "
+ "the base addess is 0xfed0000000000000. "
+ "This will make the kernel shift the address "
+ "down 32 bits to 0xfed00000.");
+ passed = false;
+ }
+
+ /*
+ * We don't need to check for GAS address space widths etc
+ * since the kernel does not care and the spec doesn't
+ * stipulate these need to be sane
+ */
+
+ /*
+ * Dump out HPET
+ */
+ fwts_log_info_verbatum(fw, "Hardware ID of Event Block:");
+ fwts_log_info_verbatum(fw, " PCI Vendor ID : 0x%" PRIx32,
+ (hpet->event_timer_block_id >> 16) & 0xffff);
+ fwts_log_info_verbatum(fw, " Legacy IRQ Routing Capable : %" PRIu32,
+ (hpet->event_timer_block_id >> 15) & 1);
+ fwts_log_info_verbatum(fw, " COUNT_SIZE_CAP counter size: %" PRIu32,
+ (hpet->event_timer_block_id >> 13) & 1);
+ fwts_log_info_verbatum(fw, " Number of comparitors : %" PRIu32,
+ (hpet->event_timer_block_id >> 8) & 0x1f);
+ fwts_log_info_verbatum(fw, " Hardwre Revision ID : 0x%" PRIx8,
+ hpet->event_timer_block_id & 0xff);
+
+ fwts_log_info_verbatum(fw, "Lower 32 bit base Address : 0x%" PRIx64,
+ hpet->base_address.address);
+ fwts_log_info_verbatum(fw, " Address Space ID : 0x%" PRIx8,
+ hpet->base_address.address_space_id);
+ fwts_log_info_verbatum(fw, " Register Bit Width : 0x%" PRIx8,
+ hpet->base_address.register_bit_width);
+ fwts_log_info_verbatum(fw, " Register Bit Offset : 0x%" PRIx8,
+ hpet->base_address.register_bit_offset);
+ fwts_log_info_verbatum(fw, " Address Width : 0x%" PRIx8,
+ hpet->base_address.access_width);
+ fwts_log_info_verbatum(fw, "HPET sequence number : 0x%" PRIx8,
+ hpet->hpet_number);
+ fwts_log_info_verbatum(fw, "Minimum clock tick : 0x%" PRIx16,
+ hpet->main_counter_minimum);
+
+ switch (hpet->page_prot_and_oem_attribute & 0xf) {
+ case 0:
+ page_prot = "No guaranteed protection";
+ break;
+ case 1:
+ page_prot = "4K page protected";
+ break;
+ case 2:
+ page_prot = "64K page protected";
+ break;
+ default:
+ page_prot = "Reserved";
+ break;
+ }
+ fwts_log_info_verbatum(fw, "Page Protection : 0x%" PRIx8 " (%s)",
+ hpet->page_prot_and_oem_attribute & 0xf,
+ page_prot);
+ fwts_log_info_verbatum(fw, "OEM attributes : 0x%" PRIx8,
+ (hpet->page_prot_and_oem_attribute >> 4) & 0xf);
+
+ if (passed)
+ fwts_passed(fw, "HPET looks sane.");
+
+ return FWTS_OK;
+}
+
+static int hpet_check_test3(fwts_framework *fw)
+{
+ int i;
+
+ if (hpet_base_p == 0) {
+ fwts_log_info(fw, "Test skipped because HPET address was not found.");
+ return FWTS_SKIP;
+ }
+
+ if (fwts_iasl_init(fw) != FWTS_OK) {
+ fwts_warning(fw, "Failure to initialise iasl, aborting.");
+ fwts_iasl_deinit();
+ return FWTS_ERROR;
+ }
+
+ hpet_check_base_acpi_table(fw, "DSDT", 0);
+
+ for (i = 0; i < 11; i++)
+ hpet_check_base_acpi_table(fw, "SSDT", i);
+
+ fwts_iasl_deinit();
+
+ return FWTS_OK;
+}
+
+
+static int hpet_check_test4(fwts_framework *fw)
+{
+ uint64_t hpet_id;
+ uint32_t vendor_id;
+ uint32_t clk_period;
+
+ if (hpet_base_p == 0) {
+ fwts_log_info(fw, "Test skipped because HPET address was not found.");
+ return FWTS_SKIP;
+ }
+
+ hpet_base_v = fwts_mmap(hpet_base_p, HPET_REG_SIZE);
+ if (hpet_base_v == NULL) {
+ fwts_log_error(fw, "Cannot mmap to /dev/mem.");
+ return FWTS_ERROR;
+ }
+
+ hpet_id = *(uint64_t*) hpet_base_v;
+ vendor_id = (hpet_id & 0xffff0000) >> 16;
+
+ if (vendor_id == 0xffff)
+ fwts_failed(fw, LOG_LEVEL_MEDIUM, "HPETVendorId",
+ "Invalid Vendor ID: %04" PRIx32 " - this should be configured.",
+ vendor_id);
+ else
+ fwts_passed(fw, "Vendor ID looks sane: 0x%04" PRIx32 ".", vendor_id);
+
+ clk_period = hpet_id >> 32;
+ if ((clk_period > MAX_CLK_PERIOD) || (clk_period == 0))
+ fwts_failed(fw, LOG_LEVEL_MEDIUM, "HPETClockPeriod",
+ "Invalid clock period %" PRIu32 ", must be non-zero and "
+ "less than 10^8.", clk_period);
+ else
+ fwts_passed(fw, "Valid clock period %" PRIu32 ".", clk_period);
+
+ (void)fwts_munmap(hpet_base_v, HPET_REG_SIZE);
+
+ return FWTS_OK;
+}
+
+
+static fwts_framework_minor_test hpet_check_tests[] = {
+ { hpet_check_test1, "Test HPET base in kernel log." },
+ { hpet_check_test2, "Test HPET base in HPET table."},
+ { hpet_check_test3, "Test HPET base in DSDT and/or SSDT."},
+ { hpet_check_test4, "Test HPET configuration." },
+ { NULL, NULL }
+};
+
+static fwts_framework_ops hpet_check_ops = {
+ .description = "HPET configuration tests.",
+ .init = hpet_check_init,
+ .deinit = hpet_check_deinit,
+ .minor_tests = hpet_check_tests
+};
+
+FWTS_REGISTER("hpet_check", &hpet_check_ops, FWTS_TEST_ANYTIME,
+ FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV | FWTS_FLAG_TEST_ACPI)
+
+#endif
diff --git a/src/hpet/hpet_check/hpet_check.c b/src/hpet/hpet_check/hpet_check.c
deleted file mode 100644
index 6ccd3b0..0000000
--- a/src/hpet/hpet_check/hpet_check.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Copyright (C) 2006, Intel Corporation
- * Copyright (C) 2010-2015 Canonical
- *
- * This code was originally part of the Linux-ready Firmware Developer Kit
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-#include <string.h>
-#include <inttypes.h>
-
-#include "fwts.h"
-
-#ifdef FWTS_ARCH_INTEL
-
-static fwts_list *klog;
-
-#define HPET_REG_SIZE (0x400)
-#define MAX_CLK_PERIOD (100000000)
-
-static uint64_t hpet_base_p = 0;
-static void *hpet_base_v = 0;
-
-static void hpet_parse_check_base(fwts_framework *fw,
- const char *table, fwts_list_link *item)
-{
- char *val;
-
- if ((val = strstr(fwts_text_list_text(item), "0x")) != NULL) {
- uint64_t address_base;
- char *idx = index(val, ',');
- if (idx)
- *idx = '\0';
-
- address_base = strtoul(val, NULL, 0x10);
-
- if (hpet_base_p != 0) {
- if (hpet_base_p != address_base)
- fwts_failed(fw, LOG_LEVEL_MEDIUM,
- "HPETBaseMismatch",
- "Mismatched HPET base between %s (%" PRIx64 ") "
- "and the kernel (0x%" PRIx64 ").",
- table,
- hpet_base_p,
- address_base);
- else
- fwts_passed(fw,
- "HPET base matches that between %s and "
- "the kernel (0x%" PRIx64 ").",
- table,
- hpet_base_p);
- }
- }
-}
-
-static void hpet_parse_device_hpet(fwts_framework *fw,
- const char *table, fwts_list_link *item)
-{
- for (;item != NULL; item = item->next) {
- const char *str = fwts_text_list_text(item);
-
- if ((strstr(str, "Name") != NULL) &&
- (strstr(str, "ResourceTemplate") != NULL)) {
- fwts_list_link *tmp_item = item->next;
- for (; tmp_item != NULL; tmp_item = tmp_item->next) {
- const char *tmpstr = fwts_text_list_text(tmp_item);
-
- if (strstr(tmpstr, "Memory32Fixed") != NULL) {
- /* Next line contains base address */
- if (tmp_item->next != NULL) {
- hpet_parse_check_base(fw, table, tmp_item->next);
- return;
- }
- } else if (strstr(tmpstr, "DWordMemory") != NULL) {
- if (tmp_item->next != NULL && /* Granularity */
- tmp_item->next->next != NULL) { /* Base address */
- hpet_parse_check_base(fw, table, tmp_item->next->next);
- return;
- }
- }
- }
- }
- }
-}
-
-/*
- * check_hpet_base_dsdt()
- * used to parse the DSDT for HPET base info
- */
-static void hpet_check_base_acpi_table(fwts_framework *fw,
- const char *table, const int which)
-{
- fwts_list *output;
- fwts_list_link *item;
-
- if (fwts_iasl_disassemble(fw, table, which, &output) != FWTS_OK) {
- fwts_iasl_deinit();
- return;
- }
- if (output == NULL)
- return;
-
- fwts_list_foreach(item, output)
- if (strstr(fwts_text_list_text(item), "Device (HPET)") != NULL)
- hpet_parse_device_hpet(fw, table, item);
-
- fwts_text_list_free(output);
-}
-
-
-static int hpet_check_init(fwts_framework *fw)
-{
- if ((klog = fwts_klog_read()) == NULL) {
- fwts_log_error(fw, "Cannot read kernel log.");
- return FWTS_ERROR;
- }
- return FWTS_OK;
-}
-
-static int hpet_check_deinit(fwts_framework *fw)
-{
- FWTS_UNUSED(fw);
-
- if (klog)
- fwts_text_list_free(klog);
-
- return FWTS_OK;
-}
-
-static int hpet_check_test1(fwts_framework *fw)
-{
- fwts_list_link *item;
-
- if (klog == NULL)
- return FWTS_ERROR;
-
- fwts_log_info(fw,
- "This test checks the HPET PCI BAR for each timer block "
- "in the timer. The base address is passed by the firmware "
- "via an ACPI table. IRQ routing and initialization is also "
- "verified by the test.");
-
- fwts_list_foreach(item, klog) {
- char *text = fwts_text_list_text(item);
- /* Old format */
- if (strstr(text, "ACPI: HPET id:") != NULL) {
- char *str = strstr(text, "base: ");
- if (str) {
- hpet_base_p = strtoul(str+6, NULL, 0x10);
- fwts_passed(fw,
- "Found HPET base 0x%" PRIx64 " in kernel log.",
- hpet_base_p);
- break;
- }
- }
- /* New format */
- /* [ 0.277934] hpet0: at MMIO 0xfed00000, IRQs 2, 8, 0 */
- if ((strstr(text, "hpet") != NULL) &&
- (strstr(text, "IRQs") != NULL)) {
- char *str = strstr(text, "at MMIO ");
- if (str) {
- hpet_base_p = strtoul(str+8, NULL, 0x10);
- fwts_passed(fw,
- "Found HPET base 0x%" PRIx64 " in kernel log.",
- hpet_base_p);
- break;
- }
- }
- }
-
- if (hpet_base_p == 0) {
- fwts_log_info(fw, "No base address found for HPET in the kernel log.");
- return FWTS_ERROR;
- }
-
- return FWTS_OK;
-}
-
-/*
- * Sanity check HPET table, see:
- * http://www.intel.co.uk/content/www/uk/en/software-developers/software-developers-hpet-spec-1-0a.html
- */
-static int hpet_check_test2(fwts_framework *fw)
-{
- fwts_acpi_table_info *table;
- fwts_acpi_table_hpet *hpet;
- bool passed = true;
- char *page_prot;
-
- if (fwts_acpi_find_table(fw, "HPET", 0, &table) != FWTS_OK) {
- fwts_log_error(fw, "Cannot read ACPI table HPET.");
- return FWTS_ERROR;
- }
-
- if (table == NULL) {
- fwts_log_error(fw, "ACPI table HPET does not exist!");
- return FWTS_ERROR;
- }
-
- if (table->length < sizeof(fwts_acpi_table_hpet)) {
- fwts_failed(fw, LOG_LEVEL_HIGH, "HPETAcpiTableTooSmall",
- "HPET ACPI table is %zd bytes long which is smaller "
- "than the expected size of %zd bytes.",
- table->length, sizeof(fwts_acpi_table_hpet));
- return FWTS_ERROR;
- }
-
- hpet = (fwts_acpi_table_hpet *)table->data;
-
- if (hpet->base_address.address == 0) {
- fwts_failed(fw, LOG_LEVEL_HIGH, "HPETAcpiBaseAddressNull",
- "HPET base address in ACPI HPET table is null.");
- passed = false;
- }
-
- /*
- * If we've already figured out the HPET base address then
- * sanity check it against HPET. This should never happen.
- */
- if ((hpet_base_p != 0) &&
- (hpet_base_p != hpet->base_address.address)) {
- fwts_failed(fw, LOG_LEVEL_MEDIUM,
- "HPETAcpiBaseAddressDifferFromKernel",
- "HPET base address in ACPI HPET table "
- "is 0x%" PRIx64 " which is different from "
- "the kernel HPET base address of "
- "0x%" PRIx64 ".",
- hpet->base_address.address, hpet_base_p);
- passed = false;
- }
-
-#if 0
- /*
- * The Intel spec states that the address space ID
- * must be memory or I/O space.
- */
- if ((hpet->base_address.address_space_id != 0) &&
- (hpet->base_address.address_space_id != 1)) {
- fwts_failed(fw, LOG_LEVEL_HIGH,
- "HPETAcpiBaseAddressSpaceId",
- "The HPET base address space ID was 0x%" PRIx8
- ", was expecting 0 (System Memory) or "
- "1 (System I/O).",
- hpet->base_address.address_space_id);
- passed = false;
- }
-#endif
- /*
- * The kernel expects the HPET address space ID
- * to be memory.
- */
- if (hpet->base_address.address_space_id != 0) {
- fwts_failed(fw, LOG_LEVEL_HIGH,
- "HPETAcpiBaseAddressSpaceIdNotMemory",
- "The HPET base address space ID was 0x%" PRIx8
- ", however, the Kernel expects the HPET address "
- "space ID to be 0 (System Memory). The kernel "
- "will not parse this and the HPET configuration "
- "will be ignored.",
- hpet->base_address.address_space_id);
- }
-
- /*
- * Some broken firmware advertises the HPET at
- * 0xfed0000000000000 instead of 0xfed00000. The kernel
- * detects this and fixes it, but even so, it is wrong
- * so lets check for this.
- */
- if ((hpet->base_address.address >> 32) != 0) {
- fwts_failed(fw, LOG_LEVEL_CRITICAL,
- "HPETAcpiBaseAddressBogus",
- "The HPET base address is bogus: 0x%" PRIx64 ".",
- hpet->base_address.address);
- fwts_advice(fw,
- "Bogus HPET base address can be worked around "
- "by using the kernel parameter 'hpet=force' if "
- "the base addess is 0xfed0000000000000. "
- "This will make the kernel shift the address "
- "down 32 bits to 0xfed00000.");
- passed = false;
- }
-
- /*
- * We don't need to check for GAS address space widths etc
- * since the kernel does not care and the spec doesn't
- * stipulate these need to be sane
- */
-
- /*
- * Dump out HPET
- */
- fwts_log_info_verbatum(fw, "Hardware ID of Event Block:");
- fwts_log_info_verbatum(fw, " PCI Vendor ID : 0x%" PRIx32,
- (hpet->event_timer_block_id >> 16) & 0xffff);
- fwts_log_info_verbatum(fw, " Legacy IRQ Routing Capable : %" PRIu32,
- (hpet->event_timer_block_id >> 15) & 1);
- fwts_log_info_verbatum(fw, " COUNT_SIZE_CAP counter size: %" PRIu32,
- (hpet->event_timer_block_id >> 13) & 1);
- fwts_log_info_verbatum(fw, " Number of comparitors : %" PRIu32,
- (hpet->event_timer_block_id >> 8) & 0x1f);
- fwts_log_info_verbatum(fw, " Hardwre Revision ID : 0x%" PRIx8,
- hpet->event_timer_block_id & 0xff);
-
- fwts_log_info_verbatum(fw, "Lower 32 bit base Address : 0x%" PRIx64,
- hpet->base_address.address);
- fwts_log_info_verbatum(fw, " Address Space ID : 0x%" PRIx8,
- hpet->base_address.address_space_id);
- fwts_log_info_verbatum(fw, " Register Bit Width : 0x%" PRIx8,
- hpet->base_address.register_bit_width);
- fwts_log_info_verbatum(fw, " Register Bit Offset : 0x%" PRIx8,
- hpet->base_address.register_bit_offset);
- fwts_log_info_verbatum(fw, " Address Width : 0x%" PRIx8,
- hpet->base_address.access_width);
- fwts_log_info_verbatum(fw, "HPET sequence number : 0x%" PRIx8,
- hpet->hpet_number);
- fwts_log_info_verbatum(fw, "Minimum clock tick : 0x%" PRIx16,
- hpet->main_counter_minimum);
-
- switch (hpet->page_prot_and_oem_attribute & 0xf) {
- case 0:
- page_prot = "No guaranteed protection";
- break;
- case 1:
- page_prot = "4K page protected";
- break;
- case 2:
- page_prot = "64K page protected";
- break;
- default:
- page_prot = "Reserved";
- break;
- }
- fwts_log_info_verbatum(fw, "Page Protection : 0x%" PRIx8 " (%s)",
- hpet->page_prot_and_oem_attribute & 0xf,
- page_prot);
- fwts_log_info_verbatum(fw, "OEM attributes : 0x%" PRIx8,
- (hpet->page_prot_and_oem_attribute >> 4) & 0xf);
-
- if (passed)
- fwts_passed(fw, "HPET looks sane.");
-
- return FWTS_OK;
-}
-
-static int hpet_check_test3(fwts_framework *fw)
-{
- int i;
-
- if (hpet_base_p == 0) {
- fwts_log_info(fw, "Test skipped because HPET address was not found.");
- return FWTS_SKIP;
- }
-
- if (fwts_iasl_init(fw) != FWTS_OK) {
- fwts_warning(fw, "Failure to initialise iasl, aborting.");
- fwts_iasl_deinit();
- return FWTS_ERROR;
- }
-
- hpet_check_base_acpi_table(fw, "DSDT", 0);
-
- for (i = 0; i < 11; i++)
- hpet_check_base_acpi_table(fw, "SSDT", i);
-
- fwts_iasl_deinit();
-
- return FWTS_OK;
-}
-
-
-static int hpet_check_test4(fwts_framework *fw)
-{
- uint64_t hpet_id;
- uint32_t vendor_id;
- uint32_t clk_period;
-
- if (hpet_base_p == 0) {
- fwts_log_info(fw, "Test skipped because HPET address was not found.");
- return FWTS_SKIP;
- }
-
- hpet_base_v = fwts_mmap(hpet_base_p, HPET_REG_SIZE);
- if (hpet_base_v == NULL) {
- fwts_log_error(fw, "Cannot mmap to /dev/mem.");
- return FWTS_ERROR;
- }
-
- hpet_id = *(uint64_t*) hpet_base_v;
- vendor_id = (hpet_id & 0xffff0000) >> 16;
-
- if (vendor_id == 0xffff)
- fwts_failed(fw, LOG_LEVEL_MEDIUM, "HPETVendorId",
- "Invalid Vendor ID: %04" PRIx32 " - this should be configured.",
- vendor_id);
- else
- fwts_passed(fw, "Vendor ID looks sane: 0x%04" PRIx32 ".", vendor_id);
-
- clk_period = hpet_id >> 32;
- if ((clk_period > MAX_CLK_PERIOD) || (clk_period == 0))
- fwts_failed(fw, LOG_LEVEL_MEDIUM, "HPETClockPeriod",
- "Invalid clock period %" PRIu32 ", must be non-zero and "
- "less than 10^8.", clk_period);
- else
- fwts_passed(fw, "Valid clock period %" PRIu32 ".", clk_period);
-
- (void)fwts_munmap(hpet_base_v, HPET_REG_SIZE);
-
- return FWTS_OK;
-}
-
-
-static fwts_framework_minor_test hpet_check_tests[] = {
- { hpet_check_test1, "Test HPET base in kernel log." },
- { hpet_check_test2, "Test HPET base in HPET table."},
- { hpet_check_test3, "Test HPET base in DSDT and/or SSDT."},
- { hpet_check_test4, "Test HPET configuration." },
- { NULL, NULL }
-};
-
-static fwts_framework_ops hpet_check_ops = {
- .description = "HPET configuration tests.",
- .init = hpet_check_init,
- .deinit = hpet_check_deinit,
- .minor_tests = hpet_check_tests
-};
-
-FWTS_REGISTER("hpet_check", &hpet_check_ops, FWTS_TEST_ANYTIME,
- FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV | FWTS_FLAG_TEST_ACPI)
-
-#endif
--
2.1.4
More information about the fwts-devel
mailing list