thermal: int340x: processor_thermal: Common function to clear SOC interrupt
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Mon, 9 Oct 2023 19:05:33 +0000 (12:05 -0700)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 12 Oct 2023 19:09:48 +0000 (21:09 +0200)
The SOC interrupt status register contains multiple interrupt sources
(workload hint interrupt and power floor interrupt). It is not possible
to clear individual interrupt source with read-modify-write, as it may
clear the new interrupt from the firmware after a read operation. It is
also not possible to set the interrupt status bit to 1 for the other
interrupt source, which is not part of clearing.

Hence, create a common function, to clear all status bits at once.

Call this function after processing all interrupt sources.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
[ rjw: Changelog edits ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c

index 8ed6e8e94c8a03f904259bed5da49cffa1d761f2..f9a381b3e55c52ded4a154be00a898b71d288863 100644 (file)
@@ -92,6 +92,7 @@ void proc_thermal_wt_req_remove(struct pci_dev *pdev);
 #define MBOX_DATA_BIT_VALID            31
 
 #define SOC_WT_RES_INT_STATUS_OFFSET   0x5B18
+#define SOC_WT_RES_INT_STATUS_MASK     GENMASK_ULL(3, 2)
 
 int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp);
 int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data);
index 3c5ced79ead06c205c6a3d6596b6cf1a13daebe4..d353a190ce44439d1669ce4ed30c6b89a4d8cfea 100644 (file)
@@ -122,11 +122,24 @@ static void pkg_thermal_schedule_work(struct delayed_work *work)
        schedule_delayed_work(work, ms);
 }
 
+static void proc_thermal_clear_soc_int_status(struct proc_thermal_device *proc_priv)
+{
+       u64 status;
+
+       if (!(proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_HINT))
+               return;
+
+       status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
+       writeq(status & ~SOC_WT_RES_INT_STATUS_MASK,
+              proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
+}
+
 static irqreturn_t proc_thermal_irq_thread_handler(int irq, void *devid)
 {
        struct proc_thermal_pci *pci_info = devid;
 
        proc_thermal_wt_intr_callback(pci_info->pdev, pci_info->proc_priv);
+       proc_thermal_clear_soc_int_status(pci_info->proc_priv);
 
        return IRQ_HANDLED;
 }
index c08838eb10c8890a83342bee4ed280e976f0374d..9d5e4c169d1bcb74b06c3ef910a2865ccfbe6c95 100644 (file)
@@ -215,8 +215,6 @@ void proc_thermal_wt_intr_callback(struct pci_dev *pdev, struct proc_thermal_dev
        if (!(status & SOC_WT_PREDICTION_INT_ACTIVE))
                return;
 
-       writeq(status & ~SOC_WT_PREDICTION_INT_ACTIVE,
-                      proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
        sysfs_notify(&pdev->dev.kobj, "workload_hint", "workload_type_index");
 }
 EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_intr_callback, INT340X_THERMAL);