From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DFA1AC433DB for ; Fri, 15 Jan 2021 09:55:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8854E23772 for ; Fri, 15 Jan 2021 09:55:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730598AbhAOJzC convert rfc822-to-8bit (ORCPT ); Fri, 15 Jan 2021 04:55:02 -0500 Received: from mga03.intel.com ([134.134.136.65]:42653 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726045AbhAOJyy (ORCPT ); Fri, 15 Jan 2021 04:54:54 -0500 IronPort-SDR: uKV1AB5pp7liwsmukLrb4h0LcNyTz3y/LpeSfnOD2OaNAdamezsgdmNBmgLCE9PqEcfaIV13Ax JsvVozN7D7aQ== X-IronPort-AV: E=McAfee;i="6000,8403,9864"; a="178613549" X-IronPort-AV: E=Sophos;i="5.79,349,1602572400"; d="scan'208";a="178613549" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Jan 2021 01:54:14 -0800 IronPort-SDR: 1gbUbZEHHSo4hpjAVaN3O9GgfwmYEqpx5esJeL4eHUMm0bCL6JQ49n8oUqVyb/YaG4fNP7vG3K PLJPFIz5DV3A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,349,1602572400"; d="scan'208";a="354245437" Received: from fmsmsx604.amr.corp.intel.com ([10.18.126.84]) by fmsmga008.fm.intel.com with ESMTP; 15 Jan 2021 01:54:14 -0800 Received: from fmsmsx612.amr.corp.intel.com (10.18.126.92) by fmsmsx604.amr.corp.intel.com (10.18.126.84) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1713.5; Fri, 15 Jan 2021 01:54:11 -0800 Received: from shsmsx603.ccr.corp.intel.com (10.109.6.143) by fmsmsx612.amr.corp.intel.com (10.18.126.92) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1713.5; Fri, 15 Jan 2021 01:54:10 -0800 Received: from shsmsx603.ccr.corp.intel.com ([10.109.6.143]) by SHSMSX603.ccr.corp.intel.com ([10.109.6.143]) with mapi id 15.01.1713.004; Fri, 15 Jan 2021 17:54:08 +0800 From: "Zhang, Rui" To: "linux-acpi@vger.kernel.org" CC: "rjw@rjwysocki.net" , "Brandt, Todd E" Subject: RE: [PATCH] ACPI: introduce support for FPDT table Thread-Topic: [PATCH] ACPI: introduce support for FPDT table Thread-Index: AQHW6yPttTA6p3cmHUumoINghDd9BKoocbPg Date: Fri, 15 Jan 2021 09:54:08 +0000 Message-ID: <3f226cbdc7bd46dd9ad458a64004cd7c@intel.com> References: <20210115100220.21686-1-rui.zhang@intel.com> In-Reply-To: <20210115100220.21686-1-rui.zhang@intel.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-product: dlpe-windows dlp-reaction: no-action dlp-version: 11.5.1.3 x-originating-ip: [10.239.127.36] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 8BIT MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org Sorry that I lost track of this patch for a long time. Now it seems that this feature is needed, when /dev/mem is not available. Thanks, rui > -----Original Message----- > From: Zhang, Rui > Sent: Friday, January 15, 2021 6:02 PM > To: linux-acpi@vger.kernel.org > Cc: rjw@rjwysocki.net; Brandt, Todd E ; Zhang, > Rui > Subject: [PATCH] ACPI: introduce support for FPDT table > Importance: High > > ACPI Firmware Performance Data Table (FPDT) provides information about > firmware performance during system boot, S3 suspend and S3 resume. > > Have the kernel parse the FPDT table, and expose the firmware performance > data to userspace as sysfs attributes under /sys/firmware/acpi/fpdt/. > > Tested-by: Todd Brandt > Signed-off-by: Zhang Rui > --- > Documentation/ABI/testing/sysfs-firmware-acpi | 43 +++ > drivers/acpi/Kconfig | 8 + > drivers/acpi/Makefile | 1 + > drivers/acpi/acpi_fpdt.c | 263 ++++++++++++++++++ > 4 files changed, 315 insertions(+) > create mode 100644 drivers/acpi/acpi_fpdt.c > > diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi > b/Documentation/ABI/testing/sysfs-firmware-acpi > index b16d30a71709..819939d858c9 100644 > --- a/Documentation/ABI/testing/sysfs-firmware-acpi > +++ b/Documentation/ABI/testing/sysfs-firmware-acpi > @@ -1,3 +1,46 @@ > +What: /sys/firmware/acpi/fpdt/ > +Date: Jan 2021 > +Contact: Zhang Rui > +Description: > + ACPI Firmware Performance Data Table (FPDT) provides > + information for firmware performance data for system boot, > + S3 suspend and S3 resume. This sysfs entry contains the > + performance data retrieved from the FPDT. > + > + boot: > + firmware_start_ns: Timer value logged at the > beginning > + of firmware image execution. In > nanoseconds. > + bootloader_load_ns: Timer value logged just prior to > + loading the OS boot loader into memory. > + In nanoseconds. > + bootloader_launch_ns: Timer value logged just prior > to > + launching the currently loaded OS boot > loader > + image. In nanoseconds. > + exitbootservice_start_ns: Timer value logged at the > + point when the OS loader calls the > + ExitBootServices function for UEFI compatible > + firmware. In nanoseconds. > + exitbootservice_end_ns: Timer value logged at the > point > + just prior to the OS loader gaining control > + back from the ExitBootServices function for > + UEFI compatible firmware. In nanoseconds. > + suspend: > + suspend_start_ns: Timer value recorded at the > previous > + OS write to SLP_TYP upon entry to S3. In > + nanoseconds. > + suspend_end_ns: Timer value recorded at the > previous > + firmware write to SLP_TYP used to trigger > + hardware entry to S3. In nanoseconds. > + resume: > + resume_count: A count of the number of S3 resume > cycles > + since the last full boot sequence. > + resume_avg_ns: Average timer value of all resume > cycles > + logged since the last full boot sequence, > + including the most recent resume. In > nanoseconds. > + resume_prev_ns: Timer recorded at the end of the > previous > + platform runtime firmware S3 resume, just > prior to > + handoff to the OS waking vector. In > nanoseconds. > + > What: /sys/firmware/acpi/bgrt/ > Date: January 2012 > Contact: Matthew Garrett > diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index > ebcf534514be..84930fa2dc32 100644 > --- a/drivers/acpi/Kconfig > +++ b/drivers/acpi/Kconfig > @@ -87,6 +87,14 @@ config ACPI_SPCR_TABLE > This table provides information about the configuration of the > earlycon console. > > +config ACPI_FPDT > + bool "ACPI Firmware Performance Data Table(FPDT)" > + depends on X86_64 > + help > + Enable support for the Firmware Performance Data Table (FPDT). > + This table provides information on the timing of the system > + boot, S3 suspend and S3 resume firmware code paths. > + > config ACPI_LPIT > bool > depends on X86_64 > diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index > 076894a3330f..eb93bb7b6479 100644 > --- a/drivers/acpi/Makefile > +++ b/drivers/acpi/Makefile > @@ -57,6 +57,7 @@ acpi-$(CONFIG_X86) += x86/utils.o > acpi-$(CONFIG_X86) += x86/s2idle.o > acpi-$(CONFIG_DEBUG_FS) += debugfs.o > acpi-y += acpi_lpat.o > +acpi-$(CONFIG_ACPI_FPDT) += acpi_fpdt.o > acpi-$(CONFIG_ACPI_LPIT) += acpi_lpit.o > acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o > acpi-$(CONFIG_ACPI_WATCHDOG) += acpi_watchdog.o > diff --git a/drivers/acpi/acpi_fpdt.c b/drivers/acpi/acpi_fpdt.c new file mode > 100644 index 000000000000..b8108117262a > --- /dev/null > +++ b/drivers/acpi/acpi_fpdt.c > @@ -0,0 +1,263 @@ > +// SPDX-License-Identifier: GPL-2.0-only > + > +/* > + * FPDT support for exporting boot and suspend/resume performance data > + * > + * Copyright (C) 2021 Intel Corporation. All rights reserved. > + */ > + > +#define pr_fmt(fmt) "ACPI FPDT: " fmt > + > +#include > + > +/* > + * FPDT contains ACPI table header and a number of fpdt_subtable_entries. > + * Each fpdt_subtable_entry points to a subtable: FBPT or S3PT. > + * Each FPDT subtable (FBPT/S3PT) is composed of a fpdt_subtable_header > + * and a number of fpdt performance records. > + * Each FPDT performance record is composed of a fpdt_record_header and > + * performance data fields, for boot or suspend or resume phase. > + */ > +enum fpdt_subtable_type { > + SUBTABLE_FBPT, > + SUBTABLE_S3PT, > +}; > + > +struct fpdt_subtable_entry { > + u16 type; /* refer to enum fpdt_subtable_type */ > + u8 length; > + u8 revision; > + u32 reserved; > + u64 address; /* physical address of the S3PT/FBPT table */ > +}; > + > +struct fpdt_subtable_header { > + u32 signature; > + u32 length; > +}; > + > +enum fpdt_record_type { > + RECORD_S3_RESUME, > + RECORD_S3_SUSPEND, > + RECORD_BOOT, > +}; > + > +struct fpdt_record_header { > + u16 type; /* refer to enum fpdt_record_type */ > + u8 length; > + u8 revision; > +}; > + > +struct resume_performance_record { > + struct fpdt_record_header header; > + u32 resume_count; > + u64 resume_prev; > + u64 resume_avg; > +} __attribute__((packed)); > + > +struct boot_performance_record { > + struct fpdt_record_header header; > + u32 reserved; > + u64 firmware_start; > + u64 bootloader_load; > + u64 bootloader_launch; > + u64 exitbootservice_start; > + u64 exitbootservice_end; > +} __attribute__((packed)); > + > +struct suspend_performance_record { > + struct fpdt_record_header header; > + u64 suspend_start; > + u64 suspend_end; > +} __attribute__((packed)); > + > + > +static struct resume_performance_record *record_resume; static struct > +suspend_performance_record *record_suspend; static struct > +boot_performance_record *record_boot; > + > +#define FPDT_ATTR(phase, name) \ > +static ssize_t name##_show(struct kobject *kobj, \ > + struct kobj_attribute *attr, char *buf) \ > +{ \ > + return sprintf(buf, "%llu\n", record_##phase->name); \ > +} \ > +static struct kobj_attribute name##_attr = \ > +__ATTR(name##_ns, 0444, name##_show, NULL) > + > +FPDT_ATTR(resume, resume_prev); > +FPDT_ATTR(resume, resume_avg); > +FPDT_ATTR(suspend, suspend_start); > +FPDT_ATTR(suspend, suspend_end); > +FPDT_ATTR(boot, firmware_start); > +FPDT_ATTR(boot, bootloader_load); > +FPDT_ATTR(boot, bootloader_launch); > +FPDT_ATTR(boot, exitbootservice_start); FPDT_ATTR(boot, > +exitbootservice_end); > + > +static ssize_t resume_count_show(struct kobject *kobj, > + struct kobj_attribute *attr, char *buf) { > + return sprintf(buf, "%u\n", record_resume->resume_count); } > + > +static struct kobj_attribute resume_count_attr = > +__ATTR_RO(resume_count); > + > +static struct attribute *resume_attrs[] = { > + &resume_count_attr.attr, > + &resume_prev_attr.attr, > + &resume_avg_attr.attr, > + NULL > +}; > + > +static const struct attribute_group resume_attr_group = { > + .attrs = resume_attrs, > + .name = "resume", > +}; > + > +static struct attribute *suspend_attrs[] = { > + &suspend_start_attr.attr, > + &suspend_end_attr.attr, > + NULL > +}; > + > +static const struct attribute_group suspend_attr_group = { > + .attrs = suspend_attrs, > + .name = "suspend", > +}; > + > +static struct attribute *boot_attrs[] = { > + &firmware_start_attr.attr, > + &bootloader_load_attr.attr, > + &bootloader_launch_attr.attr, > + &exitbootservice_start_attr.attr, > + &exitbootservice_end_attr.attr, > + NULL > +}; > + > +static const struct attribute_group boot_attr_group = { > + .attrs = boot_attrs, > + .name = "boot", > +}; > + > +static struct kobject *fpdt_kobj; > + > +static int fpdt_process_subtable(u64 address, u32 subtable_type) { > + struct fpdt_subtable_header *subtable_header; > + struct fpdt_record_header *record_header; > + char *signature = (subtable_type == SUBTABLE_FBPT ? "FBPT" : > "S3PT"); > + u32 length, offset; > + int result; > + > + subtable_header = acpi_os_map_memory(address, > sizeof(*subtable_header)); > + if (!subtable_header) > + return -ENOMEM; > + > + if (strncmp((char *)&subtable_header->signature, signature, 4)) { > + pr_info(FW_BUG "subtable signature and type > mismatch!\n"); > + return -EINVAL; > + } > + > + length = subtable_header->length; > + acpi_os_unmap_memory(subtable_header, > sizeof(*subtable_header)); > + > + subtable_header = acpi_os_map_memory(address, length); > + if (!subtable_header) > + return -ENOMEM; > + > + offset = sizeof(*subtable_header); > + while (offset < length) { > + record_header = (void *)subtable_header + offset; > + offset += record_header->length; > + > + switch (record_header->type) { > + case RECORD_S3_RESUME: > + if (subtable_type != SUBTABLE_S3PT) { > + pr_err(FW_BUG "Invalid record %d for > subtable %s\n", > + record_header->type, signature); > + return -EINVAL; > + } > + if (record_resume) { > + pr_err("Duplicate resume performance > record found.\n"); > + continue; > + } > + record_resume = (struct > resume_performance_record *)record_header; > + result = sysfs_create_group(fpdt_kobj, > &resume_attr_group); > + if (result) > + return result; > + break; > + case RECORD_S3_SUSPEND: > + if (subtable_type != SUBTABLE_S3PT) { > + pr_err(FW_BUG "Invalid %d for > subtable %s\n", > + record_header->type, signature); > + continue; > + } > + if (record_suspend) { > + pr_err("Duplicate suspend performance > record found.\n"); > + continue; > + } > + record_suspend = (struct > suspend_performance_record *)record_header; > + result = sysfs_create_group(fpdt_kobj, > &suspend_attr_group); > + if (result) > + return result; > + break; > + case RECORD_BOOT: > + if (subtable_type != SUBTABLE_FBPT) { > + pr_err(FW_BUG "Invalid %d for > subtable %s\n", > + record_header->type, signature); > + return -EINVAL; > + } > + if (record_boot) { > + pr_err("Duplicate boot performance record > found.\n"); > + continue; > + } > + record_boot = (struct boot_performance_record > *)record_header; > + result = sysfs_create_group(fpdt_kobj, > &boot_attr_group); > + if (result) > + return result; > + break; > + > + default: > + pr_err(FW_BUG "Invalid record %d found.\n", > record_header->type); > + return -EINVAL; > + } > + } > + return 0; > +} > + > +void acpi_init_fpdt(void) > +{ > + acpi_status status; > + struct acpi_table_header *header; > + struct fpdt_subtable_entry *subtable; > + u32 offset = sizeof(*header); > + > + status = acpi_get_table(ACPI_SIG_FPDT, 0, &header); > + > + if (ACPI_FAILURE(status)) > + return; > + > + fpdt_kobj = kobject_create_and_add("fpdt", acpi_kobj); > + if (!fpdt_kobj) > + return; > + > + while (offset < header->length) { > + subtable = (void *)header + offset; > + switch (subtable->type) { > + case SUBTABLE_FBPT: > + case SUBTABLE_S3PT: > + fpdt_process_subtable(subtable->address, > + subtable->type); > + break; > + default: > + pr_info(FW_BUG, "Invalid subtable type %d > found.\n", > + subtable->type); > + return; > + } > + offset += sizeof(*subtable); > + } > +} > + > +fs_initcall(acpi_init_fpdt); > -- > 2.17.1