diff --git a/patches.suse/platform-x86-intel-Move-intel_pmt-from-MFD-to-Auxili.patch b/patches.suse/platform-x86-intel-Move-intel_pmt-from-MFD-to-Auxili.patch new file mode 100644 index 0000000..3d72a52 --- /dev/null +++ b/patches.suse/platform-x86-intel-Move-intel_pmt-from-MFD-to-Auxili.patch @@ -0,0 +1,1185 @@ +From a3c8f906ed5fc1d4895b5e1a5c6ad6e942d6c0ca Mon Sep 17 00:00:00 2001 +From: "David E. Box" +Date: Tue, 7 Dec 2021 17:50:12 -0800 +Subject: [PATCH] platform/x86/intel: Move intel_pmt from MFD to Auxiliary Bus +Git-commit: a3c8f906ed5fc1d4895b5e1a5c6ad6e942d6c0ca +Patch-mainline: v5.17-rc1 +References: bsc#1196591 + +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: Mark Gross +Acked-by: Hans de Goede +Signed-off-by: David E. Box +Link: https://lore.kernel.org/r/20211208015015.891275-4-david.e.box@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Acked-by: Takashi Iwai + +--- + MAINTAINERS | 12 + drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/intel_pmt.c | 261 ------------------ + drivers/platform/x86/intel/Kconfig | 11 + drivers/platform/x86/intel/Makefile | 3 + drivers/platform/x86/intel/pmt/Kconfig | 4 + drivers/platform/x86/intel/pmt/class.c | 21 - + drivers/platform/x86/intel/pmt/class.h | 5 + drivers/platform/x86/intel/pmt/crashlog.c | 47 +-- + drivers/platform/x86/intel/pmt/telemetry.c | 46 +-- + drivers/platform/x86/intel/vsec.c | 408 +++++++++++++++++++++++++++++ + drivers/platform/x86/intel/vsec.h | 43 +++ + 13 files changed, 537 insertions(+), 335 deletions(-) + delete mode 100644 drivers/mfd/intel_pmt.c + create mode 100644 drivers/platform/x86/intel/vsec.c + create mode 100644 drivers/platform/x86/intel/vsec.h + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -9526,10 +9526,9 @@ S: Maintained + F: drivers/mfd/intel_soc_pmic* + F: include/linux/mfd/intel_soc_pmic* + +-INTEL PMT DRIVER +-M: "David E. Box" +-S: Maintained +-F: drivers/mfd/intel_pmt.c ++INTEL PMT DRIVERS ++M: David E. Box ++S: Supported + F: drivers/platform/x86/intel/pmt/ + + INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT +@@ -9596,6 +9595,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 ++S: Supported ++F: drivers/platform/x86/intel/vsec.* ++ + INTEL VIRTUAL BUTTON DRIVER + M: AceLan Kao + L: platform-driver-x86@vger.kernel.org +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -674,16 +674,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 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 +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -212,7 +212,6 @@ obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lp + 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 +--- a/drivers/mfd/intel_pmt.c ++++ /dev/null +@@ -1,261 +0,0 @@ +-// 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), +- +- /* 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 "); +-MODULE_DESCRIPTION("Intel Platform Monitoring Technology PMT driver"); +-MODULE_LICENSE("GPL v2"); +--- a/drivers/platform/x86/intel/Kconfig ++++ b/drivers/platform/x86/intel/Kconfig +@@ -21,4 +21,15 @@ source "drivers/platform/x86/intel/int34 + source "drivers/platform/x86/intel/pmc/Kconfig" + source "drivers/platform/x86/intel/pmt/Kconfig" + ++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 +--- a/drivers/platform/x86/intel/Makefile ++++ b/drivers/platform/x86/intel/Makefile +@@ -8,3 +8,6 @@ obj-$(CONFIG_INTEL_CHT_INT33FE) += int3 + obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/ + obj-$(CONFIG_INTEL_PMC_CORE) += pmc/ + obj-$(CONFIG_INTEL_PMT_CLASS) += pmt/ ++ ++intel_vsec-y := vsec.o ++obj-$(CONFIG_INTEL_VSEC) += intel_vsec.o +--- a/drivers/platform/x86/intel/pmt/Kconfig ++++ b/drivers/platform/x86/intel/pmt/Kconfig +@@ -17,7 +17,7 @@ config INTEL_PMT_CLASS + + config INTEL_PMT_TELEMETRY + tristate "Intel Platform Monitoring Technology (PMT) Telemetry driver" +- depends on MFD_INTEL_PMT ++ depends on INTEL_VSEC + select INTEL_PMT_CLASS + help + The Intel Platform Monitory Technology (PMT) Telemetry driver provides +@@ -29,7 +29,7 @@ config INTEL_PMT_TELEMETRY + + config INTEL_PMT_CRASHLOG + tristate "Intel Platform Monitoring Technology (PMT) Crashlog driver" +- depends on MFD_INTEL_PMT ++ depends on INTEL_VSEC + select INTEL_PMT_CLASS + help + The Intel Platform Monitoring Technology (PMT) crashlog driver provides +--- a/drivers/platform/x86/intel/pmt/class.c ++++ b/drivers/platform/x86/intel/pmt/class.c +@@ -13,6 +13,7 @@ + #include + #include + ++#include "../vsec.h" + #include "class.h" + + #define PMT_XA_START 0 +@@ -281,31 +282,29 @@ fail_dev_create: + return ret; + } + +-int intel_pmt_dev_create(struct intel_pmt_entry *entry, +- struct intel_pmt_namespace *ns, +- struct platform_device *pdev, int idx) ++int intel_pmt_dev_create(struct intel_pmt_entry *entry, struct intel_pmt_namespace *ns, ++ struct intel_vsec_device *intel_vsec_dev, int idx) + { ++ struct device *dev = &intel_vsec_dev->auxdev.dev; + struct intel_pmt_header header; + struct resource *disc_res; +- int ret = -ENODEV; ++ int ret; + +- disc_res = platform_get_resource(pdev, IORESOURCE_MEM, idx); +- if (!disc_res) +- return ret; ++ disc_res = &intel_vsec_dev->resource[idx]; + +- entry->disc_table = devm_platform_ioremap_resource(pdev, idx); ++ entry->disc_table = devm_ioremap_resource(dev, disc_res); + if (IS_ERR(entry->disc_table)) + return PTR_ERR(entry->disc_table); + +- ret = ns->pmt_header_decode(entry, &header, &pdev->dev); ++ ret = ns->pmt_header_decode(entry, &header, dev); + if (ret) + return ret; + +- ret = intel_pmt_populate_entry(entry, &header, &pdev->dev, disc_res); ++ ret = intel_pmt_populate_entry(entry, &header, dev, disc_res); + if (ret) + return ret; + +- return intel_pmt_dev_register(entry, ns, &pdev->dev); ++ return intel_pmt_dev_register(entry, ns, dev); + + } + EXPORT_SYMBOL_GPL(intel_pmt_dev_create); +--- a/drivers/platform/x86/intel/pmt/class.h ++++ b/drivers/platform/x86/intel/pmt/class.h +@@ -2,13 +2,14 @@ + #ifndef _INTEL_PMT_CLASS_H + #define _INTEL_PMT_CLASS_H + +-#include + #include + #include + #include + #include + #include + ++#include "../vsec.h" ++ + /* PMT access types */ + #define ACCESS_BARID 2 + #define ACCESS_LOCAL 3 +@@ -47,7 +48,7 @@ struct intel_pmt_namespace { + bool intel_pmt_is_early_client_hw(struct device *dev); + int intel_pmt_dev_create(struct intel_pmt_entry *entry, + struct intel_pmt_namespace *ns, +- struct platform_device *pdev, int idx); ++ struct intel_vsec_device *dev, int idx); + void intel_pmt_dev_destroy(struct intel_pmt_entry *entry, + struct intel_pmt_namespace *ns); + #endif +--- a/drivers/platform/x86/intel/pmt/crashlog.c ++++ b/drivers/platform/x86/intel/pmt/crashlog.c +@@ -8,6 +8,7 @@ + * Author: "Alexander Duyck" + */ + ++#include + #include + #include + #include +@@ -15,10 +16,9 @@ + #include + #include + ++#include "../vsec.h" + #include "class.h" + +-#define DRV_NAME "pmt_crashlog" +- + /* Crashlog discovery header types */ + #define CRASH_TYPE_OOBMSM 1 + +@@ -257,34 +257,34 @@ static struct intel_pmt_namespace pmt_cr + /* + * initialization + */ +-static int pmt_crashlog_remove(struct platform_device *pdev) ++static void pmt_crashlog_remove(struct auxiliary_device *auxdev) + { +- struct pmt_crashlog_priv *priv = platform_get_drvdata(pdev); ++ struct pmt_crashlog_priv *priv = auxiliary_get_drvdata(auxdev); + 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) ++static int pmt_crashlog_probe(struct auxiliary_device *auxdev, ++ const struct auxiliary_device_id *id) + { ++ struct intel_vsec_device *intel_vsec_dev = auxdev_to_ivdev(auxdev); + struct pmt_crashlog_priv *priv; + size_t size; + int i, ret; + +- size = struct_size(priv, entry, pdev->num_resources); +- priv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); ++ size = struct_size(priv, entry, intel_vsec_dev->num_resources); ++ priv = devm_kzalloc(&auxdev->dev, size, GFP_KERNEL); + if (!priv) + return -ENOMEM; + +- platform_set_drvdata(pdev, priv); ++ auxiliary_set_drvdata(auxdev, priv); + +- for (i = 0; i < pdev->num_resources; i++) { ++ for (i = 0; i < intel_vsec_dev->num_resources; i++) { + struct intel_pmt_entry *entry = &priv->entry[i].entry; + +- ret = intel_pmt_dev_create(entry, &pmt_crashlog_ns, pdev, i); ++ ret = intel_pmt_dev_create(entry, &pmt_crashlog_ns, intel_vsec_dev, i); + if (ret < 0) + goto abort_probe; + if (ret) +@@ -295,26 +295,30 @@ static int pmt_crashlog_probe(struct pla + + return 0; + abort_probe: +- pmt_crashlog_remove(pdev); ++ pmt_crashlog_remove(auxdev); + return ret; + } + +-static struct platform_driver pmt_crashlog_driver = { +- .driver = { +- .name = DRV_NAME, +- }, +- .remove = pmt_crashlog_remove, +- .probe = pmt_crashlog_probe, ++static const struct auxiliary_device_id pmt_crashlog_id_table[] = { ++ { .name = "intel_vsec.crashlog" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(auxiliary, pmt_crashlog_id_table); ++ ++static struct auxiliary_driver pmt_crashlog_aux_driver = { ++ .id_table = pmt_crashlog_id_table, ++ .remove = pmt_crashlog_remove, ++ .probe = pmt_crashlog_probe, + }; + + static int __init pmt_crashlog_init(void) + { +- return platform_driver_register(&pmt_crashlog_driver); ++ return auxiliary_driver_register(&pmt_crashlog_aux_driver); + } + + static void __exit pmt_crashlog_exit(void) + { +- platform_driver_unregister(&pmt_crashlog_driver); ++ auxiliary_driver_unregister(&pmt_crashlog_aux_driver); + xa_destroy(&crashlog_array); + } + +@@ -323,5 +327,4 @@ module_exit(pmt_crashlog_exit); + + MODULE_AUTHOR("Alexander Duyck "); + MODULE_DESCRIPTION("Intel PMT Crashlog driver"); +-MODULE_ALIAS("platform:" DRV_NAME); + MODULE_LICENSE("GPL v2"); +--- a/drivers/platform/x86/intel/pmt/telemetry.c ++++ b/drivers/platform/x86/intel/pmt/telemetry.c +@@ -8,6 +8,7 @@ + * Author: "David E. Box" + */ + ++#include + #include + #include + #include +@@ -15,10 +16,9 @@ + #include + #include + ++#include "../vsec.h" + #include "class.h" + +-#define TELEM_DEV_NAME "pmt_telemetry" +- + #define TELEM_SIZE_OFFSET 0x0 + #define TELEM_GUID_OFFSET 0x4 + #define TELEM_BASE_OFFSET 0x8 +@@ -79,34 +79,33 @@ static struct intel_pmt_namespace pmt_te + .pmt_header_decode = pmt_telem_header_decode, + }; + +-static int pmt_telem_remove(struct platform_device *pdev) ++static void pmt_telem_remove(struct auxiliary_device *auxdev) + { +- struct pmt_telem_priv *priv = platform_get_drvdata(pdev); ++ struct pmt_telem_priv *priv = auxiliary_get_drvdata(auxdev); + 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) ++static int pmt_telem_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id) + { ++ struct intel_vsec_device *intel_vsec_dev = auxdev_to_ivdev(auxdev); + struct pmt_telem_priv *priv; + size_t size; + int i, ret; + +- size = struct_size(priv, entry, pdev->num_resources); +- priv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); ++ size = struct_size(priv, entry, intel_vsec_dev->num_resources); ++ priv = devm_kzalloc(&auxdev->dev, size, GFP_KERNEL); + if (!priv) + return -ENOMEM; + +- platform_set_drvdata(pdev, priv); ++ auxiliary_set_drvdata(auxdev, priv); + +- for (i = 0; i < pdev->num_resources; i++) { ++ for (i = 0; i < intel_vsec_dev->num_resources; i++) { + struct intel_pmt_entry *entry = &priv->entry[i]; + +- ret = intel_pmt_dev_create(entry, &pmt_telem_ns, pdev, i); ++ ret = intel_pmt_dev_create(entry, &pmt_telem_ns, intel_vsec_dev, i); + if (ret < 0) + goto abort_probe; + if (ret) +@@ -117,32 +116,35 @@ static int pmt_telem_probe(struct platfo + + return 0; + abort_probe: +- pmt_telem_remove(pdev); ++ pmt_telem_remove(auxdev); + return ret; + } + +-static struct platform_driver pmt_telem_driver = { +- .driver = { +- .name = TELEM_DEV_NAME, +- }, +- .remove = pmt_telem_remove, +- .probe = pmt_telem_probe, ++static const struct auxiliary_device_id pmt_telem_id_table[] = { ++ { .name = "intel_vsec.telemetry" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(auxiliary, pmt_telem_id_table); ++ ++static struct auxiliary_driver pmt_telem_aux_driver = { ++ .id_table = pmt_telem_id_table, ++ .remove = pmt_telem_remove, ++ .probe = pmt_telem_probe, + }; + + static int __init pmt_telem_init(void) + { +- return platform_driver_register(&pmt_telem_driver); ++ return auxiliary_driver_register(&pmt_telem_aux_driver); + } + module_init(pmt_telem_init); + + static void __exit pmt_telem_exit(void) + { +- platform_driver_unregister(&pmt_telem_driver); ++ auxiliary_driver_unregister(&pmt_telem_aux_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"); +--- /dev/null ++++ b/drivers/platform/x86/intel/vsec.c +@@ -0,0 +1,408 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Intel Vendor Specific Extended Capabilities auxiliary bus driver ++ * ++ * Copyright (c) 2021, Intel Corporation. ++ * All Rights Reserved. ++ * ++ * Author: David E. Box ++ * ++ * This driver discovers and creates auxiliary devices for Intel defined PCIe ++ * "Vendor Specific" and "Designated Vendor Specific" Extended Capabilities, ++ * VSEC and DVSEC respectively. The driver supports features on specific PCIe ++ * endpoints that exist primarily to expose them. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vsec.h" ++ ++/* Intel DVSEC 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 TABLE_OFFSET_SHIFT 3 ++ ++static DEFINE_IDA(intel_vsec_ida); ++ ++/** ++ * struct intel_vsec_header - Common fields of Intel VSEC and DVSEC registers. ++ * @rev: Revision ID of the VSEC/DVSEC register space ++ * @length: Length of the VSEC/DVSEC register space ++ * @id: ID of the feature ++ * @num_entries: Number of instances of the feature ++ * @entry_size: Size of the discovery table for each feature ++ * @tbir: BAR containing the discovery tables ++ * @offset: BAR offset of start of the first discovery table ++ */ ++struct intel_vsec_header { ++ u8 rev; ++ u16 length; ++ u16 id; ++ u8 num_entries; ++ u8 entry_size; ++ u8 tbir; ++ u32 offset; ++}; ++ ++/* Platform specific data */ ++struct intel_vsec_platform_info { ++ struct intel_vsec_header **capabilities; ++ unsigned long quirks; ++}; ++ ++enum intel_vsec_id { ++ VSEC_ID_TELEMETRY = 2, ++ VSEC_ID_WATCHER = 3, ++ VSEC_ID_CRASHLOG = 4, ++}; ++ ++static enum intel_vsec_id intel_vsec_allow_list[] = { ++ VSEC_ID_TELEMETRY, ++ VSEC_ID_WATCHER, ++ VSEC_ID_CRASHLOG, ++}; ++ ++static const char *intel_vsec_name(enum intel_vsec_id id) ++{ ++ switch (id) { ++ case VSEC_ID_TELEMETRY: ++ return "telemetry"; ++ ++ case VSEC_ID_WATCHER: ++ return "watcher"; ++ ++ case VSEC_ID_CRASHLOG: ++ return "crashlog"; ++ ++ default: ++ return NULL; ++ } ++} ++ ++static bool intel_vsec_allowed(u16 id) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(intel_vsec_allow_list); i++) ++ if (intel_vsec_allow_list[i] == id) ++ return true; ++ ++ return false; ++} ++ ++static bool intel_vsec_disabled(u16 id, unsigned long quirks) ++{ ++ switch (id) { ++ case VSEC_ID_WATCHER: ++ return !!(quirks & VSEC_QUIRK_NO_WATCHER); ++ ++ case VSEC_ID_CRASHLOG: ++ return !!(quirks & VSEC_QUIRK_NO_CRASHLOG); ++ ++ default: ++ return false; ++ } ++} ++ ++static void intel_vsec_remove_aux(void *data) ++{ ++ auxiliary_device_delete(data); ++ auxiliary_device_uninit(data); ++} ++ ++static void intel_vsec_dev_release(struct device *dev) ++{ ++ struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(dev); ++ ++ ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id); ++ kfree(intel_vsec_dev->resource); ++ kfree(intel_vsec_dev); ++} ++ ++static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *intel_vsec_dev, ++ const char *name) ++{ ++ struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev; ++ int ret; ++ ++ ret = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL); ++ if (ret < 0) { ++ kfree(intel_vsec_dev); ++ return ret; ++ } ++ ++ auxdev->id = ret; ++ auxdev->name = name; ++ auxdev->dev.parent = &pdev->dev; ++ auxdev->dev.release = intel_vsec_dev_release; ++ ++ ret = auxiliary_device_init(auxdev); ++ if (ret < 0) { ++ ida_free(intel_vsec_dev->ida, auxdev->id); ++ kfree(intel_vsec_dev->resource); ++ kfree(intel_vsec_dev); ++ return ret; ++ } ++ ++ ret = auxiliary_device_add(auxdev); ++ if (ret < 0) { ++ auxiliary_device_uninit(auxdev); ++ return ret; ++ } ++ ++ return devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux, auxdev); ++} ++ ++static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header, ++ unsigned long quirks) ++{ ++ struct intel_vsec_device *intel_vsec_dev; ++ struct resource *res, *tmp; ++ int i; ++ ++ if (!intel_vsec_allowed(header->id) || intel_vsec_disabled(header->id, quirks)) ++ return -EINVAL; ++ ++ if (!header->num_entries) { ++ dev_dbg(&pdev->dev, "Invalid 0 entry count for header id %d\n", header->id); ++ return -EINVAL; ++ } ++ ++ if (!header->entry_size) { ++ dev_dbg(&pdev->dev, "Invalid 0 entry size for header id %d\n", header->id); ++ return -EINVAL; ++ } ++ ++ intel_vsec_dev = kzalloc(sizeof(*intel_vsec_dev), GFP_KERNEL); ++ if (!intel_vsec_dev) ++ return -ENOMEM; ++ ++ res = kcalloc(header->num_entries, sizeof(*res), GFP_KERNEL); ++ if (!res) { ++ kfree(intel_vsec_dev); ++ return -ENOMEM; ++ } ++ ++ if (quirks & VSEC_QUIRK_TABLE_SHIFT) ++ header->offset >>= TABLE_OFFSET_SHIFT; ++ ++ /* ++ * The DVSEC/VSEC contains the starting offset and count for a block of ++ * discovery tables. Create a resource array of these tables to the ++ * auxiliary device driver. ++ */ ++ for (i = 0, tmp = res; i < header->num_entries; i++, tmp++) { ++ tmp->start = pdev->resource[header->tbir].start + ++ header->offset + i * (header->entry_size * sizeof(u32)); ++ tmp->end = tmp->start + (header->entry_size * sizeof(u32)) - 1; ++ tmp->flags = IORESOURCE_MEM; ++ } ++ ++ intel_vsec_dev->pcidev = pdev; ++ intel_vsec_dev->resource = res; ++ intel_vsec_dev->num_resources = header->num_entries; ++ intel_vsec_dev->quirks = quirks; ++ intel_vsec_dev->ida = &intel_vsec_ida; ++ ++ return intel_vsec_add_aux(pdev, intel_vsec_dev, intel_vsec_name(header->id)); ++} ++ ++static bool intel_vsec_walk_header(struct pci_dev *pdev, unsigned long quirks, ++ struct intel_vsec_header **header) ++{ ++ bool have_devices = false; ++ int ret; ++ ++ for ( ; *header; header++) { ++ ret = intel_vsec_add_dev(pdev, *header, quirks); ++ if (ret) ++ dev_info(&pdev->dev, "Could not add device for DVSEC id %d\n", ++ (*header)->id); ++ else ++ have_devices = true; ++ } ++ ++ return have_devices; ++} ++ ++static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, unsigned long quirks) ++{ ++ bool have_devices = false; ++ int pos = 0; ++ ++ do { ++ struct intel_vsec_header header; ++ u32 table, hdr; ++ u16 vid; ++ int ret; ++ ++ pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC); ++ if (!pos) ++ break; ++ ++ pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER1, &hdr); ++ vid = PCI_DVSEC_HEADER1_VID(hdr); ++ if (vid != PCI_VENDOR_ID_INTEL) ++ continue; ++ ++ /* Support only revision 1 */ ++ header.rev = PCI_DVSEC_HEADER1_REV(hdr); ++ if (header.rev != 1) { ++ dev_info(&pdev->dev, "Unsupported DVSEC revision %d\n", header.rev); ++ continue; ++ } ++ ++ header.length = PCI_DVSEC_HEADER1_LEN(hdr); ++ ++ 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); ++ ++ pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER2, &hdr); ++ header.id = PCI_DVSEC_HEADER2_ID(hdr); ++ ++ ret = intel_vsec_add_dev(pdev, &header, quirks); ++ if (ret) ++ continue; ++ ++ have_devices = true; ++ } while (true); ++ ++ return have_devices; ++} ++ ++static bool intel_vsec_walk_vsec(struct pci_dev *pdev, unsigned long quirks) ++{ ++ bool have_devices = false; ++ int pos = 0; ++ ++ do { ++ struct intel_vsec_header header; ++ u32 table, hdr; ++ int ret; ++ ++ pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_VNDR); ++ if (!pos) ++ break; ++ ++ pci_read_config_dword(pdev, pos + PCI_VNDR_HEADER, &hdr); ++ ++ /* Support only revision 1 */ ++ header.rev = PCI_VNDR_HEADER_REV(hdr); ++ if (header.rev != 1) { ++ dev_info(&pdev->dev, "Unsupported VSEC revision %d\n", header.rev); ++ continue; ++ } ++ ++ header.id = PCI_VNDR_HEADER_ID(hdr); ++ header.length = PCI_VNDR_HEADER_LEN(hdr); ++ ++ /* entry, size, and table offset are the same as DVSEC */ ++ 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 = intel_vsec_add_dev(pdev, &header, quirks); ++ if (ret) ++ continue; ++ ++ have_devices = true; ++ } while (true); ++ ++ return have_devices; ++} ++ ++static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ++{ ++ struct intel_vsec_platform_info *info; ++ bool have_devices = false; ++ unsigned long quirks = 0; ++ int ret; ++ ++ ret = pcim_enable_device(pdev); ++ if (ret) ++ return ret; ++ ++ info = (struct intel_vsec_platform_info *)id->driver_data; ++ if (info) ++ quirks = info->quirks; ++ ++ if (intel_vsec_walk_dvsec(pdev, quirks)) ++ have_devices = true; ++ ++ if (intel_vsec_walk_vsec(pdev, quirks)) ++ have_devices = true; ++ ++ if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) && ++ intel_vsec_walk_header(pdev, quirks, info->capabilities)) ++ have_devices = true; ++ ++ if (!have_devices) ++ return -ENODEV; ++ ++ return 0; ++} ++ ++/* TGL info */ ++static const struct intel_vsec_platform_info tgl_info = { ++ .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG | VSEC_QUIRK_TABLE_SHIFT, ++}; ++ ++/* DG1 info */ ++static struct intel_vsec_header dg1_telemetry = { ++ .length = 0x10, ++ .id = 2, ++ .num_entries = 1, ++ .entry_size = 3, ++ .tbir = 0, ++ .offset = 0x466000, ++}; ++ ++static struct intel_vsec_header *dg1_capabilities[] = { ++ &dg1_telemetry, ++ NULL ++}; ++ ++static const struct intel_vsec_platform_info dg1_info = { ++ .capabilities = dg1_capabilities, ++ .quirks = VSEC_QUIRK_NO_DVSEC, ++}; ++ ++#define PCI_DEVICE_ID_INTEL_VSEC_ADL 0x467d ++#define PCI_DEVICE_ID_INTEL_VSEC_DG1 0x490e ++#define PCI_DEVICE_ID_INTEL_VSEC_OOBMSM 0x09a7 ++#define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d ++static const struct pci_device_id intel_vsec_pci_ids[] = { ++ { PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) }, ++ { PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) }, ++ { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, NULL) }, ++ { PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) }, ++ { } ++}; ++MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids); ++ ++static struct pci_driver intel_vsec_pci_driver = { ++ .name = "intel_vsec", ++ .id_table = intel_vsec_pci_ids, ++ .probe = intel_vsec_pci_probe, ++}; ++module_pci_driver(intel_vsec_pci_driver); ++ ++MODULE_AUTHOR("David E. Box "); ++MODULE_DESCRIPTION("Intel Extended Capabilities auxiliary bus driver"); ++MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/drivers/platform/x86/intel/vsec.h +@@ -0,0 +1,43 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _VSEC_H ++#define _VSEC_H ++ ++#include ++#include ++ ++struct pci_dev; ++struct resource; ++ ++enum intel_vsec_quirks { ++ /* Watcher feature not supported */ ++ VSEC_QUIRK_NO_WATCHER = BIT(0), ++ ++ /* Crashlog feature not supported */ ++ VSEC_QUIRK_NO_CRASHLOG = BIT(1), ++ ++ /* Use shift instead of mask to read discovery table offset */ ++ VSEC_QUIRK_TABLE_SHIFT = BIT(2), ++ ++ /* DVSEC not present (provided in driver data) */ ++ VSEC_QUIRK_NO_DVSEC = BIT(3), ++}; ++ ++struct intel_vsec_device { ++ struct auxiliary_device auxdev; ++ struct pci_dev *pcidev; ++ struct resource *resource; ++ struct ida *ida; ++ unsigned long quirks; ++ int num_resources; ++}; ++ ++static inline struct intel_vsec_device *dev_to_ivdev(struct device *dev) ++{ ++ return container_of(dev, struct intel_vsec_device, auxdev.dev); ++} ++ ++static inline struct intel_vsec_device *auxdev_to_ivdev(struct auxiliary_device *auxdev) ++{ ++ return container_of(auxdev, struct intel_vsec_device, auxdev); ++} ++#endif diff --git a/series.conf b/series.conf index a564ed2..70a3e70 100644 --- a/series.conf +++ b/series.conf @@ -7851,6 +7851,7 @@ patches.suse/pinctrl-renesas-rza1-Fix-kerneldoc-function-names.patch patches.suse/PCI-Add-defines-for-accessing-PCIe-DVSEC-fields.patch patches.suse/driver-core-auxiliary-bus-Add-driver-data-helpers.patch + patches.suse/platform-x86-intel-Move-intel_pmt-from-MFD-to-Auxili.patch patches.suse/debugfs-lockdown-Allow-reading-debugfs-files-that-ar.patch patches.suse/drivers-firmware-Add-missing-platform_device_put-in-.patch patches.suse/staging-rtl8192e-return-error-code-from-rtllib_softm.patch