diff mbox series

[2/3] thermal: intel: int340x: Support MSI interrupt for Lunar Lake

Message ID 20240619172109.497639-3-srinivas.pandruvada@linux.intel.com
State Accepted
Commit 7a9a8c5faf418538b53cd63e8fcb1a34b1e3b680
Headers show
Series Processor thermal interrupts for Lunar Lake | expand

Commit Message

Srinivas Pandruvada June 19, 2024, 5:21 p.m. UTC
The legacy PCI interrupt is no longer supported for processor thermal
device on Lunar Lake. The support is via MSI.

Add feature PROC_THERMAL_FEATURE_MSI_SUPPORT to support MSI feature per
generation. Define this feature for Lunar Lake processors.

There are 4 MSI sources:
0 - Package thermal
1 - DDR Thermal
2 - Power floor interrupt
3 - Workload type hint

On interrupt check the source and call the corresponding handler. Here
don't need to call proc_thermal_check_wt_intr() and
proc_thermal_check_power_floor_intr to check if the interrupt is for
those sources as there is a dedicated MSI interrupt.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
 .../processor_thermal_device.h                |   1 +
 .../processor_thermal_device_pci.c            | 112 ++++++++++++++----
 2 files changed, 90 insertions(+), 23 deletions(-)
diff mbox series

Patch

diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
index 674f3c85dfbc..d5eca6db2c00 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -65,6 +65,7 @@  struct rapl_mmio_regs {
 #define PROC_THERMAL_FEATURE_DLVR	0x10
 #define PROC_THERMAL_FEATURE_WT_HINT	0x20
 #define PROC_THERMAL_FEATURE_POWER_FLOOR	0x40
+#define PROC_THERMAL_FEATURE_MSI_SUPPORT	0x80
 
 #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
 int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
index 59eb76d4dd81..8c6d19fe37c0 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
@@ -63,6 +63,18 @@  static struct proc_thermal_mmio_info proc_thermal_mmio_info[] = {
 	{ PROC_THERMAL_MMIO_INT_STATUS_1, 0x7200, 8, 0x01 },
 };
 
+/* List of supported MSI IDs (sources) */
+enum proc_thermal_msi_ids {
+	PKG_THERMAL,
+	DDR_THERMAL,
+	THERM_POWER_FLOOR,
+	WORKLOAD_CHANGE,
+	MSI_THERMAL_MAX
+};
+
+/* Stores IRQ associated with a MSI ID */
+static int proc_thermal_msi_map[MSI_THERMAL_MAX];
+
 #define B0D4_THERMAL_NOTIFY_DELAY	1000
 static int notify_delay_ms = B0D4_THERMAL_NOTIFY_DELAY;
 
@@ -146,22 +158,41 @@  static irqreturn_t proc_thermal_irq_thread_handler(int irq, void *devid)
 	return IRQ_HANDLED;
 }
 
+static int proc_thermal_match_msi_irq(int irq)
+{
+	int i;
+
+	if (!use_msi)
+		goto msi_fail;
+
+	for (i = 0; i < MSI_THERMAL_MAX; i++) {
+		if (proc_thermal_msi_map[i] == irq)
+			return i;
+	}
+
+msi_fail:
+	return -EOPNOTSUPP;
+}
+
 static irqreturn_t proc_thermal_irq_handler(int irq, void *devid)
 {
 	struct proc_thermal_pci *pci_info = devid;
 	struct proc_thermal_device *proc_priv;
-	int ret = IRQ_NONE;
+	int ret = IRQ_NONE, msi_id;
 	u32 status;
 
 	proc_priv = pci_info->proc_priv;
 
+	msi_id = proc_thermal_match_msi_irq(irq);
+
 	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_HINT) {
-		if (proc_thermal_check_wt_intr(pci_info->proc_priv))
+		if (msi_id == WORKLOAD_CHANGE || proc_thermal_check_wt_intr(pci_info->proc_priv))
 			ret = IRQ_WAKE_THREAD;
 	}
 
 	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_POWER_FLOOR) {
-		if (proc_thermal_check_power_floor_intr(pci_info->proc_priv))
+		if (msi_id == THERM_POWER_FLOOR ||
+		    proc_thermal_check_power_floor_intr(pci_info->proc_priv))
 			ret = IRQ_WAKE_THREAD;
 	}
 
@@ -171,7 +202,7 @@  static irqreturn_t proc_thermal_irq_handler(int irq, void *devid)
 	 * interrupt before scheduling work function for thermal threshold.
 	 */
 	proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
-	if (status) {
+	if (msi_id == PKG_THERMAL || status) {
 		/* Disable enable interrupt flag */
 		proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
 		pkg_thermal_schedule_work(&pci_info->work);
@@ -244,6 +275,45 @@  static struct thermal_zone_params tzone_params = {
 	.no_hwmon = true,
 };
 
+static bool msi_irq;
+
+static int proc_thermal_setup_msi(struct pci_dev *pdev, struct proc_thermal_pci *pci_info)
+{
+	int ret, i, irq;
+
+	ret = pci_alloc_irq_vectors(pdev, 1, MSI_THERMAL_MAX, PCI_IRQ_MSI | PCI_IRQ_MSIX);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to allocate vectors!\n");
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "msi enabled:%d msix enabled:%d\n", pdev->msi_enabled,
+		 pdev->msix_enabled);
+
+	for (i = 0; i < MSI_THERMAL_MAX; i++) {
+		irq =  pci_irq_vector(pdev, i);
+
+		ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
+						proc_thermal_irq_thread_handler,
+						0, KBUILD_MODNAME, pci_info);
+		if (ret) {
+			dev_err(&pdev->dev, "Request IRQ %d failed\n", irq);
+			goto err_free_msi_vectors;
+		}
+
+		proc_thermal_msi_map[i] = irq;
+	}
+
+	msi_irq = true;
+
+	return 0;
+
+err_free_msi_vectors:
+	pci_free_irq_vectors(pdev);
+
+	return ret;
+}
+
 static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct proc_thermal_device *proc_priv;
@@ -253,7 +323,6 @@  static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
 		.flags = THERMAL_TRIP_FLAG_RW_TEMP,
 	};
 	int irq_flag = 0, irq, ret;
-	bool msi_irq = false;
 
 	proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
 	if (!proc_priv)
@@ -299,27 +368,24 @@  static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
 		goto err_del_legacy;
 	}
 
-	if (use_msi && (pdev->msi_enabled || pdev->msix_enabled)) {
-		/* request and enable interrupt */
-		ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
-		if (ret < 0) {
-			dev_err(&pdev->dev, "Failed to allocate vectors!\n");
-			goto err_ret_tzone;
-		}
+	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MSI_SUPPORT)
+		use_msi = true;
 
-		irq =  pci_irq_vector(pdev, 0);
-		msi_irq = true;
+	if (use_msi) {
+		ret = proc_thermal_setup_msi(pdev, pci_info);
+		if (ret)
+			goto err_ret_tzone;
 	} else {
 		irq_flag = IRQF_SHARED;
 		irq = pdev->irq;
-	}
 
-	ret = devm_request_threaded_irq(&pdev->dev, irq,
-					proc_thermal_irq_handler, proc_thermal_irq_thread_handler,
-					irq_flag, KBUILD_MODNAME, pci_info);
-	if (ret) {
-		dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
-		goto err_free_vectors;
+		ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
+						proc_thermal_irq_thread_handler, irq_flag,
+						KBUILD_MODNAME, pci_info);
+		if (ret) {
+			dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
+			goto err_ret_tzone;
+		}
 	}
 
 	ret = thermal_zone_device_enable(pci_info->tzone);
@@ -405,8 +471,8 @@  static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
 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 | PROC_THERMAL_FEATURE_WT_REQ) },
-	{ PCI_DEVICE_DATA(INTEL, LNLM_THERMAL, PROC_THERMAL_FEATURE_RAPL |
-	  PROC_THERMAL_FEATURE_DLVR) },
+	{ PCI_DEVICE_DATA(INTEL, LNLM_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT |
+	  PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR) },
 	{ PCI_DEVICE_DATA(INTEL, MTLP_THERMAL, PROC_THERMAL_FEATURE_RAPL |
 	  PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR |
 	  PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR) },