Unverified Commit a0192c4a authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!25 Intel SPR: Intel PMT support

Intel PMT support for SPR

Intel-kernel issue:
https://gitee.com/open_euler/dashboard?issue_id=I596K9

Intel Platform Monitoring Technology (PMT) is an architecture for
enumerating and accessing hardware monitoring capabilities on a device.
PMT defines several capabilities to support collecting monitoring data from
hardware. All are discoverable as separate instances of the PCIE Designated
Vendor extended capability (DVSEC) with the Intel vendor code. The DVSEC ID
field uniquely identifies the capability.
This patch set provides support for the PMT framework.
new ABI listed in below page:
https://www.kernel.org/doc/html/latest/admin-guide/abi-testing.html#file-srv-docbuild-lib-git-linux-testing-sysfs-class-intel-pmt



Test:
pmt driver initial successfully
pmt class interface is ready on /sys/class/intel_pmt/
pmt data can be read from /sys/class/intel_pmt/telem

Known issue:
crashlog is not supported due to BIOS update. Need update driver to support new BIOS.

Default config change:(these will submit another patch for changing x86 default configs based on kernel release team's decision)
if any recommended config change vs upstream default config, please list as git diff format:
Below configs changed from n to m
< CONFIG_MFD_INTEL_PMT=m
< CONFIG_INTEL_PMT_CLASS=m
< CONFIG_INTEL_PMT_TELEMETRY=m
< CONFIG_INTEL_PMT_CRASHLOG=m 

From: @juntianlinux 
Reviewed-by: default avatarXie XiuQi <xiexiuqi@huawei.com>
Reviewed-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
Reviewed-by: default avatarJiao Fenfang <jiaofenfang@uniontech.com>
Signed-off-by: default avatarXie XiuQi <xiexiuqi@huawei.com>
parents 0314681b 21db19cf
Loading
Loading
Loading
Loading
+119 −0
Original line number Diff line number Diff line
What:		/sys/class/intel_pmt/
Date:		October 2020
KernelVersion:	5.10
Contact:	David Box <david.e.box@linux.intel.com>
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<x>
Date:		October 2020
KernelVersion:	5.10
Contact:	David Box <david.e.box@linux.intel.com>
Description:
		The telem<x> directory contains files describing an instance of
		a PMT telemetry device that exposes hardware telemetry. Each
		telem<x> 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<x>/telem
Date:		October 2020
KernelVersion:	5.10
Contact:	David Box <david.e.box@linux.intel.com>
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<x>/guid
Date:		October 2020
KernelVersion:	5.10
Contact:	David Box <david.e.box@linux.intel.com>
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<x>/size
Date:		October 2020
KernelVersion:	5.10
Contact:	David Box <david.e.box@linux.intel.com>
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<x>/offset
Date:		October 2020
KernelVersion:	5.10
Contact:	David Box <david.e.box@linux.intel.com>
Description:
		(RO) The offset of telemetry region in bytes that corresponds to
		the mapping for the telem file.

What:		/sys/class/intel_pmt/crashlog<x>
Date:		October 2020
KernelVersion:	5.10
Contact:	Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
		The crashlog<x> directory contains files for configuring an
		instance of a PMT crashlog device that can perform crash data
		recording. Each crashlog<x> 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<x>/crashlog
Date:		October 2020
KernelVersion:	5.10
Contact:	David Box <david.e.box@linux.intel.com>
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<x>/guid
Date:		October 2020
KernelVersion:	5.10
Contact:	Alexander Duyck <alexander.h.duyck@linux.intel.com>
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<x>/size
Date:		October 2020
KernelVersion:	5.10
Contact:	Alexander Duyck <alexander.h.duyck@linux.intel.com>
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<x>/offset
Date:		October 2020
KernelVersion:	5.10
Contact:	Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
		(RO) The offset of the buffer in bytes that corresponds
		to the mapping for the crashlog device.

What:		/sys/class/intel_pmt/crashlog<x>/enable
Date:		October 2020
KernelVersion:	5.10
Contact:	Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
		(RW) Boolean value controlling if the crashlog functionality
		is enabled for the crashlog device.

What:		/sys/class/intel_pmt/crashlog<x>/trigger
Date:		October 2020
KernelVersion:	5.10
Contact:	Alexander Duyck <alexander.h.duyck@linux.intel.com>
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.
+6 −0
Original line number Diff line number Diff line
@@ -9038,6 +9038,12 @@ 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" <david.e.box@linux.intel.com>
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 <stas.yakovlev@gmail.com>
L:	linux-wireless@vger.kernel.org
+10 −0
Original line number Diff line number Diff line
@@ -699,6 +699,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
+1 −0
Original line number Diff line number Diff line
@@ -216,6 +216,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
+261 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Intel Platform Monitoring Technology PMT driver
 *
 * Copyright (c) 2020, Intel Corporation.
 * All Rights Reserved.
 *
 * Author: David E. Box <david.e.box@linux.intel.com>
 */

#include <linux/bits.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>

/* 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),

	/* DVSEC not present (provided in driver data) */
	PMT_QUIRK_NO_DVSEC	= BIT(3),
};

struct pmt_platform_info {
	unsigned long quirks;
	struct intel_dvsec_header **capabilities;
};

static const struct pmt_platform_info tgl_info = {
	.quirks = PMT_QUIRK_NO_WATCHER | PMT_QUIRK_NO_CRASHLOG |
		  PMT_QUIRK_TABLE_SHIFT,
};

/* DG1 Platform with DVSEC quirk*/
static struct intel_dvsec_header dg1_telemetry = {
	.length = 0x10,
	.id = 2,
	.num_entries = 1,
	.entry_size = 3,
	.tbir = 0,
	.offset = 0x466000,
};

static struct intel_dvsec_header *dg1_capabilities[] = {
	&dg1_telemetry,
	NULL
};

static const struct pmt_platform_info dg1_info = {
	.quirks = PMT_QUIRK_NO_DVSEC,
	.capabilities = dg1_capabilities,
};

static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header,
		       unsigned long quirks)
{
	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 (quirks & PMT_QUIRK_NO_WATCHER) {
			dev_info(dev, "Watcher not supported\n");
			return -EINVAL;
		}
		name = "pmt_watcher";
		break;
	case DVSEC_INTEL_ID_CRASHLOG:
		if (quirks & PMT_QUIRK_NO_CRASHLOG) {
			dev_info(dev, "Crashlog not supported\n");
			return -EINVAL;
		}
		name = "pmt_crashlog";
		break;
	default:
		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 (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;
	unsigned long quirks = 0;
	bool found_devices = false;
	int ret, pos = 0;

	ret = pcim_enable_device(pdev);
	if (ret)
		return ret;

	info = (struct pmt_platform_info *)id->driver_data;

	if (info)
		quirks = info->quirks;

	if (info && (info->quirks & PMT_QUIRK_NO_DVSEC)) {
		struct intel_dvsec_header **header;

		header = info->capabilities;
		while (*header) {
			ret = pmt_add_dev(pdev, *header, quirks);
			if (ret)
				dev_warn(&pdev->dev,
					 "Failed to add device for DVSEC id %d\n",
					 (*header)->id);
			else
				found_devices = true;

			++header;
		}
	} else {
		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, quirks);
			if (ret)
				continue;

			found_devices = true;
		} while (true);
	}

	if (!found_devices)
		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_DG1	0x490e
#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_DG1, &dg1_info) },
	{ PCI_DEVICE_DATA(INTEL, PMT_OOBMSM, NULL) },
	{ 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 <david.e.box@linux.intel.com>");
MODULE_DESCRIPTION("Intel Platform Monitoring Technology PMT driver");
MODULE_LICENSE("GPL v2");
Loading