Commit a3c8f906 authored by David E. Box's avatar David E. Box Committed by Greg Kroah-Hartman
Browse files

platform/x86/intel: Move intel_pmt from MFD to Auxiliary Bus



Intel Platform Monitoring Technology (PMT) support is indicated by presence
of an Intel defined PCIe Designated Vendor Specific Extended Capabilities
(DVSEC) structure with a PMT specific ID. The current MFD implementation
creates child devices for each PMT feature, currently telemetry, watcher,
and crashlog. However DVSEC structures may also be used by Intel to
indicate support for other features. The Out Of Band Management Services
Module (OOBMSM) uses DVSEC to enumerate several features, including PMT.
In order to support them it is necessary to modify the intel_pmt driver to
handle the creation of the child devices more generically. To that end,
modify the driver to create child devices for any VSEC/DVSEC features on
supported devices (indicated by PCI ID).  Additionally, move the
implementation from MFD to the Auxiliary bus.  VSEC/DVSEC features are
really multifunctional PCI devices, not platform devices as MFD was
designed for. Auxiliary bus gives more flexibility by allowing the
definition of custom structures that can be shared between associated
auxiliary devices and the parent device. Also, rename the driver from
intel_pmt to intel_vsec to better reflect the purpose.

This series also removes the current runtime pm support which was not
complete to begin with. None of the current devices require runtime pm.
However the support will be replaced when a device is added that requires
it.

Reviewed-by: default avatarMark Gross <markgross@kernel.org>
Acked-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarDavid E. Box <david.e.box@linux.intel.com>
Link: https://lore.kernel.org/r/20211208015015.891275-4-david.e.box@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 365481e4
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -9741,10 +9741,9 @@ S: Maintained
F:	drivers/mfd/intel_soc_pmic*
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
INTEL PMT DRIVERS
M:	David E. Box <david.e.box@linux.intel.com>
S:	Supported
F:	drivers/platform/x86/intel/pmt/
INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
@@ -9811,6 +9810,11 @@ L: platform-driver-x86@vger.kernel.org
S:	Maintained
F:	drivers/platform/x86/intel/uncore-frequency.c
INTEL VENDOR SPECIFIC EXTENDED CAPABILITIES DRIVER
M:	David E. Box <david.e.box@linux.intel.com>
S:	Supported
F:	drivers/platform/x86/intel/vsec.*
INTEL VIRTUAL BUTTON DRIVER
M:	AceLan Kao <acelan.kao@canonical.com>
L:	platform-driver-x86@vger.kernel.org
+0 −10
Original line number Diff line number Diff line
@@ -692,16 +692,6 @@ 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 X86 && 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
+0 −1
Original line number Diff line number Diff line
@@ -211,7 +211,6 @@ obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o
obj-$(CONFIG_MFD_INTEL_LPSS_PCI)	+= intel-lpss-pci.o
obj-$(CONFIG_MFD_INTEL_LPSS_ACPI)	+= intel-lpss-acpi.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_NTXEC)		+= ntxec.o

drivers/mfd/intel_pmt.c

deleted100644 → 0
+0 −261
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");
+11 −0
Original line number Diff line number Diff line
@@ -184,4 +184,15 @@ config INTEL_UNCORE_FREQ_CONTROL
	  To compile this driver as a module, choose M here: the module
	  will be called intel-uncore-frequency.

config INTEL_VSEC
	tristate "Intel Vendor Specific Extended Capabilities Driver"
	depends on PCI
	select AUXILIARY_BUS
	help
	  Adds support for feature drivers exposed using Intel PCIe VSEC and
	  DVSEC.

	  To compile this driver as a module, choose M here: the module will
	  be called intel_vsec.

endif # X86_PLATFORM_DRIVERS_INTEL
Loading