diff --git a/MAINTAINERS b/MAINTAINERS index ca6d6fde85cf88..4e55a9f33fa377 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9369,6 +9369,11 @@ S: Supported F: drivers/infiniband/hw/irdma/ F: include/uapi/rdma/irdma-abi.h +INTEL EXTENDED CAPABILITIES DRIVER +M: "David E. Box" +S: Supported +F: drivers/platform/x86/intel/extended_caps.* + INTEL FRAMEBUFFER DRIVER (excluding 810 and 815) M: Maik Broemme L: linux-fbdev@vger.kernel.org @@ -9578,10 +9583,9 @@ S: Maintained F: drivers/mfd/intel_soc_pmic* F: include/linux/mfd/intel_soc_pmic* -INTEL PMT DRIVER +INTEL PMT DRIVERS M: "David E. Box" -S: Maintained -F: drivers/mfd/intel_pmt.c +S: Supported F: drivers/platform/x86/intel/pmt/ INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ca0edab91aeb63..d7648473bbec44 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -690,16 +690,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 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2ba6646e874cdd..e0db12a24d1f96 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -212,7 +212,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 diff --git a/drivers/mfd/intel_pmt.c b/drivers/mfd/intel_pmt.c deleted file mode 100644 index dd7eb614c28e47..00000000000000 --- 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"); diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index 0b21468e1bd01f..d7492372efc3ae 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -26,6 +26,17 @@ source "drivers/platform/x86/intel/speed_select_if/Kconfig" source "drivers/platform/x86/intel/telemetry/Kconfig" source "drivers/platform/x86/intel/wmi/Kconfig" +config INTEL_EXTENDED_CAPS + tristate "Intel Extended Capabilities support" + 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_extended_caps. + config INTEL_HID_EVENT tristate "Intel HID Event" depends on ACPI diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index 8b3a3f7bab49ad..6f5bee0e1f5876 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -21,6 +21,8 @@ intel-vbtn-y := vbtn.o obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o # Intel miscellaneous drivers +intel_extended_caps-y := extended_caps.o +obj-$(CONFIG_INTEL_EXTENDED_CAPS) += intel_extended_caps.o intel_int0002_vgpio-y := int0002_vgpio.o obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o intel_oaktrail-y := oaktrail.o diff --git a/drivers/platform/x86/intel/extended_caps.c b/drivers/platform/x86/intel/extended_caps.c new file mode 100644 index 00000000000000..03acea20b6753e --- /dev/null +++ b/drivers/platform/x86/intel/extended_caps.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Extended Capabilities auxiliary bus driver + * + * Copyright (c) 2021, Intel Corporation. + * All Rights Reserved. + * + * Author: David E. Box + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "extended_caps.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 + +/* EXT_CAPS capabilities */ +#define EXTENDED_CAP_ID_TELEMETRY 2 +#define EXTENDED_CAP_ID_WATCHER 3 +#define EXTENDED_CAP_ID_CRASHLOG 4 + +static DEFINE_IDA(extended_caps_ida); + +static int extended_caps_allow_list[] = { + EXTENDED_CAP_ID_TELEMETRY, + EXTENDED_CAP_ID_WATCHER, + EXTENDED_CAP_ID_CRASHLOG, +}; + +struct extended_caps_platform_info { + struct extended_caps_header **capabilities; + unsigned long quirks; +}; + +static const struct extended_caps_platform_info tgl_info = { + .quirks = EXT_CAPS_QUIRK_NO_WATCHER | EXT_CAPS_QUIRK_NO_CRASHLOG | + EXT_CAPS_QUIRK_TABLE_SHIFT, +}; + +/* DG1 Platform with DVSEC quirk*/ +static struct extended_caps_header dg1_telemetry = { + .length = 0x10, + .id = 2, + .num_entries = 1, + .entry_size = 3, + .tbir = 0, + .offset = 0x466000, +}; + +static struct extended_caps_header *dg1_capabilities[] = { + &dg1_telemetry, + NULL +}; + +static const struct extended_caps_platform_info dg1_info = { + .capabilities = dg1_capabilities, + .quirks = EXT_CAPS_QUIRK_NO_DVSEC, +}; + +static bool extended_caps_allowed(u16 id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(extended_caps_allow_list); i++) + if (extended_caps_allow_list[i] == id) + return true; + + return false; +} + +static bool extended_caps_disabled(u16 id, unsigned long quirks) +{ + switch (id) { + case EXTENDED_CAP_ID_WATCHER: + return !!(quirks & EXT_CAPS_QUIRK_NO_WATCHER); + + case EXTENDED_CAP_ID_CRASHLOG: + return !!(quirks & EXT_CAPS_QUIRK_NO_CRASHLOG); + + default: + return false; + } +} + +struct resource *intel_ext_cap_get_resource(struct intel_extended_cap_device *intel_cap_dev, + unsigned int num) +{ + u32 i; + + for (i = 0; i < intel_cap_dev->num_resources; i++) { + struct resource *r = &intel_cap_dev->resource[i]; + + if (num-- == 0) + return r; + } + return NULL; +} +EXPORT_SYMBOL_NS(intel_ext_cap_get_resource, INTEL_EXT_CAPS); + +static void extended_caps_remove_aux(void *data) +{ + auxiliary_device_delete(data); + auxiliary_device_uninit(data); +} + +static void extended_caps_dev_release(struct device *dev) +{ + struct intel_extended_cap_device *intel_cap_dev = + container_of(dev, struct intel_extended_cap_device, aux_dev.dev); + + ida_free(&extended_caps_ida, intel_cap_dev->aux_dev.id); + kfree(intel_cap_dev->resource); + kfree(intel_cap_dev); +} + +static int extended_caps_add_dev(struct pci_dev *pdev, struct extended_caps_header *header, + unsigned long quirks) +{ + struct intel_extended_cap_device *intel_cap_dev; + struct auxiliary_device *aux_dev; + struct resource *res, *tmp; + int count = header->num_entries; + int size = header->entry_size; + int id = header->id; + char id_str[8]; + int ret, i; + + if (!extended_caps_allowed(id)) + return -EINVAL; + + if (extended_caps_disabled(id, quirks)) + return -EINVAL; + + if (!header->num_entries) { + dev_err(&pdev->dev, "Invalid 0 entry count for header id %d\n", id); + return -EINVAL; + } + + if (!header->entry_size) { + dev_err(&pdev->dev, "Invalid 0 entry size for headerid %d\n", id); + return -EINVAL; + } + + intel_cap_dev = kzalloc(sizeof(*intel_cap_dev), GFP_KERNEL); + if (!intel_cap_dev) + return -ENOMEM; + + res = kcalloc(count, sizeof(*res), GFP_KERNEL); + if (!res) { + kfree(intel_cap_dev); + return -ENOMEM; + } + + if (quirks & EXT_CAPS_QUIRK_TABLE_SHIFT) + header->offset >>= 3; + + /* + * The DVSEC/VSEC contains the starting offset and count for a block of + * discovery tables. Create a resource list of these tables to the + * auxiliary device driver. + */ + for (i = 0, tmp = res; i < count; i++, tmp++) { + tmp->start = pdev->resource[header->tbir].start + + header->offset + i * (size * sizeof(u32)); + tmp->end = tmp->start + (size * sizeof(u32)) - 1; + tmp->flags = IORESOURCE_MEM; + } + + intel_cap_dev->header = header; + intel_cap_dev->pcidev = pdev; + intel_cap_dev->resource = res; + intel_cap_dev->num_resources = count; + intel_cap_dev->quirks = quirks; + + snprintf(id_str, sizeof(id_str), "%d", id); + + aux_dev = &intel_cap_dev->aux_dev; + aux_dev->name = id_str; + aux_dev->dev.parent = &pdev->dev; + aux_dev->dev.release = extended_caps_dev_release; + + ret = ida_alloc(&extended_caps_ida, GFP_KERNEL); + if (ret < 0) { + kfree(res); + kfree(intel_cap_dev); + return ret; + } + aux_dev->id = ret; + + ret = auxiliary_device_init(aux_dev); + if (ret < 0) { + ida_free(&extended_caps_ida, aux_dev->id); + kfree(res); + kfree(intel_cap_dev); + return ret; + } + + ret = auxiliary_device_add(aux_dev); + if (ret) { + auxiliary_device_uninit(aux_dev); + ida_free(&extended_caps_ida, aux_dev->id); + kfree(res); + kfree(intel_cap_dev); + return ret; + } + + return devm_add_action_or_reset(&pdev->dev, extended_caps_remove_aux, aux_dev); +} + +static bool extended_caps_walk_header(struct pci_dev *pdev, unsigned long quirks, + struct extended_caps_header **header) +{ + bool have_devices = false; + int ret; + + while (*header) { + ret = extended_caps_add_dev(pdev, *header, quirks); + if (ret) + dev_warn(&pdev->dev, + "Failed to add device for DVSEC id %d\n", + (*header)->id); + else + have_devices = true; + + ++header; + } + + return have_devices; +} + +static bool extended_caps_walk_dvsec(struct pci_dev *pdev, unsigned long quirks) +{ + bool have_devices = false; + int pos = 0; + + do { + struct extended_caps_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_warn(&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 = extended_caps_add_dev(pdev, &header, quirks); + if (ret) + continue; + + have_devices = true; + } while (true); + + return have_devices; +} + +static int extended_caps_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct extended_caps_platform_info *info; + bool have_devices = false; + unsigned long quirks = 0; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + info = (struct extended_caps_platform_info *)id->driver_data; + if (info) + quirks = info->quirks; + + have_devices |= extended_caps_walk_dvsec(pdev, quirks); + + if (info && (info->quirks & EXT_CAPS_QUIRK_NO_DVSEC)) + have_devices |= extended_caps_walk_header(pdev, quirks, info->capabilities); + + if (!have_devices) + return -ENODEV; + + return 0; +} + +static void extended_caps_pci_remove(struct pci_dev *pdev) +{ +} + +#define PCI_DEVICE_ID_INTEL_EXT_CAPS_ADL 0x467d +#define PCI_DEVICE_ID_INTEL_EXT_CAPS_DG1 0x490e +#define PCI_DEVICE_ID_INTEL_EXT_CAPS_OOBMSM 0x09a7 +#define PCI_DEVICE_ID_INTEL_EXT_CAPS_TGL 0x9a0d +static const struct pci_device_id extended_caps_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, EXT_CAPS_ADL, &tgl_info) }, + { PCI_DEVICE_DATA(INTEL, EXT_CAPS_DG1, &dg1_info) }, + { PCI_DEVICE_DATA(INTEL, EXT_CAPS_OOBMSM, NULL) }, + { PCI_DEVICE_DATA(INTEL, EXT_CAPS_TGL, &tgl_info) }, + { } +}; +MODULE_DEVICE_TABLE(pci, extended_caps_pci_ids); + +static struct pci_driver extended_caps_pci_driver = { + .name = "intel_extended_caps", + .id_table = extended_caps_pci_ids, + .probe = extended_caps_pci_probe, + .remove = extended_caps_pci_remove, +}; +module_pci_driver(extended_caps_pci_driver); + +MODULE_AUTHOR("David E. Box "); +MODULE_DESCRIPTION("Intel Extended Capabilities auxiliary bus driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/intel/extended_caps.h b/drivers/platform/x86/intel/extended_caps.h new file mode 100644 index 00000000000000..952e7150f30899 --- /dev/null +++ b/drivers/platform/x86/intel/extended_caps.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _EXTENDED_CAPS_H +#define _EXTENDED_CAPS_H + +#include + +struct extended_caps_header { + u8 rev; + u16 length; + u16 id; + u8 num_entries; + u8 entry_size; + u8 tbir; + u32 offset; +}; + +enum extended_caps_quirks { + /* Watcher capability not supported */ + EXT_CAPS_QUIRK_NO_WATCHER = BIT(0), + + /* Crashlog capability not supported */ + EXT_CAPS_QUIRK_NO_CRASHLOG = BIT(1), + + /* Use shift instead of mask to read discovery table offset */ + EXT_CAPS_QUIRK_TABLE_SHIFT = BIT(2), + + /* DVSEC not present (provided in driver data) */ + EXT_CAPS_QUIRK_NO_DVSEC = BIT(3), +}; + +struct intel_extended_cap_device { + struct auxiliary_device aux_dev; + struct extended_caps_header *header; + struct pci_dev *pcidev; + struct resource *resource; + unsigned long quirks; + int num_resources; +}; + +struct resource *intel_ext_cap_get_resource(struct intel_extended_cap_device *intel_cap_dev, + unsigned int num); +#endif diff --git a/drivers/platform/x86/intel/pmt/Kconfig b/drivers/platform/x86/intel/pmt/Kconfig index d630f883a71732..8eaedd242dba17 100644 --- 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_EXTENDED_CAPS 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_EXTENDED_CAPS select INTEL_PMT_CLASS help The Intel Platform Monitoring Technology (PMT) crashlog driver provides diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c index 659b1073033c2e..1414170b0aebfe 100644 --- a/drivers/platform/x86/intel/pmt/class.c +++ b/drivers/platform/x86/intel/pmt/class.c @@ -14,6 +14,7 @@ #include #include "class.h" +#include "../extended_caps.h" #define PMT_XA_START 0 #define PMT_XA_MAX INT_MAX @@ -281,31 +282,31 @@ static int intel_pmt_dev_register(struct intel_pmt_entry *entry, 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_extended_cap_device *intel_cap_dev, int idx) { + struct device *dev = &intel_cap_dev->aux_dev.dev; struct intel_pmt_header header; struct resource *disc_res; int ret = -ENODEV; - disc_res = platform_get_resource(pdev, IORESOURCE_MEM, idx); + disc_res = intel_ext_cap_get_resource(intel_cap_dev, idx); if (!disc_res) return ret; - 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); @@ -342,3 +343,4 @@ module_exit(pmt_class_exit); MODULE_AUTHOR("Alexander Duyck "); MODULE_DESCRIPTION("Intel PMT Class driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(INTEL_EXT_CAPS); diff --git a/drivers/platform/x86/intel/pmt/class.h b/drivers/platform/x86/intel/pmt/class.h index 1337019c2873eb..b2a5e459a7edb1 100644 --- 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 "../extended_caps.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_extended_cap_device *dev, int idx); void intel_pmt_dev_destroy(struct intel_pmt_entry *entry, struct intel_pmt_namespace *ns); #endif diff --git a/drivers/platform/x86/intel/pmt/crashlog.c b/drivers/platform/x86/intel/pmt/crashlog.c index 1c1021f04d3ca4..1565f9e9f8362b 100644 --- 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 "../extended_caps.h" #include "class.h" -#define DRV_NAME "pmt_crashlog" - /* Crashlog discovery header types */ #define CRASH_TYPE_OOBMSM 1 @@ -257,34 +257,35 @@ static struct intel_pmt_namespace pmt_crashlog_ns = { /* * initialization */ -static int pmt_crashlog_remove(struct platform_device *pdev) +static void pmt_crashlog_remove(struct auxiliary_device *adev) { - struct pmt_crashlog_priv *priv = platform_get_drvdata(pdev); + struct pmt_crashlog_priv *priv = dev_get_drvdata(&adev->dev); 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 *adev, + const struct auxiliary_device_id *id) { + struct intel_extended_cap_device *intel_cap_dev = + container_of(adev, struct intel_extended_cap_device, aux_dev); 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_cap_dev->num_resources); + priv = devm_kzalloc(&adev->dev, size, GFP_KERNEL); if (!priv) return -ENOMEM; - platform_set_drvdata(pdev, priv); + dev_set_drvdata(&adev->dev, priv); - for (i = 0; i < pdev->num_resources; i++) { + for (i = 0; i < intel_cap_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_cap_dev, i); if (ret < 0) goto abort_probe; if (ret) @@ -295,26 +296,29 @@ static int pmt_crashlog_probe(struct platform_device *pdev) return 0; abort_probe: - pmt_crashlog_remove(pdev); + pmt_crashlog_remove(adev); return ret; } -static struct platform_driver pmt_crashlog_driver = { - .driver = { - .name = DRV_NAME, - }, +static const struct auxiliary_device_id pmt_crashlog_aux_id_table[] = { + { .name = "intel_extended_caps.4", }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, pmt_crashlog_aux_id_table); + +static struct auxiliary_driver pmt_crashlog_aux_driver = { .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"); diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c index 38d52651c5729e..2f6a10772cbe82 100644 --- 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 "../extended_caps.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,34 @@ static struct intel_pmt_namespace pmt_telem_ns = { .pmt_header_decode = pmt_telem_header_decode, }; -static int pmt_telem_remove(struct platform_device *pdev) +static void pmt_telem_remove(struct auxiliary_device *adev) { - struct pmt_telem_priv *priv = platform_get_drvdata(pdev); + struct pmt_telem_priv *priv = dev_get_drvdata(&adev->dev); 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 *adev, const struct auxiliary_device_id *id) { + struct intel_extended_cap_device *intel_cap_dev = + container_of(adev, struct intel_extended_cap_device, aux_dev); 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_cap_dev->num_resources); + priv = devm_kzalloc(&adev->dev, size, GFP_KERNEL); if (!priv) return -ENOMEM; - platform_set_drvdata(pdev, priv); + dev_set_drvdata(&adev->dev, priv); - for (i = 0; i < pdev->num_resources; i++) { + for (i = 0; i < intel_cap_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_cap_dev, i); if (ret < 0) goto abort_probe; if (ret) @@ -117,32 +117,35 @@ static int pmt_telem_probe(struct platform_device *pdev) return 0; abort_probe: - pmt_telem_remove(pdev); + pmt_telem_remove(adev); 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_aux_id_table[] = { + { .name = "intel_extended_caps.2", }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, pmt_telem_aux_id_table); + +static struct auxiliary_driver pmt_telem_aux_driver = { + .id_table = pmt_telem_aux_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");