Message ID | 20200505023149.11630-1-david.e.box@linux.intel.com |
---|---|
State | New |
Headers | show |
Series | [1/3] pci: Add Designated Vendor Specific Capability | expand |
On 5/4/20 7:31 PM, David E. Box wrote: > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig > index 0a59249198d3..c673031acdf1 100644 > --- a/drivers/mfd/Kconfig > +++ b/drivers/mfd/Kconfig > @@ -632,6 +632,16 @@ config MFD_INTEL_MSIC > Passage) chip. This chip embeds audio, battery, GPIO, etc. > devices used in Intel Medfield platforms. > > +config MFD_INTEL_PMT > + tristate "Intel Platform Monitoring Technology 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 PTM capabilities/devices for What is PTM? > + platforms starting from Tiger Lake. > + > config MFD_IPAQ_MICRO > bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" > depends on SA1100_H3100 || SA1100_H3600
On Tue, May 5, 2020 at 5:32 AM David E. Box <david.e.box@linux.intel.com> wrote: > > Intel Platform Monitoring Technology (PMT) is an architecture for > enumerating and accessing hardware monitoring facilities. PMT supports > multiple types of monitoring capabilities. Capabilities are discovered > using PCIe DVSEC with the Intel VID. Each capability is discovered as a > separate DVSEC instance in a device's config space. This driver uses MFD to > manage the creation of platform devices for each type so that they may be > controlled by their own drivers (to be introduced). 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. Tiger Lake however will not support Watcher and > Crashlog even though the capabilities appear on the device. So add a quirk > facility and use it to disable them. ... > include/linux/intel-dvsec.h | 44 +++++++++ I guess it's no go for a such header, since we may end up with tons of a such. Perhaps simple pcie-dvsec.h ? ... > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -8783,6 +8783,11 @@ S: Maintained > F: arch/x86/include/asm/intel_telemetry.h > F: drivers/platform/x86/intel_telemetry* > > +INTEL PMT DRIVER > +M: "David E. Box" <david.e.box@linux.intel.com> > +S: Maintained > +F: drivers/mfd/intel_pmt.c I believe you forgot to run parse-maintainers.pl --order --input=MAINTAINERS --output=MAINTAINERS ... > + info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), > + GFP_KERNEL); > + Extra blank line. > + if (!info) > + return -ENOMEM; > + > + while ((pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC))) { > + pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid); > + if (vid != PCI_VENDOR_ID_INTEL) > + continue; Perhaps a candidate for for_each_vendor_cap() macro in pcie-dvsec.h. Or how is it done for the rest of capabilities? > + } ... > +static const struct pci_device_id pmt_pci_ids[] = { > + /* TGL */ > + { PCI_VDEVICE(INTEL, 0x9a0d), (kernel_ulong_t)&tgl_info }, PCI_DEVICE_DATA()? > + { } > +};
On Mon, 2020-05-04 at 19:53 -0700, Randy Dunlap wrote: > On 5/4/20 7:31 PM, David E. Box wrote: > > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig > > index 0a59249198d3..c673031acdf1 100644 > > --- a/drivers/mfd/Kconfig > > +++ b/drivers/mfd/Kconfig > > @@ -632,6 +632,16 @@ config MFD_INTEL_MSIC > > Passage) chip. This chip embeds audio, battery, GPIO, etc. > > devices used in Intel Medfield platforms. > > > > +config MFD_INTEL_PMT > > + tristate "Intel Platform Monitoring Technology 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 PTM capabilities/devices for > > What is PTM? s/PTM/PMT I have the fortune of working on another project involving PCI Precision Time Management.
On Tue, 2020-05-05 at 12:02 +0300, Andy Shevchenko wrote: > On Tue, May 5, 2020 at 5:32 AM David E. Box < > david.e.box@linux.intel.com> wrote: > > Intel Platform Monitoring Technology (PMT) is an architecture for > > enumerating and accessing hardware monitoring facilities. PMT > > supports > > multiple types of monitoring capabilities. Capabilities are > > discovered > > using PCIe DVSEC with the Intel VID. Each capability is discovered > > as a > > separate DVSEC instance in a device's config space. This driver > > uses MFD to > > manage the creation of platform devices for each type so that they > > may be > > controlled by their own drivers (to be introduced). 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. Tiger Lake however will not support Watcher > > and > > Crashlog even though the capabilities appear on the device. So add > > a quirk > > facility and use it to disable them. > > ... > > > include/linux/intel-dvsec.h | 44 +++++++++ > > I guess it's no go for a such header, since we may end up with tons > of > a such. Perhaps simple pcie-dvsec.h ? Too general. Nothing in here applies to all PCIE DVSEC capabilities. The file describes only the vendor defined space in a DVSEC region. > > ... > > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -8783,6 +8783,11 @@ S: Maintained > > F: arch/x86/include/asm/intel_telemetry.h > > F: drivers/platform/x86/intel_telemetry* > > > > +INTEL PMT DRIVER > > +M: "David E. Box" <david.e.box@linux.intel.com> > > +S: Maintained > > +F: drivers/mfd/intel_pmt.c > > I believe you forgot to run parse-maintainers.pl --order > --input=MAINTAINERS --output=MAINTAINERS > > ... > > > + info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, > > sizeof(*info), > > + GFP_KERNEL); > > + > > Extra blank line. > > > + if (!info) > > + return -ENOMEM; > > + > > + while ((pos = pci_find_next_ext_capability(pdev, pos, > > PCI_EXT_CAP_ID_DVSEC))) { > > + pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, > > &vid); > > + if (vid != PCI_VENDOR_ID_INTEL) > > + continue; > > Perhaps a candidate for for_each_vendor_cap() macro in pcie-dvsec.h. > Or how is it done for the rest of capabilities? > > > + } > > ... > > > +static const struct pci_device_id pmt_pci_ids[] = { > > + /* TGL */ > > + { PCI_VDEVICE(INTEL, 0x9a0d), (kernel_ulong_t)&tgl_info }, > > PCI_DEVICE_DATA()? Ack on the rest of the changes.
diff --git a/MAINTAINERS b/MAINTAINERS index e64e5db31497..bacf7ecd4d21 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8783,6 +8783,11 @@ S: Maintained F: arch/x86/include/asm/intel_telemetry.h F: drivers/platform/x86/intel_telemetry* +INTEL PMT DRIVER +M: "David E. Box" <david.e.box@linux.intel.com> +S: Maintained +F: drivers/mfd/intel_pmt.c + INTEL UNCORE FREQUENCY CONTROL M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> L: platform-driver-x86@vger.kernel.org diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0a59249198d3..c673031acdf1 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -632,6 +632,16 @@ config MFD_INTEL_MSIC Passage) chip. This chip embeds audio, battery, GPIO, etc. devices used in Intel Medfield platforms. +config MFD_INTEL_PMT + tristate "Intel Platform Monitoring Technology 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 PTM 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 f935d10cbf0f..0041f673faa1 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -212,6 +212,7 @@ 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_MSIC) += intel_msic.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..c48a2b82ca99 --- /dev/null +++ b/drivers/mfd/intel_pmt.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Platform Monitoring Technology MFD driver + * + * Copyright (c) 2020, Intel Corporation. + * All Rights Reserved. + * + * Authors: David E. Box <david.e.box@linux.intel.com> + */ + +#include <linux/kernel.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/mfd/core.h> +#include <linux/intel-dvsec.h> + +#define TELEM_DEV_NAME "pmt_telemetry" +#define WATCHER_DEV_NAME "pmt_watcher" +#define CRASHLOG_DEV_NAME "pmt_crashlog" + +static const struct pmt_platform_info tgl_info = { + .quirks = PMT_QUIRK_NO_WATCHER | PMT_QUIRK_NO_CRASHLOG, +}; + +static int +pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header, + struct pmt_platform_info *info) +{ + struct mfd_cell *cell, *tmp; + const char *name; + int i; + + switch (header->id) { + case DVSEC_INTEL_ID_TELEM: + name = TELEM_DEV_NAME; + break; + case DVSEC_INTEL_ID_WATCHER: + if (info->quirks && PMT_QUIRK_NO_WATCHER) { + dev_info(&pdev->dev, "Watcher not supported\n"); + return 0; + } + name = WATCHER_DEV_NAME; + break; + case DVSEC_INTEL_ID_CRASHLOG: + if (info->quirks && PMT_QUIRK_NO_WATCHER) { + dev_info(&pdev->dev, "Crashlog not supported\n"); + return 0; + } + name = CRASHLOG_DEV_NAME; + break; + default: + return -EINVAL; + } + + cell = devm_kcalloc(&pdev->dev, header->num_entries, + sizeof(*cell), GFP_KERNEL); + if (!cell) + return -ENOMEM; + + /* Create a platform device for each entry. */ + for (i = 0, tmp = cell; i < header->num_entries; i++, tmp++) { + struct resource *res; + + res = devm_kzalloc(&pdev->dev, sizeof(*res), GFP_KERNEL); + if (!res) + return -ENOMEM; + + tmp->name = name; + + res->start = pdev->resource[header->tbir].start + + header->offset + + (i * (INTEL_DVSEC_ENTRY_SIZE << 2)); + res->end = res->start + (header->entry_size << 2) - 1; + res->flags = IORESOURCE_MEM; + + tmp->resources = res; + tmp->num_resources = 1; + tmp->platform_data = header; + tmp->pdata_size = sizeof(*header); + + } + + return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO, cell, + header->num_entries, NULL, 0, NULL); +} + +static int +pmt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + u16 vid; + u32 table; + int ret, pos = 0, last_pos = 0; + struct pmt_platform_info *info; + struct intel_dvsec_header header; + + 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; + + while ((pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC))) { + 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); + + if (!header.num_entries || !header.entry_size) + return -EINVAL; + + 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 devices for DVSEC id %d\n", + header.id); + last_pos = pos; + } + + if (!last_pos) { + 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); +} + +static const struct pci_device_id pmt_pci_ids[] = { + /* TGL */ + { PCI_VDEVICE(INTEL, 0x9a0d), (kernel_ulong_t)&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 MFD driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/intel-dvsec.h b/include/linux/intel-dvsec.h new file mode 100644 index 000000000000..94f606bf8eae --- /dev/null +++ b/include/linux/intel-dvsec.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef INTEL_DVSEC_H +#define INTEL_DVSEC_H + +#include <linux/types.h> + +#define DVSEC_INTEL_ID_TELEM 2 +#define DVSEC_INTEL_ID_WATCHER 3 +#define DVSEC_INTEL_ID_CRASHLOG 4 + +/* 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) >> 3) + +#define INTEL_DVSEC_ENTRY_SIZE 4 + +/* DVSEC header */ +struct intel_dvsec_header { + u16 length; + u16 id; + u8 num_entries; + u8 entry_size; + u8 entry_max; + u8 tbir; + u32 offset; +}; + +enum pmt_quirks { + /* Watcher capability not supported */ + PMT_QUIRK_NO_WATCHER = (1 << 0), + + /* Crashlog capability not supported */ + PMT_QUIRK_NO_CRASHLOG = (1 << 1), +}; + +struct pmt_platform_info { + unsigned long quirks; + struct intel_dvsec_header **capabilities; +}; + +#endif