Commit 2cbe1a33 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge earlier changes in Intel thermal drivers for v6.7.

parents a56cc0a8 1ced5dce
Loading
Loading
Loading
Loading
+54 −0
Original line number Diff line number Diff line
@@ -315,3 +315,57 @@ DPTF Fan Control
----------------------------------------

Refer to Documentation/admin-guide/acpi/fan_performance_states.rst

Workload Type Hints
----------------------------------------

The firmware in Meteor Lake processor generation is capable of identifying
workload type and passing hints regarding it to the OS. A special sysfs
interface is provided to allow user space to obtain workload type hints from
the firmware and control the rate at which they are provided.

User space can poll attribute "workload_type_index" for the current hint or
can receive a notification whenever the value of this attribute is updated.

file:`/sys/bus/pci/devices/0000:00:04.0/workload_hint/`
Segment 0, bus 0, device 4, function 0 is reserved for the processor thermal
device on all Intel client processors. So, the above path doesn't change
based on the processor generation.

``workload_hint_enable`` (RW)
	Enable firmware to send workload type hints to user space.

``notification_delay_ms`` (RW)
	Minimum delay in milliseconds before firmware will notify OS. This is
	for the rate control of notifications. This delay is between changing
	the workload type prediction in the firmware and notifying the OS about
	the change. The default delay is 1024 ms. The delay of 0 is invalid.
	The delay is rounded up to the nearest power of 2 to simplify firmware
	programming of the delay value. The read of notification_delay_ms
	attribute shows the effective value used.

``workload_type_index`` (RO)
	Predicted workload type index. User space can get notification of
	change via existing sysfs attribute change notification mechanism.

	The supported index values and their meaning for the Meteor Lake
	processor generation are as follows:

	0 -  Idle: System performs no tasks, power and idle residency are
		consistently low for long periods of time.

	1 – Battery Life: Power is relatively low, but the processor may
		still be actively performing a task, such as video playback for
		a long period of time.

	2 – Sustained: Power level that is relatively high for a long period
		of time, with very few to no periods of idleness, which will
		eventually exhaust RAPL Power Limit 1 and 2.

	3 – Bursty: Consumes a relatively constant average amount of power, but
		periods of relative idleness are interrupted by bursts of
		activity. The bursts are relatively short and the periods of
		relative idleness between them typically prevent RAPL Power
		Limit 1 from being exhausted.

	4 – Unknown: Can't classify.
+2 −0
Original line number Diff line number Diff line
@@ -10,5 +10,7 @@ obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci.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_INT340X_THERMAL)	+= processor_thermal_wt_req.o
obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_wt_hint.o
obj-$(CONFIG_INT3406_THERMAL)	+= int3406_thermal.o
obj-$(CONFIG_ACPI_THERMAL_REL)	+= acpi_thermal_rel.o
+13 −4
Original line number Diff line number Diff line
@@ -346,12 +346,18 @@ 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 (feature_mask & PROC_THERMAL_FEATURE_WT_REQ) {
		ret = proc_thermal_wt_req_add(pdev, proc_priv);
		if (ret) {
			dev_err(&pdev->dev, "failed to add MBOX interface\n");
			goto err_rem_rfim;
		}
	} else if (feature_mask & PROC_THERMAL_FEATURE_WT_HINT) {
		ret = proc_thermal_wt_hint_add(pdev, proc_priv);
		if (ret) {
			dev_err(&pdev->dev, "failed to add WT Hint\n");
			goto err_rem_rfim;
		}
	}

	return 0;
@@ -374,12 +380,15 @@ void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *
	    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);
	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_REQ)
		proc_thermal_wt_req_remove(pdev);
	else if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_HINT)
		proc_thermal_wt_hint_remove(pdev);
}
EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove);

MODULE_IMPORT_NS(INTEL_TCC);
MODULE_IMPORT_NS(INT340X_THERMAL);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
MODULE_LICENSE("GPL v2");
+19 −3
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/intel_rapl.h>

#define PCI_DEVICE_ID_INTEL_ADL_THERMAL	0x461d
#define PCI_DEVICE_ID_INTEL_ARL_S_THERMAL 0xAD03
#define PCI_DEVICE_ID_INTEL_BDW_THERMAL	0x1603
#define PCI_DEVICE_ID_INTEL_BSW_THERMAL	0x22DC

@@ -59,8 +60,9 @@ 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
#define PROC_THERMAL_FEATURE_WT_REQ	0x08
#define PROC_THERMAL_FEATURE_DLVR	0x10
#define PROC_THERMAL_FEATURE_WT_HINT	0x20

#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
@@ -80,13 +82,27 @@ 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);
int proc_thermal_wt_req_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
void proc_thermal_wt_req_remove(struct pci_dev *pdev);

#define MBOX_CMD_WORKLOAD_TYPE_READ	0x0E
#define MBOX_CMD_WORKLOAD_TYPE_WRITE	0x0F

#define MBOX_DATA_BIT_AC_DC		30
#define MBOX_DATA_BIT_VALID		31

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);
int processor_thermal_mbox_interrupt_config(struct pci_dev *pdev, bool enable, int enable_bit,
					    int time_window);
int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv);
void proc_thermal_remove(struct proc_thermal_device *proc_priv);

int proc_thermal_wt_hint_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
void proc_thermal_wt_hint_remove(struct pci_dev *pdev);
void proc_thermal_wt_intr_callback(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
bool proc_thermal_check_wt_intr(struct proc_thermal_device *proc_priv);

int proc_thermal_suspend(struct device *dev);
int proc_thermal_resume(struct device *dev);
int proc_thermal_mmio_add(struct pci_dev *pdev,
+62 −18
Original line number Diff line number Diff line
@@ -15,6 +15,11 @@

#define DRV_NAME "proc_thermal_pci"

static bool use_msi;
module_param(use_msi, bool, 0644);
MODULE_PARM_DESC(use_msi,
	"Use PCI MSI based interrupts for processor thermal device.");

struct proc_thermal_pci {
	struct pci_dev *pdev;
	struct proc_thermal_device *proc_priv;
@@ -117,20 +122,44 @@ static void pkg_thermal_schedule_work(struct delayed_work *work)
	schedule_delayed_work(work, ms);
}

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);

	return IRQ_HANDLED;
}

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_HANDLED;
	u32 status;

	proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
	proc_priv = pci_info->proc_priv;

	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_HINT) {
		if (proc_thermal_check_wt_intr(pci_info->proc_priv))
			ret = IRQ_WAKE_THREAD;
	}

	/*
	 * Since now there are two sources of interrupts: one from thermal threshold
	 * and another from workload hint, add a check if there was really a threshold
	 * interrupt before scheduling work function for thermal threshold.
	 */
	proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
	if (status) {
		/* Disable enable interrupt flag */
		proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
	pci_write_config_byte(pci_info->pdev, 0xdc, 0x01);

		pkg_thermal_schedule_work(&pci_info->work);
	}

	return IRQ_HANDLED;
	pci_write_config_byte(pci_info->pdev, 0xdc, 0x01);

	return ret;
}

static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
@@ -203,6 +232,7 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
	struct proc_thermal_device *proc_priv;
	struct proc_thermal_pci *pci_info;
	int irq_flag = 0, irq, ret;
	bool msi_irq = false;

	proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
	if (!proc_priv)
@@ -248,18 +278,23 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
		goto err_ret_mmio;
	}

	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 (!pdev->msi_enabled && !pdev->msix_enabled)
		irq_flag = IRQF_SHARED;

		irq =  pci_irq_vector(pdev, 0);
		msi_irq = true;
	} else {
		irq_flag = IRQF_SHARED;
		irq = pdev->irq;
	}

	ret = devm_request_threaded_irq(&pdev->dev, irq,
					proc_thermal_irq_handler, NULL,
					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);
@@ -273,6 +308,7 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
	return 0;

err_free_vectors:
	if (msi_irq)
		pci_free_irq_vectors(pdev);
err_ret_tzone:
	thermal_zone_device_unregister(pci_info->tzone);
@@ -350,9 +386,15 @@ static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
			 proc_thermal_pci_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 | PROC_THERMAL_FEATURE_MBOX) },
	{ PCI_DEVICE_DATA(INTEL, MTLP_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX | PROC_THERMAL_FEATURE_DLVR) },
	{ PCI_DEVICE_DATA(INTEL, RPL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
	{ 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, MTLP_THERMAL, PROC_THERMAL_FEATURE_RAPL |
	  PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR |
	  PROC_THERMAL_FEATURE_WT_HINT) },
	{ PCI_DEVICE_DATA(INTEL, ARL_S_THERMAL, PROC_THERMAL_FEATURE_RAPL |
	  PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_WT_HINT) },
	{ PCI_DEVICE_DATA(INTEL, RPL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
	  PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_REQ) },
	{ },
};

@@ -368,6 +410,8 @@ static struct pci_driver proc_thermal_pci_driver = {

module_pci_driver(proc_thermal_pci_driver);

MODULE_IMPORT_NS(INT340X_THERMAL);

MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
MODULE_LICENSE("GPL v2");
Loading