mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-17 22:05:08 +00:00
thermal: intel: int340x: Support MSI interrupt for Lunar Lake
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> Link: https://patch.msgid.link/20240619172109.497639-3-srinivas.pandruvada@linux.intel.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
a264cee31f
commit
7a9a8c5faf
@ -65,6 +65,7 @@ struct rapl_mmio_regs {
|
|||||||
#define PROC_THERMAL_FEATURE_DLVR 0x10
|
#define PROC_THERMAL_FEATURE_DLVR 0x10
|
||||||
#define PROC_THERMAL_FEATURE_WT_HINT 0x20
|
#define PROC_THERMAL_FEATURE_WT_HINT 0x20
|
||||||
#define PROC_THERMAL_FEATURE_POWER_FLOOR 0x40
|
#define PROC_THERMAL_FEATURE_POWER_FLOOR 0x40
|
||||||
|
#define PROC_THERMAL_FEATURE_MSI_SUPPORT 0x80
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
|
#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
|
||||||
int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
|
int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
|
||||||
|
@ -63,6 +63,18 @@ static struct proc_thermal_mmio_info proc_thermal_mmio_info[] = {
|
|||||||
{ PROC_THERMAL_MMIO_INT_STATUS_1, 0x7200, 8, 0x01 },
|
{ 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
|
#define B0D4_THERMAL_NOTIFY_DELAY 1000
|
||||||
static int notify_delay_ms = B0D4_THERMAL_NOTIFY_DELAY;
|
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;
|
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)
|
static irqreturn_t proc_thermal_irq_handler(int irq, void *devid)
|
||||||
{
|
{
|
||||||
struct proc_thermal_pci *pci_info = devid;
|
struct proc_thermal_pci *pci_info = devid;
|
||||||
struct proc_thermal_device *proc_priv;
|
struct proc_thermal_device *proc_priv;
|
||||||
int ret = IRQ_NONE;
|
int ret = IRQ_NONE, msi_id;
|
||||||
u32 status;
|
u32 status;
|
||||||
|
|
||||||
proc_priv = pci_info->proc_priv;
|
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_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;
|
ret = IRQ_WAKE_THREAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_POWER_FLOOR) {
|
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;
|
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.
|
* interrupt before scheduling work function for thermal threshold.
|
||||||
*/
|
*/
|
||||||
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
|
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 */
|
/* Disable enable interrupt flag */
|
||||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
|
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
|
||||||
pkg_thermal_schedule_work(&pci_info->work);
|
pkg_thermal_schedule_work(&pci_info->work);
|
||||||
@ -244,6 +275,45 @@ static struct thermal_zone_params tzone_params = {
|
|||||||
.no_hwmon = true,
|
.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)
|
static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
{
|
{
|
||||||
struct proc_thermal_device *proc_priv;
|
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,
|
.flags = THERMAL_TRIP_FLAG_RW_TEMP,
|
||||||
};
|
};
|
||||||
int irq_flag = 0, irq, ret;
|
int irq_flag = 0, irq, ret;
|
||||||
bool msi_irq = false;
|
|
||||||
|
|
||||||
proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
|
proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
|
||||||
if (!proc_priv)
|
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;
|
goto err_del_legacy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_msi && (pdev->msi_enabled || pdev->msix_enabled)) {
|
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MSI_SUPPORT)
|
||||||
/* request and enable interrupt */
|
use_msi = true;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
irq = pci_irq_vector(pdev, 0);
|
if (use_msi) {
|
||||||
msi_irq = true;
|
ret = proc_thermal_setup_msi(pdev, pci_info);
|
||||||
|
if (ret)
|
||||||
|
goto err_ret_tzone;
|
||||||
} else {
|
} else {
|
||||||
irq_flag = IRQF_SHARED;
|
irq_flag = IRQF_SHARED;
|
||||||
irq = pdev->irq;
|
irq = pdev->irq;
|
||||||
}
|
|
||||||
|
|
||||||
ret = devm_request_threaded_irq(&pdev->dev, irq,
|
ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
|
||||||
proc_thermal_irq_handler, proc_thermal_irq_thread_handler,
|
proc_thermal_irq_thread_handler, irq_flag,
|
||||||
irq_flag, KBUILD_MODNAME, pci_info);
|
KBUILD_MODNAME, pci_info);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
|
dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
|
||||||
goto err_free_vectors;
|
goto err_ret_tzone;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = thermal_zone_device_enable(pci_info->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[] = {
|
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 | PROC_THERMAL_FEATURE_WT_REQ) },
|
PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_REQ) },
|
||||||
{ PCI_DEVICE_DATA(INTEL, LNLM_THERMAL, PROC_THERMAL_FEATURE_RAPL |
|
{ PCI_DEVICE_DATA(INTEL, LNLM_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT |
|
||||||
PROC_THERMAL_FEATURE_DLVR) },
|
PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR) },
|
||||||
{ PCI_DEVICE_DATA(INTEL, MTLP_THERMAL, PROC_THERMAL_FEATURE_RAPL |
|
{ 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_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR |
|
||||||
PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR) },
|
PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR) },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user