Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'ib-mfd-x86-v5.11' into review-hans

Immutable branch between MFD and x86 due for the v5.11 merge window

+1238
+119
Documentation/ABI/testing/sysfs-class-intel_pmt
··· 1 + What: /sys/class/intel_pmt/ 2 + Date: October 2020 3 + KernelVersion: 5.10 4 + Contact: David Box <david.e.box@linux.intel.com> 5 + Description: 6 + The intel_pmt/ class directory contains information for 7 + devices that expose hardware telemetry using Intel Platform 8 + Monitoring Technology (PMT) 9 + 10 + What: /sys/class/intel_pmt/telem<x> 11 + Date: October 2020 12 + KernelVersion: 5.10 13 + Contact: David Box <david.e.box@linux.intel.com> 14 + Description: 15 + The telem<x> directory contains files describing an instance of 16 + a PMT telemetry device that exposes hardware telemetry. Each 17 + telem<x> directory has an associated telem file. This file 18 + may be opened and mapped or read to access the telemetry space 19 + of the device. The register layout of the telemetry space is 20 + determined from an XML file that matches the PCI device id and 21 + GUID for the device. 22 + 23 + What: /sys/class/intel_pmt/telem<x>/telem 24 + Date: October 2020 25 + KernelVersion: 5.10 26 + Contact: David Box <david.e.box@linux.intel.com> 27 + Description: 28 + (RO) The telemetry data for this telemetry device. This file 29 + may be mapped or read to obtain the data. 30 + 31 + What: /sys/class/intel_pmt/telem<x>/guid 32 + Date: October 2020 33 + KernelVersion: 5.10 34 + Contact: David Box <david.e.box@linux.intel.com> 35 + Description: 36 + (RO) The GUID for this telemetry device. The GUID identifies 37 + the version of the XML file for the parent device that is to 38 + be used to get the register layout. 39 + 40 + What: /sys/class/intel_pmt/telem<x>/size 41 + Date: October 2020 42 + KernelVersion: 5.10 43 + Contact: David Box <david.e.box@linux.intel.com> 44 + Description: 45 + (RO) The size of telemetry region in bytes that corresponds to 46 + the mapping size for the telem file. 47 + 48 + What: /sys/class/intel_pmt/telem<x>/offset 49 + Date: October 2020 50 + KernelVersion: 5.10 51 + Contact: David Box <david.e.box@linux.intel.com> 52 + Description: 53 + (RO) The offset of telemetry region in bytes that corresponds to 54 + the mapping for the telem file. 55 + 56 + What: /sys/class/intel_pmt/crashlog<x> 57 + Date: October 2020 58 + KernelVersion: 5.10 59 + Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com> 60 + Description: 61 + The crashlog<x> directory contains files for configuring an 62 + instance of a PMT crashlog device that can perform crash data 63 + recording. Each crashlog<x> device has an associated crashlog 64 + file. This file can be opened and mapped or read to access the 65 + resulting crashlog buffer. The register layout for the buffer 66 + can be determined from an XML file of specified GUID for the 67 + parent device. 68 + 69 + What: /sys/class/intel_pmt/crashlog<x>/crashlog 70 + Date: October 2020 71 + KernelVersion: 5.10 72 + Contact: David Box <david.e.box@linux.intel.com> 73 + Description: 74 + (RO) The crashlog buffer for this crashlog device. This file 75 + may be mapped or read to obtain the data. 76 + 77 + What: /sys/class/intel_pmt/crashlog<x>/guid 78 + Date: October 2020 79 + KernelVersion: 5.10 80 + Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com> 81 + Description: 82 + (RO) The GUID for this crashlog device. The GUID identifies the 83 + version of the XML file for the parent device that should be 84 + used to determine the register layout. 85 + 86 + What: /sys/class/intel_pmt/crashlog<x>/size 87 + Date: October 2020 88 + KernelVersion: 5.10 89 + Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com> 90 + Description: 91 + (RO) The length of the result buffer in bytes that corresponds 92 + to the size for the crashlog buffer. 93 + 94 + What: /sys/class/intel_pmt/crashlog<x>/offset 95 + Date: October 2020 96 + KernelVersion: 5.10 97 + Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com> 98 + Description: 99 + (RO) The offset of the buffer in bytes that corresponds 100 + to the mapping for the crashlog device. 101 + 102 + What: /sys/class/intel_pmt/crashlog<x>/enable 103 + Date: October 2020 104 + KernelVersion: 5.10 105 + Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com> 106 + Description: 107 + (RW) Boolean value controlling if the crashlog functionality 108 + is enabled for the crashlog device. 109 + 110 + What: /sys/class/intel_pmt/crashlog<x>/trigger 111 + Date: October 2020 112 + KernelVersion: 5.10 113 + Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com> 114 + Description: 115 + (RW) Boolean value controlling the triggering of the crashlog 116 + device node. When read it provides data on if the crashlog has 117 + been triggered. When written to it can be used to either clear 118 + the current trigger by writing false, or to trigger a new 119 + event if the trigger is not currently set.
+6
MAINTAINERS
··· 9030 9030 F: include/linux/mfd/intel_msic.h 9031 9031 F: include/linux/mfd/intel_soc_pmic* 9032 9032 9033 + INTEL PMT DRIVER 9034 + M: "David E. Box" <david.e.box@linux.intel.com> 9035 + S: Maintained 9036 + F: drivers/mfd/intel_pmt.c 9037 + F: drivers/platform/x86/intel_pmt_* 9038 + 9033 9039 INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT 9034 9040 M: Stanislav Yakovlev <stas.yakovlev@gmail.com> 9035 9041 L: linux-wireless@vger.kernel.org
+10
drivers/mfd/Kconfig
··· 682 682 Register and P-unit access. In addition this creates devices 683 683 for iTCO watchdog and telemetry that are part of the PMC. 684 684 685 + config MFD_INTEL_PMT 686 + tristate "Intel Platform Monitoring Technology (PMT) support" 687 + depends on PCI 688 + select MFD_CORE 689 + help 690 + The Intel Platform Monitoring Technology (PMT) is an interface that 691 + provides access to hardware monitor registers. This driver supports 692 + Telemetry, Watcher, and Crashlog PMT capabilities/devices for 693 + platforms starting from Tiger Lake. 694 + 685 695 config MFD_IPAQ_MICRO 686 696 bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" 687 697 depends on SA1100_H3100 || SA1100_H3600
+1
drivers/mfd/Makefile
··· 216 216 obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o 217 217 obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o 218 218 obj-$(CONFIG_MFD_INTEL_PMC_BXT) += intel_pmc_bxt.o 219 + obj-$(CONFIG_MFD_INTEL_PMT) += intel_pmt.o 219 220 obj-$(CONFIG_MFD_PALMAS) += palmas.o 220 221 obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o 221 222 obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
+223
drivers/mfd/intel_pmt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Intel Platform Monitoring Technology PMT driver 4 + * 5 + * Copyright (c) 2020, Intel Corporation. 6 + * All Rights Reserved. 7 + * 8 + * Author: David E. Box <david.e.box@linux.intel.com> 9 + */ 10 + 11 + #include <linux/bits.h> 12 + #include <linux/kernel.h> 13 + #include <linux/mfd/core.h> 14 + #include <linux/module.h> 15 + #include <linux/pci.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/pm.h> 18 + #include <linux/pm_runtime.h> 19 + #include <linux/types.h> 20 + 21 + /* Intel DVSEC capability vendor space offsets */ 22 + #define INTEL_DVSEC_ENTRIES 0xA 23 + #define INTEL_DVSEC_SIZE 0xB 24 + #define INTEL_DVSEC_TABLE 0xC 25 + #define INTEL_DVSEC_TABLE_BAR(x) ((x) & GENMASK(2, 0)) 26 + #define INTEL_DVSEC_TABLE_OFFSET(x) ((x) & GENMASK(31, 3)) 27 + #define INTEL_DVSEC_ENTRY_SIZE 4 28 + 29 + /* PMT capabilities */ 30 + #define DVSEC_INTEL_ID_TELEMETRY 2 31 + #define DVSEC_INTEL_ID_WATCHER 3 32 + #define DVSEC_INTEL_ID_CRASHLOG 4 33 + 34 + struct intel_dvsec_header { 35 + u16 length; 36 + u16 id; 37 + u8 num_entries; 38 + u8 entry_size; 39 + u8 tbir; 40 + u32 offset; 41 + }; 42 + 43 + enum pmt_quirks { 44 + /* Watcher capability not supported */ 45 + PMT_QUIRK_NO_WATCHER = BIT(0), 46 + 47 + /* Crashlog capability not supported */ 48 + PMT_QUIRK_NO_CRASHLOG = BIT(1), 49 + 50 + /* Use shift instead of mask to read discovery table offset */ 51 + PMT_QUIRK_TABLE_SHIFT = BIT(2), 52 + }; 53 + 54 + struct pmt_platform_info { 55 + unsigned long quirks; 56 + }; 57 + 58 + static const struct pmt_platform_info tgl_info = { 59 + .quirks = PMT_QUIRK_NO_WATCHER | PMT_QUIRK_NO_CRASHLOG | 60 + PMT_QUIRK_TABLE_SHIFT, 61 + }; 62 + 63 + static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header, 64 + unsigned long quirks) 65 + { 66 + struct device *dev = &pdev->dev; 67 + struct resource *res, *tmp; 68 + struct mfd_cell *cell; 69 + const char *name; 70 + int count = header->num_entries; 71 + int size = header->entry_size; 72 + int id = header->id; 73 + int i; 74 + 75 + switch (id) { 76 + case DVSEC_INTEL_ID_TELEMETRY: 77 + name = "pmt_telemetry"; 78 + break; 79 + case DVSEC_INTEL_ID_WATCHER: 80 + if (quirks & PMT_QUIRK_NO_WATCHER) { 81 + dev_info(dev, "Watcher not supported\n"); 82 + return 0; 83 + } 84 + name = "pmt_watcher"; 85 + break; 86 + case DVSEC_INTEL_ID_CRASHLOG: 87 + if (quirks & PMT_QUIRK_NO_CRASHLOG) { 88 + dev_info(dev, "Crashlog not supported\n"); 89 + return 0; 90 + } 91 + name = "pmt_crashlog"; 92 + break; 93 + default: 94 + dev_err(dev, "Unrecognized PMT capability: %d\n", id); 95 + return -EINVAL; 96 + } 97 + 98 + if (!header->num_entries || !header->entry_size) { 99 + dev_err(dev, "Invalid count or size for %s header\n", name); 100 + return -EINVAL; 101 + } 102 + 103 + cell = devm_kzalloc(dev, sizeof(*cell), GFP_KERNEL); 104 + if (!cell) 105 + return -ENOMEM; 106 + 107 + res = devm_kcalloc(dev, count, sizeof(*res), GFP_KERNEL); 108 + if (!res) 109 + return -ENOMEM; 110 + 111 + if (quirks & PMT_QUIRK_TABLE_SHIFT) 112 + header->offset >>= 3; 113 + 114 + /* 115 + * The PMT DVSEC contains the starting offset and count for a block of 116 + * discovery tables, each providing access to monitoring facilities for 117 + * a section of the device. Create a resource list of these tables to 118 + * provide to the driver. 119 + */ 120 + for (i = 0, tmp = res; i < count; i++, tmp++) { 121 + tmp->start = pdev->resource[header->tbir].start + 122 + header->offset + i * (size << 2); 123 + tmp->end = tmp->start + (size << 2) - 1; 124 + tmp->flags = IORESOURCE_MEM; 125 + } 126 + 127 + cell->resources = res; 128 + cell->num_resources = count; 129 + cell->name = name; 130 + 131 + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cell, 1, NULL, 0, 132 + NULL); 133 + } 134 + 135 + static int pmt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 136 + { 137 + struct pmt_platform_info *info; 138 + unsigned long quirks = 0; 139 + bool found_devices = false; 140 + int ret, pos = 0; 141 + 142 + ret = pcim_enable_device(pdev); 143 + if (ret) 144 + return ret; 145 + 146 + info = (struct pmt_platform_info *)id->driver_data; 147 + 148 + if (info) 149 + quirks = info->quirks; 150 + 151 + do { 152 + struct intel_dvsec_header header; 153 + u32 table; 154 + u16 vid; 155 + 156 + pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC); 157 + if (!pos) 158 + break; 159 + 160 + pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid); 161 + if (vid != PCI_VENDOR_ID_INTEL) 162 + continue; 163 + 164 + pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2, 165 + &header.id); 166 + pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES, 167 + &header.num_entries); 168 + pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE, 169 + &header.entry_size); 170 + pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE, 171 + &table); 172 + 173 + header.tbir = INTEL_DVSEC_TABLE_BAR(table); 174 + header.offset = INTEL_DVSEC_TABLE_OFFSET(table); 175 + 176 + ret = pmt_add_dev(pdev, &header, quirks); 177 + if (ret) { 178 + dev_warn(&pdev->dev, 179 + "Failed to add device for DVSEC id %d\n", 180 + header.id); 181 + continue; 182 + } 183 + 184 + found_devices = true; 185 + } while (true); 186 + 187 + if (!found_devices) 188 + return -ENODEV; 189 + 190 + pm_runtime_put(&pdev->dev); 191 + pm_runtime_allow(&pdev->dev); 192 + 193 + return 0; 194 + } 195 + 196 + static void pmt_pci_remove(struct pci_dev *pdev) 197 + { 198 + pm_runtime_forbid(&pdev->dev); 199 + pm_runtime_get_sync(&pdev->dev); 200 + } 201 + 202 + #define PCI_DEVICE_ID_INTEL_PMT_ADL 0x467d 203 + #define PCI_DEVICE_ID_INTEL_PMT_OOBMSM 0x09a7 204 + #define PCI_DEVICE_ID_INTEL_PMT_TGL 0x9a0d 205 + static const struct pci_device_id pmt_pci_ids[] = { 206 + { PCI_DEVICE_DATA(INTEL, PMT_ADL, &tgl_info) }, 207 + { PCI_DEVICE_DATA(INTEL, PMT_OOBMSM, NULL) }, 208 + { PCI_DEVICE_DATA(INTEL, PMT_TGL, &tgl_info) }, 209 + { } 210 + }; 211 + MODULE_DEVICE_TABLE(pci, pmt_pci_ids); 212 + 213 + static struct pci_driver pmt_pci_driver = { 214 + .name = "intel-pmt", 215 + .id_table = pmt_pci_ids, 216 + .probe = pmt_pci_probe, 217 + .remove = pmt_pci_remove, 218 + }; 219 + module_pci_driver(pmt_pci_driver); 220 + 221 + MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); 222 + MODULE_DESCRIPTION("Intel Platform Monitoring Technology PMT driver"); 223 + MODULE_LICENSE("GPL v2");
+34
drivers/platform/x86/Kconfig
··· 1343 1343 - LTR Ignore 1344 1344 - MPHY/PLL gating status (Sunrisepoint PCH only) 1345 1345 1346 + config INTEL_PMT_CLASS 1347 + tristate "Intel Platform Monitoring Technology (PMT) Class driver" 1348 + help 1349 + The Intel Platform Monitoring Technology (PMT) class driver provides 1350 + the basic sysfs interface and file hierarchy uses by PMT devices. 1351 + 1352 + For more information, see: 1353 + <file:Documentation/ABI/testing/sysfs-class-intel_pmt> 1354 + 1355 + To compile this driver as a module, choose M here: the module 1356 + will be called intel_pmt_class. 1357 + 1358 + config INTEL_PMT_TELEMETRY 1359 + tristate "Intel Platform Monitoring Technology (PMT) Telemetry driver" 1360 + select INTEL_PMT_CLASS 1361 + help 1362 + The Intel Platform Monitory Technology (PMT) Telemetry driver provides 1363 + access to hardware telemetry metrics on devices that support the 1364 + feature. 1365 + 1366 + To compile this driver as a module, choose M here: the module 1367 + will be called intel_pmt_telemetry. 1368 + 1369 + config INTEL_PMT_CRASHLOG 1370 + tristate "Intel Platform Monitoring Technology (PMT) Crashlog driver" 1371 + select INTEL_PMT_CLASS 1372 + help 1373 + The Intel Platform Monitoring Technology (PMT) crashlog driver provides 1374 + access to hardware crashlog capabilities on devices that support the 1375 + feature. 1376 + 1377 + To compile this driver as a module, choose M here: the module 1378 + will be called intel_pmt_crashlog. 1379 + 1346 1380 config INTEL_PUNIT_IPC 1347 1381 tristate "Intel P-Unit IPC Driver" 1348 1382 help
+3
drivers/platform/x86/Makefile
··· 135 135 obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o 136 136 obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o 137 137 obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv.o 138 + obj-$(CONFIG_INTEL_PMT_CLASS) += intel_pmt_class.o 139 + obj-$(CONFIG_INTEL_PMT_TELEMETRY) += intel_pmt_telemetry.o 140 + obj-$(CONFIG_INTEL_PMT_CRASHLOG) += intel_pmt_crashlog.o 138 141 obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o 139 142 obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 140 143 obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o
+297
drivers/platform/x86/intel_pmt_class.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Intel Platform Monitory Technology Telemetry driver 4 + * 5 + * Copyright (c) 2020, Intel Corporation. 6 + * All Rights Reserved. 7 + * 8 + * Author: "Alexander Duyck" <alexander.h.duyck@linux.intel.com> 9 + */ 10 + 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/mm.h> 14 + #include <linux/pci.h> 15 + 16 + #include "intel_pmt_class.h" 17 + 18 + #define PMT_XA_START 0 19 + #define PMT_XA_MAX INT_MAX 20 + #define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX) 21 + 22 + /* 23 + * sysfs 24 + */ 25 + static ssize_t 26 + intel_pmt_read(struct file *filp, struct kobject *kobj, 27 + struct bin_attribute *attr, char *buf, loff_t off, 28 + size_t count) 29 + { 30 + struct intel_pmt_entry *entry = container_of(attr, 31 + struct intel_pmt_entry, 32 + pmt_bin_attr); 33 + 34 + if (off < 0) 35 + return -EINVAL; 36 + 37 + if (off >= entry->size) 38 + return 0; 39 + 40 + if (count > entry->size - off) 41 + count = entry->size - off; 42 + 43 + memcpy_fromio(buf, entry->base + off, count); 44 + 45 + return count; 46 + } 47 + 48 + static int 49 + intel_pmt_mmap(struct file *filp, struct kobject *kobj, 50 + struct bin_attribute *attr, struct vm_area_struct *vma) 51 + { 52 + struct intel_pmt_entry *entry = container_of(attr, 53 + struct intel_pmt_entry, 54 + pmt_bin_attr); 55 + unsigned long vsize = vma->vm_end - vma->vm_start; 56 + struct device *dev = kobj_to_dev(kobj); 57 + unsigned long phys = entry->base_addr; 58 + unsigned long pfn = PFN_DOWN(phys); 59 + unsigned long psize; 60 + 61 + if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) 62 + return -EROFS; 63 + 64 + psize = (PFN_UP(entry->base_addr + entry->size) - pfn) * PAGE_SIZE; 65 + if (vsize > psize) { 66 + dev_err(dev, "Requested mmap size is too large\n"); 67 + return -EINVAL; 68 + } 69 + 70 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 71 + if (io_remap_pfn_range(vma, vma->vm_start, pfn, 72 + vsize, vma->vm_page_prot)) 73 + return -EAGAIN; 74 + 75 + return 0; 76 + } 77 + 78 + static ssize_t 79 + guid_show(struct device *dev, struct device_attribute *attr, char *buf) 80 + { 81 + struct intel_pmt_entry *entry = dev_get_drvdata(dev); 82 + 83 + return sprintf(buf, "0x%x\n", entry->guid); 84 + } 85 + static DEVICE_ATTR_RO(guid); 86 + 87 + static ssize_t size_show(struct device *dev, struct device_attribute *attr, 88 + char *buf) 89 + { 90 + struct intel_pmt_entry *entry = dev_get_drvdata(dev); 91 + 92 + return sprintf(buf, "%zu\n", entry->size); 93 + } 94 + static DEVICE_ATTR_RO(size); 95 + 96 + static ssize_t 97 + offset_show(struct device *dev, struct device_attribute *attr, char *buf) 98 + { 99 + struct intel_pmt_entry *entry = dev_get_drvdata(dev); 100 + 101 + return sprintf(buf, "%lu\n", offset_in_page(entry->base_addr)); 102 + } 103 + static DEVICE_ATTR_RO(offset); 104 + 105 + static struct attribute *intel_pmt_attrs[] = { 106 + &dev_attr_guid.attr, 107 + &dev_attr_size.attr, 108 + &dev_attr_offset.attr, 109 + NULL 110 + }; 111 + ATTRIBUTE_GROUPS(intel_pmt); 112 + 113 + static struct class intel_pmt_class = { 114 + .name = "intel_pmt", 115 + .owner = THIS_MODULE, 116 + .dev_groups = intel_pmt_groups, 117 + }; 118 + 119 + static int intel_pmt_populate_entry(struct intel_pmt_entry *entry, 120 + struct intel_pmt_header *header, 121 + struct device *dev, 122 + struct resource *disc_res) 123 + { 124 + struct pci_dev *pci_dev = to_pci_dev(dev->parent); 125 + u8 bir; 126 + 127 + /* 128 + * The base offset should always be 8 byte aligned. 129 + * 130 + * For non-local access types the lower 3 bits of base offset 131 + * contains the index of the base address register where the 132 + * telemetry can be found. 133 + */ 134 + bir = GET_BIR(header->base_offset); 135 + 136 + /* Local access and BARID only for now */ 137 + switch (header->access_type) { 138 + case ACCESS_LOCAL: 139 + if (bir) { 140 + dev_err(dev, 141 + "Unsupported BAR index %d for access type %d\n", 142 + bir, header->access_type); 143 + return -EINVAL; 144 + } 145 + /* 146 + * For access_type LOCAL, the base address is as follows: 147 + * base address = end of discovery region + base offset 148 + */ 149 + entry->base_addr = disc_res->end + 1 + header->base_offset; 150 + break; 151 + case ACCESS_BARID: 152 + /* 153 + * If another BAR was specified then the base offset 154 + * represents the offset within that BAR. SO retrieve the 155 + * address from the parent PCI device and add offset. 156 + */ 157 + entry->base_addr = pci_resource_start(pci_dev, bir) + 158 + GET_ADDRESS(header->base_offset); 159 + break; 160 + default: 161 + dev_err(dev, "Unsupported access type %d\n", 162 + header->access_type); 163 + return -EINVAL; 164 + } 165 + 166 + entry->guid = header->guid; 167 + entry->size = header->size; 168 + 169 + return 0; 170 + } 171 + 172 + static int intel_pmt_dev_register(struct intel_pmt_entry *entry, 173 + struct intel_pmt_namespace *ns, 174 + struct device *parent) 175 + { 176 + struct resource res; 177 + struct device *dev; 178 + int ret; 179 + 180 + ret = xa_alloc(ns->xa, &entry->devid, entry, PMT_XA_LIMIT, GFP_KERNEL); 181 + if (ret) 182 + return ret; 183 + 184 + dev = device_create(&intel_pmt_class, parent, MKDEV(0, 0), entry, 185 + "%s%d", ns->name, entry->devid); 186 + 187 + if (IS_ERR(dev)) { 188 + dev_err(parent, "Could not create %s%d device node\n", 189 + ns->name, entry->devid); 190 + ret = PTR_ERR(dev); 191 + goto fail_dev_create; 192 + } 193 + 194 + entry->kobj = &dev->kobj; 195 + 196 + if (ns->attr_grp) { 197 + ret = sysfs_create_group(entry->kobj, ns->attr_grp); 198 + if (ret) 199 + goto fail_sysfs; 200 + } 201 + 202 + /* if size is 0 assume no data buffer, so no file needed */ 203 + if (!entry->size) 204 + return 0; 205 + 206 + res.start = entry->base_addr; 207 + res.end = res.start + entry->size - 1; 208 + res.flags = IORESOURCE_MEM; 209 + 210 + entry->base = devm_ioremap_resource(dev, &res); 211 + if (IS_ERR(entry->base)) { 212 + ret = PTR_ERR(entry->base); 213 + goto fail_ioremap; 214 + } 215 + 216 + sysfs_bin_attr_init(&entry->pmt_bin_attr); 217 + entry->pmt_bin_attr.attr.name = ns->name; 218 + entry->pmt_bin_attr.attr.mode = 0440; 219 + entry->pmt_bin_attr.mmap = intel_pmt_mmap; 220 + entry->pmt_bin_attr.read = intel_pmt_read; 221 + entry->pmt_bin_attr.size = entry->size; 222 + 223 + ret = sysfs_create_bin_file(&dev->kobj, &entry->pmt_bin_attr); 224 + if (!ret) 225 + return 0; 226 + 227 + fail_ioremap: 228 + sysfs_remove_group(entry->kobj, ns->attr_grp); 229 + fail_sysfs: 230 + device_unregister(dev); 231 + fail_dev_create: 232 + xa_erase(ns->xa, entry->devid); 233 + 234 + return ret; 235 + } 236 + 237 + int intel_pmt_dev_create(struct intel_pmt_entry *entry, 238 + struct intel_pmt_namespace *ns, 239 + struct platform_device *pdev, int idx) 240 + { 241 + struct intel_pmt_header header; 242 + struct resource *disc_res; 243 + int ret = -ENODEV; 244 + 245 + disc_res = platform_get_resource(pdev, IORESOURCE_MEM, idx); 246 + if (!disc_res) 247 + return ret; 248 + 249 + entry->disc_table = devm_platform_ioremap_resource(pdev, idx); 250 + if (IS_ERR(entry->disc_table)) 251 + return PTR_ERR(entry->disc_table); 252 + 253 + ret = ns->pmt_header_decode(entry, &header, &pdev->dev); 254 + if (ret) 255 + return ret; 256 + 257 + ret = intel_pmt_populate_entry(entry, &header, &pdev->dev, disc_res); 258 + if (ret) 259 + return ret; 260 + 261 + return intel_pmt_dev_register(entry, ns, &pdev->dev); 262 + 263 + } 264 + EXPORT_SYMBOL_GPL(intel_pmt_dev_create); 265 + 266 + void intel_pmt_dev_destroy(struct intel_pmt_entry *entry, 267 + struct intel_pmt_namespace *ns) 268 + { 269 + struct device *dev = kobj_to_dev(entry->kobj); 270 + 271 + if (entry->size) 272 + sysfs_remove_bin_file(entry->kobj, &entry->pmt_bin_attr); 273 + 274 + if (ns->attr_grp) 275 + sysfs_remove_group(entry->kobj, ns->attr_grp); 276 + 277 + device_unregister(dev); 278 + xa_erase(ns->xa, entry->devid); 279 + } 280 + EXPORT_SYMBOL_GPL(intel_pmt_dev_destroy); 281 + 282 + static int __init pmt_class_init(void) 283 + { 284 + return class_register(&intel_pmt_class); 285 + } 286 + 287 + static void __exit pmt_class_exit(void) 288 + { 289 + class_unregister(&intel_pmt_class); 290 + } 291 + 292 + module_init(pmt_class_init); 293 + module_exit(pmt_class_exit); 294 + 295 + MODULE_AUTHOR("Alexander Duyck <alexander.h.duyck@linux.intel.com>"); 296 + MODULE_DESCRIPTION("Intel PMT Class driver"); 297 + MODULE_LICENSE("GPL v2");
+52
drivers/platform/x86/intel_pmt_class.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _INTEL_PMT_CLASS_H 3 + #define _INTEL_PMT_CLASS_H 4 + 5 + #include <linux/platform_device.h> 6 + #include <linux/xarray.h> 7 + #include <linux/types.h> 8 + #include <linux/bits.h> 9 + #include <linux/err.h> 10 + #include <linux/io.h> 11 + 12 + /* PMT access types */ 13 + #define ACCESS_BARID 2 14 + #define ACCESS_LOCAL 3 15 + 16 + /* PMT discovery base address/offset register layout */ 17 + #define GET_BIR(v) ((v) & GENMASK(2, 0)) 18 + #define GET_ADDRESS(v) ((v) & GENMASK(31, 3)) 19 + 20 + struct intel_pmt_entry { 21 + struct bin_attribute pmt_bin_attr; 22 + struct kobject *kobj; 23 + void __iomem *disc_table; 24 + void __iomem *base; 25 + unsigned long base_addr; 26 + size_t size; 27 + u32 guid; 28 + int devid; 29 + }; 30 + 31 + struct intel_pmt_header { 32 + u32 base_offset; 33 + u32 size; 34 + u32 guid; 35 + u8 access_type; 36 + }; 37 + 38 + struct intel_pmt_namespace { 39 + const char *name; 40 + struct xarray *xa; 41 + const struct attribute_group *attr_grp; 42 + int (*pmt_header_decode)(struct intel_pmt_entry *entry, 43 + struct intel_pmt_header *header, 44 + struct device *dev); 45 + }; 46 + 47 + int intel_pmt_dev_create(struct intel_pmt_entry *entry, 48 + struct intel_pmt_namespace *ns, 49 + struct platform_device *pdev, int idx); 50 + void intel_pmt_dev_destroy(struct intel_pmt_entry *entry, 51 + struct intel_pmt_namespace *ns); 52 + #endif
+328
drivers/platform/x86/intel_pmt_crashlog.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Intel Platform Monitoring Technology Crashlog driver 4 + * 5 + * Copyright (c) 2020, Intel Corporation. 6 + * All Rights Reserved. 7 + * 8 + * Author: "Alexander Duyck" <alexander.h.duyck@linux.intel.com> 9 + */ 10 + 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/pci.h> 14 + #include <linux/slab.h> 15 + #include <linux/uaccess.h> 16 + #include <linux/overflow.h> 17 + 18 + #include "intel_pmt_class.h" 19 + 20 + #define DRV_NAME "pmt_crashlog" 21 + 22 + /* Crashlog discovery header types */ 23 + #define CRASH_TYPE_OOBMSM 1 24 + 25 + /* Control Flags */ 26 + #define CRASHLOG_FLAG_DISABLE BIT(27) 27 + 28 + /* 29 + * Bits 28 and 29 control the state of bit 31. 30 + * 31 + * Bit 28 will clear bit 31, if set, allowing a new crashlog to be captured. 32 + * Bit 29 will immediately trigger a crashlog to be generated, setting bit 31. 33 + * Bit 30 is read-only and reserved as 0. 34 + * Bit 31 is the read-only status with a 1 indicating log is complete. 35 + */ 36 + #define CRASHLOG_FLAG_TRIGGER_CLEAR BIT(28) 37 + #define CRASHLOG_FLAG_TRIGGER_EXECUTE BIT(29) 38 + #define CRASHLOG_FLAG_TRIGGER_COMPLETE BIT(31) 39 + #define CRASHLOG_FLAG_TRIGGER_MASK GENMASK(31, 28) 40 + 41 + /* Crashlog Discovery Header */ 42 + #define CONTROL_OFFSET 0x0 43 + #define GUID_OFFSET 0x4 44 + #define BASE_OFFSET 0x8 45 + #define SIZE_OFFSET 0xC 46 + #define GET_ACCESS(v) ((v) & GENMASK(3, 0)) 47 + #define GET_TYPE(v) (((v) & GENMASK(7, 4)) >> 4) 48 + #define GET_VERSION(v) (((v) & GENMASK(19, 16)) >> 16) 49 + /* size is in bytes */ 50 + #define GET_SIZE(v) ((v) * sizeof(u32)) 51 + 52 + struct crashlog_entry { 53 + /* entry must be first member of struct */ 54 + struct intel_pmt_entry entry; 55 + struct mutex control_mutex; 56 + }; 57 + 58 + struct pmt_crashlog_priv { 59 + int num_entries; 60 + struct crashlog_entry entry[]; 61 + }; 62 + 63 + /* 64 + * I/O 65 + */ 66 + static bool pmt_crashlog_complete(struct intel_pmt_entry *entry) 67 + { 68 + u32 control = readl(entry->disc_table + CONTROL_OFFSET); 69 + 70 + /* return current value of the crashlog complete flag */ 71 + return !!(control & CRASHLOG_FLAG_TRIGGER_COMPLETE); 72 + } 73 + 74 + static bool pmt_crashlog_disabled(struct intel_pmt_entry *entry) 75 + { 76 + u32 control = readl(entry->disc_table + CONTROL_OFFSET); 77 + 78 + /* return current value of the crashlog disabled flag */ 79 + return !!(control & CRASHLOG_FLAG_DISABLE); 80 + } 81 + 82 + static bool pmt_crashlog_supported(struct intel_pmt_entry *entry) 83 + { 84 + u32 discovery_header = readl(entry->disc_table + CONTROL_OFFSET); 85 + u32 crash_type, version; 86 + 87 + crash_type = GET_TYPE(discovery_header); 88 + version = GET_VERSION(discovery_header); 89 + 90 + /* 91 + * Currently we only recognize OOBMSM version 0 devices. 92 + * We can ignore all other crashlog devices in the system. 93 + */ 94 + return crash_type == CRASH_TYPE_OOBMSM && version == 0; 95 + } 96 + 97 + static void pmt_crashlog_set_disable(struct intel_pmt_entry *entry, 98 + bool disable) 99 + { 100 + u32 control = readl(entry->disc_table + CONTROL_OFFSET); 101 + 102 + /* clear trigger bits so we are only modifying disable flag */ 103 + control &= ~CRASHLOG_FLAG_TRIGGER_MASK; 104 + 105 + if (disable) 106 + control |= CRASHLOG_FLAG_DISABLE; 107 + else 108 + control &= ~CRASHLOG_FLAG_DISABLE; 109 + 110 + writel(control, entry->disc_table + CONTROL_OFFSET); 111 + } 112 + 113 + static void pmt_crashlog_set_clear(struct intel_pmt_entry *entry) 114 + { 115 + u32 control = readl(entry->disc_table + CONTROL_OFFSET); 116 + 117 + control &= ~CRASHLOG_FLAG_TRIGGER_MASK; 118 + control |= CRASHLOG_FLAG_TRIGGER_CLEAR; 119 + 120 + writel(control, entry->disc_table + CONTROL_OFFSET); 121 + } 122 + 123 + static void pmt_crashlog_set_execute(struct intel_pmt_entry *entry) 124 + { 125 + u32 control = readl(entry->disc_table + CONTROL_OFFSET); 126 + 127 + control &= ~CRASHLOG_FLAG_TRIGGER_MASK; 128 + control |= CRASHLOG_FLAG_TRIGGER_EXECUTE; 129 + 130 + writel(control, entry->disc_table + CONTROL_OFFSET); 131 + } 132 + 133 + /* 134 + * sysfs 135 + */ 136 + static ssize_t 137 + enable_show(struct device *dev, struct device_attribute *attr, char *buf) 138 + { 139 + struct intel_pmt_entry *entry = dev_get_drvdata(dev); 140 + int enabled = !pmt_crashlog_disabled(entry); 141 + 142 + return sprintf(buf, "%d\n", enabled); 143 + } 144 + 145 + static ssize_t 146 + enable_store(struct device *dev, struct device_attribute *attr, 147 + const char *buf, size_t count) 148 + { 149 + struct crashlog_entry *entry; 150 + bool enabled; 151 + int result; 152 + 153 + entry = dev_get_drvdata(dev); 154 + 155 + result = kstrtobool(buf, &enabled); 156 + if (result) 157 + return result; 158 + 159 + mutex_lock(&entry->control_mutex); 160 + pmt_crashlog_set_disable(&entry->entry, !enabled); 161 + mutex_unlock(&entry->control_mutex); 162 + 163 + return count; 164 + } 165 + static DEVICE_ATTR_RW(enable); 166 + 167 + static ssize_t 168 + trigger_show(struct device *dev, struct device_attribute *attr, char *buf) 169 + { 170 + struct intel_pmt_entry *entry; 171 + int trigger; 172 + 173 + entry = dev_get_drvdata(dev); 174 + trigger = pmt_crashlog_complete(entry); 175 + 176 + return sprintf(buf, "%d\n", trigger); 177 + } 178 + 179 + static ssize_t 180 + trigger_store(struct device *dev, struct device_attribute *attr, 181 + const char *buf, size_t count) 182 + { 183 + struct crashlog_entry *entry; 184 + bool trigger; 185 + int result; 186 + 187 + entry = dev_get_drvdata(dev); 188 + 189 + result = kstrtobool(buf, &trigger); 190 + if (result) 191 + return result; 192 + 193 + mutex_lock(&entry->control_mutex); 194 + 195 + if (!trigger) { 196 + pmt_crashlog_set_clear(&entry->entry); 197 + } else if (pmt_crashlog_complete(&entry->entry)) { 198 + /* we cannot trigger a new crash if one is still pending */ 199 + result = -EEXIST; 200 + goto err; 201 + } else if (pmt_crashlog_disabled(&entry->entry)) { 202 + /* if device is currently disabled, return busy */ 203 + result = -EBUSY; 204 + goto err; 205 + } else { 206 + pmt_crashlog_set_execute(&entry->entry); 207 + } 208 + 209 + result = count; 210 + err: 211 + mutex_unlock(&entry->control_mutex); 212 + return result; 213 + } 214 + static DEVICE_ATTR_RW(trigger); 215 + 216 + static struct attribute *pmt_crashlog_attrs[] = { 217 + &dev_attr_enable.attr, 218 + &dev_attr_trigger.attr, 219 + NULL 220 + }; 221 + 222 + static struct attribute_group pmt_crashlog_group = { 223 + .attrs = pmt_crashlog_attrs, 224 + }; 225 + 226 + static int pmt_crashlog_header_decode(struct intel_pmt_entry *entry, 227 + struct intel_pmt_header *header, 228 + struct device *dev) 229 + { 230 + void __iomem *disc_table = entry->disc_table; 231 + struct crashlog_entry *crashlog; 232 + 233 + if (!pmt_crashlog_supported(entry)) 234 + return 1; 235 + 236 + /* initialize control mutex */ 237 + crashlog = container_of(entry, struct crashlog_entry, entry); 238 + mutex_init(&crashlog->control_mutex); 239 + 240 + header->access_type = GET_ACCESS(readl(disc_table)); 241 + header->guid = readl(disc_table + GUID_OFFSET); 242 + header->base_offset = readl(disc_table + BASE_OFFSET); 243 + 244 + /* Size is measured in DWORDS, but accessor returns bytes */ 245 + header->size = GET_SIZE(readl(disc_table + SIZE_OFFSET)); 246 + 247 + return 0; 248 + } 249 + 250 + static DEFINE_XARRAY_ALLOC(crashlog_array); 251 + static struct intel_pmt_namespace pmt_crashlog_ns = { 252 + .name = "crashlog", 253 + .xa = &crashlog_array, 254 + .attr_grp = &pmt_crashlog_group, 255 + .pmt_header_decode = pmt_crashlog_header_decode, 256 + }; 257 + 258 + /* 259 + * initialization 260 + */ 261 + static int pmt_crashlog_remove(struct platform_device *pdev) 262 + { 263 + struct pmt_crashlog_priv *priv = platform_get_drvdata(pdev); 264 + int i; 265 + 266 + for (i = 0; i < priv->num_entries; i++) 267 + intel_pmt_dev_destroy(&priv->entry[i].entry, &pmt_crashlog_ns); 268 + 269 + return 0; 270 + } 271 + 272 + static int pmt_crashlog_probe(struct platform_device *pdev) 273 + { 274 + struct pmt_crashlog_priv *priv; 275 + size_t size; 276 + int i, ret; 277 + 278 + size = struct_size(priv, entry, pdev->num_resources); 279 + priv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); 280 + if (!priv) 281 + return -ENOMEM; 282 + 283 + platform_set_drvdata(pdev, priv); 284 + 285 + for (i = 0; i < pdev->num_resources; i++) { 286 + struct intel_pmt_entry *entry = &priv->entry[i].entry; 287 + 288 + ret = intel_pmt_dev_create(entry, &pmt_crashlog_ns, pdev, i); 289 + if (ret < 0) 290 + goto abort_probe; 291 + if (ret) 292 + continue; 293 + 294 + priv->num_entries++; 295 + } 296 + 297 + return 0; 298 + abort_probe: 299 + pmt_crashlog_remove(pdev); 300 + return ret; 301 + } 302 + 303 + static struct platform_driver pmt_crashlog_driver = { 304 + .driver = { 305 + .name = DRV_NAME, 306 + }, 307 + .remove = pmt_crashlog_remove, 308 + .probe = pmt_crashlog_probe, 309 + }; 310 + 311 + static int __init pmt_crashlog_init(void) 312 + { 313 + return platform_driver_register(&pmt_crashlog_driver); 314 + } 315 + 316 + static void __exit pmt_crashlog_exit(void) 317 + { 318 + platform_driver_unregister(&pmt_crashlog_driver); 319 + xa_destroy(&crashlog_array); 320 + } 321 + 322 + module_init(pmt_crashlog_init); 323 + module_exit(pmt_crashlog_exit); 324 + 325 + MODULE_AUTHOR("Alexander Duyck <alexander.h.duyck@linux.intel.com>"); 326 + MODULE_DESCRIPTION("Intel PMT Crashlog driver"); 327 + MODULE_ALIAS("platform:" DRV_NAME); 328 + MODULE_LICENSE("GPL v2");
+160
drivers/platform/x86/intel_pmt_telemetry.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Intel Platform Monitory Technology Telemetry driver 4 + * 5 + * Copyright (c) 2020, Intel Corporation. 6 + * All Rights Reserved. 7 + * 8 + * Author: "David E. Box" <david.e.box@linux.intel.com> 9 + */ 10 + 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/pci.h> 14 + #include <linux/slab.h> 15 + #include <linux/uaccess.h> 16 + #include <linux/overflow.h> 17 + 18 + #include "intel_pmt_class.h" 19 + 20 + #define TELEM_DEV_NAME "pmt_telemetry" 21 + 22 + #define TELEM_SIZE_OFFSET 0x0 23 + #define TELEM_GUID_OFFSET 0x4 24 + #define TELEM_BASE_OFFSET 0x8 25 + #define TELEM_ACCESS(v) ((v) & GENMASK(3, 0)) 26 + /* size is in bytes */ 27 + #define TELEM_SIZE(v) (((v) & GENMASK(27, 12)) >> 10) 28 + 29 + /* Used by client hardware to identify a fixed telemetry entry*/ 30 + #define TELEM_CLIENT_FIXED_BLOCK_GUID 0x10000000 31 + 32 + struct pmt_telem_priv { 33 + int num_entries; 34 + struct intel_pmt_entry entry[]; 35 + }; 36 + 37 + /* 38 + * Early implementations of PMT on client platforms have some 39 + * differences from the server platforms (which use the Out Of Band 40 + * Management Services Module OOBMSM). This list tracks those 41 + * platforms as needed to handle those differences. Newer client 42 + * platforms are expected to be fully compatible with server. 43 + */ 44 + static const struct pci_device_id pmt_telem_early_client_pci_ids[] = { 45 + { PCI_VDEVICE(INTEL, 0x9a0d) }, /* TGL */ 46 + { PCI_VDEVICE(INTEL, 0x467d) }, /* ADL */ 47 + { } 48 + }; 49 + 50 + static bool intel_pmt_is_early_client_hw(struct device *dev) 51 + { 52 + struct pci_dev *parent = to_pci_dev(dev->parent); 53 + 54 + return !!pci_match_id(pmt_telem_early_client_pci_ids, parent); 55 + } 56 + 57 + static bool pmt_telem_region_overlaps(struct intel_pmt_entry *entry, 58 + struct device *dev) 59 + { 60 + u32 guid = readl(entry->disc_table + TELEM_GUID_OFFSET); 61 + 62 + if (guid != TELEM_CLIENT_FIXED_BLOCK_GUID) 63 + return false; 64 + 65 + return intel_pmt_is_early_client_hw(dev); 66 + } 67 + 68 + static int pmt_telem_header_decode(struct intel_pmt_entry *entry, 69 + struct intel_pmt_header *header, 70 + struct device *dev) 71 + { 72 + void __iomem *disc_table = entry->disc_table; 73 + 74 + if (pmt_telem_region_overlaps(entry, dev)) 75 + return 1; 76 + 77 + header->access_type = TELEM_ACCESS(readl(disc_table)); 78 + header->guid = readl(disc_table + TELEM_GUID_OFFSET); 79 + header->base_offset = readl(disc_table + TELEM_BASE_OFFSET); 80 + 81 + /* Size is measured in DWORDS, but accessor returns bytes */ 82 + header->size = TELEM_SIZE(readl(disc_table)); 83 + 84 + return 0; 85 + } 86 + 87 + static DEFINE_XARRAY_ALLOC(telem_array); 88 + static struct intel_pmt_namespace pmt_telem_ns = { 89 + .name = "telem", 90 + .xa = &telem_array, 91 + .pmt_header_decode = pmt_telem_header_decode, 92 + }; 93 + 94 + static int pmt_telem_remove(struct platform_device *pdev) 95 + { 96 + struct pmt_telem_priv *priv = platform_get_drvdata(pdev); 97 + int i; 98 + 99 + for (i = 0; i < priv->num_entries; i++) 100 + intel_pmt_dev_destroy(&priv->entry[i], &pmt_telem_ns); 101 + 102 + return 0; 103 + } 104 + 105 + static int pmt_telem_probe(struct platform_device *pdev) 106 + { 107 + struct pmt_telem_priv *priv; 108 + size_t size; 109 + int i, ret; 110 + 111 + size = struct_size(priv, entry, pdev->num_resources); 112 + priv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); 113 + if (!priv) 114 + return -ENOMEM; 115 + 116 + platform_set_drvdata(pdev, priv); 117 + 118 + for (i = 0; i < pdev->num_resources; i++) { 119 + struct intel_pmt_entry *entry = &priv->entry[i]; 120 + 121 + ret = intel_pmt_dev_create(entry, &pmt_telem_ns, pdev, i); 122 + if (ret < 0) 123 + goto abort_probe; 124 + if (ret) 125 + continue; 126 + 127 + priv->num_entries++; 128 + } 129 + 130 + return 0; 131 + abort_probe: 132 + pmt_telem_remove(pdev); 133 + return ret; 134 + } 135 + 136 + static struct platform_driver pmt_telem_driver = { 137 + .driver = { 138 + .name = TELEM_DEV_NAME, 139 + }, 140 + .remove = pmt_telem_remove, 141 + .probe = pmt_telem_probe, 142 + }; 143 + 144 + static int __init pmt_telem_init(void) 145 + { 146 + return platform_driver_register(&pmt_telem_driver); 147 + } 148 + module_init(pmt_telem_init); 149 + 150 + static void __exit pmt_telem_exit(void) 151 + { 152 + platform_driver_unregister(&pmt_telem_driver); 153 + xa_destroy(&telem_array); 154 + } 155 + module_exit(pmt_telem_exit); 156 + 157 + MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); 158 + MODULE_DESCRIPTION("Intel PMT Telemetry driver"); 159 + MODULE_ALIAS("platform:" TELEM_DEV_NAME); 160 + MODULE_LICENSE("GPL v2");
+5
include/uapi/linux/pci_regs.h
··· 723 723 #define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */ 724 724 #define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */ 725 725 #define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */ 726 + #define PCI_EXT_CAP_ID_DVSEC 0x23 /* Designated Vendor-Specific */ 726 727 #define PCI_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */ 727 728 #define PCI_EXT_CAP_ID_PL_16GT 0x26 /* Physical Layer 16.0 GT/s */ 728 729 #define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_16GT ··· 1066 1065 #define PCI_L1SS_CTL1_LTR_L12_TH_VALUE 0x03ff0000 /* LTR_L1.2_THRESHOLD_Value */ 1067 1066 #define PCI_L1SS_CTL1_LTR_L12_TH_SCALE 0xe0000000 /* LTR_L1.2_THRESHOLD_Scale */ 1068 1067 #define PCI_L1SS_CTL2 0x0c /* Control 2 Register */ 1068 + 1069 + /* Designated Vendor-Specific (DVSEC, PCI_EXT_CAP_ID_DVSEC) */ 1070 + #define PCI_DVSEC_HEADER1 0x4 /* Designated Vendor-Specific Header1 */ 1071 + #define PCI_DVSEC_HEADER2 0x8 /* Designated Vendor-Specific Header2 */ 1069 1072 1070 1073 /* Data Link Feature */ 1071 1074 #define PCI_DLF_CAP 0x04 /* Capabilities Register */