All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface
@ 2020-11-26 17:18 Srinivas Pandruvada
  2020-11-26 17:18 ` [PATCH 2/4] thermal: int340x: processor_thermal: Add AlderLake PCI device id Srinivas Pandruvada
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Srinivas Pandruvada @ 2020-11-26 17:18 UTC (permalink / raw)
  To: rui.zhang, daniel.lezcano, amitk
  Cc: linux-kernel, linux-pm, Srinivas Pandruvada

The Processor Thermal PCI device supports multiple features. Currently
we export only RAPL. But we need more features from this device exposed
for Tiger Lake and Alder Lake based platforms. So re-structure the
current MMIO interface, so that more features can be added cleanly.

No functional changes are expected with this change.

Changes done in this patch:
- Using PCI_DEVICE_DATA(), hence names of defines changed
- Move RAPL MMIO code to its own module
- Move the RAPL MMIO offsets to RAPL MMIO module
- Adjust Kconfig dependency of PROC_THERMAL_MMIO_RAPL
- Per processor driver data now contains the supported features
- Moved all the common data structures and defines to a common header
  file
- This new header file contains all the processor_thermal_* interfaces
- Based on the features supported the module interface is called
- Each module atleast provides one add and one remove function

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
 drivers/thermal/intel/int340x_thermal/Kconfig |   6 +-
 .../thermal/intel/int340x_thermal/Makefile    |   1 +
 .../processor_thermal_device.c                | 261 ++++--------------
 .../processor_thermal_device.h                |  72 +++++
 .../int340x_thermal/processor_thermal_rapl.c  | 134 +++++++++
 5 files changed, 263 insertions(+), 211 deletions(-)
 create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
 create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c

diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig b/drivers/thermal/intel/int340x_thermal/Kconfig
index 797907542e43..45c31f3d6054 100644
--- a/drivers/thermal/intel/int340x_thermal/Kconfig
+++ b/drivers/thermal/intel/int340x_thermal/Kconfig
@@ -10,6 +10,7 @@ config INT340X_THERMAL
 	select ACPI_THERMAL_REL
 	select ACPI_FAN
 	select INTEL_SOC_DTS_IOSF_CORE
+	select PROC_THERMAL_MMIO_RAPL if X86_64 && POWERCAP
 	help
 	  Newer laptops and tablets that use ACPI may have thermal sensors and
 	  other devices with thermal control capabilities outside the core
@@ -41,9 +42,6 @@ config INT3406_THERMAL
 	  power consumed by display device.
 
 config PROC_THERMAL_MMIO_RAPL
-	bool
-	depends on 64BIT
-	depends on POWERCAP
+	tristate
 	select INTEL_RAPL_CORE
-	default y
 endif
diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile
index 287eb0a1476d..86e8d3c87df7 100644
--- a/drivers/thermal/intel/int340x_thermal/Makefile
+++ b/drivers/thermal/intel/int340x_thermal/Makefile
@@ -4,5 +4,6 @@ obj-$(CONFIG_INT340X_THERMAL)	+= int340x_thermal_zone.o
 obj-$(CONFIG_INT340X_THERMAL)	+= int3402_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)	+= int3403_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_device.o
+obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
 obj-$(CONFIG_INT3406_THERMAL)	+= int3406_thermal.o
 obj-$(CONFIG_ACPI_THERMAL_REL)	+= acpi_thermal_rel.o
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 81e8b15ef405..5b8dc5e9ec86 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -12,74 +12,18 @@
 #include <linux/acpi.h>
 #include <linux/thermal.h>
 #include <linux/cpuhotplug.h>
-#include <linux/intel_rapl.h>
 #include "int340x_thermal_zone.h"
+#include "processor_thermal_device.h"
 #include "../intel_soc_dts_iosf.h"
 
-/* Broadwell-U/HSB thermal reporting device */
-#define PCI_DEVICE_ID_PROC_BDW_THERMAL	0x1603
-#define PCI_DEVICE_ID_PROC_HSB_THERMAL	0x0A03
-
-/* Skylake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_SKL_THERMAL	0x1903
-
-/* CannonLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_CNL_THERMAL	0x5a03
-#define PCI_DEVICE_ID_PROC_CFL_THERMAL	0x3E83
-
-/* Braswell thermal reporting device */
-#define PCI_DEVICE_ID_PROC_BSW_THERMAL	0x22DC
-
-/* Broxton thermal reporting device */
-#define PCI_DEVICE_ID_PROC_BXT0_THERMAL  0x0A8C
-#define PCI_DEVICE_ID_PROC_BXT1_THERMAL  0x1A8C
-#define PCI_DEVICE_ID_PROC_BXTX_THERMAL  0x4A8C
-#define PCI_DEVICE_ID_PROC_BXTP_THERMAL  0x5A8C
-
-/* GeminiLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_GLK_THERMAL	0x318C
-
-/* IceLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_ICL_THERMAL	0x8a03
-
-/* JasperLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_JSL_THERMAL	0x4E03
-
-/* TigerLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_TGL_THERMAL	0x9A03
-
 #define DRV_NAME "proc_thermal"
 
-struct power_config {
-	u32	index;
-	u32	min_uw;
-	u32	max_uw;
-	u32	tmin_us;
-	u32	tmax_us;
-	u32	step_uw;
-};
-
-struct proc_thermal_device {
-	struct device *dev;
-	struct acpi_device *adev;
-	struct power_config power_limits[2];
-	struct int34x_thermal_zone *int340x_zone;
-	struct intel_soc_dts_sensors *soc_dts;
-	void __iomem *mmio_base;
-};
-
 enum proc_thermal_emum_mode_type {
 	PROC_THERMAL_NONE,
 	PROC_THERMAL_PCI,
 	PROC_THERMAL_PLATFORM_DEV
 };
 
-struct rapl_mmio_regs {
-	u64 reg_unit;
-	u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
-	int limits[RAPL_DOMAIN_MAX];
-};
-
 /*
  * We can have only one type of enumeration, PCI or Platform,
  * not both. So we don't need instance specific data.
@@ -461,84 +405,13 @@ static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid)
 	return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_PROC_THERMAL_MMIO_RAPL
-
 #define MCHBAR 0
 
-/* RAPL Support via MMIO interface */
-static struct rapl_if_priv rapl_mmio_priv;
-
-static int rapl_mmio_cpu_online(unsigned int cpu)
-{
-	struct rapl_package *rp;
-
-	/* mmio rapl supports package 0 only for now */
-	if (topology_physical_package_id(cpu))
-		return 0;
-
-	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
-	if (!rp) {
-		rp = rapl_add_package(cpu, &rapl_mmio_priv);
-		if (IS_ERR(rp))
-			return PTR_ERR(rp);
-	}
-	cpumask_set_cpu(cpu, &rp->cpumask);
-	return 0;
-}
-
-static int rapl_mmio_cpu_down_prep(unsigned int cpu)
+static int proc_thermal_set_mmio_base(struct pci_dev *pdev,
+				      struct proc_thermal_device *proc_priv)
 {
-	struct rapl_package *rp;
-	int lead_cpu;
-
-	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
-	if (!rp)
-		return 0;
-
-	cpumask_clear_cpu(cpu, &rp->cpumask);
-	lead_cpu = cpumask_first(&rp->cpumask);
-	if (lead_cpu >= nr_cpu_ids)
-		rapl_remove_package(rp);
-	else if (rp->lead_cpu == cpu)
-		rp->lead_cpu = lead_cpu;
-	return 0;
-}
-
-static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
-{
-	if (!ra->reg)
-		return -EINVAL;
-
-	ra->value = readq((void __iomem *)ra->reg);
-	ra->value &= ra->mask;
-	return 0;
-}
-
-static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
-{
-	u64 val;
-
-	if (!ra->reg)
-		return -EINVAL;
-
-	val = readq((void __iomem *)ra->reg);
-	val &= ~ra->mask;
-	val |= ra->value;
-	writeq(val, (void __iomem *)ra->reg);
-	return 0;
-}
-
-static int proc_thermal_rapl_add(struct pci_dev *pdev,
-				 struct proc_thermal_device *proc_priv,
-				 struct rapl_mmio_regs *rapl_regs)
-{
-	enum rapl_domain_reg_id reg;
-	enum rapl_domain_type domain;
 	int ret;
 
-	if (!rapl_regs)
-		return 0;
-
 	ret = pcim_iomap_regions(pdev, 1 << MCHBAR, DRV_NAME);
 	if (ret) {
 		dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
@@ -547,66 +420,42 @@ static int proc_thermal_rapl_add(struct pci_dev *pdev,
 
 	proc_priv->mmio_base = pcim_iomap_table(pdev)[MCHBAR];
 
-	for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) {
-		for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++)
-			if (rapl_regs->regs[domain][reg])
-				rapl_mmio_priv.regs[domain][reg] =
-						(u64)proc_priv->mmio_base +
-						rapl_regs->regs[domain][reg];
-		rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain];
-	}
-	rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit;
+	return 0;
+}
 
-	rapl_mmio_priv.read_raw = rapl_mmio_read_raw;
-	rapl_mmio_priv.write_raw = rapl_mmio_write_raw;
+static int proc_thermal_mmio_add(struct pci_dev *pdev,
+				 struct proc_thermal_device *proc_priv,
+				 kernel_ulong_t feature_mask)
+{
+	int ret;
 
-	rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL);
-	if (IS_ERR(rapl_mmio_priv.control_type)) {
-		pr_debug("failed to register powercap control_type.\n");
-		return PTR_ERR(rapl_mmio_priv.control_type);
+	if (feature_mask) {
+		ret = proc_thermal_set_mmio_base(pdev, proc_priv);
+		if (ret)
+			return ret;
 	}
 
-	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
-				rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep);
-	if (ret < 0) {
-		powercap_unregister_control_type(rapl_mmio_priv.control_type);
-		rapl_mmio_priv.control_type = NULL;
-		return ret;
+	if (feature_mask & PROC_THERMAL_FEATURE_RAPL) {
+		ret = proc_thermal_rapl_add(pdev, proc_priv);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to add RAPL MMIO interface\n");
+			return ret;
+		}
 	}
-	rapl_mmio_priv.pcap_rapl_online = ret;
+
+	proc_priv->mmio_feature_mask = feature_mask;
 
 	return 0;
 }
 
-static void proc_thermal_rapl_remove(void)
+static void proc_thermal_mmio_remove(struct pci_dev *pdev)
 {
-	if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type))
-		return;
-
-	cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online);
-	powercap_unregister_control_type(rapl_mmio_priv.control_type);
-}
+	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
 
-static const struct rapl_mmio_regs rapl_mmio_hsw = {
-	.reg_unit = 0x5938,
-	.regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930},
-	.regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
-	.limits[RAPL_DOMAIN_PACKAGE] = 2,
-	.limits[RAPL_DOMAIN_DRAM] = 2,
-};
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
+		proc_thermal_rapl_remove();
 
-#else
-
-static int proc_thermal_rapl_add(struct pci_dev *pdev,
-				 struct proc_thermal_device *proc_priv,
-				 struct rapl_mmio_regs *rapl_regs)
-{
-	return 0;
 }
-static void proc_thermal_rapl_remove(void) {}
-static const struct rapl_mmio_regs rapl_mmio_hsw;
-
-#endif /* CONFIG_MMIO_RAPL */
 
 static int  proc_thermal_pci_probe(struct pci_dev *pdev,
 				   const struct pci_device_id *id)
@@ -629,18 +478,10 @@ static int  proc_thermal_pci_probe(struct pci_dev *pdev,
 	if (ret)
 		return ret;
 
-	ret = proc_thermal_rapl_add(pdev, proc_priv,
-				(struct rapl_mmio_regs *)id->driver_data);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to add RAPL MMIO interface\n");
-		proc_thermal_remove(proc_priv);
-		return ret;
-	}
-
 	pci_set_drvdata(pdev, proc_priv);
 	proc_thermal_emum_mode = PROC_THERMAL_PCI;
 
-	if (pdev->device == PCI_DEVICE_ID_PROC_BSW_THERMAL) {
+	if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) {
 		/*
 		 * Enumerate additional DTS sensors available via IOSF.
 		 * But we are not treating as a failure condition, if
@@ -676,10 +517,18 @@ static int  proc_thermal_pci_probe(struct pci_dev *pdev,
 		return ret;
 
 	ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group);
-	if (ret)
+	if (ret) {
 		sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
+		return ret;
+	}
 
-	return ret;
+	ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
+	if (ret) {
+		proc_thermal_remove(proc_priv);
+		return ret;
+	}
+
+	return 0;
 }
 
 static void  proc_thermal_pci_remove(struct pci_dev *pdev)
@@ -693,7 +542,8 @@ static void  proc_thermal_pci_remove(struct pci_dev *pdev)
 			pci_disable_msi(pdev);
 		}
 	}
-	proc_thermal_rapl_remove();
+
+	proc_thermal_mmio_remove(pdev);
 	proc_thermal_remove(proc_priv);
 }
 
@@ -716,24 +566,21 @@ static int proc_thermal_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
 
 static const struct pci_device_id proc_thermal_pci_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BDW_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_HSB_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_SKL_THERMAL),
-		.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BSW_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT0_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT1_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTX_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTP_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_CNL_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_CFL_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_GLK_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_ICL_THERMAL),
-		.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_JSL_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_TGL_THERMAL),
-		.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
-	{ 0, },
+	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+	{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+	{ },
 };
 
 MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
new file mode 100644
index 000000000000..e20d142a55b4
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * processor_thermal_device.h
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#ifndef __PROCESSOR_THERMAL_DEVICE_H__
+#define __PROCESSOR_THERMAL_DEVICE_H__
+
+#include <linux/intel_rapl.h>
+
+#define PCI_DEVICE_ID_INTEL_BDW_THERMAL	0x1603
+#define PCI_DEVICE_ID_INTEL_BSW_THERMAL	0x22DC
+
+#define PCI_DEVICE_ID_INTEL_BXT0_THERMAL	0x0A8C
+#define PCI_DEVICE_ID_INTEL_BXT1_THERMAL	0x1A8C
+#define PCI_DEVICE_ID_INTEL_BXTX_THERMAL	0x4A8C
+#define PCI_DEVICE_ID_INTEL_BXTP_THERMAL	0x5A8C
+
+#define PCI_DEVICE_ID_INTEL_CNL_THERMAL	0x5a03
+#define PCI_DEVICE_ID_INTEL_CFL_THERMAL	0x3E83
+#define PCI_DEVICE_ID_INTEL_GLK_THERMAL	0x318C
+#define PCI_DEVICE_ID_INTEL_HSB_THERMAL	0x0A03
+#define PCI_DEVICE_ID_INTEL_ICL_THERMAL	0x8a03
+#define PCI_DEVICE_ID_INTEL_JSL_THERMAL	0x4E03
+#define PCI_DEVICE_ID_INTEL_SKL_THERMAL	0x1903
+#define PCI_DEVICE_ID_INTEL_TGL_THERMAL	0x9A03
+
+struct power_config {
+	u32	index;
+	u32	min_uw;
+	u32	max_uw;
+	u32	tmin_us;
+	u32	tmax_us;
+	u32	step_uw;
+};
+
+struct proc_thermal_device {
+	struct device *dev;
+	struct acpi_device *adev;
+	struct power_config power_limits[2];
+	struct int34x_thermal_zone *int340x_zone;
+	struct intel_soc_dts_sensors *soc_dts;
+	u32 mmio_feature_mask;
+	void __iomem *mmio_base;
+};
+
+struct rapl_mmio_regs {
+	u64 reg_unit;
+	u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
+	int limits[RAPL_DOMAIN_MAX];
+};
+
+#define PROC_THERMAL_FEATURE_NONE	0x00
+#define PROC_THERMAL_FEATURE_RAPL	0x01
+
+#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
+int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
+void proc_thermal_rapl_remove(void);
+#else
+static int __maybe_unused proc_thermal_rapl_add(struct pci_dev *pdev,
+						struct proc_thermal_device *proc_priv)
+{
+	return 0;
+}
+
+static void __maybe_unused proc_thermal_rapl_remove(void)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
new file mode 100644
index 000000000000..a205221ec8df
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * processor thermal device RFIM control
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "processor_thermal_device.h"
+
+static struct rapl_if_priv rapl_mmio_priv;
+
+static const struct rapl_mmio_regs rapl_mmio_default = {
+	.reg_unit = 0x5938,
+	.regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930},
+	.regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
+	.limits[RAPL_DOMAIN_PACKAGE] = 2,
+	.limits[RAPL_DOMAIN_DRAM] = 2,
+};
+
+static int rapl_mmio_cpu_online(unsigned int cpu)
+{
+	struct rapl_package *rp;
+
+	/* mmio rapl supports package 0 only for now */
+	if (topology_physical_package_id(cpu))
+		return 0;
+
+	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
+	if (!rp) {
+		rp = rapl_add_package(cpu, &rapl_mmio_priv);
+		if (IS_ERR(rp))
+			return PTR_ERR(rp);
+	}
+	cpumask_set_cpu(cpu, &rp->cpumask);
+	return 0;
+}
+
+static int rapl_mmio_cpu_down_prep(unsigned int cpu)
+{
+	struct rapl_package *rp;
+	int lead_cpu;
+
+	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
+	if (!rp)
+		return 0;
+
+	cpumask_clear_cpu(cpu, &rp->cpumask);
+	lead_cpu = cpumask_first(&rp->cpumask);
+	if (lead_cpu >= nr_cpu_ids)
+		rapl_remove_package(rp);
+	else if (rp->lead_cpu == cpu)
+		rp->lead_cpu = lead_cpu;
+	return 0;
+}
+
+static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
+{
+	if (!ra->reg)
+		return -EINVAL;
+
+	ra->value = readq((void __iomem *)ra->reg);
+	ra->value &= ra->mask;
+	return 0;
+}
+
+static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
+{
+	u64 val;
+
+	if (!ra->reg)
+		return -EINVAL;
+
+	val = readq((void __iomem *)ra->reg);
+	val &= ~ra->mask;
+	val |= ra->value;
+	writeq(val, (void __iomem *)ra->reg);
+	return 0;
+}
+
+int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
+{
+	const struct rapl_mmio_regs *rapl_regs = &rapl_mmio_default;
+	enum rapl_domain_reg_id reg;
+	enum rapl_domain_type domain;
+	int ret;
+
+	if (!rapl_regs)
+		return 0;
+
+	for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) {
+		for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++)
+			if (rapl_regs->regs[domain][reg])
+				rapl_mmio_priv.regs[domain][reg] =
+						(u64)proc_priv->mmio_base +
+						rapl_regs->regs[domain][reg];
+		rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain];
+	}
+	rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit;
+
+	rapl_mmio_priv.read_raw = rapl_mmio_read_raw;
+	rapl_mmio_priv.write_raw = rapl_mmio_write_raw;
+
+	rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL);
+	if (IS_ERR(rapl_mmio_priv.control_type)) {
+		pr_debug("failed to register powercap control_type.\n");
+		return PTR_ERR(rapl_mmio_priv.control_type);
+	}
+
+	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
+				rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep);
+	if (ret < 0) {
+		powercap_unregister_control_type(rapl_mmio_priv.control_type);
+		rapl_mmio_priv.control_type = NULL;
+		return ret;
+	}
+	rapl_mmio_priv.pcap_rapl_online = ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(proc_thermal_rapl_add);
+
+void proc_thermal_rapl_remove(void)
+{
+	if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type))
+		return;
+
+	cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online);
+	powercap_unregister_control_type(rapl_mmio_priv.control_type);
+}
+EXPORT_SYMBOL_GPL(proc_thermal_rapl_remove);
+
+MODULE_LICENSE("GPL v2");
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/4] thermal: int340x: processor_thermal: Add AlderLake PCI device id
  2020-11-26 17:18 [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface Srinivas Pandruvada
@ 2020-11-26 17:18 ` Srinivas Pandruvada
  2020-12-11 13:09   ` [thermal: thermal/next] " thermal-bot for Srinivas Pandruvada
  2020-11-26 17:18 ` [PATCH 3/4] thermal: int340x: processor_thermal: Add RFIM driver Srinivas Pandruvada
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Srinivas Pandruvada @ 2020-11-26 17:18 UTC (permalink / raw)
  To: rui.zhang, daniel.lezcano, amitk
  Cc: linux-kernel, linux-pm, Srinivas Pandruvada

Added AlderLake PCI device id to support processor thermal driver. Reuse
the feature set (just includes RAPL) from previous generations.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
 drivers/thermal/intel/int340x_thermal/processor_thermal_device.c | 1 +
 drivers/thermal/intel/int340x_thermal/processor_thermal_device.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 5b8dc5e9ec86..589ac7deec02 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -566,6 +566,7 @@ static int proc_thermal_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
 
 static const struct pci_device_id proc_thermal_pci_ids[] = {
+	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
 	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
index e20d142a55b4..45214571e00d 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -9,6 +9,7 @@
 
 #include <linux/intel_rapl.h>
 
+#define PCI_DEVICE_ID_INTEL_ADL_THERMAL	0x461d
 #define PCI_DEVICE_ID_INTEL_BDW_THERMAL	0x1603
 #define PCI_DEVICE_ID_INTEL_BSW_THERMAL	0x22DC
 
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/4] thermal: int340x: processor_thermal: Add RFIM driver
  2020-11-26 17:18 [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface Srinivas Pandruvada
  2020-11-26 17:18 ` [PATCH 2/4] thermal: int340x: processor_thermal: Add AlderLake PCI device id Srinivas Pandruvada
@ 2020-11-26 17:18 ` Srinivas Pandruvada
  2020-12-09 20:48   ` Daniel Lezcano
  2020-12-11 13:09   ` [thermal: thermal/next] " thermal-bot for Srinivas Pandruvada
  2020-11-26 17:18 ` [PATCH 4/4] thermal: int340x: processor_thermal: Add mailbox driver Srinivas Pandruvada
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 11+ messages in thread
From: Srinivas Pandruvada @ 2020-11-26 17:18 UTC (permalink / raw)
  To: rui.zhang, daniel.lezcano, amitk
  Cc: linux-kernel, linux-pm, Srinivas Pandruvada

Add support for RFIM (Radio Frequency Interference Mitigation) support
via processor thermal PCI device. This drivers allows adjustment of
FIVR (Fully Integrated Voltage Regulator) and DDR (Double Data Rate)
frequencies to avoid RF interference with WiFi and 5G.

Switching voltage regulators (VR) generate radiated EMI or RFI at the
fundamental frequency and its harmonics. Some harmonics may interfere
with very sensitive wireless receivers such as Wi-Fi and cellular that
are integrated into host systems like notebook PCs.  One of mitigation
methods is requesting SOC integrated VR (IVR) switching frequency to a
small % and shift away the switching noise harmonic interference from
radio channels.  OEM or ODMs can use the driver to control SOC IVR
operation within the range where it does not impact IVR performance.

DRAM devices of DDR IO interface and their power plane can generate EMI
at the data rates. Similar to IVR control mechanism, Intel offers a
mechanism by which DDR data rates can be changed if several conditions
are met: there is strong RFI interference because of DDR; CPU power
management has no other restriction in changing DDR data rates;
PC ODMs enable this feature (real time DDR RFI Mitigation referred to as
DDR-RFIM) for Wi-Fi from BIOS.

This change exports two folders under /sys/bus/pci/devices/0000:00:04.0.
One folder "fivr" contains all attributes exposed for controling FIVR
features. The other folder "dvfs" contains all attributes for DDR
features.

Changes done to implement:
- New module for rfim interfaces
- Two new per processor features for DDR and FIVR
- Enable feature for Tiger Lake (FIVR only) and Alder Lake

The attributes exposed and explanation:

FIVR attributes

vco_ref_code_lo (RW): The VCO reference code is an 11-bit field and
controls the FIVR switching frequency. This is the 3-bit LSB field.

vco_ref_code_hi (RW): The VCO reference code is an 11-bit field and
controls the FIVR switching frequency. This is the 8-bit MSB field.

spread_spectrum_pct (RW): Set the FIVR spread spectrum clocking
percentage

spread_spectrum_clk_enable (RW): Enable/disable of the FIVR spread
spectrum clocking feature

rfi_vco_ref_code (RW): This field is a read only status register which
reflects the current FIVR switching frequency

fivr_fffc_rev (RW): This field indicated the revision of the FIVR HW.

DVFS attributes

rfi_restriction_run_busy (RW): Request the restriction of specific DDR
data rate and set this value 1. Self reset to 0 after operation.

rfi_restriction_err_code (RW): Values:  0 :Request is accepted, 1:Feature
disabled, 2: the request restricts more points than it is allowed

rfi_restriction_data_rate_Delta (RW): Restricted DDR data rate for RFI
protection: Lower Limit

rfi_restriction_data_rate_Base (RW): Restricted DDR data rate for RFI
protection: Upper Limit

ddr_data_rate_point_0 (RO): DDR data rate selection 1st point

ddr_data_rate_point_1 (RO): DDR data rate selection 2nd point

ddr_data_rate_point_2 (RO): DDR data rate selection 3rd point

ddr_data_rate_point_3 (RO): DDR data rate selection 4th point

rfi_disable (RW): Disable DDR rate change feature

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
 .../thermal/intel/int340x_thermal/Makefile    |   1 +
 .../processor_thermal_device.c                |  23 +-
 .../processor_thermal_device.h                |   5 +
 .../int340x_thermal/processor_thermal_rfim.c  | 244 ++++++++++++++++++
 4 files changed, 270 insertions(+), 3 deletions(-)
 create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c

diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile
index 86e8d3c87df7..f4e2eb7d9606 100644
--- a/drivers/thermal/intel/int340x_thermal/Makefile
+++ b/drivers/thermal/intel/int340x_thermal/Makefile
@@ -5,5 +5,6 @@ obj-$(CONFIG_INT340X_THERMAL)	+= int3402_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)	+= int3403_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_device.o
 obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
+obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_rfim.o
 obj-$(CONFIG_INT3406_THERMAL)	+= int3406_thermal.o
 obj-$(CONFIG_ACPI_THERMAL_REL)	+= acpi_thermal_rel.o
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 589ac7deec02..b6a7358b989d 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -429,6 +429,8 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev,
 {
 	int ret;
 
+	proc_priv->mmio_feature_mask = feature_mask;
+
 	if (feature_mask) {
 		ret = proc_thermal_set_mmio_base(pdev, proc_priv);
 		if (ret)
@@ -443,9 +445,21 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev,
 		}
 	}
 
-	proc_priv->mmio_feature_mask = feature_mask;
+	if (feature_mask & PROC_THERMAL_FEATURE_FIVR ||
+	    feature_mask & PROC_THERMAL_FEATURE_DVFS) {
+		ret = proc_thermal_rfim_add(pdev, proc_priv);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to add RFIM interface\n");
+			goto err_rem_rapl;
+		}
+	}
 
 	return 0;
+
+err_rem_rapl:
+	proc_thermal_rapl_remove();
+
+	return ret;
 }
 
 static void proc_thermal_mmio_remove(struct pci_dev *pdev)
@@ -455,6 +469,9 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev)
 	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
 		proc_thermal_rapl_remove();
 
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR ||
+	    proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
+		proc_thermal_rfim_remove(pdev);
 }
 
 static int  proc_thermal_pci_probe(struct pci_dev *pdev,
@@ -566,7 +583,7 @@ static int proc_thermal_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
 
 static const struct pci_device_id proc_thermal_pci_ids[] = {
-	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS) },
 	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
@@ -580,7 +597,7 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
 	{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
 	{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
-	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR) },
 	{ },
 };
 
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
index 45214571e00d..4bbb88f6b4a7 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -54,6 +54,8 @@ struct rapl_mmio_regs {
 
 #define PROC_THERMAL_FEATURE_NONE	0x00
 #define PROC_THERMAL_FEATURE_RAPL	0x01
+#define PROC_THERMAL_FEATURE_FIVR	0x02
+#define PROC_THERMAL_FEATURE_DVFS	0x04
 
 #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
 int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
@@ -70,4 +72,7 @@ static void __maybe_unused proc_thermal_rapl_remove(void)
 }
 #endif
 
+int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
+void proc_thermal_rfim_remove(struct pci_dev *pdev);
+
 #endif
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
new file mode 100644
index 000000000000..aef993a813e2
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * processor thermal device RFIM control
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "processor_thermal_device.h"
+
+struct mmio_reg {
+	int read_only;
+	u32 offset;
+	int bits;
+	u16 mask;
+	u16 shift;
+};
+
+/* These will represent sysfs attribute names */
+static const char * const fivr_strings[] = {
+	"vco_ref_code_lo",
+	"vco_ref_code_hi",
+	"spread_spectrum_pct",
+	"spread_spectrum_clk_enable",
+	"rfi_vco_ref_code",
+	"fivr_fffc_rev",
+	NULL
+};
+
+static const struct mmio_reg tgl_fivr_mmio_regs[] = {
+	{ 0, 0x5A18, 3, 0x7, 12}, /* vco_ref_code_lo */
+	{ 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */
+	{ 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */
+	{ 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */
+	{ 1, 0x5A10, 12, 0xFFF, 0}, /* rfi_vco_ref_code */
+	{ 1, 0x5A14, 2, 0x3, 1}, /* fivr_fffc_rev */
+};
+
+/* These will represent sysfs attribute names */
+static const char * const dvfs_strings[] = {
+	"rfi_restriction_run_busy",
+	"rfi_restriction_err_code",
+	"rfi_restriction_data_rate",
+	"rfi_restriction_data_rate_base",
+	"ddr_data_rate_point_0",
+	"ddr_data_rate_point_1",
+	"ddr_data_rate_point_2",
+	"ddr_data_rate_point_3",
+	"rfi_disable",
+	NULL
+};
+
+static const struct mmio_reg adl_dvfs_mmio_regs[] = {
+	{ 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */
+	{ 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */
+	{ 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */
+	{ 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base */
+	{ 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */
+	{ 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */
+	{ 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */
+	{ 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */
+	{ 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */
+};
+
+#define RFIM_SHOW(suffix, table)\
+static ssize_t suffix##_show(struct device *dev,\
+			      struct device_attribute *attr,\
+			      char *buf)\
+{\
+	struct proc_thermal_device *proc_priv;\
+	struct pci_dev *pdev = to_pci_dev(dev);\
+	const struct mmio_reg *mmio_regs;\
+	const char **match_strs;\
+	u32 reg_val;\
+	int ret;\
+\
+	proc_priv = pci_get_drvdata(pdev);\
+	if (table) {\
+		match_strs = (const char **)dvfs_strings;\
+		mmio_regs = adl_dvfs_mmio_regs;\
+	} else { \
+		match_strs = (const char **)fivr_strings;\
+		mmio_regs = tgl_fivr_mmio_regs;\
+	} \
+	\
+	ret = match_string(match_strs, -1, attr->attr.name);\
+	if (ret < 0)\
+		return ret;\
+	reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
+	ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\
+	return sprintf(buf, "%u\n", ret);\
+}
+
+#define RFIM_STORE(suffix, table)\
+static ssize_t suffix##_store(struct device *dev,\
+			       struct device_attribute *attr,\
+			       const char *buf, size_t count)\
+{\
+	struct proc_thermal_device *proc_priv;\
+	struct pci_dev *pdev = to_pci_dev(dev);\
+	unsigned int input;\
+	const char **match_strs;\
+	const struct mmio_reg *mmio_regs;\
+	int ret, err;\
+	u32 reg_val;\
+	u32 mask;\
+\
+	proc_priv = pci_get_drvdata(pdev);\
+	if (table) {\
+		match_strs = (const char **)dvfs_strings;\
+		mmio_regs = adl_dvfs_mmio_regs;\
+	} else { \
+		match_strs = (const char **)fivr_strings;\
+		mmio_regs = tgl_fivr_mmio_regs;\
+	} \
+	\
+	ret = match_string(match_strs, -1, attr->attr.name);\
+	if (ret < 0)\
+		return ret;\
+	if (mmio_regs[ret].read_only)\
+		return -EPERM;\
+	err = kstrtouint(buf, 10, &input);\
+	if (err)\
+		return err;\
+	mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\
+	reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
+	reg_val &= ~mask;\
+	reg_val |= (input << mmio_regs[ret].shift);\
+	writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
+	return count;\
+}
+
+RFIM_SHOW(vco_ref_code_lo, 0)
+RFIM_SHOW(vco_ref_code_hi, 0)
+RFIM_SHOW(spread_spectrum_pct, 0)
+RFIM_SHOW(spread_spectrum_clk_enable, 0)
+RFIM_SHOW(rfi_vco_ref_code, 0)
+RFIM_SHOW(fivr_fffc_rev, 0)
+
+RFIM_STORE(vco_ref_code_lo, 0)
+RFIM_STORE(vco_ref_code_hi, 0)
+RFIM_STORE(spread_spectrum_pct, 0)
+RFIM_STORE(spread_spectrum_clk_enable, 0)
+RFIM_STORE(rfi_vco_ref_code, 0)
+RFIM_STORE(fivr_fffc_rev, 0)
+
+static DEVICE_ATTR_RW(vco_ref_code_lo);
+static DEVICE_ATTR_RW(vco_ref_code_hi);
+static DEVICE_ATTR_RW(spread_spectrum_pct);
+static DEVICE_ATTR_RW(spread_spectrum_clk_enable);
+static DEVICE_ATTR_RW(rfi_vco_ref_code);
+static DEVICE_ATTR_RW(fivr_fffc_rev);
+
+static struct attribute *fivr_attrs[] = {
+	&dev_attr_vco_ref_code_lo.attr,
+	&dev_attr_vco_ref_code_hi.attr,
+	&dev_attr_spread_spectrum_pct.attr,
+	&dev_attr_spread_spectrum_clk_enable.attr,
+	&dev_attr_rfi_vco_ref_code.attr,
+	&dev_attr_fivr_fffc_rev.attr,
+	NULL
+};
+
+static const struct attribute_group fivr_attribute_group = {
+	.attrs = fivr_attrs,
+	.name = "fivr"
+};
+
+RFIM_SHOW(rfi_restriction_run_busy, 1)
+RFIM_SHOW(rfi_restriction_err_code, 1)
+RFIM_SHOW(rfi_restriction_data_rate, 1)
+RFIM_SHOW(ddr_data_rate_point_0, 1)
+RFIM_SHOW(ddr_data_rate_point_1, 1)
+RFIM_SHOW(ddr_data_rate_point_2, 1)
+RFIM_SHOW(ddr_data_rate_point_3, 1)
+RFIM_SHOW(rfi_disable, 1)
+
+RFIM_STORE(rfi_restriction_run_busy, 1)
+RFIM_STORE(rfi_restriction_err_code, 1)
+RFIM_STORE(rfi_restriction_data_rate, 1)
+RFIM_STORE(rfi_disable, 1)
+
+static DEVICE_ATTR_RW(rfi_restriction_run_busy);
+static DEVICE_ATTR_RW(rfi_restriction_err_code);
+static DEVICE_ATTR_RW(rfi_restriction_data_rate);
+static DEVICE_ATTR_RO(ddr_data_rate_point_0);
+static DEVICE_ATTR_RO(ddr_data_rate_point_1);
+static DEVICE_ATTR_RO(ddr_data_rate_point_2);
+static DEVICE_ATTR_RO(ddr_data_rate_point_3);
+static DEVICE_ATTR_RW(rfi_disable);
+
+static struct attribute *dvfs_attrs[] = {
+	&dev_attr_rfi_restriction_run_busy.attr,
+	&dev_attr_rfi_restriction_err_code.attr,
+	&dev_attr_rfi_restriction_data_rate.attr,
+	&dev_attr_ddr_data_rate_point_0.attr,
+	&dev_attr_ddr_data_rate_point_1.attr,
+	&dev_attr_ddr_data_rate_point_2.attr,
+	&dev_attr_ddr_data_rate_point_3.attr,
+	&dev_attr_rfi_disable.attr,
+	NULL
+};
+
+static const struct attribute_group dvfs_attribute_group = {
+	.attrs = dvfs_attrs,
+	.name = "dvfs"
+};
+
+int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
+{
+	int ret;
+
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
+		ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group);
+		if (ret)
+			return ret;
+	}
+
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {
+		ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group);
+		if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
+			sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(proc_thermal_rfim_add);
+
+void proc_thermal_rfim_remove(struct pci_dev *pdev)
+{
+	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
+
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
+		sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
+
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
+		sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group);
+}
+EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);
+
+MODULE_LICENSE("GPL v2");
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/4] thermal: int340x: processor_thermal: Add mailbox driver
  2020-11-26 17:18 [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface Srinivas Pandruvada
  2020-11-26 17:18 ` [PATCH 2/4] thermal: int340x: processor_thermal: Add AlderLake PCI device id Srinivas Pandruvada
  2020-11-26 17:18 ` [PATCH 3/4] thermal: int340x: processor_thermal: Add RFIM driver Srinivas Pandruvada
@ 2020-11-26 17:18 ` Srinivas Pandruvada
  2020-12-11 13:09   ` [thermal: thermal/next] " thermal-bot for Srinivas Pandruvada
  2020-12-09 16:15 ` [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface Srinivas Pandruvada
  2020-12-11 13:09 ` [thermal: thermal/next] " thermal-bot for Srinivas Pandruvada
  4 siblings, 1 reply; 11+ messages in thread
From: Srinivas Pandruvada @ 2020-11-26 17:18 UTC (permalink / raw)
  To: rui.zhang, daniel.lezcano, amitk
  Cc: linux-kernel, linux-pm, Srinivas Pandruvada

Added processor thermal device mail box interface for workload hints
setting. These hints will give indication to hardware to better manage
power and thermals. The supported hints are:
idle
semi_active
burusty
sustained
battery_life

For example when the system is on battery, the hardware can be less
aggressive in power ramp up.

This will create an attribute group at
/sys/bus/pci/devices/0000:00:04.0/workload_request

This folder contains two attributes:
workload_available_types : (RO):  This shows available workload types
workload_type: (RW) : Allows to set and get current workload type
setting

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
 .../thermal/intel/int340x_thermal/Makefile    |   1 +
 .../processor_thermal_device.c                |  17 +-
 .../processor_thermal_device.h                |   4 +
 .../int340x_thermal/processor_thermal_mbox.c  | 212 ++++++++++++++++++
 4 files changed, 232 insertions(+), 2 deletions(-)
 create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c

diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile
index f4e2eb7d9606..38a2731e503c 100644
--- a/drivers/thermal/intel/int340x_thermal/Makefile
+++ b/drivers/thermal/intel/int340x_thermal/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_INT340X_THERMAL)	+= int3403_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_device.o
 obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
 obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_rfim.o
+obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_mbox.o
 obj-$(CONFIG_INT3406_THERMAL)	+= int3406_thermal.o
 obj-$(CONFIG_ACPI_THERMAL_REL)	+= acpi_thermal_rel.o
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index b6a7358b989d..9e6f2a895a23 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -454,8 +454,18 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev,
 		}
 	}
 
+	if (feature_mask & PROC_THERMAL_FEATURE_MBOX) {
+		ret = proc_thermal_mbox_add(pdev, proc_priv);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to add MBOX interface\n");
+			goto err_rem_rfim;
+		}
+	}
+
 	return 0;
 
+err_rem_rfim:
+	proc_thermal_rfim_remove(pdev);
 err_rem_rapl:
 	proc_thermal_rapl_remove();
 
@@ -472,6 +482,9 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev)
 	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR ||
 	    proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
 		proc_thermal_rfim_remove(pdev);
+
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX)
+		proc_thermal_mbox_remove(pdev);
 }
 
 static int  proc_thermal_pci_probe(struct pci_dev *pdev,
@@ -583,7 +596,7 @@ static int proc_thermal_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
 
 static const struct pci_device_id proc_thermal_pci_ids[] = {
-	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS) },
+	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
 	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
@@ -597,7 +610,7 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
 	{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
 	{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
-	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR) },
+	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) },
 	{ },
 };
 
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
index 4bbb88f6b4a7..b9ed64561aaf 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -56,6 +56,7 @@ struct rapl_mmio_regs {
 #define PROC_THERMAL_FEATURE_RAPL	0x01
 #define PROC_THERMAL_FEATURE_FIVR	0x02
 #define PROC_THERMAL_FEATURE_DVFS	0x04
+#define PROC_THERMAL_FEATURE_MBOX	0x08
 
 #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
 int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
@@ -75,4 +76,7 @@ static void __maybe_unused proc_thermal_rapl_remove(void)
 int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
 void proc_thermal_rfim_remove(struct pci_dev *pdev);
 
+int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
+void proc_thermal_mbox_remove(struct pci_dev *pdev);
+
 #endif
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
new file mode 100644
index 000000000000..2c105fed2d7b
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * processor thermal device mailbox driver for Workload type hints
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "processor_thermal_device.h"
+
+#define MBOX_CMD_WORKLOAD_TYPE_READ	0x0E
+#define MBOX_CMD_WORKLOAD_TYPE_WRITE	0x0F
+
+#define MBOX_OFFSET_DATA		0x5810
+#define MBOX_OFFSET_INTERFACE		0x5818
+
+#define MBOX_BUSY_BIT			31
+#define MBOX_RETRY_COUNT		100
+
+#define MBOX_DATA_BIT_VALID		31
+#define MBOX_DATA_BIT_AC_DC		30
+
+static DEFINE_MUTEX(mbox_lock);
+
+static int send_mbox_cmd(struct pci_dev *pdev, u8 cmd_id, u32 cmd_data, u8 *cmd_resp)
+{
+	struct proc_thermal_device *proc_priv;
+	u32 retries, data;
+	int ret;
+
+	mutex_lock(&mbox_lock);
+	proc_priv = pci_get_drvdata(pdev);
+
+	/* Poll for rb bit == 0 */
+	retries = MBOX_RETRY_COUNT;
+	do {
+		data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
+		if (data & BIT_ULL(MBOX_BUSY_BIT)) {
+			ret = -EBUSY;
+			continue;
+		}
+		ret = 0;
+		break;
+	} while (--retries);
+
+	if (ret)
+		goto unlock_mbox;
+
+	if (cmd_id == MBOX_CMD_WORKLOAD_TYPE_WRITE)
+		writel(cmd_data, (void __iomem *) ((proc_priv->mmio_base + MBOX_OFFSET_DATA)));
+
+	/* Write command register */
+	data = BIT_ULL(MBOX_BUSY_BIT) | cmd_id;
+	writel(data, (void __iomem *) ((proc_priv->mmio_base + MBOX_OFFSET_INTERFACE)));
+
+	/* Poll for rb bit == 0 */
+	retries = MBOX_RETRY_COUNT;
+	do {
+		data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
+		if (data & BIT_ULL(MBOX_BUSY_BIT)) {
+			ret = -EBUSY;
+			continue;
+		}
+
+		if (data) {
+			ret = -ENXIO;
+			goto unlock_mbox;
+		}
+
+		if (cmd_id == MBOX_CMD_WORKLOAD_TYPE_READ) {
+			data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_DATA));
+			*cmd_resp = data & 0xff;
+		}
+
+		ret = 0;
+		break;
+	} while (--retries);
+
+unlock_mbox:
+	mutex_unlock(&mbox_lock);
+	return ret;
+}
+
+/* List of workload types */
+static const char * const workload_types[] = {
+	"none",
+	"idle",
+	"semi_active",
+	"burusty",
+	"sustained",
+	"battery_life",
+	NULL
+};
+
+
+static ssize_t workload_available_types_show(struct device *dev,
+					       struct device_attribute *attr,
+					       char *buf)
+{
+	int i = 0;
+	int ret = 0;
+
+	while (workload_types[i] != NULL)
+		ret += sprintf(&buf[ret], "%s ", workload_types[i++]);
+
+	ret += sprintf(&buf[ret], "\n");
+
+	return ret;
+}
+
+static DEVICE_ATTR_RO(workload_available_types);
+
+static ssize_t workload_type_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	char str_preference[15];
+	u32 data = 0;
+	ssize_t ret;
+
+	ret = sscanf(buf, "%14s", str_preference);
+	if (ret != 1)
+		return -EINVAL;
+
+	ret = match_string(workload_types, -1, str_preference);
+	if (ret < 0)
+		return ret;
+
+	ret &= 0xff;
+
+	if (ret)
+		data = BIT(MBOX_DATA_BIT_VALID) | BIT(MBOX_DATA_BIT_AC_DC);
+
+	data |= ret;
+
+	ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_WRITE, data, NULL);
+	if (ret)
+		return false;
+
+	return count;
+}
+
+static ssize_t workload_type_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u8 cmd_resp;
+	int ret;
+
+	ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
+	if (ret)
+		return false;
+
+	cmd_resp &= 0xff;
+
+	if (cmd_resp > ARRAY_SIZE(workload_types) - 1)
+		return -EINVAL;
+
+	return sprintf(buf, "%s\n", workload_types[cmd_resp]);
+}
+
+static DEVICE_ATTR_RW(workload_type);
+
+static struct attribute *workload_req_attrs[] = {
+	&dev_attr_workload_available_types.attr,
+	&dev_attr_workload_type.attr,
+	NULL
+};
+
+static const struct attribute_group workload_req_attribute_group = {
+	.attrs = workload_req_attrs,
+	.name = "workload_request"
+};
+
+
+
+static bool workload_req_created;
+
+int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
+{
+	u8 cmd_resp;
+	int ret;
+
+	/* Check if there is a mailbox support, if fails return success */
+	ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
+	if (ret)
+		return 0;
+
+	ret = sysfs_create_group(&pdev->dev.kobj, &workload_req_attribute_group);
+	if (ret)
+		return ret;
+
+	workload_req_created = true;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(proc_thermal_mbox_add);
+
+void proc_thermal_mbox_remove(struct pci_dev *pdev)
+{
+	if (workload_req_created)
+		sysfs_remove_group(&pdev->dev.kobj, &workload_req_attribute_group);
+
+	workload_req_created = false;
+
+}
+EXPORT_SYMBOL_GPL(proc_thermal_mbox_remove);
+
+MODULE_LICENSE("GPL v2");
-- 
2.25.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface
  2020-11-26 17:18 [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface Srinivas Pandruvada
                   ` (2 preceding siblings ...)
  2020-11-26 17:18 ` [PATCH 4/4] thermal: int340x: processor_thermal: Add mailbox driver Srinivas Pandruvada
@ 2020-12-09 16:15 ` Srinivas Pandruvada
  2020-12-11 13:09 ` [thermal: thermal/next] " thermal-bot for Srinivas Pandruvada
  4 siblings, 0 replies; 11+ messages in thread
From: Srinivas Pandruvada @ 2020-12-09 16:15 UTC (permalink / raw)
  To: rui.zhang, daniel.lezcano, amitk; +Cc: linux-kernel, linux-pm

On Thu, 2020-11-26 at 09:18 -0800, Srinivas Pandruvada wrote:
> The Processor Thermal PCI device supports multiple features.
> Currently
> we export only RAPL. But we need more features from this device
> exposed
> for Tiger Lake and Alder Lake based platforms. So re-structure the
> current MMIO interface, so that more features can be added cleanly.
> 
> No functional changes are expected with this change.
> 
Any objection for this series for 5.11?

Thanks,
Srinivas

> Changes done in this patch:
> - Using PCI_DEVICE_DATA(), hence names of defines changed
> - Move RAPL MMIO code to its own module
> - Move the RAPL MMIO offsets to RAPL MMIO module
> - Adjust Kconfig dependency of PROC_THERMAL_MMIO_RAPL
> - Per processor driver data now contains the supported features
> - Moved all the common data structures and defines to a common header
>   file
> - This new header file contains all the processor_thermal_*
> interfaces
> - Based on the features supported the module interface is called
> - Each module atleast provides one add and one remove function
> 
> Signed-off-by: Srinivas Pandruvada <
> srinivas.pandruvada@linux.intel.com>
> ---
>  drivers/thermal/intel/int340x_thermal/Kconfig |   6 +-
>  .../thermal/intel/int340x_thermal/Makefile    |   1 +
>  .../processor_thermal_device.c                | 261 ++++----------
> ----
>  .../processor_thermal_device.h                |  72 +++++
>  .../int340x_thermal/processor_thermal_rapl.c  | 134 +++++++++
>  5 files changed, 263 insertions(+), 211 deletions(-)
>  create mode 100644
> drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
>  create mode 100644
> drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
> 
> diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig
> b/drivers/thermal/intel/int340x_thermal/Kconfig
> index 797907542e43..45c31f3d6054 100644
> --- a/drivers/thermal/intel/int340x_thermal/Kconfig
> +++ b/drivers/thermal/intel/int340x_thermal/Kconfig
> @@ -10,6 +10,7 @@ config INT340X_THERMAL
>  	select ACPI_THERMAL_REL
>  	select ACPI_FAN
>  	select INTEL_SOC_DTS_IOSF_CORE
> +	select PROC_THERMAL_MMIO_RAPL if X86_64 && POWERCAP
>  	help
>  	  Newer laptops and tablets that use ACPI may have thermal
> sensors and
>  	  other devices with thermal control capabilities outside the
> core
> @@ -41,9 +42,6 @@ config INT3406_THERMAL
>  	  power consumed by display device.
>  
>  config PROC_THERMAL_MMIO_RAPL
> -	bool
> -	depends on 64BIT
> -	depends on POWERCAP
> +	tristate
>  	select INTEL_RAPL_CORE
> -	default y
>  endif
> diff --git a/drivers/thermal/intel/int340x_thermal/Makefile
> b/drivers/thermal/intel/int340x_thermal/Makefile
> index 287eb0a1476d..86e8d3c87df7 100644
> --- a/drivers/thermal/intel/int340x_thermal/Makefile
> +++ b/drivers/thermal/intel/int340x_thermal/Makefile
> @@ -4,5 +4,6 @@ obj-$(CONFIG_INT340X_THERMAL)	+=
> int340x_thermal_zone.o
>  obj-$(CONFIG_INT340X_THERMAL)	+= int3402_thermal.o
>  obj-$(CONFIG_INT340X_THERMAL)	+= int3403_thermal.o
>  obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_device.o
> +obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
>  obj-$(CONFIG_INT3406_THERMAL)	+= int3406_thermal.o
>  obj-$(CONFIG_ACPI_THERMAL_REL)	+= acpi_thermal_rel.o
> diff --git
> a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> index 81e8b15ef405..5b8dc5e9ec86 100644
> ---
> a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> +++
> b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> @@ -12,74 +12,18 @@
>  #include <linux/acpi.h>
>  #include <linux/thermal.h>
>  #include <linux/cpuhotplug.h>
> -#include <linux/intel_rapl.h>
>  #include "int340x_thermal_zone.h"
> +#include "processor_thermal_device.h"
>  #include "../intel_soc_dts_iosf.h"
>  
> -/* Broadwell-U/HSB thermal reporting device */
> -#define PCI_DEVICE_ID_PROC_BDW_THERMAL	0x1603
> -#define PCI_DEVICE_ID_PROC_HSB_THERMAL	0x0A03
> -
> -/* Skylake thermal reporting device */
> -#define PCI_DEVICE_ID_PROC_SKL_THERMAL	0x1903
> -
> -/* CannonLake thermal reporting device */
> -#define PCI_DEVICE_ID_PROC_CNL_THERMAL	0x5a03
> -#define PCI_DEVICE_ID_PROC_CFL_THERMAL	0x3E83
> -
> -/* Braswell thermal reporting device */
> -#define PCI_DEVICE_ID_PROC_BSW_THERMAL	0x22DC
> -
> -/* Broxton thermal reporting device */
> -#define PCI_DEVICE_ID_PROC_BXT0_THERMAL  0x0A8C
> -#define PCI_DEVICE_ID_PROC_BXT1_THERMAL  0x1A8C
> -#define PCI_DEVICE_ID_PROC_BXTX_THERMAL  0x4A8C
> -#define PCI_DEVICE_ID_PROC_BXTP_THERMAL  0x5A8C
> -
> -/* GeminiLake thermal reporting device */
> -#define PCI_DEVICE_ID_PROC_GLK_THERMAL	0x318C
> -
> -/* IceLake thermal reporting device */
> -#define PCI_DEVICE_ID_PROC_ICL_THERMAL	0x8a03
> -
> -/* JasperLake thermal reporting device */
> -#define PCI_DEVICE_ID_PROC_JSL_THERMAL	0x4E03
> -
> -/* TigerLake thermal reporting device */
> -#define PCI_DEVICE_ID_PROC_TGL_THERMAL	0x9A03
> -
>  #define DRV_NAME "proc_thermal"
>  
> -struct power_config {
> -	u32	index;
> -	u32	min_uw;
> -	u32	max_uw;
> -	u32	tmin_us;
> -	u32	tmax_us;
> -	u32	step_uw;
> -};
> -
> -struct proc_thermal_device {
> -	struct device *dev;
> -	struct acpi_device *adev;
> -	struct power_config power_limits[2];
> -	struct int34x_thermal_zone *int340x_zone;
> -	struct intel_soc_dts_sensors *soc_dts;
> -	void __iomem *mmio_base;
> -};
> -
>  enum proc_thermal_emum_mode_type {
>  	PROC_THERMAL_NONE,
>  	PROC_THERMAL_PCI,
>  	PROC_THERMAL_PLATFORM_DEV
>  };
>  
> -struct rapl_mmio_regs {
> -	u64 reg_unit;
> -	u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
> -	int limits[RAPL_DOMAIN_MAX];
> -};
> -
>  /*
>   * We can have only one type of enumeration, PCI or Platform,
>   * not both. So we don't need instance specific data.
> @@ -461,84 +405,13 @@ static irqreturn_t proc_thermal_pci_msi_irq(int
> irq, void *devid)
>  	return IRQ_HANDLED;
>  }
>  
> -#ifdef CONFIG_PROC_THERMAL_MMIO_RAPL
> -
>  #define MCHBAR 0
>  
> -/* RAPL Support via MMIO interface */
> -static struct rapl_if_priv rapl_mmio_priv;
> -
> -static int rapl_mmio_cpu_online(unsigned int cpu)
> -{
> -	struct rapl_package *rp;
> -
> -	/* mmio rapl supports package 0 only for now */
> -	if (topology_physical_package_id(cpu))
> -		return 0;
> -
> -	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
> -	if (!rp) {
> -		rp = rapl_add_package(cpu, &rapl_mmio_priv);
> -		if (IS_ERR(rp))
> -			return PTR_ERR(rp);
> -	}
> -	cpumask_set_cpu(cpu, &rp->cpumask);
> -	return 0;
> -}
> -
> -static int rapl_mmio_cpu_down_prep(unsigned int cpu)
> +static int proc_thermal_set_mmio_base(struct pci_dev *pdev,
> +				      struct proc_thermal_device
> *proc_priv)
>  {
> -	struct rapl_package *rp;
> -	int lead_cpu;
> -
> -	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
> -	if (!rp)
> -		return 0;
> -
> -	cpumask_clear_cpu(cpu, &rp->cpumask);
> -	lead_cpu = cpumask_first(&rp->cpumask);
> -	if (lead_cpu >= nr_cpu_ids)
> -		rapl_remove_package(rp);
> -	else if (rp->lead_cpu == cpu)
> -		rp->lead_cpu = lead_cpu;
> -	return 0;
> -}
> -
> -static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
> -{
> -	if (!ra->reg)
> -		return -EINVAL;
> -
> -	ra->value = readq((void __iomem *)ra->reg);
> -	ra->value &= ra->mask;
> -	return 0;
> -}
> -
> -static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
> -{
> -	u64 val;
> -
> -	if (!ra->reg)
> -		return -EINVAL;
> -
> -	val = readq((void __iomem *)ra->reg);
> -	val &= ~ra->mask;
> -	val |= ra->value;
> -	writeq(val, (void __iomem *)ra->reg);
> -	return 0;
> -}
> -
> -static int proc_thermal_rapl_add(struct pci_dev *pdev,
> -				 struct proc_thermal_device *proc_priv,
> -				 struct rapl_mmio_regs *rapl_regs)
> -{
> -	enum rapl_domain_reg_id reg;
> -	enum rapl_domain_type domain;
>  	int ret;
>  
> -	if (!rapl_regs)
> -		return 0;
> -
>  	ret = pcim_iomap_regions(pdev, 1 << MCHBAR, DRV_NAME);
>  	if (ret) {
>  		dev_err(&pdev->dev, "cannot reserve PCI memory
> region\n");
> @@ -547,66 +420,42 @@ static int proc_thermal_rapl_add(struct pci_dev
> *pdev,
>  
>  	proc_priv->mmio_base = pcim_iomap_table(pdev)[MCHBAR];
>  
> -	for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX;
> domain++) {
> -		for (reg = RAPL_DOMAIN_REG_LIMIT; reg <
> RAPL_DOMAIN_REG_MAX; reg++)
> -			if (rapl_regs->regs[domain][reg])
> -				rapl_mmio_priv.regs[domain][reg] =
> -						(u64)proc_priv-
> >mmio_base +
> -						rapl_regs-
> >regs[domain][reg];
> -		rapl_mmio_priv.limits[domain] = rapl_regs-
> >limits[domain];
> -	}
> -	rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base +
> rapl_regs->reg_unit;
> +	return 0;
> +}
>  
> -	rapl_mmio_priv.read_raw = rapl_mmio_read_raw;
> -	rapl_mmio_priv.write_raw = rapl_mmio_write_raw;
> +static int proc_thermal_mmio_add(struct pci_dev *pdev,
> +				 struct proc_thermal_device *proc_priv,
> +				 kernel_ulong_t feature_mask)
> +{
> +	int ret;
>  
> -	rapl_mmio_priv.control_type =
> powercap_register_control_type(NULL, "intel-rapl-mmio", NULL);
> -	if (IS_ERR(rapl_mmio_priv.control_type)) {
> -		pr_debug("failed to register powercap
> control_type.\n");
> -		return PTR_ERR(rapl_mmio_priv.control_type);
> +	if (feature_mask) {
> +		ret = proc_thermal_set_mmio_base(pdev, proc_priv);
> +		if (ret)
> +			return ret;
>  	}
>  
> -	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
> "powercap/rapl:online",
> -				rapl_mmio_cpu_online,
> rapl_mmio_cpu_down_prep);
> -	if (ret < 0) {
> -		powercap_unregister_control_type(rapl_mmio_priv.control
> _type);
> -		rapl_mmio_priv.control_type = NULL;
> -		return ret;
> +	if (feature_mask & PROC_THERMAL_FEATURE_RAPL) {
> +		ret = proc_thermal_rapl_add(pdev, proc_priv);
> +		if (ret) {
> +			dev_err(&pdev->dev, "failed to add RAPL MMIO
> interface\n");
> +			return ret;
> +		}
>  	}
> -	rapl_mmio_priv.pcap_rapl_online = ret;
> +
> +	proc_priv->mmio_feature_mask = feature_mask;
>  
>  	return 0;
>  }
>  
> -static void proc_thermal_rapl_remove(void)
> +static void proc_thermal_mmio_remove(struct pci_dev *pdev)
>  {
> -	if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type))
> -		return;
> -
> -	cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online);
> -	powercap_unregister_control_type(rapl_mmio_priv.control_type);
> -}
> +	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
>  
> -static const struct rapl_mmio_regs rapl_mmio_hsw = {
> -	.reg_unit = 0x5938,
> -	.regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0,
> 0x5930},
> -	.regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
> -	.limits[RAPL_DOMAIN_PACKAGE] = 2,
> -	.limits[RAPL_DOMAIN_DRAM] = 2,
> -};
> +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
> +		proc_thermal_rapl_remove();
>  
> -#else
> -
> -static int proc_thermal_rapl_add(struct pci_dev *pdev,
> -				 struct proc_thermal_device *proc_priv,
> -				 struct rapl_mmio_regs *rapl_regs)
> -{
> -	return 0;
>  }
> -static void proc_thermal_rapl_remove(void) {}
> -static const struct rapl_mmio_regs rapl_mmio_hsw;
> -
> -#endif /* CONFIG_MMIO_RAPL */
>  
>  static int  proc_thermal_pci_probe(struct pci_dev *pdev,
>  				   const struct pci_device_id *id)
> @@ -629,18 +478,10 @@ static int  proc_thermal_pci_probe(struct
> pci_dev *pdev,
>  	if (ret)
>  		return ret;
>  
> -	ret = proc_thermal_rapl_add(pdev, proc_priv,
> -				(struct rapl_mmio_regs *)id-
> >driver_data);
> -	if (ret) {
> -		dev_err(&pdev->dev, "failed to add RAPL MMIO
> interface\n");
> -		proc_thermal_remove(proc_priv);
> -		return ret;
> -	}
> -
>  	pci_set_drvdata(pdev, proc_priv);
>  	proc_thermal_emum_mode = PROC_THERMAL_PCI;
>  
> -	if (pdev->device == PCI_DEVICE_ID_PROC_BSW_THERMAL) {
> +	if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) {
>  		/*
>  		 * Enumerate additional DTS sensors available via IOSF.
>  		 * But we are not treating as a failure condition, if
> @@ -676,10 +517,18 @@ static int  proc_thermal_pci_probe(struct
> pci_dev *pdev,
>  		return ret;
>  
>  	ret = sysfs_create_group(&pdev->dev.kobj,
> &power_limit_attribute_group);
> -	if (ret)
> +	if (ret) {
>  		sysfs_remove_file(&pdev->dev.kobj,
> &dev_attr_tcc_offset_degree_celsius.attr);
> +		return ret;
> +	}
>  
> -	return ret;
> +	ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
> +	if (ret) {
> +		proc_thermal_remove(proc_priv);
> +		return ret;
> +	}
> +
> +	return 0;
>  }
>  
>  static void  proc_thermal_pci_remove(struct pci_dev *pdev)
> @@ -693,7 +542,8 @@ static void  proc_thermal_pci_remove(struct
> pci_dev *pdev)
>  			pci_disable_msi(pdev);
>  		}
>  	}
> -	proc_thermal_rapl_remove();
> +
> +	proc_thermal_mmio_remove(pdev);
>  	proc_thermal_remove(proc_priv);
>  }
>  
> @@ -716,24 +566,21 @@ static int proc_thermal_resume(struct device
> *dev)
>  static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL,
> proc_thermal_resume);
>  
>  static const struct pci_device_id proc_thermal_pci_ids[] = {
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_BDW_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_HSB_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_SKL_THERMAL),
> -		.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_BSW_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_BXT0_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_BXT1_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_BXTX_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_BXTP_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_CNL_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_CFL_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_GLK_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_ICL_THERMAL),
> -		.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_JSL_THERMAL)},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCI_DEVICE_ID_PROC_TGL_THERMAL),
> -		.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
> -	{ 0, },
> +	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL,
> PROC_THERMAL_FEATURE_RAPL) },
> +	{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
> +	{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL,
> PROC_THERMAL_FEATURE_RAPL) },
> +	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL,
> PROC_THERMAL_FEATURE_RAPL) },
> +	{ },
>  };
>  
>  MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
> diff --git
> a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
> b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
> new file mode 100644
> index 000000000000..e20d142a55b4
> --- /dev/null
> +++
> b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
> @@ -0,0 +1,72 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * processor_thermal_device.h
> + * Copyright (c) 2020, Intel Corporation.
> + */
> +
> +#ifndef __PROCESSOR_THERMAL_DEVICE_H__
> +#define __PROCESSOR_THERMAL_DEVICE_H__
> +
> +#include <linux/intel_rapl.h>
> +
> +#define PCI_DEVICE_ID_INTEL_BDW_THERMAL	0x1603
> +#define PCI_DEVICE_ID_INTEL_BSW_THERMAL	0x22DC
> +
> +#define PCI_DEVICE_ID_INTEL_BXT0_THERMAL	0x0A8C
> +#define PCI_DEVICE_ID_INTEL_BXT1_THERMAL	0x1A8C
> +#define PCI_DEVICE_ID_INTEL_BXTX_THERMAL	0x4A8C
> +#define PCI_DEVICE_ID_INTEL_BXTP_THERMAL	0x5A8C
> +
> +#define PCI_DEVICE_ID_INTEL_CNL_THERMAL	0x5a03
> +#define PCI_DEVICE_ID_INTEL_CFL_THERMAL	0x3E83
> +#define PCI_DEVICE_ID_INTEL_GLK_THERMAL	0x318C
> +#define PCI_DEVICE_ID_INTEL_HSB_THERMAL	0x0A03
> +#define PCI_DEVICE_ID_INTEL_ICL_THERMAL	0x8a03
> +#define PCI_DEVICE_ID_INTEL_JSL_THERMAL	0x4E03
> +#define PCI_DEVICE_ID_INTEL_SKL_THERMAL	0x1903
> +#define PCI_DEVICE_ID_INTEL_TGL_THERMAL	0x9A03
> +
> +struct power_config {
> +	u32	index;
> +	u32	min_uw;
> +	u32	max_uw;
> +	u32	tmin_us;
> +	u32	tmax_us;
> +	u32	step_uw;
> +};
> +
> +struct proc_thermal_device {
> +	struct device *dev;
> +	struct acpi_device *adev;
> +	struct power_config power_limits[2];
> +	struct int34x_thermal_zone *int340x_zone;
> +	struct intel_soc_dts_sensors *soc_dts;
> +	u32 mmio_feature_mask;
> +	void __iomem *mmio_base;
> +};
> +
> +struct rapl_mmio_regs {
> +	u64 reg_unit;
> +	u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
> +	int limits[RAPL_DOMAIN_MAX];
> +};
> +
> +#define PROC_THERMAL_FEATURE_NONE	0x00
> +#define PROC_THERMAL_FEATURE_RAPL	0x01
> +
> +#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
> +int proc_thermal_rapl_add(struct pci_dev *pdev, struct
> proc_thermal_device *proc_priv);
> +void proc_thermal_rapl_remove(void);
> +#else
> +static int __maybe_unused proc_thermal_rapl_add(struct pci_dev
> *pdev,
> +						struct
> proc_thermal_device *proc_priv)
> +{
> +	return 0;
> +}
> +
> +static void __maybe_unused proc_thermal_rapl_remove(void)
> +{
> +}
> +#endif
> +
> +#endif
> diff --git
> a/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
> b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
> new file mode 100644
> index 000000000000..a205221ec8df
> --- /dev/null
> +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
> @@ -0,0 +1,134 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * processor thermal device RFIM control
> + * Copyright (c) 2020, Intel Corporation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include "processor_thermal_device.h"
> +
> +static struct rapl_if_priv rapl_mmio_priv;
> +
> +static const struct rapl_mmio_regs rapl_mmio_default = {
> +	.reg_unit = 0x5938,
> +	.regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0,
> 0x5930},
> +	.regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
> +	.limits[RAPL_DOMAIN_PACKAGE] = 2,
> +	.limits[RAPL_DOMAIN_DRAM] = 2,
> +};
> +
> +static int rapl_mmio_cpu_online(unsigned int cpu)
> +{
> +	struct rapl_package *rp;
> +
> +	/* mmio rapl supports package 0 only for now */
> +	if (topology_physical_package_id(cpu))
> +		return 0;
> +
> +	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
> +	if (!rp) {
> +		rp = rapl_add_package(cpu, &rapl_mmio_priv);
> +		if (IS_ERR(rp))
> +			return PTR_ERR(rp);
> +	}
> +	cpumask_set_cpu(cpu, &rp->cpumask);
> +	return 0;
> +}
> +
> +static int rapl_mmio_cpu_down_prep(unsigned int cpu)
> +{
> +	struct rapl_package *rp;
> +	int lead_cpu;
> +
> +	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
> +	if (!rp)
> +		return 0;
> +
> +	cpumask_clear_cpu(cpu, &rp->cpumask);
> +	lead_cpu = cpumask_first(&rp->cpumask);
> +	if (lead_cpu >= nr_cpu_ids)
> +		rapl_remove_package(rp);
> +	else if (rp->lead_cpu == cpu)
> +		rp->lead_cpu = lead_cpu;
> +	return 0;
> +}
> +
> +static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
> +{
> +	if (!ra->reg)
> +		return -EINVAL;
> +
> +	ra->value = readq((void __iomem *)ra->reg);
> +	ra->value &= ra->mask;
> +	return 0;
> +}
> +
> +static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
> +{
> +	u64 val;
> +
> +	if (!ra->reg)
> +		return -EINVAL;
> +
> +	val = readq((void __iomem *)ra->reg);
> +	val &= ~ra->mask;
> +	val |= ra->value;
> +	writeq(val, (void __iomem *)ra->reg);
> +	return 0;
> +}
> +
> +int proc_thermal_rapl_add(struct pci_dev *pdev, struct
> proc_thermal_device *proc_priv)
> +{
> +	const struct rapl_mmio_regs *rapl_regs = &rapl_mmio_default;
> +	enum rapl_domain_reg_id reg;
> +	enum rapl_domain_type domain;
> +	int ret;
> +
> +	if (!rapl_regs)
> +		return 0;
> +
> +	for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX;
> domain++) {
> +		for (reg = RAPL_DOMAIN_REG_LIMIT; reg <
> RAPL_DOMAIN_REG_MAX; reg++)
> +			if (rapl_regs->regs[domain][reg])
> +				rapl_mmio_priv.regs[domain][reg] =
> +						(u64)proc_priv-
> >mmio_base +
> +						rapl_regs-
> >regs[domain][reg];
> +		rapl_mmio_priv.limits[domain] = rapl_regs-
> >limits[domain];
> +	}
> +	rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base +
> rapl_regs->reg_unit;
> +
> +	rapl_mmio_priv.read_raw = rapl_mmio_read_raw;
> +	rapl_mmio_priv.write_raw = rapl_mmio_write_raw;
> +
> +	rapl_mmio_priv.control_type =
> powercap_register_control_type(NULL, "intel-rapl-mmio", NULL);
> +	if (IS_ERR(rapl_mmio_priv.control_type)) {
> +		pr_debug("failed to register powercap
> control_type.\n");
> +		return PTR_ERR(rapl_mmio_priv.control_type);
> +	}
> +
> +	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
> "powercap/rapl:online",
> +				rapl_mmio_cpu_online,
> rapl_mmio_cpu_down_prep);
> +	if (ret < 0) {
> +		powercap_unregister_control_type(rapl_mmio_priv.control
> _type);
> +		rapl_mmio_priv.control_type = NULL;
> +		return ret;
> +	}
> +	rapl_mmio_priv.pcap_rapl_online = ret;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(proc_thermal_rapl_add);
> +
> +void proc_thermal_rapl_remove(void)
> +{
> +	if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type))
> +		return;
> +
> +	cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online);
> +	powercap_unregister_control_type(rapl_mmio_priv.control_type);
> +}
> +EXPORT_SYMBOL_GPL(proc_thermal_rapl_remove);
> +
> +MODULE_LICENSE("GPL v2");


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/4] thermal: int340x: processor_thermal: Add RFIM driver
  2020-11-26 17:18 ` [PATCH 3/4] thermal: int340x: processor_thermal: Add RFIM driver Srinivas Pandruvada
@ 2020-12-09 20:48   ` Daniel Lezcano
  2020-12-10  0:19     ` Srinivas Pandruvada
  2020-12-11 13:09   ` [thermal: thermal/next] " thermal-bot for Srinivas Pandruvada
  1 sibling, 1 reply; 11+ messages in thread
From: Daniel Lezcano @ 2020-12-09 20:48 UTC (permalink / raw)
  To: Srinivas Pandruvada, rui.zhang, amitk; +Cc: linux-kernel, linux-pm

On 26/11/2020 18:18, Srinivas Pandruvada wrote:
> Add support for RFIM (Radio Frequency Interference Mitigation) support
> via processor thermal PCI device. This drivers allows adjustment of
> FIVR (Fully Integrated Voltage Regulator) and DDR (Double Data Rate)
> frequencies to avoid RF interference with WiFi and 5G.
> 
> Switching voltage regulators (VR) generate radiated EMI or RFI at the
> fundamental frequency and its harmonics. Some harmonics may interfere
> with very sensitive wireless receivers such as Wi-Fi and cellular that
> are integrated into host systems like notebook PCs.  One of mitigation
> methods is requesting SOC integrated VR (IVR) switching frequency to a
> small % and shift away the switching noise harmonic interference from
> radio channels.  OEM or ODMs can use the driver to control SOC IVR
> operation within the range where it does not impact IVR performance.
> 
> DRAM devices of DDR IO interface and their power plane can generate EMI
> at the data rates. Similar to IVR control mechanism, Intel offers a
> mechanism by which DDR data rates can be changed if several conditions
> are met: there is strong RFI interference because of DDR; CPU power
> management has no other restriction in changing DDR data rates;
> PC ODMs enable this feature (real time DDR RFI Mitigation referred to as
> DDR-RFIM) for Wi-Fi from BIOS.

Thanks for the technical details, it is interesting.

May be I missed something but how this is related to thermal?


> This change exports two folders under /sys/bus/pci/devices/0000:00:04.0.
> One folder "fivr" contains all attributes exposed for controling FIVR
> features. The other folder "dvfs" contains all attributes for DDR
> features.
> 
> Changes done to implement:
> - New module for rfim interfaces
> - Two new per processor features for DDR and FIVR
> - Enable feature for Tiger Lake (FIVR only) and Alder Lake
> 
> The attributes exposed and explanation:
> 
> FIVR attributes
> 
> vco_ref_code_lo (RW): The VCO reference code is an 11-bit field and
> controls the FIVR switching frequency. This is the 3-bit LSB field.
> 
> vco_ref_code_hi (RW): The VCO reference code is an 11-bit field and
> controls the FIVR switching frequency. This is the 8-bit MSB field.
> 
> spread_spectrum_pct (RW): Set the FIVR spread spectrum clocking
> percentage
> 
> spread_spectrum_clk_enable (RW): Enable/disable of the FIVR spread
> spectrum clocking feature
> 
> rfi_vco_ref_code (RW): This field is a read only status register which
> reflects the current FIVR switching frequency
> 
> fivr_fffc_rev (RW): This field indicated the revision of the FIVR HW.
> 
> DVFS attributes
> 
> rfi_restriction_run_busy (RW): Request the restriction of specific DDR
> data rate and set this value 1. Self reset to 0 after operation.
> 
> rfi_restriction_err_code (RW): Values:  0 :Request is accepted, 1:Feature
> disabled, 2: the request restricts more points than it is allowed
> 
> rfi_restriction_data_rate_Delta (RW): Restricted DDR data rate for RFI
> protection: Lower Limit
> 
> rfi_restriction_data_rate_Base (RW): Restricted DDR data rate for RFI
> protection: Upper Limit
> 
> ddr_data_rate_point_0 (RO): DDR data rate selection 1st point
> 
> ddr_data_rate_point_1 (RO): DDR data rate selection 2nd point
> 
> ddr_data_rate_point_2 (RO): DDR data rate selection 3rd point
> 
> ddr_data_rate_point_3 (RO): DDR data rate selection 4th point
> 
> rfi_disable (RW): Disable DDR rate change feature
> 
> Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
> ---
>  .../thermal/intel/int340x_thermal/Makefile    |   1 +
>  .../processor_thermal_device.c                |  23 +-
>  .../processor_thermal_device.h                |   5 +
>  .../int340x_thermal/processor_thermal_rfim.c  | 244 ++++++++++++++++++
>  4 files changed, 270 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
> 
> diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile
> index 86e8d3c87df7..f4e2eb7d9606 100644
> --- a/drivers/thermal/intel/int340x_thermal/Makefile
> +++ b/drivers/thermal/intel/int340x_thermal/Makefile
> @@ -5,5 +5,6 @@ obj-$(CONFIG_INT340X_THERMAL)	+= int3402_thermal.o
>  obj-$(CONFIG_INT340X_THERMAL)	+= int3403_thermal.o
>  obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_device.o
>  obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
> +obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_rfim.o
>  obj-$(CONFIG_INT3406_THERMAL)	+= int3406_thermal.o
>  obj-$(CONFIG_ACPI_THERMAL_REL)	+= acpi_thermal_rel.o
> diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> index 589ac7deec02..b6a7358b989d 100644
> --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> @@ -429,6 +429,8 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev,
>  {
>  	int ret;
>  
> +	proc_priv->mmio_feature_mask = feature_mask;
> +
>  	if (feature_mask) {
>  		ret = proc_thermal_set_mmio_base(pdev, proc_priv);
>  		if (ret)
> @@ -443,9 +445,21 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev,
>  		}
>  	}
>  
> -	proc_priv->mmio_feature_mask = feature_mask;
> +	if (feature_mask & PROC_THERMAL_FEATURE_FIVR ||
> +	    feature_mask & PROC_THERMAL_FEATURE_DVFS) {
> +		ret = proc_thermal_rfim_add(pdev, proc_priv);
> +		if (ret) {
> +			dev_err(&pdev->dev, "failed to add RFIM interface\n");
> +			goto err_rem_rapl;
> +		}
> +	}
>  
>  	return 0;
> +
> +err_rem_rapl:
> +	proc_thermal_rapl_remove();
> +
> +	return ret;
>  }
>  
>  static void proc_thermal_mmio_remove(struct pci_dev *pdev)
> @@ -455,6 +469,9 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev)
>  	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
>  		proc_thermal_rapl_remove();
>  
> +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR ||
> +	    proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
> +		proc_thermal_rfim_remove(pdev);
>  }
>  
>  static int  proc_thermal_pci_probe(struct pci_dev *pdev,
> @@ -566,7 +583,7 @@ static int proc_thermal_resume(struct device *dev)
>  static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
>  
>  static const struct pci_device_id proc_thermal_pci_ids[] = {
> -	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
> +	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS) },
>  	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
>  	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
>  	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
> @@ -580,7 +597,7 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
>  	{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
>  	{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
>  	{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
> -	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
> +	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR) },
>  	{ },
>  };
>  
> diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
> index 45214571e00d..4bbb88f6b4a7 100644
> --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
> +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
> @@ -54,6 +54,8 @@ struct rapl_mmio_regs {
>  
>  #define PROC_THERMAL_FEATURE_NONE	0x00
>  #define PROC_THERMAL_FEATURE_RAPL	0x01
> +#define PROC_THERMAL_FEATURE_FIVR	0x02
> +#define PROC_THERMAL_FEATURE_DVFS	0x04
>  
>  #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
>  int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
> @@ -70,4 +72,7 @@ static void __maybe_unused proc_thermal_rapl_remove(void)
>  }
>  #endif
>  
> +int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
> +void proc_thermal_rfim_remove(struct pci_dev *pdev);
> +
>  #endif
> diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
> new file mode 100644
> index 000000000000..aef993a813e2
> --- /dev/null
> +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
> @@ -0,0 +1,244 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * processor thermal device RFIM control
> + * Copyright (c) 2020, Intel Corporation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include "processor_thermal_device.h"
> +
> +struct mmio_reg {
> +	int read_only;
> +	u32 offset;
> +	int bits;
> +	u16 mask;
> +	u16 shift;
> +};
> +
> +/* These will represent sysfs attribute names */
> +static const char * const fivr_strings[] = {
> +	"vco_ref_code_lo",
> +	"vco_ref_code_hi",
> +	"spread_spectrum_pct",
> +	"spread_spectrum_clk_enable",
> +	"rfi_vco_ref_code",
> +	"fivr_fffc_rev",
> +	NULL
> +};
> +
> +static const struct mmio_reg tgl_fivr_mmio_regs[] = {
> +	{ 0, 0x5A18, 3, 0x7, 12}, /* vco_ref_code_lo */
> +	{ 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */
> +	{ 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */
> +	{ 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */
> +	{ 1, 0x5A10, 12, 0xFFF, 0}, /* rfi_vco_ref_code */
> +	{ 1, 0x5A14, 2, 0x3, 1}, /* fivr_fffc_rev */
> +};
> +
> +/* These will represent sysfs attribute names */
> +static const char * const dvfs_strings[] = {
> +	"rfi_restriction_run_busy",
> +	"rfi_restriction_err_code",
> +	"rfi_restriction_data_rate",
> +	"rfi_restriction_data_rate_base",
> +	"ddr_data_rate_point_0",
> +	"ddr_data_rate_point_1",
> +	"ddr_data_rate_point_2",
> +	"ddr_data_rate_point_3",
> +	"rfi_disable",
> +	NULL
> +};
> +
> +static const struct mmio_reg adl_dvfs_mmio_regs[] = {
> +	{ 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */
> +	{ 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */
> +	{ 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */
> +	{ 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base */
> +	{ 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */
> +	{ 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */
> +	{ 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */
> +	{ 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */
> +	{ 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */
> +};
> +
> +#define RFIM_SHOW(suffix, table)\
> +static ssize_t suffix##_show(struct device *dev,\
> +			      struct device_attribute *attr,\
> +			      char *buf)\
> +{\
> +	struct proc_thermal_device *proc_priv;\
> +	struct pci_dev *pdev = to_pci_dev(dev);\
> +	const struct mmio_reg *mmio_regs;\
> +	const char **match_strs;\
> +	u32 reg_val;\
> +	int ret;\
> +\
> +	proc_priv = pci_get_drvdata(pdev);\
> +	if (table) {\
> +		match_strs = (const char **)dvfs_strings;\
> +		mmio_regs = adl_dvfs_mmio_regs;\
> +	} else { \
> +		match_strs = (const char **)fivr_strings;\
> +		mmio_regs = tgl_fivr_mmio_regs;\
> +	} \
> +	\
> +	ret = match_string(match_strs, -1, attr->attr.name);\
> +	if (ret < 0)\
> +		return ret;\
> +	reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
> +	ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\
> +	return sprintf(buf, "%u\n", ret);\
> +}
> +
> +#define RFIM_STORE(suffix, table)\
> +static ssize_t suffix##_store(struct device *dev,\
> +			       struct device_attribute *attr,\
> +			       const char *buf, size_t count)\
> +{\
> +	struct proc_thermal_device *proc_priv;\
> +	struct pci_dev *pdev = to_pci_dev(dev);\
> +	unsigned int input;\
> +	const char **match_strs;\
> +	const struct mmio_reg *mmio_regs;\
> +	int ret, err;\
> +	u32 reg_val;\
> +	u32 mask;\
> +\
> +	proc_priv = pci_get_drvdata(pdev);\
> +	if (table) {\
> +		match_strs = (const char **)dvfs_strings;\
> +		mmio_regs = adl_dvfs_mmio_regs;\
> +	} else { \
> +		match_strs = (const char **)fivr_strings;\
> +		mmio_regs = tgl_fivr_mmio_regs;\
> +	} \
> +	\
> +	ret = match_string(match_strs, -1, attr->attr.name);\
> +	if (ret < 0)\
> +		return ret;\
> +	if (mmio_regs[ret].read_only)\
> +		return -EPERM;\
> +	err = kstrtouint(buf, 10, &input);\
> +	if (err)\
> +		return err;\
> +	mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\
> +	reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
> +	reg_val &= ~mask;\
> +	reg_val |= (input << mmio_regs[ret].shift);\
> +	writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
> +	return count;\
> +}
> +
> +RFIM_SHOW(vco_ref_code_lo, 0)
> +RFIM_SHOW(vco_ref_code_hi, 0)
> +RFIM_SHOW(spread_spectrum_pct, 0)
> +RFIM_SHOW(spread_spectrum_clk_enable, 0)
> +RFIM_SHOW(rfi_vco_ref_code, 0)
> +RFIM_SHOW(fivr_fffc_rev, 0)
> +
> +RFIM_STORE(vco_ref_code_lo, 0)
> +RFIM_STORE(vco_ref_code_hi, 0)
> +RFIM_STORE(spread_spectrum_pct, 0)
> +RFIM_STORE(spread_spectrum_clk_enable, 0)
> +RFIM_STORE(rfi_vco_ref_code, 0)
> +RFIM_STORE(fivr_fffc_rev, 0)
> +
> +static DEVICE_ATTR_RW(vco_ref_code_lo);
> +static DEVICE_ATTR_RW(vco_ref_code_hi);
> +static DEVICE_ATTR_RW(spread_spectrum_pct);
> +static DEVICE_ATTR_RW(spread_spectrum_clk_enable);
> +static DEVICE_ATTR_RW(rfi_vco_ref_code);
> +static DEVICE_ATTR_RW(fivr_fffc_rev);
> +
> +static struct attribute *fivr_attrs[] = {
> +	&dev_attr_vco_ref_code_lo.attr,
> +	&dev_attr_vco_ref_code_hi.attr,
> +	&dev_attr_spread_spectrum_pct.attr,
> +	&dev_attr_spread_spectrum_clk_enable.attr,
> +	&dev_attr_rfi_vco_ref_code.attr,
> +	&dev_attr_fivr_fffc_rev.attr,
> +	NULL
> +};
> +
> +static const struct attribute_group fivr_attribute_group = {
> +	.attrs = fivr_attrs,
> +	.name = "fivr"
> +};
> +
> +RFIM_SHOW(rfi_restriction_run_busy, 1)
> +RFIM_SHOW(rfi_restriction_err_code, 1)
> +RFIM_SHOW(rfi_restriction_data_rate, 1)
> +RFIM_SHOW(ddr_data_rate_point_0, 1)
> +RFIM_SHOW(ddr_data_rate_point_1, 1)
> +RFIM_SHOW(ddr_data_rate_point_2, 1)
> +RFIM_SHOW(ddr_data_rate_point_3, 1)
> +RFIM_SHOW(rfi_disable, 1)
> +
> +RFIM_STORE(rfi_restriction_run_busy, 1)
> +RFIM_STORE(rfi_restriction_err_code, 1)
> +RFIM_STORE(rfi_restriction_data_rate, 1)
> +RFIM_STORE(rfi_disable, 1)
> +
> +static DEVICE_ATTR_RW(rfi_restriction_run_busy);
> +static DEVICE_ATTR_RW(rfi_restriction_err_code);
> +static DEVICE_ATTR_RW(rfi_restriction_data_rate);
> +static DEVICE_ATTR_RO(ddr_data_rate_point_0);
> +static DEVICE_ATTR_RO(ddr_data_rate_point_1);
> +static DEVICE_ATTR_RO(ddr_data_rate_point_2);
> +static DEVICE_ATTR_RO(ddr_data_rate_point_3);
> +static DEVICE_ATTR_RW(rfi_disable);
> +
> +static struct attribute *dvfs_attrs[] = {
> +	&dev_attr_rfi_restriction_run_busy.attr,
> +	&dev_attr_rfi_restriction_err_code.attr,
> +	&dev_attr_rfi_restriction_data_rate.attr,
> +	&dev_attr_ddr_data_rate_point_0.attr,
> +	&dev_attr_ddr_data_rate_point_1.attr,
> +	&dev_attr_ddr_data_rate_point_2.attr,
> +	&dev_attr_ddr_data_rate_point_3.attr,
> +	&dev_attr_rfi_disable.attr,
> +	NULL
> +};
> +
> +static const struct attribute_group dvfs_attribute_group = {
> +	.attrs = dvfs_attrs,
> +	.name = "dvfs"
> +};
> +
> +int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
> +{
> +	int ret;
> +
> +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
> +		ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {
> +		ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group);
> +		if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
> +			sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(proc_thermal_rfim_add);
> +
> +void proc_thermal_rfim_remove(struct pci_dev *pdev)
> +{
> +	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
> +
> +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
> +		sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
> +
> +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
> +		sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group);
> +}
> +EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);
> +
> +MODULE_LICENSE("GPL v2");
> 


-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/4] thermal: int340x: processor_thermal: Add RFIM driver
  2020-12-09 20:48   ` Daniel Lezcano
@ 2020-12-10  0:19     ` Srinivas Pandruvada
  0 siblings, 0 replies; 11+ messages in thread
From: Srinivas Pandruvada @ 2020-12-10  0:19 UTC (permalink / raw)
  To: Daniel Lezcano, rui.zhang, amitk; +Cc: linux-kernel, linux-pm

On Wed, 2020-12-09 at 21:48 +0100, Daniel Lezcano wrote:
> On 26/11/2020 18:18, Srinivas Pandruvada wrote:
> > Add support for RFIM (Radio Frequency Interference Mitigation)
> > support
> > via processor thermal PCI device. This drivers allows adjustment of
> > FIVR (Fully Integrated Voltage Regulator) and DDR (Double Data
> > Rate)
> > frequencies to avoid RF interference with WiFi and 5G.
> > 
> > Switching voltage regulators (VR) generate radiated EMI or RFI at
> > the
> > fundamental frequency and its harmonics. Some harmonics may
> > interfere
> > with very sensitive wireless receivers such as Wi-Fi and cellular
> > that
> > are integrated into host systems like notebook PCs.  One of
> > mitigation
> > methods is requesting SOC integrated VR (IVR) switching frequency
> > to a
> > small % and shift away the switching noise harmonic interference
> > from
> > radio channels.  OEM or ODMs can use the driver to control SOC IVR
> > operation within the range where it does not impact IVR
> > performance.
> > 
> > DRAM devices of DDR IO interface and their power plane can generate
> > EMI
> > at the data rates. Similar to IVR control mechanism, Intel offers a
> > mechanism by which DDR data rates can be changed if several
> > conditions
> > are met: there is strong RFI interference because of DDR; CPU power
> > management has no other restriction in changing DDR data rates;
> > PC ODMs enable this feature (real time DDR RFI Mitigation referred
> > to as
> > DDR-RFIM) for Wi-Fi from BIOS.
> 
> Thanks for the technical details, it is interesting.
> 
> May be I missed something but how this is related to thermal

Not directly offering thermal control but uses the thermal PCI device
(via MMIO) as this allows optimal RF frequencies which will result in
optimal TX power. Higher TX power consumption can result in non optimal
die temperature. Idea is manage power before this cause issue.

Thanks,
Srinivas

> 
> 
> > This change exports two folders under
> > /sys/bus/pci/devices/0000:00:04.0.
> > One folder "fivr" contains all attributes exposed for controling
> > FIVR
> > features. The other folder "dvfs" contains all attributes for DDR
> > features.
> > 
> > Changes done to implement:
> > - New module for rfim interfaces
> > - Two new per processor features for DDR and FIVR
> > - Enable feature for Tiger Lake (FIVR only) and Alder Lake
> > 
> > The attributes exposed and explanation:
> > 
> > FIVR attributes
> > 
> > vco_ref_code_lo (RW): The VCO reference code is an 11-bit field and
> > controls the FIVR switching frequency. This is the 3-bit LSB field.
> > 
> > vco_ref_code_hi (RW): The VCO reference code is an 11-bit field and
> > controls the FIVR switching frequency. This is the 8-bit MSB field.
> > 
> > spread_spectrum_pct (RW): Set the FIVR spread spectrum clocking
> > percentage
> > 
> > spread_spectrum_clk_enable (RW): Enable/disable of the FIVR spread
> > spectrum clocking feature
> > 
> > rfi_vco_ref_code (RW): This field is a read only status register
> > which
> > reflects the current FIVR switching frequency
> > 
> > fivr_fffc_rev (RW): This field indicated the revision of the FIVR
> > HW.
> > 
> > DVFS attributes
> > 
> > rfi_restriction_run_busy (RW): Request the restriction of specific
> > DDR
> > data rate and set this value 1. Self reset to 0 after operation.
> > 
> > rfi_restriction_err_code (RW): Values:  0 :Request is accepted,
> > 1:Feature
> > disabled, 2: the request restricts more points than it is allowed
> > 
> > rfi_restriction_data_rate_Delta (RW): Restricted DDR data rate for
> > RFI
> > protection: Lower Limit
> > 
> > rfi_restriction_data_rate_Base (RW): Restricted DDR data rate for
> > RFI
> > protection: Upper Limit
> > 
> > ddr_data_rate_point_0 (RO): DDR data rate selection 1st point
> > 
> > ddr_data_rate_point_1 (RO): DDR data rate selection 2nd point
> > 
> > ddr_data_rate_point_2 (RO): DDR data rate selection 3rd point
> > 
> > ddr_data_rate_point_3 (RO): DDR data rate selection 4th point
> > 
> > rfi_disable (RW): Disable DDR rate change feature
> > 
> > Signed-off-by: Srinivas Pandruvada <
> > srinivas.pandruvada@linux.intel.com>
> > ---
> >  .../thermal/intel/int340x_thermal/Makefile    |   1 +
> >  .../processor_thermal_device.c                |  23 +-
> >  .../processor_thermal_device.h                |   5 +
> >  .../int340x_thermal/processor_thermal_rfim.c  | 244
> > ++++++++++++++++++
> >  4 files changed, 270 insertions(+), 3 deletions(-)
> >  create mode 100644
> > drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
> > 
> > diff --git a/drivers/thermal/intel/int340x_thermal/Makefile
> > b/drivers/thermal/intel/int340x_thermal/Makefile
> > index 86e8d3c87df7..f4e2eb7d9606 100644
> > --- a/drivers/thermal/intel/int340x_thermal/Makefile
> > +++ b/drivers/thermal/intel/int340x_thermal/Makefile
> > @@ -5,5 +5,6 @@ obj-$(CONFIG_INT340X_THERMAL)	+=
> > int3402_thermal.o
> >  obj-$(CONFIG_INT340X_THERMAL)	+= int3403_thermal.o
> >  obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_device.o
> >  obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
> > +obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_rfim.o
> >  obj-$(CONFIG_INT3406_THERMAL)	+= int3406_thermal.o
> >  obj-$(CONFIG_ACPI_THERMAL_REL)	+= acpi_thermal_rel.o
> > diff --git
> > a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> > b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> > index 589ac7deec02..b6a7358b989d 100644
> > ---
> > a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> > +++
> > b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
> > @@ -429,6 +429,8 @@ static int proc_thermal_mmio_add(struct pci_dev
> > *pdev,
> >  {
> >  	int ret;
> >  
> > +	proc_priv->mmio_feature_mask = feature_mask;
> > +
> >  	if (feature_mask) {
> >  		ret = proc_thermal_set_mmio_base(pdev, proc_priv);
> >  		if (ret)
> > @@ -443,9 +445,21 @@ static int proc_thermal_mmio_add(struct
> > pci_dev *pdev,
> >  		}
> >  	}
> >  
> > -	proc_priv->mmio_feature_mask = feature_mask;
> > +	if (feature_mask & PROC_THERMAL_FEATURE_FIVR ||
> > +	    feature_mask & PROC_THERMAL_FEATURE_DVFS) {
> > +		ret = proc_thermal_rfim_add(pdev, proc_priv);
> > +		if (ret) {
> > +			dev_err(&pdev->dev, "failed to add RFIM
> > interface\n");
> > +			goto err_rem_rapl;
> > +		}
> > +	}
> >  
> >  	return 0;
> > +
> > +err_rem_rapl:
> > +	proc_thermal_rapl_remove();
> > +
> > +	return ret;
> >  }
> >  
> >  static void proc_thermal_mmio_remove(struct pci_dev *pdev)
> > @@ -455,6 +469,9 @@ static void proc_thermal_mmio_remove(struct
> > pci_dev *pdev)
> >  	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
> >  		proc_thermal_rapl_remove();
> >  
> > +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR ||
> > +	    proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
> > +		proc_thermal_rfim_remove(pdev);
> >  }
> >  
> >  static int  proc_thermal_pci_probe(struct pci_dev *pdev,
> > @@ -566,7 +583,7 @@ static int proc_thermal_resume(struct device
> > *dev)
> >  static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL,
> > proc_thermal_resume);
> >  
> >  static const struct pci_device_id proc_thermal_pci_ids[] = {
> > -	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL,
> > PROC_THERMAL_FEATURE_RAPL) },
> > +	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL
> > | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS) },
> >  	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
> >  	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
> >  	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
> > @@ -580,7 +597,7 @@ static const struct pci_device_id
> > proc_thermal_pci_ids[] = {
> >  	{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL,
> > PROC_THERMAL_FEATURE_RAPL) },
> >  	{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
> >  	{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL,
> > PROC_THERMAL_FEATURE_RAPL) },
> > -	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL,
> > PROC_THERMAL_FEATURE_RAPL) },
> > +	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL
> > | PROC_THERMAL_FEATURE_FIVR) },
> >  	{ },
> >  };
> >  
> > diff --git
> > a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
> > b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
> > index 45214571e00d..4bbb88f6b4a7 100644
> > ---
> > a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
> > +++
> > b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
> > @@ -54,6 +54,8 @@ struct rapl_mmio_regs {
> >  
> >  #define PROC_THERMAL_FEATURE_NONE	0x00
> >  #define PROC_THERMAL_FEATURE_RAPL	0x01
> > +#define PROC_THERMAL_FEATURE_FIVR	0x02
> > +#define PROC_THERMAL_FEATURE_DVFS	0x04
> >  
> >  #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
> >  int proc_thermal_rapl_add(struct pci_dev *pdev, struct
> > proc_thermal_device *proc_priv);
> > @@ -70,4 +72,7 @@ static void __maybe_unused
> > proc_thermal_rapl_remove(void)
> >  }
> >  #endif
> >  
> > +int proc_thermal_rfim_add(struct pci_dev *pdev, struct
> > proc_thermal_device *proc_priv);
> > +void proc_thermal_rfim_remove(struct pci_dev *pdev);
> > +
> >  #endif
> > diff --git
> > a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
> > b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
> > new file mode 100644
> > index 000000000000..aef993a813e2
> > --- /dev/null
> > +++
> > b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
> > @@ -0,0 +1,244 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * processor thermal device RFIM control
> > + * Copyright (c) 2020, Intel Corporation.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/pci.h>
> > +#include "processor_thermal_device.h"
> > +
> > +struct mmio_reg {
> > +	int read_only;
> > +	u32 offset;
> > +	int bits;
> > +	u16 mask;
> > +	u16 shift;
> > +};
> > +
> > +/* These will represent sysfs attribute names */
> > +static const char * const fivr_strings[] = {
> > +	"vco_ref_code_lo",
> > +	"vco_ref_code_hi",
> > +	"spread_spectrum_pct",
> > +	"spread_spectrum_clk_enable",
> > +	"rfi_vco_ref_code",
> > +	"fivr_fffc_rev",
> > +	NULL
> > +};
> > +
> > +static const struct mmio_reg tgl_fivr_mmio_regs[] = {
> > +	{ 0, 0x5A18, 3, 0x7, 12}, /* vco_ref_code_lo */
> > +	{ 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */
> > +	{ 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */
> > +	{ 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */
> > +	{ 1, 0x5A10, 12, 0xFFF, 0}, /* rfi_vco_ref_code */
> > +	{ 1, 0x5A14, 2, 0x3, 1}, /* fivr_fffc_rev */
> > +};
> > +
> > +/* These will represent sysfs attribute names */
> > +static const char * const dvfs_strings[] = {
> > +	"rfi_restriction_run_busy",
> > +	"rfi_restriction_err_code",
> > +	"rfi_restriction_data_rate",
> > +	"rfi_restriction_data_rate_base",
> > +	"ddr_data_rate_point_0",
> > +	"ddr_data_rate_point_1",
> > +	"ddr_data_rate_point_2",
> > +	"ddr_data_rate_point_3",
> > +	"rfi_disable",
> > +	NULL
> > +};
> > +
> > +static const struct mmio_reg adl_dvfs_mmio_regs[] = {
> > +	{ 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */
> > +	{ 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */
> > +	{ 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */
> > +	{ 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base
> > */
> > +	{ 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */
> > +	{ 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */
> > +	{ 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */
> > +	{ 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */
> > +	{ 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */
> > +};
> > +
> > +#define RFIM_SHOW(suffix, table)\
> > +static ssize_t suffix##_show(struct device *dev,\
> > +			      struct device_attribute *attr,\
> > +			      char *buf)\
> > +{\
> > +	struct proc_thermal_device *proc_priv;\
> > +	struct pci_dev *pdev = to_pci_dev(dev);\
> > +	const struct mmio_reg *mmio_regs;\
> > +	const char **match_strs;\
> > +	u32 reg_val;\
> > +	int ret;\
> > +\
> > +	proc_priv = pci_get_drvdata(pdev);\
> > +	if (table) {\
> > +		match_strs = (const char **)dvfs_strings;\
> > +		mmio_regs = adl_dvfs_mmio_regs;\
> > +	} else { \
> > +		match_strs = (const char **)fivr_strings;\
> > +		mmio_regs = tgl_fivr_mmio_regs;\
> > +	} \
> > +	\
> > +	ret = match_string(match_strs, -1, attr->attr.name);\
> > +	if (ret < 0)\
> > +		return ret;\
> > +	reg_val = readl((void __iomem *) (proc_priv->mmio_base +
> > mmio_regs[ret].offset));\
> > +	ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\
> > +	return sprintf(buf, "%u\n", ret);\
> > +}
> > +
> > +#define RFIM_STORE(suffix, table)\
> > +static ssize_t suffix##_store(struct device *dev,\
> > +			       struct device_attribute *attr,\
> > +			       const char *buf, size_t count)\
> > +{\
> > +	struct proc_thermal_device *proc_priv;\
> > +	struct pci_dev *pdev = to_pci_dev(dev);\
> > +	unsigned int input;\
> > +	const char **match_strs;\
> > +	const struct mmio_reg *mmio_regs;\
> > +	int ret, err;\
> > +	u32 reg_val;\
> > +	u32 mask;\
> > +\
> > +	proc_priv = pci_get_drvdata(pdev);\
> > +	if (table) {\
> > +		match_strs = (const char **)dvfs_strings;\
> > +		mmio_regs = adl_dvfs_mmio_regs;\
> > +	} else { \
> > +		match_strs = (const char **)fivr_strings;\
> > +		mmio_regs = tgl_fivr_mmio_regs;\
> > +	} \
> > +	\
> > +	ret = match_string(match_strs, -1, attr->attr.name);\
> > +	if (ret < 0)\
> > +		return ret;\
> > +	if (mmio_regs[ret].read_only)\
> > +		return -EPERM;\
> > +	err = kstrtouint(buf, 10, &input);\
> > +	if (err)\
> > +		return err;\
> > +	mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1,
> > mmio_regs[ret].shift);\
> > +	reg_val = readl((void __iomem *) (proc_priv->mmio_base +
> > mmio_regs[ret].offset));\
> > +	reg_val &= ~mask;\
> > +	reg_val |= (input << mmio_regs[ret].shift);\
> > +	writel(reg_val, (void __iomem *) (proc_priv->mmio_base +
> > mmio_regs[ret].offset));\
> > +	return count;\
> > +}
> > +
> > +RFIM_SHOW(vco_ref_code_lo, 0)
> > +RFIM_SHOW(vco_ref_code_hi, 0)
> > +RFIM_SHOW(spread_spectrum_pct, 0)
> > +RFIM_SHOW(spread_spectrum_clk_enable, 0)
> > +RFIM_SHOW(rfi_vco_ref_code, 0)
> > +RFIM_SHOW(fivr_fffc_rev, 0)
> > +
> > +RFIM_STORE(vco_ref_code_lo, 0)
> > +RFIM_STORE(vco_ref_code_hi, 0)
> > +RFIM_STORE(spread_spectrum_pct, 0)
> > +RFIM_STORE(spread_spectrum_clk_enable, 0)
> > +RFIM_STORE(rfi_vco_ref_code, 0)
> > +RFIM_STORE(fivr_fffc_rev, 0)
> > +
> > +static DEVICE_ATTR_RW(vco_ref_code_lo);
> > +static DEVICE_ATTR_RW(vco_ref_code_hi);
> > +static DEVICE_ATTR_RW(spread_spectrum_pct);
> > +static DEVICE_ATTR_RW(spread_spectrum_clk_enable);
> > +static DEVICE_ATTR_RW(rfi_vco_ref_code);
> > +static DEVICE_ATTR_RW(fivr_fffc_rev);
> > +
> > +static struct attribute *fivr_attrs[] = {
> > +	&dev_attr_vco_ref_code_lo.attr,
> > +	&dev_attr_vco_ref_code_hi.attr,
> > +	&dev_attr_spread_spectrum_pct.attr,
> > +	&dev_attr_spread_spectrum_clk_enable.attr,
> > +	&dev_attr_rfi_vco_ref_code.attr,
> > +	&dev_attr_fivr_fffc_rev.attr,
> > +	NULL
> > +};
> > +
> > +static const struct attribute_group fivr_attribute_group = {
> > +	.attrs = fivr_attrs,
> > +	.name = "fivr"
> > +};
> > +
> > +RFIM_SHOW(rfi_restriction_run_busy, 1)
> > +RFIM_SHOW(rfi_restriction_err_code, 1)
> > +RFIM_SHOW(rfi_restriction_data_rate, 1)
> > +RFIM_SHOW(ddr_data_rate_point_0, 1)
> > +RFIM_SHOW(ddr_data_rate_point_1, 1)
> > +RFIM_SHOW(ddr_data_rate_point_2, 1)
> > +RFIM_SHOW(ddr_data_rate_point_3, 1)
> > +RFIM_SHOW(rfi_disable, 1)
> > +
> > +RFIM_STORE(rfi_restriction_run_busy, 1)
> > +RFIM_STORE(rfi_restriction_err_code, 1)
> > +RFIM_STORE(rfi_restriction_data_rate, 1)
> > +RFIM_STORE(rfi_disable, 1)
> > +
> > +static DEVICE_ATTR_RW(rfi_restriction_run_busy);
> > +static DEVICE_ATTR_RW(rfi_restriction_err_code);
> > +static DEVICE_ATTR_RW(rfi_restriction_data_rate);
> > +static DEVICE_ATTR_RO(ddr_data_rate_point_0);
> > +static DEVICE_ATTR_RO(ddr_data_rate_point_1);
> > +static DEVICE_ATTR_RO(ddr_data_rate_point_2);
> > +static DEVICE_ATTR_RO(ddr_data_rate_point_3);
> > +static DEVICE_ATTR_RW(rfi_disable);
> > +
> > +static struct attribute *dvfs_attrs[] = {
> > +	&dev_attr_rfi_restriction_run_busy.attr,
> > +	&dev_attr_rfi_restriction_err_code.attr,
> > +	&dev_attr_rfi_restriction_data_rate.attr,
> > +	&dev_attr_ddr_data_rate_point_0.attr,
> > +	&dev_attr_ddr_data_rate_point_1.attr,
> > +	&dev_attr_ddr_data_rate_point_2.attr,
> > +	&dev_attr_ddr_data_rate_point_3.attr,
> > +	&dev_attr_rfi_disable.attr,
> > +	NULL
> > +};
> > +
> > +static const struct attribute_group dvfs_attribute_group = {
> > +	.attrs = dvfs_attrs,
> > +	.name = "dvfs"
> > +};
> > +
> > +int proc_thermal_rfim_add(struct pci_dev *pdev, struct
> > proc_thermal_device *proc_priv)
> > +{
> > +	int ret;
> > +
> > +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
> > +		ret = sysfs_create_group(&pdev->dev.kobj,
> > &fivr_attribute_group);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {
> > +		ret = sysfs_create_group(&pdev->dev.kobj,
> > &dvfs_attribute_group);
> > +		if (ret && proc_priv->mmio_feature_mask &
> > PROC_THERMAL_FEATURE_FIVR) {
> > +			sysfs_remove_group(&pdev->dev.kobj,
> > &fivr_attribute_group);
> > +			return ret;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(proc_thermal_rfim_add);
> > +
> > +void proc_thermal_rfim_remove(struct pci_dev *pdev)
> > +{
> > +	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
> > +
> > +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
> > +		sysfs_remove_group(&pdev->dev.kobj,
> > &fivr_attribute_group);
> > +
> > +	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
> > +		sysfs_remove_group(&pdev->dev.kobj,
> > &dvfs_attribute_group);
> > +}
> > +EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);
> > +
> > +MODULE_LICENSE("GPL v2");
> > 
> 
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [thermal: thermal/next] thermal: int340x: processor_thermal: Add mailbox driver
  2020-11-26 17:18 ` [PATCH 4/4] thermal: int340x: processor_thermal: Add mailbox driver Srinivas Pandruvada
@ 2020-12-11 13:09   ` thermal-bot for Srinivas Pandruvada
  0 siblings, 0 replies; 11+ messages in thread
From: thermal-bot for Srinivas Pandruvada @ 2020-12-11 13:09 UTC (permalink / raw)
  To: linux-pm; +Cc: Srinivas Pandruvada, Daniel Lezcano, rui.zhang, amitk

The following commit has been merged into the thermal/next branch of thermal:

Commit-ID:     729a866af3b3f63ccdb91b3af61f3e07b668b757
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//729a866af3b3f63ccdb91b3af61f3e07b668b757
Author:        Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
AuthorDate:    Thu, 26 Nov 2020 09:18:29 -08:00
Committer:     Daniel Lezcano <daniel.lezcano@linaro.org>
CommitterDate: Thu, 10 Dec 2020 12:29:50 +01:00

thermal: int340x: processor_thermal: Add mailbox driver

Added processor thermal device mail box interface for workload hints
setting. These hints will give indication to hardware to better manage
power and thermals. The supported hints are:
idle
semi_active
burusty
sustained
battery_life

For example when the system is on battery, the hardware can be less
aggressive in power ramp up.

This will create an attribute group at
/sys/bus/pci/devices/0000:00:04.0/workload_request

This folder contains two attributes:
workload_available_types : (RO):  This shows available workload types
workload_type: (RW) : Allows to set and get current workload type
setting

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20201126171829.945969-4-srinivas.pandruvada@linux.intel.com
---
 drivers/thermal/intel/int340x_thermal/Makefile                   |   1 +-
 drivers/thermal/intel/int340x_thermal/processor_thermal_device.c |  17 +++++-
 drivers/thermal/intel/int340x_thermal/processor_thermal_device.h |   4 +-
 drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c   | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 232 insertions(+), 2 deletions(-)
 create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c

diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile
index f4e2eb7..38a2731 100644
--- a/drivers/thermal/intel/int340x_thermal/Makefile
+++ b/drivers/thermal/intel/int340x_thermal/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_INT340X_THERMAL)	+= int3403_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_device.o
 obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
 obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_rfim.o
+obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_mbox.o
 obj-$(CONFIG_INT3406_THERMAL)	+= int3406_thermal.o
 obj-$(CONFIG_ACPI_THERMAL_REL)	+= acpi_thermal_rel.o
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index b6a7358..9e6f2a8 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -454,8 +454,18 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev,
 		}
 	}
 
+	if (feature_mask & PROC_THERMAL_FEATURE_MBOX) {
+		ret = proc_thermal_mbox_add(pdev, proc_priv);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to add MBOX interface\n");
+			goto err_rem_rfim;
+		}
+	}
+
 	return 0;
 
+err_rem_rfim:
+	proc_thermal_rfim_remove(pdev);
 err_rem_rapl:
 	proc_thermal_rapl_remove();
 
@@ -472,6 +482,9 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev)
 	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR ||
 	    proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
 		proc_thermal_rfim_remove(pdev);
+
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX)
+		proc_thermal_mbox_remove(pdev);
 }
 
 static int  proc_thermal_pci_probe(struct pci_dev *pdev,
@@ -583,7 +596,7 @@ static int proc_thermal_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
 
 static const struct pci_device_id proc_thermal_pci_ids[] = {
-	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS) },
+	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
 	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
@@ -597,7 +610,7 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
 	{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
 	{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
-	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR) },
+	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) },
 	{ },
 };
 
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
index 4bbb88f..b9ed645 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -56,6 +56,7 @@ struct rapl_mmio_regs {
 #define PROC_THERMAL_FEATURE_RAPL	0x01
 #define PROC_THERMAL_FEATURE_FIVR	0x02
 #define PROC_THERMAL_FEATURE_DVFS	0x04
+#define PROC_THERMAL_FEATURE_MBOX	0x08
 
 #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
 int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
@@ -75,4 +76,7 @@ static void __maybe_unused proc_thermal_rapl_remove(void)
 int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
 void proc_thermal_rfim_remove(struct pci_dev *pdev);
 
+int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
+void proc_thermal_mbox_remove(struct pci_dev *pdev);
+
 #endif
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
new file mode 100644
index 0000000..2c105fe
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * processor thermal device mailbox driver for Workload type hints
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "processor_thermal_device.h"
+
+#define MBOX_CMD_WORKLOAD_TYPE_READ	0x0E
+#define MBOX_CMD_WORKLOAD_TYPE_WRITE	0x0F
+
+#define MBOX_OFFSET_DATA		0x5810
+#define MBOX_OFFSET_INTERFACE		0x5818
+
+#define MBOX_BUSY_BIT			31
+#define MBOX_RETRY_COUNT		100
+
+#define MBOX_DATA_BIT_VALID		31
+#define MBOX_DATA_BIT_AC_DC		30
+
+static DEFINE_MUTEX(mbox_lock);
+
+static int send_mbox_cmd(struct pci_dev *pdev, u8 cmd_id, u32 cmd_data, u8 *cmd_resp)
+{
+	struct proc_thermal_device *proc_priv;
+	u32 retries, data;
+	int ret;
+
+	mutex_lock(&mbox_lock);
+	proc_priv = pci_get_drvdata(pdev);
+
+	/* Poll for rb bit == 0 */
+	retries = MBOX_RETRY_COUNT;
+	do {
+		data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
+		if (data & BIT_ULL(MBOX_BUSY_BIT)) {
+			ret = -EBUSY;
+			continue;
+		}
+		ret = 0;
+		break;
+	} while (--retries);
+
+	if (ret)
+		goto unlock_mbox;
+
+	if (cmd_id == MBOX_CMD_WORKLOAD_TYPE_WRITE)
+		writel(cmd_data, (void __iomem *) ((proc_priv->mmio_base + MBOX_OFFSET_DATA)));
+
+	/* Write command register */
+	data = BIT_ULL(MBOX_BUSY_BIT) | cmd_id;
+	writel(data, (void __iomem *) ((proc_priv->mmio_base + MBOX_OFFSET_INTERFACE)));
+
+	/* Poll for rb bit == 0 */
+	retries = MBOX_RETRY_COUNT;
+	do {
+		data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
+		if (data & BIT_ULL(MBOX_BUSY_BIT)) {
+			ret = -EBUSY;
+			continue;
+		}
+
+		if (data) {
+			ret = -ENXIO;
+			goto unlock_mbox;
+		}
+
+		if (cmd_id == MBOX_CMD_WORKLOAD_TYPE_READ) {
+			data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_DATA));
+			*cmd_resp = data & 0xff;
+		}
+
+		ret = 0;
+		break;
+	} while (--retries);
+
+unlock_mbox:
+	mutex_unlock(&mbox_lock);
+	return ret;
+}
+
+/* List of workload types */
+static const char * const workload_types[] = {
+	"none",
+	"idle",
+	"semi_active",
+	"burusty",
+	"sustained",
+	"battery_life",
+	NULL
+};
+
+
+static ssize_t workload_available_types_show(struct device *dev,
+					       struct device_attribute *attr,
+					       char *buf)
+{
+	int i = 0;
+	int ret = 0;
+
+	while (workload_types[i] != NULL)
+		ret += sprintf(&buf[ret], "%s ", workload_types[i++]);
+
+	ret += sprintf(&buf[ret], "\n");
+
+	return ret;
+}
+
+static DEVICE_ATTR_RO(workload_available_types);
+
+static ssize_t workload_type_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	char str_preference[15];
+	u32 data = 0;
+	ssize_t ret;
+
+	ret = sscanf(buf, "%14s", str_preference);
+	if (ret != 1)
+		return -EINVAL;
+
+	ret = match_string(workload_types, -1, str_preference);
+	if (ret < 0)
+		return ret;
+
+	ret &= 0xff;
+
+	if (ret)
+		data = BIT(MBOX_DATA_BIT_VALID) | BIT(MBOX_DATA_BIT_AC_DC);
+
+	data |= ret;
+
+	ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_WRITE, data, NULL);
+	if (ret)
+		return false;
+
+	return count;
+}
+
+static ssize_t workload_type_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u8 cmd_resp;
+	int ret;
+
+	ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
+	if (ret)
+		return false;
+
+	cmd_resp &= 0xff;
+
+	if (cmd_resp > ARRAY_SIZE(workload_types) - 1)
+		return -EINVAL;
+
+	return sprintf(buf, "%s\n", workload_types[cmd_resp]);
+}
+
+static DEVICE_ATTR_RW(workload_type);
+
+static struct attribute *workload_req_attrs[] = {
+	&dev_attr_workload_available_types.attr,
+	&dev_attr_workload_type.attr,
+	NULL
+};
+
+static const struct attribute_group workload_req_attribute_group = {
+	.attrs = workload_req_attrs,
+	.name = "workload_request"
+};
+
+
+
+static bool workload_req_created;
+
+int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
+{
+	u8 cmd_resp;
+	int ret;
+
+	/* Check if there is a mailbox support, if fails return success */
+	ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
+	if (ret)
+		return 0;
+
+	ret = sysfs_create_group(&pdev->dev.kobj, &workload_req_attribute_group);
+	if (ret)
+		return ret;
+
+	workload_req_created = true;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(proc_thermal_mbox_add);
+
+void proc_thermal_mbox_remove(struct pci_dev *pdev)
+{
+	if (workload_req_created)
+		sysfs_remove_group(&pdev->dev.kobj, &workload_req_attribute_group);
+
+	workload_req_created = false;
+
+}
+EXPORT_SYMBOL_GPL(proc_thermal_mbox_remove);
+
+MODULE_LICENSE("GPL v2");

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [thermal: thermal/next] thermal: int340x: processor_thermal: Add AlderLake PCI device id
  2020-11-26 17:18 ` [PATCH 2/4] thermal: int340x: processor_thermal: Add AlderLake PCI device id Srinivas Pandruvada
@ 2020-12-11 13:09   ` thermal-bot for Srinivas Pandruvada
  0 siblings, 0 replies; 11+ messages in thread
From: thermal-bot for Srinivas Pandruvada @ 2020-12-11 13:09 UTC (permalink / raw)
  To: linux-pm; +Cc: Srinivas Pandruvada, Daniel Lezcano, rui.zhang, amitk

The following commit has been merged into the thermal/next branch of thermal:

Commit-ID:     df2537f910400cd4f90d2ecb40a0a1a204d8470c
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//df2537f910400cd4f90d2ecb40a0a1a204d8470c
Author:        Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
AuthorDate:    Thu, 26 Nov 2020 09:18:27 -08:00
Committer:     Daniel Lezcano <daniel.lezcano@linaro.org>
CommitterDate: Thu, 10 Dec 2020 12:29:48 +01:00

thermal: int340x: processor_thermal: Add AlderLake PCI device id

Added AlderLake PCI device id to support processor thermal driver. Reuse
the feature set (just includes RAPL) from previous generations.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20201126171829.945969-2-srinivas.pandruvada@linux.intel.com
---
 drivers/thermal/intel/int340x_thermal/processor_thermal_device.c | 1 +
 drivers/thermal/intel/int340x_thermal/processor_thermal_device.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 5b8dc5e..589ac7d 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -566,6 +566,7 @@ static int proc_thermal_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
 
 static const struct pci_device_id proc_thermal_pci_ids[] = {
+	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
 	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
index e20d142..4521457 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -9,6 +9,7 @@
 
 #include <linux/intel_rapl.h>
 
+#define PCI_DEVICE_ID_INTEL_ADL_THERMAL	0x461d
 #define PCI_DEVICE_ID_INTEL_BDW_THERMAL	0x1603
 #define PCI_DEVICE_ID_INTEL_BSW_THERMAL	0x22DC
 

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [thermal: thermal/next] thermal: int340x: processor_thermal: Add RFIM driver
  2020-11-26 17:18 ` [PATCH 3/4] thermal: int340x: processor_thermal: Add RFIM driver Srinivas Pandruvada
  2020-12-09 20:48   ` Daniel Lezcano
@ 2020-12-11 13:09   ` thermal-bot for Srinivas Pandruvada
  1 sibling, 0 replies; 11+ messages in thread
From: thermal-bot for Srinivas Pandruvada @ 2020-12-11 13:09 UTC (permalink / raw)
  To: linux-pm; +Cc: Srinivas Pandruvada, Daniel Lezcano, rui.zhang, amitk

The following commit has been merged into the thermal/next branch of thermal:

Commit-ID:     473be51142adba7ce769da728a37c8e80a343e27
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//473be51142adba7ce769da728a37c8e80a343e27
Author:        Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
AuthorDate:    Thu, 26 Nov 2020 09:18:28 -08:00
Committer:     Daniel Lezcano <daniel.lezcano@linaro.org>
CommitterDate: Thu, 10 Dec 2020 12:29:49 +01:00

thermal: int340x: processor_thermal: Add RFIM driver

Add support for RFIM (Radio Frequency Interference Mitigation) support
via processor thermal PCI device. This drivers allows adjustment of
FIVR (Fully Integrated Voltage Regulator) and DDR (Double Data Rate)
frequencies to avoid RF interference with WiFi and 5G.

Switching voltage regulators (VR) generate radiated EMI or RFI at the
fundamental frequency and its harmonics. Some harmonics may interfere
with very sensitive wireless receivers such as Wi-Fi and cellular that
are integrated into host systems like notebook PCs.  One of mitigation
methods is requesting SOC integrated VR (IVR) switching frequency to a
small % and shift away the switching noise harmonic interference from
radio channels.  OEM or ODMs can use the driver to control SOC IVR
operation within the range where it does not impact IVR performance.

DRAM devices of DDR IO interface and their power plane can generate EMI
at the data rates. Similar to IVR control mechanism, Intel offers a
mechanism by which DDR data rates can be changed if several conditions
are met: there is strong RFI interference because of DDR; CPU power
management has no other restriction in changing DDR data rates;
PC ODMs enable this feature (real time DDR RFI Mitigation referred to as
DDR-RFIM) for Wi-Fi from BIOS.

This change exports two folders under /sys/bus/pci/devices/0000:00:04.0.
One folder "fivr" contains all attributes exposed for controling FIVR
features. The other folder "dvfs" contains all attributes for DDR
features.

Changes done to implement:
- New module for rfim interfaces
- Two new per processor features for DDR and FIVR
- Enable feature for Tiger Lake (FIVR only) and Alder Lake

The attributes exposed and explanation:

FIVR attributes

vco_ref_code_lo (RW): The VCO reference code is an 11-bit field and
controls the FIVR switching frequency. This is the 3-bit LSB field.

vco_ref_code_hi (RW): The VCO reference code is an 11-bit field and
controls the FIVR switching frequency. This is the 8-bit MSB field.

spread_spectrum_pct (RW): Set the FIVR spread spectrum clocking
percentage

spread_spectrum_clk_enable (RW): Enable/disable of the FIVR spread
spectrum clocking feature

rfi_vco_ref_code (RW): This field is a read only status register which
reflects the current FIVR switching frequency

fivr_fffc_rev (RW): This field indicated the revision of the FIVR HW.

DVFS attributes

rfi_restriction_run_busy (RW): Request the restriction of specific DDR
data rate and set this value 1. Self reset to 0 after operation.

rfi_restriction_err_code (RW): Values:  0 :Request is accepted, 1:Feature
disabled, 2: the request restricts more points than it is allowed

rfi_restriction_data_rate_Delta (RW): Restricted DDR data rate for RFI
protection: Lower Limit

rfi_restriction_data_rate_Base (RW): Restricted DDR data rate for RFI
protection: Upper Limit

ddr_data_rate_point_0 (RO): DDR data rate selection 1st point

ddr_data_rate_point_1 (RO): DDR data rate selection 2nd point

ddr_data_rate_point_2 (RO): DDR data rate selection 3rd point

ddr_data_rate_point_3 (RO): DDR data rate selection 4th point

rfi_disable (RW): Disable DDR rate change feature

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20201126171829.945969-3-srinivas.pandruvada@linux.intel.com
---
 drivers/thermal/intel/int340x_thermal/Makefile                   |   1 +-
 drivers/thermal/intel/int340x_thermal/processor_thermal_device.c |  23 ++++++-
 drivers/thermal/intel/int340x_thermal/processor_thermal_device.h |   5 +-
 drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c   | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 270 insertions(+), 3 deletions(-)
 create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c

diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile
index 86e8d3c..f4e2eb7 100644
--- a/drivers/thermal/intel/int340x_thermal/Makefile
+++ b/drivers/thermal/intel/int340x_thermal/Makefile
@@ -5,5 +5,6 @@ obj-$(CONFIG_INT340X_THERMAL)	+= int3402_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)	+= int3403_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_device.o
 obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
+obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_rfim.o
 obj-$(CONFIG_INT3406_THERMAL)	+= int3406_thermal.o
 obj-$(CONFIG_ACPI_THERMAL_REL)	+= acpi_thermal_rel.o
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 589ac7d..b6a7358 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -429,6 +429,8 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev,
 {
 	int ret;
 
+	proc_priv->mmio_feature_mask = feature_mask;
+
 	if (feature_mask) {
 		ret = proc_thermal_set_mmio_base(pdev, proc_priv);
 		if (ret)
@@ -443,9 +445,21 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev,
 		}
 	}
 
-	proc_priv->mmio_feature_mask = feature_mask;
+	if (feature_mask & PROC_THERMAL_FEATURE_FIVR ||
+	    feature_mask & PROC_THERMAL_FEATURE_DVFS) {
+		ret = proc_thermal_rfim_add(pdev, proc_priv);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to add RFIM interface\n");
+			goto err_rem_rapl;
+		}
+	}
 
 	return 0;
+
+err_rem_rapl:
+	proc_thermal_rapl_remove();
+
+	return ret;
 }
 
 static void proc_thermal_mmio_remove(struct pci_dev *pdev)
@@ -455,6 +469,9 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev)
 	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
 		proc_thermal_rapl_remove();
 
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR ||
+	    proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
+		proc_thermal_rfim_remove(pdev);
 }
 
 static int  proc_thermal_pci_probe(struct pci_dev *pdev,
@@ -566,7 +583,7 @@ static int proc_thermal_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
 
 static const struct pci_device_id proc_thermal_pci_ids[] = {
-	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS) },
 	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
@@ -580,7 +597,7 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
 	{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
 	{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
 	{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
-	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR) },
 	{ },
 };
 
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
index 4521457..4bbb88f 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -54,6 +54,8 @@ struct rapl_mmio_regs {
 
 #define PROC_THERMAL_FEATURE_NONE	0x00
 #define PROC_THERMAL_FEATURE_RAPL	0x01
+#define PROC_THERMAL_FEATURE_FIVR	0x02
+#define PROC_THERMAL_FEATURE_DVFS	0x04
 
 #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
 int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
@@ -70,4 +72,7 @@ static void __maybe_unused proc_thermal_rapl_remove(void)
 }
 #endif
 
+int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
+void proc_thermal_rfim_remove(struct pci_dev *pdev);
+
 #endif
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
new file mode 100644
index 0000000..aef993a
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * processor thermal device RFIM control
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "processor_thermal_device.h"
+
+struct mmio_reg {
+	int read_only;
+	u32 offset;
+	int bits;
+	u16 mask;
+	u16 shift;
+};
+
+/* These will represent sysfs attribute names */
+static const char * const fivr_strings[] = {
+	"vco_ref_code_lo",
+	"vco_ref_code_hi",
+	"spread_spectrum_pct",
+	"spread_spectrum_clk_enable",
+	"rfi_vco_ref_code",
+	"fivr_fffc_rev",
+	NULL
+};
+
+static const struct mmio_reg tgl_fivr_mmio_regs[] = {
+	{ 0, 0x5A18, 3, 0x7, 12}, /* vco_ref_code_lo */
+	{ 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */
+	{ 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */
+	{ 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */
+	{ 1, 0x5A10, 12, 0xFFF, 0}, /* rfi_vco_ref_code */
+	{ 1, 0x5A14, 2, 0x3, 1}, /* fivr_fffc_rev */
+};
+
+/* These will represent sysfs attribute names */
+static const char * const dvfs_strings[] = {
+	"rfi_restriction_run_busy",
+	"rfi_restriction_err_code",
+	"rfi_restriction_data_rate",
+	"rfi_restriction_data_rate_base",
+	"ddr_data_rate_point_0",
+	"ddr_data_rate_point_1",
+	"ddr_data_rate_point_2",
+	"ddr_data_rate_point_3",
+	"rfi_disable",
+	NULL
+};
+
+static const struct mmio_reg adl_dvfs_mmio_regs[] = {
+	{ 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */
+	{ 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */
+	{ 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */
+	{ 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base */
+	{ 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */
+	{ 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */
+	{ 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */
+	{ 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */
+	{ 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */
+};
+
+#define RFIM_SHOW(suffix, table)\
+static ssize_t suffix##_show(struct device *dev,\
+			      struct device_attribute *attr,\
+			      char *buf)\
+{\
+	struct proc_thermal_device *proc_priv;\
+	struct pci_dev *pdev = to_pci_dev(dev);\
+	const struct mmio_reg *mmio_regs;\
+	const char **match_strs;\
+	u32 reg_val;\
+	int ret;\
+\
+	proc_priv = pci_get_drvdata(pdev);\
+	if (table) {\
+		match_strs = (const char **)dvfs_strings;\
+		mmio_regs = adl_dvfs_mmio_regs;\
+	} else { \
+		match_strs = (const char **)fivr_strings;\
+		mmio_regs = tgl_fivr_mmio_regs;\
+	} \
+	\
+	ret = match_string(match_strs, -1, attr->attr.name);\
+	if (ret < 0)\
+		return ret;\
+	reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
+	ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\
+	return sprintf(buf, "%u\n", ret);\
+}
+
+#define RFIM_STORE(suffix, table)\
+static ssize_t suffix##_store(struct device *dev,\
+			       struct device_attribute *attr,\
+			       const char *buf, size_t count)\
+{\
+	struct proc_thermal_device *proc_priv;\
+	struct pci_dev *pdev = to_pci_dev(dev);\
+	unsigned int input;\
+	const char **match_strs;\
+	const struct mmio_reg *mmio_regs;\
+	int ret, err;\
+	u32 reg_val;\
+	u32 mask;\
+\
+	proc_priv = pci_get_drvdata(pdev);\
+	if (table) {\
+		match_strs = (const char **)dvfs_strings;\
+		mmio_regs = adl_dvfs_mmio_regs;\
+	} else { \
+		match_strs = (const char **)fivr_strings;\
+		mmio_regs = tgl_fivr_mmio_regs;\
+	} \
+	\
+	ret = match_string(match_strs, -1, attr->attr.name);\
+	if (ret < 0)\
+		return ret;\
+	if (mmio_regs[ret].read_only)\
+		return -EPERM;\
+	err = kstrtouint(buf, 10, &input);\
+	if (err)\
+		return err;\
+	mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\
+	reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
+	reg_val &= ~mask;\
+	reg_val |= (input << mmio_regs[ret].shift);\
+	writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
+	return count;\
+}
+
+RFIM_SHOW(vco_ref_code_lo, 0)
+RFIM_SHOW(vco_ref_code_hi, 0)
+RFIM_SHOW(spread_spectrum_pct, 0)
+RFIM_SHOW(spread_spectrum_clk_enable, 0)
+RFIM_SHOW(rfi_vco_ref_code, 0)
+RFIM_SHOW(fivr_fffc_rev, 0)
+
+RFIM_STORE(vco_ref_code_lo, 0)
+RFIM_STORE(vco_ref_code_hi, 0)
+RFIM_STORE(spread_spectrum_pct, 0)
+RFIM_STORE(spread_spectrum_clk_enable, 0)
+RFIM_STORE(rfi_vco_ref_code, 0)
+RFIM_STORE(fivr_fffc_rev, 0)
+
+static DEVICE_ATTR_RW(vco_ref_code_lo);
+static DEVICE_ATTR_RW(vco_ref_code_hi);
+static DEVICE_ATTR_RW(spread_spectrum_pct);
+static DEVICE_ATTR_RW(spread_spectrum_clk_enable);
+static DEVICE_ATTR_RW(rfi_vco_ref_code);
+static DEVICE_ATTR_RW(fivr_fffc_rev);
+
+static struct attribute *fivr_attrs[] = {
+	&dev_attr_vco_ref_code_lo.attr,
+	&dev_attr_vco_ref_code_hi.attr,
+	&dev_attr_spread_spectrum_pct.attr,
+	&dev_attr_spread_spectrum_clk_enable.attr,
+	&dev_attr_rfi_vco_ref_code.attr,
+	&dev_attr_fivr_fffc_rev.attr,
+	NULL
+};
+
+static const struct attribute_group fivr_attribute_group = {
+	.attrs = fivr_attrs,
+	.name = "fivr"
+};
+
+RFIM_SHOW(rfi_restriction_run_busy, 1)
+RFIM_SHOW(rfi_restriction_err_code, 1)
+RFIM_SHOW(rfi_restriction_data_rate, 1)
+RFIM_SHOW(ddr_data_rate_point_0, 1)
+RFIM_SHOW(ddr_data_rate_point_1, 1)
+RFIM_SHOW(ddr_data_rate_point_2, 1)
+RFIM_SHOW(ddr_data_rate_point_3, 1)
+RFIM_SHOW(rfi_disable, 1)
+
+RFIM_STORE(rfi_restriction_run_busy, 1)
+RFIM_STORE(rfi_restriction_err_code, 1)
+RFIM_STORE(rfi_restriction_data_rate, 1)
+RFIM_STORE(rfi_disable, 1)
+
+static DEVICE_ATTR_RW(rfi_restriction_run_busy);
+static DEVICE_ATTR_RW(rfi_restriction_err_code);
+static DEVICE_ATTR_RW(rfi_restriction_data_rate);
+static DEVICE_ATTR_RO(ddr_data_rate_point_0);
+static DEVICE_ATTR_RO(ddr_data_rate_point_1);
+static DEVICE_ATTR_RO(ddr_data_rate_point_2);
+static DEVICE_ATTR_RO(ddr_data_rate_point_3);
+static DEVICE_ATTR_RW(rfi_disable);
+
+static struct attribute *dvfs_attrs[] = {
+	&dev_attr_rfi_restriction_run_busy.attr,
+	&dev_attr_rfi_restriction_err_code.attr,
+	&dev_attr_rfi_restriction_data_rate.attr,
+	&dev_attr_ddr_data_rate_point_0.attr,
+	&dev_attr_ddr_data_rate_point_1.attr,
+	&dev_attr_ddr_data_rate_point_2.attr,
+	&dev_attr_ddr_data_rate_point_3.attr,
+	&dev_attr_rfi_disable.attr,
+	NULL
+};
+
+static const struct attribute_group dvfs_attribute_group = {
+	.attrs = dvfs_attrs,
+	.name = "dvfs"
+};
+
+int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
+{
+	int ret;
+
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
+		ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group);
+		if (ret)
+			return ret;
+	}
+
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {
+		ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group);
+		if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
+			sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(proc_thermal_rfim_add);
+
+void proc_thermal_rfim_remove(struct pci_dev *pdev)
+{
+	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
+
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
+		sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
+
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
+		sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group);
+}
+EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);
+
+MODULE_LICENSE("GPL v2");

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [thermal: thermal/next] thermal: int340x: processor_thermal: Refactor MMIO interface
  2020-11-26 17:18 [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface Srinivas Pandruvada
                   ` (3 preceding siblings ...)
  2020-12-09 16:15 ` [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface Srinivas Pandruvada
@ 2020-12-11 13:09 ` thermal-bot for Srinivas Pandruvada
  4 siblings, 0 replies; 11+ messages in thread
From: thermal-bot for Srinivas Pandruvada @ 2020-12-11 13:09 UTC (permalink / raw)
  To: linux-pm; +Cc: Srinivas Pandruvada, Daniel Lezcano, rui.zhang, amitk

The following commit has been merged into the thermal/next branch of thermal:

Commit-ID:     a5923b6c3137b9d4fc2ea1c997f6e4d51ac5d774
Gitweb:        https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git//a5923b6c3137b9d4fc2ea1c997f6e4d51ac5d774
Author:        Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
AuthorDate:    Thu, 26 Nov 2020 09:18:26 -08:00
Committer:     Daniel Lezcano <daniel.lezcano@linaro.org>
CommitterDate: Thu, 10 Dec 2020 12:29:47 +01:00

thermal: int340x: processor_thermal: Refactor MMIO interface

The Processor Thermal PCI device supports multiple features. Currently
we export only RAPL. But we need more features from this device exposed
for Tiger Lake and Alder Lake based platforms. So re-structure the
current MMIO interface, so that more features can be added cleanly.

No functional changes are expected with this change.

Changes done in this patch:
- Using PCI_DEVICE_DATA(), hence names of defines changed
- Move RAPL MMIO code to its own module
- Move the RAPL MMIO offsets to RAPL MMIO module
- Adjust Kconfig dependency of PROC_THERMAL_MMIO_RAPL
- Per processor driver data now contains the supported features
- Moved all the common data structures and defines to a common header
  file
- This new header file contains all the processor_thermal_* interfaces
- Based on the features supported the module interface is called
- Each module atleast provides one add and one remove function

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20201126171829.945969-1-srinivas.pandruvada@linux.intel.com
---
 drivers/thermal/intel/int340x_thermal/Kconfig                    |   6 +--
 drivers/thermal/intel/int340x_thermal/Makefile                   |   1 +-
 drivers/thermal/intel/int340x_thermal/processor_thermal_device.c | 261 ++++++++++++++--------------------------------------------------------
 drivers/thermal/intel/int340x_thermal/processor_thermal_device.h |  72 +++++++++++++++++++-
 drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c   | 134 ++++++++++++++++++++++++++++++++++++-
 5 files changed, 263 insertions(+), 211 deletions(-)
 create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
 create mode 100644 drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c

diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig b/drivers/thermal/intel/int340x_thermal/Kconfig
index 7979075..45c31f3 100644
--- a/drivers/thermal/intel/int340x_thermal/Kconfig
+++ b/drivers/thermal/intel/int340x_thermal/Kconfig
@@ -10,6 +10,7 @@ config INT340X_THERMAL
 	select ACPI_THERMAL_REL
 	select ACPI_FAN
 	select INTEL_SOC_DTS_IOSF_CORE
+	select PROC_THERMAL_MMIO_RAPL if X86_64 && POWERCAP
 	help
 	  Newer laptops and tablets that use ACPI may have thermal sensors and
 	  other devices with thermal control capabilities outside the core
@@ -41,9 +42,6 @@ config INT3406_THERMAL
 	  power consumed by display device.
 
 config PROC_THERMAL_MMIO_RAPL
-	bool
-	depends on 64BIT
-	depends on POWERCAP
+	tristate
 	select INTEL_RAPL_CORE
-	default y
 endif
diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile
index 287eb0a..86e8d3c 100644
--- a/drivers/thermal/intel/int340x_thermal/Makefile
+++ b/drivers/thermal/intel/int340x_thermal/Makefile
@@ -4,5 +4,6 @@ obj-$(CONFIG_INT340X_THERMAL)	+= int340x_thermal_zone.o
 obj-$(CONFIG_INT340X_THERMAL)	+= int3402_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)	+= int3403_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_device.o
+obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
 obj-$(CONFIG_INT3406_THERMAL)	+= int3406_thermal.o
 obj-$(CONFIG_ACPI_THERMAL_REL)	+= acpi_thermal_rel.o
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 81e8b15..5b8dc5e 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -12,74 +12,18 @@
 #include <linux/acpi.h>
 #include <linux/thermal.h>
 #include <linux/cpuhotplug.h>
-#include <linux/intel_rapl.h>
 #include "int340x_thermal_zone.h"
+#include "processor_thermal_device.h"
 #include "../intel_soc_dts_iosf.h"
 
-/* Broadwell-U/HSB thermal reporting device */
-#define PCI_DEVICE_ID_PROC_BDW_THERMAL	0x1603
-#define PCI_DEVICE_ID_PROC_HSB_THERMAL	0x0A03
-
-/* Skylake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_SKL_THERMAL	0x1903
-
-/* CannonLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_CNL_THERMAL	0x5a03
-#define PCI_DEVICE_ID_PROC_CFL_THERMAL	0x3E83
-
-/* Braswell thermal reporting device */
-#define PCI_DEVICE_ID_PROC_BSW_THERMAL	0x22DC
-
-/* Broxton thermal reporting device */
-#define PCI_DEVICE_ID_PROC_BXT0_THERMAL  0x0A8C
-#define PCI_DEVICE_ID_PROC_BXT1_THERMAL  0x1A8C
-#define PCI_DEVICE_ID_PROC_BXTX_THERMAL  0x4A8C
-#define PCI_DEVICE_ID_PROC_BXTP_THERMAL  0x5A8C
-
-/* GeminiLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_GLK_THERMAL	0x318C
-
-/* IceLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_ICL_THERMAL	0x8a03
-
-/* JasperLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_JSL_THERMAL	0x4E03
-
-/* TigerLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_TGL_THERMAL	0x9A03
-
 #define DRV_NAME "proc_thermal"
 
-struct power_config {
-	u32	index;
-	u32	min_uw;
-	u32	max_uw;
-	u32	tmin_us;
-	u32	tmax_us;
-	u32	step_uw;
-};
-
-struct proc_thermal_device {
-	struct device *dev;
-	struct acpi_device *adev;
-	struct power_config power_limits[2];
-	struct int34x_thermal_zone *int340x_zone;
-	struct intel_soc_dts_sensors *soc_dts;
-	void __iomem *mmio_base;
-};
-
 enum proc_thermal_emum_mode_type {
 	PROC_THERMAL_NONE,
 	PROC_THERMAL_PCI,
 	PROC_THERMAL_PLATFORM_DEV
 };
 
-struct rapl_mmio_regs {
-	u64 reg_unit;
-	u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
-	int limits[RAPL_DOMAIN_MAX];
-};
-
 /*
  * We can have only one type of enumeration, PCI or Platform,
  * not both. So we don't need instance specific data.
@@ -461,84 +405,13 @@ static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid)
 	return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_PROC_THERMAL_MMIO_RAPL
-
 #define MCHBAR 0
 
-/* RAPL Support via MMIO interface */
-static struct rapl_if_priv rapl_mmio_priv;
-
-static int rapl_mmio_cpu_online(unsigned int cpu)
-{
-	struct rapl_package *rp;
-
-	/* mmio rapl supports package 0 only for now */
-	if (topology_physical_package_id(cpu))
-		return 0;
-
-	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
-	if (!rp) {
-		rp = rapl_add_package(cpu, &rapl_mmio_priv);
-		if (IS_ERR(rp))
-			return PTR_ERR(rp);
-	}
-	cpumask_set_cpu(cpu, &rp->cpumask);
-	return 0;
-}
-
-static int rapl_mmio_cpu_down_prep(unsigned int cpu)
+static int proc_thermal_set_mmio_base(struct pci_dev *pdev,
+				      struct proc_thermal_device *proc_priv)
 {
-	struct rapl_package *rp;
-	int lead_cpu;
-
-	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
-	if (!rp)
-		return 0;
-
-	cpumask_clear_cpu(cpu, &rp->cpumask);
-	lead_cpu = cpumask_first(&rp->cpumask);
-	if (lead_cpu >= nr_cpu_ids)
-		rapl_remove_package(rp);
-	else if (rp->lead_cpu == cpu)
-		rp->lead_cpu = lead_cpu;
-	return 0;
-}
-
-static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
-{
-	if (!ra->reg)
-		return -EINVAL;
-
-	ra->value = readq((void __iomem *)ra->reg);
-	ra->value &= ra->mask;
-	return 0;
-}
-
-static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
-{
-	u64 val;
-
-	if (!ra->reg)
-		return -EINVAL;
-
-	val = readq((void __iomem *)ra->reg);
-	val &= ~ra->mask;
-	val |= ra->value;
-	writeq(val, (void __iomem *)ra->reg);
-	return 0;
-}
-
-static int proc_thermal_rapl_add(struct pci_dev *pdev,
-				 struct proc_thermal_device *proc_priv,
-				 struct rapl_mmio_regs *rapl_regs)
-{
-	enum rapl_domain_reg_id reg;
-	enum rapl_domain_type domain;
 	int ret;
 
-	if (!rapl_regs)
-		return 0;
-
 	ret = pcim_iomap_regions(pdev, 1 << MCHBAR, DRV_NAME);
 	if (ret) {
 		dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
@@ -547,66 +420,42 @@ static int proc_thermal_rapl_add(struct pci_dev *pdev,
 
 	proc_priv->mmio_base = pcim_iomap_table(pdev)[MCHBAR];
 
-	for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) {
-		for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++)
-			if (rapl_regs->regs[domain][reg])
-				rapl_mmio_priv.regs[domain][reg] =
-						(u64)proc_priv->mmio_base +
-						rapl_regs->regs[domain][reg];
-		rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain];
-	}
-	rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit;
+	return 0;
+}
 
-	rapl_mmio_priv.read_raw = rapl_mmio_read_raw;
-	rapl_mmio_priv.write_raw = rapl_mmio_write_raw;
+static int proc_thermal_mmio_add(struct pci_dev *pdev,
+				 struct proc_thermal_device *proc_priv,
+				 kernel_ulong_t feature_mask)
+{
+	int ret;
 
-	rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL);
-	if (IS_ERR(rapl_mmio_priv.control_type)) {
-		pr_debug("failed to register powercap control_type.\n");
-		return PTR_ERR(rapl_mmio_priv.control_type);
+	if (feature_mask) {
+		ret = proc_thermal_set_mmio_base(pdev, proc_priv);
+		if (ret)
+			return ret;
 	}
 
-	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
-				rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep);
-	if (ret < 0) {
-		powercap_unregister_control_type(rapl_mmio_priv.control_type);
-		rapl_mmio_priv.control_type = NULL;
-		return ret;
+	if (feature_mask & PROC_THERMAL_FEATURE_RAPL) {
+		ret = proc_thermal_rapl_add(pdev, proc_priv);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to add RAPL MMIO interface\n");
+			return ret;
+		}
 	}
-	rapl_mmio_priv.pcap_rapl_online = ret;
+
+	proc_priv->mmio_feature_mask = feature_mask;
 
 	return 0;
 }
 
-static void proc_thermal_rapl_remove(void)
+static void proc_thermal_mmio_remove(struct pci_dev *pdev)
 {
-	if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type))
-		return;
-
-	cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online);
-	powercap_unregister_control_type(rapl_mmio_priv.control_type);
-}
+	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
 
-static const struct rapl_mmio_regs rapl_mmio_hsw = {
-	.reg_unit = 0x5938,
-	.regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930},
-	.regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
-	.limits[RAPL_DOMAIN_PACKAGE] = 2,
-	.limits[RAPL_DOMAIN_DRAM] = 2,
-};
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
+		proc_thermal_rapl_remove();
 
-#else
-
-static int proc_thermal_rapl_add(struct pci_dev *pdev,
-				 struct proc_thermal_device *proc_priv,
-				 struct rapl_mmio_regs *rapl_regs)
-{
-	return 0;
 }
-static void proc_thermal_rapl_remove(void) {}
-static const struct rapl_mmio_regs rapl_mmio_hsw;
-
-#endif /* CONFIG_MMIO_RAPL */
 
 static int  proc_thermal_pci_probe(struct pci_dev *pdev,
 				   const struct pci_device_id *id)
@@ -629,18 +478,10 @@ static int  proc_thermal_pci_probe(struct pci_dev *pdev,
 	if (ret)
 		return ret;
 
-	ret = proc_thermal_rapl_add(pdev, proc_priv,
-				(struct rapl_mmio_regs *)id->driver_data);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to add RAPL MMIO interface\n");
-		proc_thermal_remove(proc_priv);
-		return ret;
-	}
-
 	pci_set_drvdata(pdev, proc_priv);
 	proc_thermal_emum_mode = PROC_THERMAL_PCI;
 
-	if (pdev->device == PCI_DEVICE_ID_PROC_BSW_THERMAL) {
+	if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) {
 		/*
 		 * Enumerate additional DTS sensors available via IOSF.
 		 * But we are not treating as a failure condition, if
@@ -676,10 +517,18 @@ static int  proc_thermal_pci_probe(struct pci_dev *pdev,
 		return ret;
 
 	ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group);
-	if (ret)
+	if (ret) {
 		sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
+		return ret;
+	}
 
-	return ret;
+	ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
+	if (ret) {
+		proc_thermal_remove(proc_priv);
+		return ret;
+	}
+
+	return 0;
 }
 
 static void  proc_thermal_pci_remove(struct pci_dev *pdev)
@@ -693,7 +542,8 @@ static void  proc_thermal_pci_remove(struct pci_dev *pdev)
 			pci_disable_msi(pdev);
 		}
 	}
-	proc_thermal_rapl_remove();
+
+	proc_thermal_mmio_remove(pdev);
 	proc_thermal_remove(proc_priv);
 }
 
@@ -716,24 +566,21 @@ static int proc_thermal_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
 
 static const struct pci_device_id proc_thermal_pci_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BDW_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_HSB_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_SKL_THERMAL),
-		.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BSW_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT0_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT1_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTX_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTP_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_CNL_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_CFL_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_GLK_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_ICL_THERMAL),
-		.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_JSL_THERMAL)},
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_TGL_THERMAL),
-		.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
-	{ 0, },
+	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+	{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
+	{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+	{ },
 };
 
 MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
new file mode 100644
index 0000000..e20d142
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * processor_thermal_device.h
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#ifndef __PROCESSOR_THERMAL_DEVICE_H__
+#define __PROCESSOR_THERMAL_DEVICE_H__
+
+#include <linux/intel_rapl.h>
+
+#define PCI_DEVICE_ID_INTEL_BDW_THERMAL	0x1603
+#define PCI_DEVICE_ID_INTEL_BSW_THERMAL	0x22DC
+
+#define PCI_DEVICE_ID_INTEL_BXT0_THERMAL	0x0A8C
+#define PCI_DEVICE_ID_INTEL_BXT1_THERMAL	0x1A8C
+#define PCI_DEVICE_ID_INTEL_BXTX_THERMAL	0x4A8C
+#define PCI_DEVICE_ID_INTEL_BXTP_THERMAL	0x5A8C
+
+#define PCI_DEVICE_ID_INTEL_CNL_THERMAL	0x5a03
+#define PCI_DEVICE_ID_INTEL_CFL_THERMAL	0x3E83
+#define PCI_DEVICE_ID_INTEL_GLK_THERMAL	0x318C
+#define PCI_DEVICE_ID_INTEL_HSB_THERMAL	0x0A03
+#define PCI_DEVICE_ID_INTEL_ICL_THERMAL	0x8a03
+#define PCI_DEVICE_ID_INTEL_JSL_THERMAL	0x4E03
+#define PCI_DEVICE_ID_INTEL_SKL_THERMAL	0x1903
+#define PCI_DEVICE_ID_INTEL_TGL_THERMAL	0x9A03
+
+struct power_config {
+	u32	index;
+	u32	min_uw;
+	u32	max_uw;
+	u32	tmin_us;
+	u32	tmax_us;
+	u32	step_uw;
+};
+
+struct proc_thermal_device {
+	struct device *dev;
+	struct acpi_device *adev;
+	struct power_config power_limits[2];
+	struct int34x_thermal_zone *int340x_zone;
+	struct intel_soc_dts_sensors *soc_dts;
+	u32 mmio_feature_mask;
+	void __iomem *mmio_base;
+};
+
+struct rapl_mmio_regs {
+	u64 reg_unit;
+	u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
+	int limits[RAPL_DOMAIN_MAX];
+};
+
+#define PROC_THERMAL_FEATURE_NONE	0x00
+#define PROC_THERMAL_FEATURE_RAPL	0x01
+
+#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
+int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
+void proc_thermal_rapl_remove(void);
+#else
+static int __maybe_unused proc_thermal_rapl_add(struct pci_dev *pdev,
+						struct proc_thermal_device *proc_priv)
+{
+	return 0;
+}
+
+static void __maybe_unused proc_thermal_rapl_remove(void)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
new file mode 100644
index 0000000..a205221
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * processor thermal device RFIM control
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "processor_thermal_device.h"
+
+static struct rapl_if_priv rapl_mmio_priv;
+
+static const struct rapl_mmio_regs rapl_mmio_default = {
+	.reg_unit = 0x5938,
+	.regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930},
+	.regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
+	.limits[RAPL_DOMAIN_PACKAGE] = 2,
+	.limits[RAPL_DOMAIN_DRAM] = 2,
+};
+
+static int rapl_mmio_cpu_online(unsigned int cpu)
+{
+	struct rapl_package *rp;
+
+	/* mmio rapl supports package 0 only for now */
+	if (topology_physical_package_id(cpu))
+		return 0;
+
+	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
+	if (!rp) {
+		rp = rapl_add_package(cpu, &rapl_mmio_priv);
+		if (IS_ERR(rp))
+			return PTR_ERR(rp);
+	}
+	cpumask_set_cpu(cpu, &rp->cpumask);
+	return 0;
+}
+
+static int rapl_mmio_cpu_down_prep(unsigned int cpu)
+{
+	struct rapl_package *rp;
+	int lead_cpu;
+
+	rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
+	if (!rp)
+		return 0;
+
+	cpumask_clear_cpu(cpu, &rp->cpumask);
+	lead_cpu = cpumask_first(&rp->cpumask);
+	if (lead_cpu >= nr_cpu_ids)
+		rapl_remove_package(rp);
+	else if (rp->lead_cpu == cpu)
+		rp->lead_cpu = lead_cpu;
+	return 0;
+}
+
+static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
+{
+	if (!ra->reg)
+		return -EINVAL;
+
+	ra->value = readq((void __iomem *)ra->reg);
+	ra->value &= ra->mask;
+	return 0;
+}
+
+static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
+{
+	u64 val;
+
+	if (!ra->reg)
+		return -EINVAL;
+
+	val = readq((void __iomem *)ra->reg);
+	val &= ~ra->mask;
+	val |= ra->value;
+	writeq(val, (void __iomem *)ra->reg);
+	return 0;
+}
+
+int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
+{
+	const struct rapl_mmio_regs *rapl_regs = &rapl_mmio_default;
+	enum rapl_domain_reg_id reg;
+	enum rapl_domain_type domain;
+	int ret;
+
+	if (!rapl_regs)
+		return 0;
+
+	for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) {
+		for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++)
+			if (rapl_regs->regs[domain][reg])
+				rapl_mmio_priv.regs[domain][reg] =
+						(u64)proc_priv->mmio_base +
+						rapl_regs->regs[domain][reg];
+		rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain];
+	}
+	rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit;
+
+	rapl_mmio_priv.read_raw = rapl_mmio_read_raw;
+	rapl_mmio_priv.write_raw = rapl_mmio_write_raw;
+
+	rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL);
+	if (IS_ERR(rapl_mmio_priv.control_type)) {
+		pr_debug("failed to register powercap control_type.\n");
+		return PTR_ERR(rapl_mmio_priv.control_type);
+	}
+
+	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
+				rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep);
+	if (ret < 0) {
+		powercap_unregister_control_type(rapl_mmio_priv.control_type);
+		rapl_mmio_priv.control_type = NULL;
+		return ret;
+	}
+	rapl_mmio_priv.pcap_rapl_online = ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(proc_thermal_rapl_add);
+
+void proc_thermal_rapl_remove(void)
+{
+	if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type))
+		return;
+
+	cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online);
+	powercap_unregister_control_type(rapl_mmio_priv.control_type);
+}
+EXPORT_SYMBOL_GPL(proc_thermal_rapl_remove);
+
+MODULE_LICENSE("GPL v2");

^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2020-12-11 13:11 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-26 17:18 [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface Srinivas Pandruvada
2020-11-26 17:18 ` [PATCH 2/4] thermal: int340x: processor_thermal: Add AlderLake PCI device id Srinivas Pandruvada
2020-12-11 13:09   ` [thermal: thermal/next] " thermal-bot for Srinivas Pandruvada
2020-11-26 17:18 ` [PATCH 3/4] thermal: int340x: processor_thermal: Add RFIM driver Srinivas Pandruvada
2020-12-09 20:48   ` Daniel Lezcano
2020-12-10  0:19     ` Srinivas Pandruvada
2020-12-11 13:09   ` [thermal: thermal/next] " thermal-bot for Srinivas Pandruvada
2020-11-26 17:18 ` [PATCH 4/4] thermal: int340x: processor_thermal: Add mailbox driver Srinivas Pandruvada
2020-12-11 13:09   ` [thermal: thermal/next] " thermal-bot for Srinivas Pandruvada
2020-12-09 16:15 ` [PATCH 1/4] thermal: int340x: processor_thermal: Refactor MMIO interface Srinivas Pandruvada
2020-12-11 13:09 ` [thermal: thermal/next] " thermal-bot for Srinivas Pandruvada

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.