ACK: [PATCH 02/30] acpi: re-orgainise HPET tests #1
ivanhu
ivan.hu at canonical.com
Wed Jun 24 03:27:32 UTC 2015
On 2015年06月18日 16:49, Colin King wrote:
> 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';
> +Re
> + 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);Re
> +
> + 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
Acked-by: Ivan Hu<ivan.hu at canonical.com>
More information about the fwts-devel
mailing list