From patchwork Tue Sep 29 00:53:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "David E. Box" X-Patchwork-Id: 1372959 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4C0gqt0l3Vz9s1t for ; Tue, 29 Sep 2020 10:53:46 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727217AbgI2Axc (ORCPT ); Mon, 28 Sep 2020 20:53:32 -0400 Received: from mga12.intel.com ([192.55.52.136]:33682 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726419AbgI2Ax3 (ORCPT ); Mon, 28 Sep 2020 20:53:29 -0400 IronPort-SDR: LpGccOWwAUcN6lma2U6FgSUlmJwUKUDaVdKEovlUggZfk75G+wDDRus+g2S2q/68qMwILGffw4 hDSDKqLmGyZA== X-IronPort-AV: E=McAfee;i="6000,8403,9758"; a="141490955" X-IronPort-AV: E=Sophos;i="5.77,316,1596524400"; d="scan'208";a="141490955" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Sep 2020 17:53:28 -0700 IronPort-SDR: lRYzHIje/dWR5cEmcodhASPg9/5tYxt3aHLn+WWeot7JSxaShv5fWWdfWXFmg8iuRVCp+n7nCQ h+xb+EvFZiHQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,316,1596524400"; d="scan'208";a="384617536" Received: from linux.intel.com ([10.54.29.200]) by orsmga001.jf.intel.com with ESMTP; 28 Sep 2020 17:53:28 -0700 Received: from debox1-desk2.jf.intel.com (debox1-desk2.jf.intel.com [10.54.75.16]) by linux.intel.com (Postfix) with ESMTP id 5289F580266; Mon, 28 Sep 2020 17:53:28 -0700 (PDT) From: "David E. Box" To: lee.jones@linaro.org, david.e.box@linux.intel.com, dvhart@infradead.org, andy@infradead.org, bhelgaas@google.com, alexander.h.duyck@linux.intel.com, hdegoede@redhat.com, alexey.budankov@linux.intel.com Cc: linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-pci@vger.kernel.org, Andy Shevchenko Subject: [PATCH V6 1/5] PCI: Add defines for Designated Vendor-Specific Extended Capability Date: Mon, 28 Sep 2020 17:53:16 -0700 Message-Id: <20200929005320.14739-2-david.e.box@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200929005320.14739-1-david.e.box@linux.intel.com> References: <20200929005320.14739-1-david.e.box@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org Add PCIe Designated Vendor-Specific Extended Capability (DVSEC) and defines for the header offsets. Defined in PCIe r5.0, sec 7.9.6. Signed-off-by: David E. Box Acked-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko --- include/uapi/linux/pci_regs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index f9701410d3b5..beafeee39e44 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -720,6 +720,7 @@ #define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */ #define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */ #define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */ +#define PCI_EXT_CAP_ID_DVSEC 0x23 /* Designated Vendor-Specific */ #define PCI_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */ #define PCI_EXT_CAP_ID_PL_16GT 0x26 /* Physical Layer 16.0 GT/s */ #define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_16GT @@ -1062,6 +1063,10 @@ #define PCI_L1SS_CTL1_LTR_L12_TH_SCALE 0xe0000000 /* LTR_L1.2_THRESHOLD_Scale */ #define PCI_L1SS_CTL2 0x0c /* Control 2 Register */ +/* Designated Vendor-Specific (DVSEC, PCI_EXT_CAP_ID_DVSEC) */ +#define PCI_DVSEC_HEADER1 0x4 /* Designated Vendor-Specific Header1 */ +#define PCI_DVSEC_HEADER2 0x8 /* Designated Vendor-Specific Header2 */ + /* Data Link Feature */ #define PCI_DLF_CAP 0x04 /* Capabilities Register */ #define PCI_DLF_EXCHANGE_ENABLE 0x80000000 /* Data Link Feature Exchange Enable */ From patchwork Tue Sep 29 00:53:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "David E. Box" X-Patchwork-Id: 1372963 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4C0gyd29JDz9sSf for ; Tue, 29 Sep 2020 10:59:37 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727205AbgI2A7b (ORCPT ); Mon, 28 Sep 2020 20:59:31 -0400 Received: from mga11.intel.com ([192.55.52.93]:26886 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725272AbgI2A7a (ORCPT ); Mon, 28 Sep 2020 20:59:30 -0400 IronPort-SDR: KN49WhZiScLqB12SV2mcsItBszeMsjLFWhFHMZ4hSZOL9RMGnA9HI5Xy9n6CrdoIv2LDF4yfUg XnerAEHFiVlg== X-IronPort-AV: E=McAfee;i="6000,8403,9758"; a="159425373" X-IronPort-AV: E=Sophos;i="5.77,316,1596524400"; d="scan'208";a="159425373" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Sep 2020 17:53:29 -0700 IronPort-SDR: R9qbUcfKkdHMWp+ULaEKGr6hMRiqh14+DYqrQwF5mJzXJvF7QjHkFroQMTFgo4Tp9G3yFYEJ26 bmkM5dtOmuXw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,316,1596524400"; d="scan'208";a="340644095" Received: from linux.intel.com ([10.54.29.200]) by orsmga008.jf.intel.com with ESMTP; 28 Sep 2020 17:53:28 -0700 Received: from debox1-desk2.jf.intel.com (debox1-desk2.jf.intel.com [10.54.75.16]) by linux.intel.com (Postfix) with ESMTP id B817F5801CA; Mon, 28 Sep 2020 17:53:28 -0700 (PDT) From: "David E. Box" To: lee.jones@linaro.org, david.e.box@linux.intel.com, dvhart@infradead.org, andy@infradead.org, bhelgaas@google.com, alexander.h.duyck@linux.intel.com, hdegoede@redhat.com, alexey.budankov@linux.intel.com Cc: linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-pci@vger.kernel.org, Andy Shevchenko Subject: [PATCH V6 2/5] mfd: Intel Platform Monitoring Technology support Date: Mon, 28 Sep 2020 17:53:17 -0700 Message-Id: <20200929005320.14739-3-david.e.box@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200929005320.14739-1-david.e.box@linux.intel.com> References: <20200929005320.14739-1-david.e.box@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org Intel Platform Monitoring Technology (PMT) is an architecture for enumerating and accessing hardware monitoring facilities. PMT supports multiple types of monitoring capabilities. This driver creates platform devices for each type so that they may be managed by capability specific drivers (to be introduced). Capabilities are discovered using PCIe DVSEC ids. Support is included for the 3 current capability types, Telemetry, Watcher, and Crashlog. The features are available on new Intel platforms starting from Tiger Lake for which support is added. This patch adds support for Tiger Lake (TGL), Alder Lake (ADL), and Out-of-Band Management Services Module (OOBMSM). Also add a quirk mechanism for several early hardware differences and bugs. For Tiger Lake, do not support Watcher and Crashlog capabilities since they will not be compatible with future product. Also, fix use a quirk to fix the discovery table offset. Co-developed-by: Alexander Duyck Signed-off-by: Alexander Duyck Signed-off-by: David E. Box Reviewed-by: Andy Shevchenko --- MAINTAINERS | 5 + drivers/mfd/Kconfig | 10 ++ drivers/mfd/Makefile | 1 + drivers/mfd/intel_pmt.c | 226 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 drivers/mfd/intel_pmt.c diff --git a/MAINTAINERS b/MAINTAINERS index 190c7fa2ea01..0f2663b1d376 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8946,6 +8946,11 @@ F: drivers/mfd/intel_soc_pmic* F: include/linux/mfd/intel_msic.h F: include/linux/mfd/intel_soc_pmic* +INTEL PMT DRIVER +M: "David E. Box" +S: Maintained +F: drivers/mfd/intel_pmt.c + INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT M: Stanislav Yakovlev L: linux-wireless@vger.kernel.org diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 33df0837ab41..f092db50e518 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -670,6 +670,16 @@ config MFD_INTEL_PMC_BXT Register and P-unit access. In addition this creates devices for iTCO watchdog and telemetry that are part of the PMC. +config MFD_INTEL_PMT + tristate "Intel Platform Monitoring Technology (PMT) support" + depends on PCI + select MFD_CORE + help + The Intel Platform Monitoring Technology (PMT) is an interface that + provides access to hardware monitor registers. This driver supports + Telemetry, Watcher, and Crashlog PMT capabilities/devices for + platforms starting from Tiger Lake. + config MFD_IPAQ_MICRO bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" depends on SA1100_H3100 || SA1100_H3600 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index a60e5f835283..b9565d98ab09 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -215,6 +215,7 @@ obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o obj-$(CONFIG_MFD_INTEL_PMC_BXT) += intel_pmc_bxt.o +obj-$(CONFIG_MFD_INTEL_PMT) += intel_pmt.o obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o diff --git a/drivers/mfd/intel_pmt.c b/drivers/mfd/intel_pmt.c new file mode 100644 index 000000000000..1b57a970a9d7 --- /dev/null +++ b/drivers/mfd/intel_pmt.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Platform Monitoring Technology PMT driver + * + * Copyright (c) 2020, Intel Corporation. + * All Rights Reserved. + * + * Author: David E. Box + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Intel DVSEC capability vendor space offsets */ +#define INTEL_DVSEC_ENTRIES 0xA +#define INTEL_DVSEC_SIZE 0xB +#define INTEL_DVSEC_TABLE 0xC +#define INTEL_DVSEC_TABLE_BAR(x) ((x) & GENMASK(2, 0)) +#define INTEL_DVSEC_TABLE_OFFSET(x) ((x) & GENMASK(31, 3)) +#define INTEL_DVSEC_ENTRY_SIZE 4 + +/* PMT capabilities */ +#define DVSEC_INTEL_ID_TELEMETRY 2 +#define DVSEC_INTEL_ID_WATCHER 3 +#define DVSEC_INTEL_ID_CRASHLOG 4 + +struct intel_dvsec_header { + u16 length; + u16 id; + u8 num_entries; + u8 entry_size; + u8 tbir; + u32 offset; +}; + +enum pmt_quirks { + /* Watcher capability not supported */ + PMT_QUIRK_NO_WATCHER = BIT(0), + + /* Crashlog capability not supported */ + PMT_QUIRK_NO_CRASHLOG = BIT(1), + + /* Use shift instead of mask to read discovery table offset */ + PMT_QUIRK_TABLE_SHIFT = BIT(2), +}; + +struct pmt_platform_info { + unsigned long quirks; +}; + +static const struct pmt_platform_info pmt_info; + +static const struct pmt_platform_info tgl_info = { + .quirks = PMT_QUIRK_NO_WATCHER | PMT_QUIRK_NO_CRASHLOG | + PMT_QUIRK_TABLE_SHIFT, +}; + +static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header, + struct pmt_platform_info *info) +{ + struct device *dev = &pdev->dev; + struct resource *res, *tmp; + struct mfd_cell *cell; + const char *name; + int count = header->num_entries; + int size = header->entry_size; + int id = header->id; + int i; + + switch (id) { + case DVSEC_INTEL_ID_TELEMETRY: + name = "pmt_telemetry"; + break; + case DVSEC_INTEL_ID_WATCHER: + if (info->quirks & PMT_QUIRK_NO_WATCHER) { + dev_info(dev, "Watcher not supported\n"); + return 0; + } + name = "pmt_watcher"; + break; + case DVSEC_INTEL_ID_CRASHLOG: + if (info->quirks & PMT_QUIRK_NO_CRASHLOG) { + dev_info(dev, "Crashlog not supported\n"); + return 0; + } + name = "pmt_crashlog"; + break; + default: + dev_err(dev, "Unrecognized PMT capability: %d\n", id); + return -EINVAL; + } + + if (!header->num_entries || !header->entry_size) { + dev_err(dev, "Invalid count or size for %s header\n", name); + return -EINVAL; + } + + cell = devm_kzalloc(dev, sizeof(*cell), GFP_KERNEL); + if (!cell) + return -ENOMEM; + + res = devm_kcalloc(dev, count, sizeof(*res), GFP_KERNEL); + if (!res) + return -ENOMEM; + + if (info->quirks & PMT_QUIRK_TABLE_SHIFT) + header->offset >>= 3; + + /* + * The PMT DVSEC contains the starting offset and count for a block of + * discovery tables, each providing access to monitoring facilities for + * a section of the device. Create a resource list of these tables to + * provide to the driver. + */ + for (i = 0, tmp = res; i < count; i++, tmp++) { + tmp->start = pdev->resource[header->tbir].start + + header->offset + i * (size << 2); + tmp->end = tmp->start + (size << 2) - 1; + tmp->flags = IORESOURCE_MEM; + } + + cell->resources = res; + cell->num_resources = count; + cell->name = name; + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cell, 1, NULL, 0, + NULL); +} + +static int pmt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct pmt_platform_info *info; + bool found_devices = false; + int ret, pos = 0; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + do { + struct intel_dvsec_header header; + u32 table; + u16 vid; + + pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC); + if (!pos) + break; + + pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid); + if (vid != PCI_VENDOR_ID_INTEL) + continue; + + pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2, + &header.id); + pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES, + &header.num_entries); + pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE, + &header.entry_size); + pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE, + &table); + + header.tbir = INTEL_DVSEC_TABLE_BAR(table); + header.offset = INTEL_DVSEC_TABLE_OFFSET(table); + + ret = pmt_add_dev(pdev, &header, info); + if (ret) { + dev_warn(&pdev->dev, + "Failed to add device for DVSEC id %d\n", + header.id); + continue; + } + + found_devices = true; + } while (true); + + if (!found_devices) { + dev_err(&pdev->dev, "No supported PMT capabilities found.\n"); + return -ENODEV; + } + + pm_runtime_put(&pdev->dev); + pm_runtime_allow(&pdev->dev); + + return 0; +} + +static void pmt_pci_remove(struct pci_dev *pdev) +{ + pm_runtime_forbid(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); +} + +#define PCI_DEVICE_ID_INTEL_PMT_ADL 0x467d +#define PCI_DEVICE_ID_INTEL_PMT_OOBMSM 0x09a7 +#define PCI_DEVICE_ID_INTEL_PMT_TGL 0x9a0d +static const struct pci_device_id pmt_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, PMT_ADL, &tgl_info) }, + { PCI_DEVICE_DATA(INTEL, PMT_OOBMSM, &pmt_info) }, + { PCI_DEVICE_DATA(INTEL, PMT_TGL, &tgl_info) }, + { } +}; +MODULE_DEVICE_TABLE(pci, pmt_pci_ids); + +static struct pci_driver pmt_pci_driver = { + .name = "intel-pmt", + .id_table = pmt_pci_ids, + .probe = pmt_pci_probe, + .remove = pmt_pci_remove, +}; +module_pci_driver(pmt_pci_driver); + +MODULE_AUTHOR("David E. Box "); +MODULE_DESCRIPTION("Intel Platform Monitoring Technology PMT driver"); +MODULE_LICENSE("GPL v2"); From patchwork Tue Sep 29 00:53:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "David E. Box" X-Patchwork-Id: 1372956 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4C0gqd3cldz9sT6 for ; Tue, 29 Sep 2020 10:53:33 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727220AbgI2Axc (ORCPT ); Mon, 28 Sep 2020 20:53:32 -0400 Received: from mga03.intel.com ([134.134.136.65]:54736 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727201AbgI2Axb (ORCPT ); Mon, 28 Sep 2020 20:53:31 -0400 IronPort-SDR: 6wAoDTmPwf68NxLG56BTilZLSQWMHj46ypVkjPQZX0I/AHaozaDYyvgoB2NeeKzb+F1X9kyERZ HJPeycUlZYXw== X-IronPort-AV: E=McAfee;i="6000,8403,9758"; a="162149351" X-IronPort-AV: E=Sophos;i="5.77,316,1596524400"; d="scan'208";a="162149351" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Sep 2020 17:53:29 -0700 IronPort-SDR: tc1RJEznO6wFJUHEbuO30tiDR3G/FZV+mcHsbM06rWGYFbMHKTWd8OOOTxX+j70dVQe8eloJmW hR+HRN4O3Yog== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,316,1596524400"; d="scan'208";a="513651143" Received: from linux.intel.com ([10.54.29.200]) by fmsmga006.fm.intel.com with ESMTP; 28 Sep 2020 17:53:29 -0700 Received: from debox1-desk2.jf.intel.com (debox1-desk2.jf.intel.com [10.54.75.16]) by linux.intel.com (Postfix) with ESMTP id 21B2B580266; Mon, 28 Sep 2020 17:53:29 -0700 (PDT) From: "David E. Box" To: lee.jones@linaro.org, david.e.box@linux.intel.com, dvhart@infradead.org, andy@infradead.org, bhelgaas@google.com, alexander.h.duyck@linux.intel.com, hdegoede@redhat.com, alexey.budankov@linux.intel.com Cc: linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-pci@vger.kernel.org Subject: [PATCH V6 3/5] platform/x86: Intel PMT class driver Date: Mon, 28 Sep 2020 17:53:18 -0700 Message-Id: <20200929005320.14739-4-david.e.box@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200929005320.14739-1-david.e.box@linux.intel.com> References: <20200929005320.14739-1-david.e.box@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: Alexander Duyck Intel Platform Monitoring Technology is meant to provide a common way to access telemetry and system metrics. Register mappings are not provided by the driver. Instead, a GUID is read from a header for each endpoint. The GUID identifies the device and is to be used with an XML, provided by the vendor, to discover the available set of metrics and their register mapping. This allows firmware updates to modify the register space without needing to update the driver every time with new mappings. Firmware writes a new GUID in this case to specify the new mapping. Software tools with access to the associated XML file can then interpret the changes. The module manages access to all Intel PMT endpoints on a system, independent of the device exporting them. It creates an intel_pmt class to manage the devices. For each telemetry endpoint, sysfs files provide GUID and size information as well as a pointer to the parent device the telemetry came from. Software may discover the association between endpoints and devices by iterating through the list in sysfs, or by looking for the existence of the class folder under the device of interest. A binary sysfs attribute of the same name allows software to then read or map the telemetry space for direct access. Signed-off-by: Alexander Duyck --- .../ABI/testing/sysfs-class-intel_pmt | 54 ++++ MAINTAINERS | 1 + drivers/platform/x86/Kconfig | 9 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_pmt_class.c | 295 ++++++++++++++++++ drivers/platform/x86/intel_pmt_class.h | 58 ++++ 6 files changed, 418 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-intel_pmt create mode 100644 drivers/platform/x86/intel_pmt_class.c create mode 100644 drivers/platform/x86/intel_pmt_class.h diff --git a/Documentation/ABI/testing/sysfs-class-intel_pmt b/Documentation/ABI/testing/sysfs-class-intel_pmt new file mode 100644 index 000000000000..926b5cf95fd1 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-intel_pmt @@ -0,0 +1,54 @@ +What: /sys/class/intel_pmt/ +Date: October 2020 +KernelVersion: 5.10 +Contact: David Box +Description: + The intel_pmt/ class directory contains information for + devices that expose hardware telemetry using Intel Platform + Monitoring Technology (PMT) + +What: /sys/class/intel_pmt/telem +Date: October 2020 +KernelVersion: 5.10 +Contact: David Box +Description: + The telem directory contains files describing an instance of + a PMT telemetry device that exposes hardware telemetry. Each + telem directory has an associated telem file. This file + may be opened and mapped or read to access the telemetry space + of the device. The register layout of the telemetry space is + determined from an XML file that matches the PCI device id and + GUID for the device. + +What: /sys/class/intel_pmt/telem/telem +Date: October 2020 +KernelVersion: 5.10 +Contact: David Box +Description: + (RO) The telemetry data for this telemetry device. This file + may be mapped or read to obtain the data. + +What: /sys/class/intel_pmt/telem/guid +Date: October 2020 +KernelVersion: 5.10 +Contact: David Box +Description: + (RO) The GUID for this telemetry device. The GUID identifies + the version of the XML file for the parent device that is to + be used to get the register layout. + +What: /sys/class/intel_pmt/telem/size +Date: October 2020 +KernelVersion: 5.10 +Contact: David Box +Description: + (RO) The size of telemetry region in bytes that corresponds to + the mapping size for the telem file. + +What: /sys/class/intel_pmt/telem/offset +Date: October 2020 +KernelVersion: 5.10 +Contact: David Box +Description: + (RO) The offset of telemetry region in bytes that corresponds to + the mapping for the telem file. diff --git a/MAINTAINERS b/MAINTAINERS index 0f2663b1d376..47fdb8a6e151 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8950,6 +8950,7 @@ INTEL PMT DRIVER M: "David E. Box" S: Maintained F: drivers/mfd/intel_pmt.c +F: drivers/platform/x86/intel_pmt_* INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT M: Stanislav Yakovlev diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 40219bba6801..093c43b63f48 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1360,6 +1360,15 @@ config INTEL_PMC_CORE - LTR Ignore - MPHY/PLL gating status (Sunrisepoint PCH only) +config INTEL_PMT_CLASS + tristate "Intel Platform Monitoring Technology (PMT) Class driver" + help + The Intel Platform Monitoring Technology (PMT) class driver provides + the basic sysfs interface and file heirarchy uses by PMT devices. + + For more information, see + + config INTEL_PUNIT_IPC tristate "Intel P-Unit IPC Driver" help diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 5f823f7eff45..f4b1f87f2401 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -140,6 +140,7 @@ obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv.o +obj-$(CONFIG_INTEL_PMT_CLASS) += intel_pmt_class.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o diff --git a/drivers/platform/x86/intel_pmt_class.c b/drivers/platform/x86/intel_pmt_class.c new file mode 100644 index 000000000000..b28660962ae7 --- /dev/null +++ b/drivers/platform/x86/intel_pmt_class.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Platform Monitory Technology Telemetry driver + * + * Copyright (c) 2020, Intel Corporation. + * All Rights Reserved. + * + * Author: "Alexander Duyck" + */ + +#include +#include +#include +#include +#include + +#include "intel_pmt_class.h" + +#define PMT_XA_START 0 +#define PMT_XA_MAX INT_MAX +#define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX) + +static const struct pci_device_id pmt_telem_early_client_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0x9a0d) }, /* TGL */ + { } +}; + +bool intel_pmt_is_early_client_hw(struct device *dev) +{ + struct pci_dev *parent = to_pci_dev(dev->parent); + + return !!pci_match_id(pmt_telem_early_client_pci_ids, parent); +} +EXPORT_SYMBOL_GPL(intel_pmt_is_early_client_hw); + +/* + * sysfs + */ +static ssize_t +intel_pmt_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t off, + size_t count) +{ + struct intel_pmt_entry *entry = container_of(attr, + struct intel_pmt_entry, + pmt_bin_attr); + + if (off < 0) + return -EINVAL; + + if (off >= entry->size) + return 0; + + if (count > entry->size - off) + count = entry->size - off; + + if (count) + memcpy_fromio(buf, entry->base + off, count); + + return count; +} + +static int +intel_pmt_mmap(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, struct vm_area_struct *vma) +{ + struct intel_pmt_entry *entry = container_of(attr, + struct intel_pmt_entry, + pmt_bin_attr); + unsigned long vsize = vma->vm_end - vma->vm_start; + struct device *dev = kobj_to_dev(kobj); + unsigned long phys = entry->base_addr; + unsigned long pfn = PFN_DOWN(phys); + unsigned long psize; + + if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) + return -EROFS; + + psize = (PFN_UP(entry->base_addr + entry->size) - pfn) * PAGE_SIZE; + if (vsize > psize) { + dev_err(dev, "Requested mmap size is too large\n"); + return -EINVAL; + } + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (io_remap_pfn_range(vma, vma->vm_start, pfn, + vsize, vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +static ssize_t +guid_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct intel_pmt_entry *entry = dev_get_drvdata(dev); + + return sprintf(buf, "0x%x\n", entry->guid); +} +static DEVICE_ATTR_RO(guid); + +static ssize_t size_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct intel_pmt_entry *entry = dev_get_drvdata(dev); + + return sprintf(buf, "%zu\n", entry->size); +} +static DEVICE_ATTR_RO(size); + +static ssize_t +offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct intel_pmt_entry *entry = dev_get_drvdata(dev); + + return sprintf(buf, "%lu\n", offset_in_page(entry->base_addr)); +} +static DEVICE_ATTR_RO(offset); + +static struct attribute *intel_pmt_attrs[] = { + &dev_attr_guid.attr, + &dev_attr_size.attr, + &dev_attr_offset.attr, + NULL +}; + +ATTRIBUTE_GROUPS(intel_pmt); + +static struct class intel_pmt_class = { + .name = "intel_pmt", + .owner = THIS_MODULE, + .dev_groups = intel_pmt_groups, +}; + +int intel_pmt_populate_entry(struct intel_pmt_entry *entry, + struct intel_pmt_header *header, + struct device *dev, struct resource *disc_res) +{ + struct pci_dev *pci_dev = to_pci_dev(dev->parent); + u8 bir; + + /* + * The base offset should always be 8 byte aligned. + * + * For non-local access types the lower 3 bits of base offset + * contains the index of the base address register where the + * telemetry can be found. + */ + bir = GET_BIR(header->base_offset); + + /* Local access and BARID only for now */ + switch (header->access_type) { + case ACCESS_LOCAL: + if (bir) { + dev_err(dev, + "Unsupported BAR index %d for access type %d\n", + bir, header->access_type); + return -EINVAL; + } + /* + * For access_type LOCAL, the base address is as follows: + * base address = end of discovery region + base offset + */ + entry->base_addr = disc_res->end + 1 + header->base_offset; + break; + case ACCESS_BARID: + /* + * If another BAR was specified then the base offset + * represents the offset within that BAR. SO retrieve the + * address from the parent PCI device and add offset. + */ + entry->base_addr = pci_resource_start(pci_dev, bir) + + GET_ADDRESS(header->base_offset); + break; + default: + dev_err(dev, "Unsupported access type %d\n", + header->access_type); + return -EINVAL; + } + + entry->guid = header->guid; + entry->size = header->size; + + return 0; +} +EXPORT_SYMBOL_GPL(intel_pmt_populate_entry); + +int intel_pmt_dev_create(struct intel_pmt_entry *entry, + struct intel_pmt_namespace *ns, struct device *parent) +{ + struct resource res; + struct device *dev; + dev_t devt; + int ret; + + ret = xa_alloc(ns->xa, &entry->devid, entry, PMT_XA_LIMIT, GFP_KERNEL); + if (ret) + return ret; + + ret = alloc_chrdev_region(&devt, 0, 1, "intel_pmt"); + if (ret) { + dev_err(parent, "alloc_chrdev_region err: %d\n", ret); + goto fail_chrdev_region; + } + + dev = device_create(&intel_pmt_class, parent, devt, entry, "%s%d", + ns->name, entry->devid); + + if (IS_ERR(dev)) { + dev_err(parent, "Could not create %s%d device node\n", + ns->name, entry->devid); + ret = PTR_ERR(dev); + goto fail_dev_create; + } + + entry->devt = devt; + entry->kobj = &dev->kobj; + + if (ns->attr_grp) { + ret = sysfs_create_group(entry->kobj, ns->attr_grp); + if (ret) + goto fail_sysfs; + } + + /* if size is 0 assume no data buffer, so no file needed */ + if (!entry->size) + return 0; + + res.start = entry->base_addr; + res.end = res.start + entry->size - 1; + res.flags = IORESOURCE_MEM; + + entry->base = devm_ioremap_resource(dev, &res); + if (IS_ERR(entry->base)) { + dev_err(dev, "Failed to ioremap device region\n"); + ret = -EIO; + goto fail_ioremap; + } + + sysfs_bin_attr_init(&entry->pmt_bin_attr); + entry->pmt_bin_attr.attr.name = ns->name; + entry->pmt_bin_attr.attr.mode = 0440; + entry->pmt_bin_attr.mmap = intel_pmt_mmap; + entry->pmt_bin_attr.read = intel_pmt_read; + entry->pmt_bin_attr.size = entry->size; + + ret = sysfs_create_bin_file(&dev->kobj, &entry->pmt_bin_attr); + if (!ret) + return 0; + + iounmap(entry->base); +fail_ioremap: + sysfs_remove_group(entry->kobj, ns->attr_grp); +fail_sysfs: + device_destroy(&intel_pmt_class, devt); +fail_dev_create: + unregister_chrdev_region(devt, 1); +fail_chrdev_region: + xa_erase(ns->xa, entry->devid); + + return ret; +} +EXPORT_SYMBOL_GPL(intel_pmt_dev_create); + +void intel_pmt_dev_destroy(struct intel_pmt_entry *entry, + struct intel_pmt_namespace *ns) +{ + if (entry->size) + sysfs_remove_bin_file(entry->kobj, &entry->pmt_bin_attr); + + if (ns->attr_grp) + sysfs_remove_group(entry->kobj, ns->attr_grp); + + device_destroy(&intel_pmt_class, entry->devt); + unregister_chrdev_region(entry->devt, 1); + xa_erase(ns->xa, entry->devid); +} +EXPORT_SYMBOL_GPL(intel_pmt_dev_destroy); + +static int __init pmt_class_init(void) +{ + return class_register(&intel_pmt_class); +} + +static void __exit pmt_class_exit(void) +{ + class_unregister(&intel_pmt_class); +} + +module_init(pmt_class_init); +module_exit(pmt_class_exit); + +MODULE_AUTHOR("Alexander Duyck "); +MODULE_DESCRIPTION("Intel PMT Class driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/intel_pmt_class.h b/drivers/platform/x86/intel_pmt_class.h new file mode 100644 index 000000000000..efef4352064c --- /dev/null +++ b/drivers/platform/x86/intel_pmt_class.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _INTEL_PMT_CLASS_H +#define _INTEL_PMT_CLASS_H + +#include +#include + +/* PMT access types */ +#define ACCESS_BARID 2 +#define ACCESS_LOCAL 3 + +/* PMT discovery base address/offset register layout */ +#define GET_BIR(v) ((v) & GENMASK(2, 0)) +#define GET_ADDRESS(v) ((v) & GENMASK(31, 3)) + +struct intel_pmt_entry { + struct bin_attribute pmt_bin_attr; + struct kobject *kobj; + void __iomem *disc_table; + void __iomem *base; + unsigned long base_addr; + size_t size; + u32 guid; + dev_t devt; + int devid; +}; + +struct intel_pmt_header { + u32 base_offset; + u32 size; + u32 guid; + u8 access_type; +}; + +struct intel_pmt_namespace { + const char *name; + struct xarray *xa; + const struct attribute_group *attr_grp; +}; + +bool intel_pmt_is_early_client_hw(struct device *dev); +int intel_pmt_populate_entry(struct intel_pmt_entry *entry, + struct intel_pmt_header *header, + struct device *dev, struct resource *disc_res); +int intel_pmt_dev_create(struct intel_pmt_entry *entry, + struct intel_pmt_namespace *ns, struct device *parent); +void intel_pmt_dev_destroy(struct intel_pmt_entry *entry, + struct intel_pmt_namespace *ns); + +static inline int +intel_pmt_ioremap_discovery_table(struct intel_pmt_entry *entry, + struct platform_device *pdev, int i) +{ + entry->disc_table = devm_platform_ioremap_resource(pdev, i); + + return PTR_ERR_OR_ZERO(entry->disc_table); +} +#endif From patchwork Tue Sep 29 00:53:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "David E. Box" X-Patchwork-Id: 1372958 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4C0gqs0d7Bz9s1t for ; Tue, 29 Sep 2020 10:53:45 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727226AbgI2Axc (ORCPT ); Mon, 28 Sep 2020 20:53:32 -0400 Received: from mga04.intel.com ([192.55.52.120]:31780 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727203AbgI2Axa (ORCPT ); Mon, 28 Sep 2020 20:53:30 -0400 IronPort-SDR: tfMdN/5oSkMyNEcfP5QjTj0vLopx9kaIed8zcPLwiT5me2uP+jt+4YCcjUr6DxnFLWeN0002ki WAtEB4jzCBdA== X-IronPort-AV: E=McAfee;i="6000,8403,9758"; a="159468664" X-IronPort-AV: E=Sophos;i="5.77,316,1596524400"; d="scan'208";a="159468664" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Sep 2020 17:53:29 -0700 IronPort-SDR: e3XUN6qxm+C9ewPigFKTwDz4gT20Iz3SaIKDDaYlYtJgUhZ6ciDiocUoNDsntx04TolXWyuXtC +goWPM/rsF8w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,316,1596524400"; d="scan'208";a="324482638" Received: from linux.intel.com ([10.54.29.200]) by orsmga002.jf.intel.com with ESMTP; 28 Sep 2020 17:53:29 -0700 Received: from debox1-desk2.jf.intel.com (debox1-desk2.jf.intel.com [10.54.75.16]) by linux.intel.com (Postfix) with ESMTP id 8357D58088C; Mon, 28 Sep 2020 17:53:29 -0700 (PDT) From: "David E. Box" To: lee.jones@linaro.org, david.e.box@linux.intel.com, dvhart@infradead.org, andy@infradead.org, bhelgaas@google.com, alexander.h.duyck@linux.intel.com, hdegoede@redhat.com, alexey.budankov@linux.intel.com Cc: linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-pci@vger.kernel.org Subject: [PATCH V6 4/5] platform/x86: Intel PMT Telemetry capability driver Date: Mon, 28 Sep 2020 17:53:19 -0700 Message-Id: <20200929005320.14739-5-david.e.box@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200929005320.14739-1-david.e.box@linux.intel.com> References: <20200929005320.14739-1-david.e.box@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: Alexander Duyck PMT Telemetry is a capability of the Intel Platform Monitoring Technology. The Telemetry capability provides access to device telemetry metrics that provide hardware performance data to users from read-only register spaces. With this driver present the intel_pmt directory can be populated with telem devices. These devices will contain the standard intel_pmt sysfs data and a "telem" binary sysfs attribute which can be used to access the telemetry data. Co-developed-by: David E. Box Signed-off-by: David E. Box Signed-off-by: Alexander Duyck --- drivers/platform/x86/Kconfig | 8 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_pmt_telemetry.c | 158 +++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 drivers/platform/x86/intel_pmt_telemetry.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 093c43b63f48..02cb2db11417 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1369,6 +1369,14 @@ config INTEL_PMT_CLASS For more information, see +config INTEL_PMT_TELEMETRY + tristate "Intel Platform Monitoring Technology (PMT) Telemetry driver" + select INTEL_PMT_CLASS + help + The Intel Platform Monitory Technology (PMT) Telemetry driver provides + access to hardware telemetry metrics on devices that support the + feature. + config INTEL_PUNIT_IPC tristate "Intel P-Unit IPC Driver" help diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index f4b1f87f2401..6a7b61f59ea8 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -141,6 +141,7 @@ obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv.o obj-$(CONFIG_INTEL_PMT_CLASS) += intel_pmt_class.o +obj-$(CONFIG_INTEL_PMT_TELEMETRY) += intel_pmt_telemetry.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o diff --git a/drivers/platform/x86/intel_pmt_telemetry.c b/drivers/platform/x86/intel_pmt_telemetry.c new file mode 100644 index 000000000000..d4819aefdd65 --- /dev/null +++ b/drivers/platform/x86/intel_pmt_telemetry.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Platform Monitory Technology Telemetry driver + * + * Copyright (c) 2020, Intel Corporation. + * All Rights Reserved. + * + * Author: "David E. Box" + */ + +#include +#include +#include +#include +#include + +#include "intel_pmt_class.h" + +#define TELEM_DEV_NAME "pmt_telemetry" + +#define TELEM_SIZE_OFFSET 0x0 +#define TELEM_GUID_OFFSET 0x4 +#define TELEM_BASE_OFFSET 0x8 +#define TELEM_ACCESS(v) ((v) & GENMASK(3, 0)) +/* size is in bytes */ +#define TELEM_SIZE(v) (((v) & GENMASK(27, 12)) >> 10) + +/* Used by client hardware to identify a fixed telemetry entry*/ +#define TELEM_CLIENT_FIXED_BLOCK_GUID 0x10000000 + +struct pmt_telem_priv { + int num_entries; + struct intel_pmt_entry entry[]; +}; + +static DEFINE_XARRAY_ALLOC(telem_array); +static struct intel_pmt_namespace pmt_telem_ns = { + .name = "telem", + .xa = &telem_array +}; + +/* + * driver initialization + */ +static int pmt_telem_add_entry(struct intel_pmt_entry *entry, + struct device *parent, + struct resource *disc_res) +{ + void __iomem *disc_table = entry->disc_table; + struct intel_pmt_header header; + int ret; + + header.access_type = TELEM_ACCESS(readl(disc_table)); + header.guid = readl(disc_table + TELEM_GUID_OFFSET); + header.base_offset = readl(disc_table + TELEM_BASE_OFFSET); + + /* Size is measured in DWORDS, but accessor returns bytes */ + header.size = TELEM_SIZE(readl(disc_table)); + + ret = intel_pmt_populate_entry(entry, &header, parent, disc_res); + if (ret) + return ret; + + return intel_pmt_dev_create(entry, &pmt_telem_ns, parent); +} + +static bool pmt_telem_region_overlaps(struct intel_pmt_entry *entry) +{ + u32 guid; + + guid = readl(entry->disc_table + TELEM_GUID_OFFSET); + + return guid == TELEM_CLIENT_FIXED_BLOCK_GUID; +} + +static int pmt_telem_remove(struct platform_device *pdev) +{ + struct pmt_telem_priv *priv = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < priv->num_entries; i++) + intel_pmt_dev_destroy(&priv->entry[i], &pmt_telem_ns); + + return 0; +} + +static int pmt_telem_probe(struct platform_device *pdev) +{ + struct pmt_telem_priv *priv; + bool early_hw; + size_t size; + int i, ret; + + size = offsetof(struct pmt_telem_priv, entry[pdev->num_resources]); + priv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + if (intel_pmt_is_early_client_hw(&pdev->dev)) + early_hw = true; + + for (i = 0; i < pdev->num_resources; i++) { + struct intel_pmt_entry *entry = &priv->entry[i]; + struct resource *disc_res; + + ret = -ENODEV; + + disc_res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!disc_res) + goto abort_probe; + + ret = intel_pmt_ioremap_discovery_table(entry, pdev, i); + if (ret) + goto abort_probe; + + if (pmt_telem_region_overlaps(entry) && early_hw) + continue; + + ret = pmt_telem_add_entry(entry, &pdev->dev, disc_res); + if (ret) + goto abort_probe; + + priv->num_entries++; + } + + return 0; +abort_probe: + pmt_telem_remove(pdev); + return ret; +} + +static struct platform_driver pmt_telem_driver = { + .driver = { + .name = TELEM_DEV_NAME, + }, + .remove = pmt_telem_remove, + .probe = pmt_telem_probe, +}; + +static int __init pmt_telem_init(void) +{ + return platform_driver_register(&pmt_telem_driver); +} +module_init(pmt_telem_init); + +static void __exit pmt_telem_exit(void) +{ + platform_driver_unregister(&pmt_telem_driver); + xa_destroy(&telem_array); +} +module_exit(pmt_telem_exit); + +MODULE_AUTHOR("David E. Box "); +MODULE_DESCRIPTION("Intel PMT Telemetry driver"); +MODULE_ALIAS("platform:" TELEM_DEV_NAME); +MODULE_LICENSE("GPL v2"); From patchwork Tue Sep 29 00:53:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "David E. Box" X-Patchwork-Id: 1372957 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4C0gqr2PjXz9sTC for ; Tue, 29 Sep 2020 10:53:44 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727233AbgI2Axd (ORCPT ); Mon, 28 Sep 2020 20:53:33 -0400 Received: from mga09.intel.com ([134.134.136.24]:63514 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727039AbgI2Axb (ORCPT ); Mon, 28 Sep 2020 20:53:31 -0400 IronPort-SDR: pSfjF7k9AiVQwTGnCcWrqwMUnFLVXrpk92aUhNLKIAGm90nww4JeMdj4aNWICTNQR7b17VvUhZ 09hyNF8QNKJw== X-IronPort-AV: E=McAfee;i="6000,8403,9758"; a="162969236" X-IronPort-AV: E=Sophos;i="5.77,316,1596524400"; d="scan'208";a="162969236" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Sep 2020 17:53:30 -0700 IronPort-SDR: NMvgsoHkBkMA+9m4Sh+l5tVmrWjHcSHJrt6bbtIMalsDv1XHDW/0EUPbZ3rAIB5OIm309/a0be 5QLXYc2txtiw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,316,1596524400"; d="scan'208";a="457055989" Received: from linux.intel.com ([10.54.29.200]) by orsmga004.jf.intel.com with ESMTP; 28 Sep 2020 17:53:29 -0700 Received: from debox1-desk2.jf.intel.com (debox1-desk2.jf.intel.com [10.54.75.16]) by linux.intel.com (Postfix) with ESMTP id D94E15801CA; Mon, 28 Sep 2020 17:53:29 -0700 (PDT) From: "David E. Box" To: lee.jones@linaro.org, david.e.box@linux.intel.com, dvhart@infradead.org, andy@infradead.org, bhelgaas@google.com, alexander.h.duyck@linux.intel.com, hdegoede@redhat.com, alexey.budankov@linux.intel.com Cc: linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-pci@vger.kernel.org Subject: [PATCH V6 5/5] platform/x86: Intel PMT Crashlog capability driver Date: Mon, 28 Sep 2020 17:53:20 -0700 Message-Id: <20200929005320.14739-6-david.e.box@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200929005320.14739-1-david.e.box@linux.intel.com> References: <20200929005320.14739-1-david.e.box@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: Alexander Duyck Add support for the Intel Platform Monitoring Technology crashlog interface. This interface provides a few sysfs values to allow for controlling the crashlog telemetry interface as well as a character driver to allow for mapping the crashlog memory region so that it can be accessed after a crashlog has been recorded. This driver is meant to only support the server version of the crashlog which is identified as crash_type 1 with a version of zero. Currently no other types are supported. Signed-off-by: Alexander Duyck --- .../ABI/testing/sysfs-class-intel_pmt | 65 ++++ drivers/platform/x86/Kconfig | 8 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_pmt_crashlog.c | 339 ++++++++++++++++++ 4 files changed, 413 insertions(+) create mode 100644 drivers/platform/x86/intel_pmt_crashlog.c diff --git a/Documentation/ABI/testing/sysfs-class-intel_pmt b/Documentation/ABI/testing/sysfs-class-intel_pmt index 926b5cf95fd1..67ca47123cbf 100644 --- a/Documentation/ABI/testing/sysfs-class-intel_pmt +++ b/Documentation/ABI/testing/sysfs-class-intel_pmt @@ -52,3 +52,68 @@ Contact: David Box Description: (RO) The offset of telemetry region in bytes that corresponds to the mapping for the telem file. + +What: /sys/class/intel_pmt/crashlog +Date: October 2020 +KernelVersion: 5.10 +Contact: Alexander Duyck +Description: + The crashlog directory contains files for configuring an + instance of a PMT crashlog device that can perform crash data + recoring. Each crashlog device has an associated crashlog + file. This file can be opened and mapped or read to access the + resulting crashlog buffer. The register layout for the buffer + can be determined from an XML file of specified guid for the + parent device. + +What: /sys/class/intel_pmt/crashlog/crashlog +Date: October 2020 +KernelVersion: 5.10 +Contact: David Box +Description: + (RO) The crashlog buffer for this crashlog device. This file + may be mapped or read to obtain the data. + +What: /sys/class/intel_pmt/crashlog/guid +Date: October 2020 +KernelVersion: 5.10 +Contact: Alexander Duyck +Description: + (RO) The guid for this crashlog device. The guid identifies the + version of the XML file for the parent device that should be + used to determine the register layout. + +What: /sys/class/intel_pmt/crashlog/size +Date: October 2020 +KernelVersion: 5.10 +Contact: Alexander Duyck +Description: + (RO) The length of the result buffer in bytes that corresponds + to the size for the crashlog buffer. + +What: /sys/class/intel_pmt/crashlog/offset +Date: October 2020 +KernelVersion: 5.10 +Contact: Alexander Duyck +Description: + (RO) The offset of the buffer in bytes that corresponds + to the mapping for the crashlog device. + +What: /sys/class/intel_pmt/crashlog/enable +Date: October 2020 +KernelVersion: 5.10 +Contact: Alexander Duyck +Description: + (RW) Boolean value controlling if the crashlog functionality + is enabled for the crashlog device. + +What: /sys/class/intel_pmt/crashlog/trigger +Date: October 2020 +KernelVersion: 5.10 +Contact: Alexander Duyck +Description: + (RW) Boolean value controlling the triggering of the crashlog + device node. When read it provides data on if the crashlog has + been triggered. When written to it can be used to either clear + the current trigger by writing false, or to trigger a new + event if the trigger is not currently set. diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 02cb2db11417..675f3396b341 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1377,6 +1377,14 @@ config INTEL_PMT_TELEMETRY access to hardware telemetry metrics on devices that support the feature. +config INTEL_PMT_CRASHLOG + tristate "Intel Platform Monitoring Technology (PMT) Crashlog driver" + select INTEL_PMT_CLASS + help + The Intel Platform Monitoring Technology (PMT) crashlog driver provides + access to hardware crashlog capabilities on devices that support the + feature. + config INTEL_PUNIT_IPC tristate "Intel P-Unit IPC Driver" help diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 6a7b61f59ea8..ca82c1344977 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -142,6 +142,7 @@ obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv.o obj-$(CONFIG_INTEL_PMT_CLASS) += intel_pmt_class.o obj-$(CONFIG_INTEL_PMT_TELEMETRY) += intel_pmt_telemetry.o +obj-$(CONFIG_INTEL_PMT_CRASHLOG) += intel_pmt_crashlog.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o diff --git a/drivers/platform/x86/intel_pmt_crashlog.c b/drivers/platform/x86/intel_pmt_crashlog.c new file mode 100644 index 000000000000..9c77be39ac16 --- /dev/null +++ b/drivers/platform/x86/intel_pmt_crashlog.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Platform Monitoring Technology Crashlog driver + * + * Copyright (c) 2020, Intel Corporation. + * All Rights Reserved. + * + * Author: "Alexander Duyck" + */ + +#include +#include +#include +#include +#include + +#include "intel_pmt_class.h" + +#define DRV_NAME "pmt_crashlog" + +/* Crashlog discovery header types */ +#define CRASH_TYPE_OOBMSM 1 + +/* Control Flags */ +#define CRASHLOG_FLAG_DISABLE BIT(27) +#define CRASHLOG_FLAG_CLEAR BIT(28) +#define CRASHLOG_FLAG_EXECUTE BIT(29) +#define CRASHLOG_FLAG_COMPLETE BIT(31) +#define CRASHLOG_FLAG_MASK GENMASK(31, 28) + +/* Crashlog Discovery Header */ +#define CONTROL_OFFSET 0x0 +#define GUID_OFFSET 0x4 +#define BASE_OFFSET 0x8 +#define SIZE_OFFSET 0xC +#define GET_ACCESS(v) ((v) & GENMASK(3, 0)) +#define GET_TYPE(v) (((v) & GENMASK(7, 4)) >> 4) +#define GET_VERSION(v) (((v) & GENMASK(19, 16)) >> 16) +/* size is in bytes */ +#define GET_SIZE(v) ((v) * sizeof(u32)) + +struct crashlog_entry { + /* entry must be first member of struct */ + struct intel_pmt_entry entry; + struct mutex control_mutex; +}; + +struct pmt_crashlog_priv { + int num_entries; + struct crashlog_entry entry[]; +}; + +/* + * I/O + */ +static bool pmt_crashlog_complete(struct intel_pmt_entry *entry) +{ + u32 control = readl(entry->disc_table + CONTROL_OFFSET); + + /* return current value of the crashlog complete flag */ + return !!(control & CRASHLOG_FLAG_COMPLETE); +} + +static bool pmt_crashlog_disabled(struct intel_pmt_entry *entry) +{ + u32 control = readl(entry->disc_table + CONTROL_OFFSET); + + /* return current value of the crashlog disabled flag */ + return !!(control & CRASHLOG_FLAG_DISABLE); +} + +static bool pmt_crashlog_supported(struct intel_pmt_entry *entry) +{ + u32 discovery_header = readl(entry->disc_table + CONTROL_OFFSET); + u32 crash_type, version; + + crash_type = GET_TYPE(discovery_header); + version = GET_VERSION(discovery_header); + + /* + * Currenty we only recognize OOBMSM version 0 devices. + * We can ignore all other crashlog devices in the system. + */ + return crash_type == CRASH_TYPE_OOBMSM && version == 0; +} + +static void pmt_crashlog_set_disable(struct intel_pmt_entry *entry, + bool disable) +{ + u32 control = readl(entry->disc_table + CONTROL_OFFSET); + + /* clear control bits */ + control &= ~(CRASHLOG_FLAG_MASK | CRASHLOG_FLAG_DISABLE); + if (disable) + control |= CRASHLOG_FLAG_DISABLE; + + writel(control, entry->disc_table + CONTROL_OFFSET); +} + +static void pmt_crashlog_set_clear(struct intel_pmt_entry *entry) +{ + u32 control = readl(entry->disc_table + CONTROL_OFFSET); + + /* clear control bits */ + control &= ~CRASHLOG_FLAG_MASK; + control |= CRASHLOG_FLAG_CLEAR; + + writel(control, entry->disc_table + CONTROL_OFFSET); +} + +static void pmt_crashlog_set_execute(struct intel_pmt_entry *entry) +{ + u32 control = readl(entry->disc_table + CONTROL_OFFSET); + + /* clear control bits */ + control &= ~CRASHLOG_FLAG_MASK; + control |= CRASHLOG_FLAG_EXECUTE; + + writel(control, entry->disc_table + CONTROL_OFFSET); +} + +/* + * sysfs + */ +static ssize_t +enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct intel_pmt_entry *entry; + int enabled; + + entry = dev_get_drvdata(dev); + enabled = !pmt_crashlog_disabled(entry); + + return sprintf(buf, "%d\n", enabled); +} + +static ssize_t +enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct crashlog_entry *entry; + bool enabled; + int result; + + entry = dev_get_drvdata(dev); + + result = kstrtobool(buf, &enabled); + if (result) + return result; + + mutex_lock(&entry->control_mutex); + pmt_crashlog_set_disable(&entry->entry, !enabled); + mutex_unlock(&entry->control_mutex); + + return strnlen(buf, count); +} +static DEVICE_ATTR_RW(enable); + +static ssize_t +trigger_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct intel_pmt_entry *entry; + int trigger; + + entry = dev_get_drvdata(dev); + trigger = pmt_crashlog_complete(entry); + + return sprintf(buf, "%d\n", trigger); +} + +static ssize_t +trigger_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct crashlog_entry *entry; + bool trigger; + int result; + + entry = dev_get_drvdata(dev); + + result = kstrtobool(buf, &trigger); + if (result) + return result; + + mutex_lock(&entry->control_mutex); + + if (!trigger) { + pmt_crashlog_set_clear(&entry->entry); + } else if (pmt_crashlog_complete(&entry->entry)) { + /* we cannot trigger a new crash if one is still pending */ + result = -EEXIST; + goto err; + } else if (pmt_crashlog_disabled(&entry->entry)) { + /* if device is currently disabled, return busy */ + result = -EBUSY; + goto err; + } else { + pmt_crashlog_set_execute(&entry->entry); + } + + result = strnlen(buf, count); +err: + mutex_unlock(&entry->control_mutex); + return result; +} +static DEVICE_ATTR_RW(trigger); + +static struct attribute *pmt_crashlog_attrs[] = { + &dev_attr_enable.attr, + &dev_attr_trigger.attr, + NULL +}; + +static struct attribute_group pmt_crashlog_group = { + .attrs = pmt_crashlog_attrs, +}; + +static DEFINE_XARRAY_ALLOC(crashlog_array); +static struct intel_pmt_namespace pmt_crashlog_ns = { + .name = "crashlog", + .xa = &crashlog_array, + .attr_grp = &pmt_crashlog_group +}; + +/* + * initialization + */ +static int pmt_crashlog_add_entry(struct intel_pmt_entry *entry, + struct device *parent, + struct resource *disc_res) +{ + void __iomem *disc_table = entry->disc_table; + struct intel_pmt_header header; + int ret; + + header.access_type = GET_ACCESS(readl(disc_table)); + header.guid = readl(disc_table + GUID_OFFSET); + header.base_offset = readl(disc_table + BASE_OFFSET); + + /* Size is measured in DWORDS, but accessor returns bytes */ + header.size = GET_SIZE(readl(disc_table + SIZE_OFFSET)); + + ret = intel_pmt_populate_entry(entry, &header, parent, disc_res); + if (ret) + return ret; + + ret = intel_pmt_dev_create(entry, &pmt_crashlog_ns, parent); + if (!ret) + return 0; + + dev_err(parent, "Failed to add crashlog controls\n"); + intel_pmt_dev_destroy(entry, &pmt_crashlog_ns); + + return ret; +} + +static int pmt_crashlog_remove(struct platform_device *pdev) +{ + struct pmt_crashlog_priv *priv = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < priv->num_entries; i++) + intel_pmt_dev_destroy(&priv->entry[i].entry, &pmt_crashlog_ns); + + return 0; +} + +static int pmt_crashlog_probe(struct platform_device *pdev) +{ + struct pmt_crashlog_priv *priv; + size_t size; + int i, ret; + + size = offsetof(struct pmt_crashlog_priv, entry[pdev->num_resources]); + priv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + for (i = 0; i < pdev->num_resources; i++) { + struct intel_pmt_entry *entry = &priv->entry[i].entry; + struct resource *disc_res; + + ret = -ENODEV; + + /* initialize control mutex */ + mutex_init(&priv->entry[i].control_mutex); + + disc_res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!disc_res) + goto abort_probe; + + ret = intel_pmt_ioremap_discovery_table(entry, pdev, i); + if (ret) + goto abort_probe; + + if (!pmt_crashlog_supported(entry)) + continue; + + ret = pmt_crashlog_add_entry(entry, &pdev->dev, disc_res); + if (ret) + goto abort_probe; + + priv->num_entries++; + } + + return 0; +abort_probe: + pmt_crashlog_remove(pdev); + return ret; +} + +static struct platform_driver pmt_crashlog_driver = { + .driver = { + .name = DRV_NAME, + }, + .remove = pmt_crashlog_remove, + .probe = pmt_crashlog_probe, +}; + +static int __init pmt_crashlog_init(void) +{ + return platform_driver_register(&pmt_crashlog_driver); +} + +static void __exit pmt_crashlog_exit(void) +{ + platform_driver_unregister(&pmt_crashlog_driver); + xa_destroy(&crashlog_array); +} + +module_init(pmt_crashlog_init); +module_exit(pmt_crashlog_exit); + +MODULE_AUTHOR("Alexander Duyck "); +MODULE_DESCRIPTION("Intel PMT Crashlog driver"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_LICENSE("GPL v2");