[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