File Index
Files and directories
Sign in
FILE

processor_thermal_device_pci.c

File preview with syntax highlighting.

linux-6.19.14/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Processor thermal device for newer processors
  4 * Copyright (c) 2020, Intel Corporation.
  5 */
  6
  7#include <linux/acpi.h>
  8#include <linux/kernel.h>
  9#include <linux/module.h>
 10#include <linux/pci.h>
 11#include <linux/thermal.h>
 12
 13#include "int340x_thermal_zone.h"
 14#include "processor_thermal_device.h"
 15
 16#define DRV_NAME "proc_thermal_pci"
 17
 18static bool use_msi;
 19module_param(use_msi, bool, 0644);
 20MODULE_PARM_DESC(use_msi,
 21	"Use PCI MSI based interrupts for processor thermal device.");
 22
 23struct proc_thermal_pci {
 24	struct pci_dev *pdev;
 25	struct proc_thermal_device *proc_priv;
 26	struct thermal_zone_device *tzone;
 27	struct delayed_work work;
 28	int stored_thres;
 29	int no_legacy;
 30};
 31
 32enum proc_thermal_mmio_type {
 33	PROC_THERMAL_MMIO_TJMAX,
 34	PROC_THERMAL_MMIO_PP0_TEMP,
 35	PROC_THERMAL_MMIO_PP1_TEMP,
 36	PROC_THERMAL_MMIO_PKG_TEMP,
 37	PROC_THERMAL_MMIO_THRES_0,
 38	PROC_THERMAL_MMIO_THRES_1,
 39	PROC_THERMAL_MMIO_INT_ENABLE_0,
 40	PROC_THERMAL_MMIO_INT_ENABLE_1,
 41	PROC_THERMAL_MMIO_INT_STATUS_0,
 42	PROC_THERMAL_MMIO_INT_STATUS_1,
 43	PROC_THERMAL_MMIO_MAX
 44};
 45
 46struct proc_thermal_mmio_info {
 47	enum proc_thermal_mmio_type mmio_type;
 48	u64	mmio_addr;
 49	u64	shift;
 50	u64	mask;
 51};
 52
 53static struct proc_thermal_mmio_info proc_thermal_mmio_info[] = {
 54	{ PROC_THERMAL_MMIO_TJMAX, 0x599c, 16, 0xff },
 55	{ PROC_THERMAL_MMIO_PP0_TEMP, 0x597c, 0, 0xff },
 56	{ PROC_THERMAL_MMIO_PP1_TEMP, 0x5980, 0, 0xff },
 57	{ PROC_THERMAL_MMIO_PKG_TEMP, 0x5978, 0, 0xff },
 58	{ PROC_THERMAL_MMIO_THRES_0, 0x5820, 8, 0x7F },
 59	{ PROC_THERMAL_MMIO_THRES_1, 0x5820, 16, 0x7F },
 60	{ PROC_THERMAL_MMIO_INT_ENABLE_0, 0x5820, 15, 0x01 },
 61	{ PROC_THERMAL_MMIO_INT_ENABLE_1, 0x5820, 23, 0x01 },
 62	{ PROC_THERMAL_MMIO_INT_STATUS_0, 0x7200, 6, 0x01 },
 63	{ PROC_THERMAL_MMIO_INT_STATUS_1, 0x7200, 8, 0x01 },
 64};
 65
 66/* List of supported MSI IDs (sources) */
 67enum proc_thermal_msi_ids {
 68	PKG_THERMAL,
 69	DDR_THERMAL,
 70	THERM_POWER_FLOOR,
 71	WORKLOAD_CHANGE,
 72	MSI_THERMAL_MAX
 73};
 74
 75/* Stores IRQ associated with a MSI ID */
 76static int proc_thermal_msi_map[MSI_THERMAL_MAX];
 77
 78#define B0D4_THERMAL_NOTIFY_DELAY	1000
 79static int notify_delay_ms = B0D4_THERMAL_NOTIFY_DELAY;
 80
 81static void proc_thermal_mmio_read(struct proc_thermal_pci *pci_info,
 82				    enum proc_thermal_mmio_type type,
 83				    u32 *value)
 84{
 85	*value = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base +
 86				proc_thermal_mmio_info[type].mmio_addr));
 87	*value >>= proc_thermal_mmio_info[type].shift;
 88	*value &= proc_thermal_mmio_info[type].mask;
 89}
 90
 91static void proc_thermal_mmio_write(struct proc_thermal_pci *pci_info,
 92				     enum proc_thermal_mmio_type type,
 93				     u32 value)
 94{
 95	u32 current_val;
 96	u32 mask;
 97
 98	current_val = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base +
 99				proc_thermal_mmio_info[type].mmio_addr));
100	mask = proc_thermal_mmio_info[type].mask << proc_thermal_mmio_info[type].shift;
101	current_val &= ~mask;
102
103	value &= proc_thermal_mmio_info[type].mask;
104	value <<= proc_thermal_mmio_info[type].shift;
105
106	current_val |= value;
107	iowrite32(current_val, ((u8 __iomem *)pci_info->proc_priv->mmio_base +
108				proc_thermal_mmio_info[type].mmio_addr));
109}
110
111/*
112 * To avoid sending two many messages to user space, we have 1 second delay.
113 * On interrupt we are disabling interrupt and enabling after 1 second.
114 * This workload function is delayed by 1 second.
115 */
116static void proc_thermal_threshold_work_fn(struct work_struct *work)
117{
118	struct delayed_work *delayed_work = to_delayed_work(work);
119	struct proc_thermal_pci *pci_info = container_of(delayed_work,
120						struct proc_thermal_pci, work);
121	struct thermal_zone_device *tzone = pci_info->tzone;
122
123	if (tzone)
124		thermal_zone_device_update(tzone, THERMAL_TRIP_VIOLATED);
125
126	/* Enable interrupt flag */
127	proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
128}
129
130static void pkg_thermal_schedule_work(struct delayed_work *work)
131{
132	unsigned long ms = msecs_to_jiffies(notify_delay_ms);
133
134	schedule_delayed_work(work, ms);
135}
136
137static void proc_thermal_clear_soc_int_status(struct proc_thermal_device *proc_priv)
138{
139	u64 status;
140
141	if (!(proc_priv->mmio_feature_mask &
142	    (PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR)))
143		return;
144
145	status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
146	writeq(status & ~SOC_WT_RES_INT_STATUS_MASK,
147	       proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
148}
149
150static irqreturn_t proc_thermal_irq_thread_handler(int irq, void *devid)
151{
152	struct proc_thermal_pci *pci_info = devid;
153
154	proc_thermal_wt_intr_callback(pci_info->pdev, pci_info->proc_priv);
155	proc_thermal_power_floor_intr_callback(pci_info->pdev, pci_info->proc_priv);
156	proc_thermal_clear_soc_int_status(pci_info->proc_priv);
157
158	return IRQ_HANDLED;
159}
160
161static int proc_thermal_match_msi_irq(int irq)
162{
163	int i;
164
165	if (!use_msi)
166		goto msi_fail;
167
168	for (i = 0; i < MSI_THERMAL_MAX; i++) {
169		if (proc_thermal_msi_map[i] == irq)
170			return i;
171	}
172
173msi_fail:
174	return -EOPNOTSUPP;
175}
176
177static irqreturn_t proc_thermal_irq_handler(int irq, void *devid)
178{
179	struct proc_thermal_pci *pci_info = devid;
180	struct proc_thermal_device *proc_priv;
181	int ret = IRQ_NONE, msi_id;
182	u32 status;
183
184	proc_priv = pci_info->proc_priv;
185
186	msi_id = proc_thermal_match_msi_irq(irq);
187
188	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_HINT) {
189		if (msi_id == WORKLOAD_CHANGE || proc_thermal_check_wt_intr(pci_info->proc_priv))
190			ret = IRQ_WAKE_THREAD;
191	}
192
193	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_POWER_FLOOR) {
194		if (msi_id == THERM_POWER_FLOOR ||
195		    proc_thermal_check_power_floor_intr(pci_info->proc_priv))
196			ret = IRQ_WAKE_THREAD;
197	}
198
199	/*
200	 * Since now there are two sources of interrupts: one from thermal threshold
201	 * and another from workload hint, add a check if there was really a threshold
202	 * interrupt before scheduling work function for thermal threshold.
203	 */
204	proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
205	if (msi_id == PKG_THERMAL || status) {
206		/* Disable enable interrupt flag */
207		proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
208		pkg_thermal_schedule_work(&pci_info->work);
209		ret = IRQ_HANDLED;
210	}
211
212	pci_write_config_byte(pci_info->pdev, 0xdc, 0x01);
213
214	return ret;
215}
216
217static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
218{
219	struct proc_thermal_pci *pci_info = thermal_zone_device_priv(tzd);
220	u32 _temp;
221
222	proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_PKG_TEMP, &_temp);
223	*temp = (unsigned long)_temp * 1000;
224
225	return 0;
226}
227
228static int sys_set_trip_temp(struct thermal_zone_device *tzd,
229			     const struct thermal_trip *trip, int temp)
230{
231	struct proc_thermal_pci *pci_info = thermal_zone_device_priv(tzd);
232	int tjmax, _temp;
233
234	if (temp <= 0) {
235		cancel_delayed_work_sync(&pci_info->work);
236		proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
237		proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0);
238		pci_info->stored_thres = 0;
239		return 0;
240	}
241
242	proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax);
243	_temp = tjmax - (temp / 1000);
244	if (_temp < 0)
245		return -EINVAL;
246
247	proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, _temp);
248	proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
249
250	pci_info->stored_thres = temp;
251
252	return 0;
253}
254
255static int get_trip_temp(struct proc_thermal_pci *pci_info)
256{
257	int temp, tjmax;
258
259	proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_THRES_0, &temp);
260	if (!temp)
261		return THERMAL_TEMP_INVALID;
262
263	proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax);
264	temp = (tjmax - temp) * 1000;
265
266	return temp;
267}
268
269static const struct thermal_zone_device_ops tzone_ops = {
270	.get_temp = sys_get_curr_temp,
271	.set_trip_temp	= sys_set_trip_temp,
272};
273
274static struct thermal_zone_params tzone_params = {
275	.no_hwmon = true,
276};
277
278static bool msi_irq;
279
280static void proc_thermal_free_msi(struct pci_dev *pdev, struct proc_thermal_pci *pci_info)
281{
282	int i;
283
284	for (i = 0; i < MSI_THERMAL_MAX; i++) {
285		if (proc_thermal_msi_map[i])
286			devm_free_irq(&pdev->dev, proc_thermal_msi_map[i], pci_info);
287	}
288
289	pci_free_irq_vectors(pdev);
290}
291
292static int proc_thermal_setup_msi(struct pci_dev *pdev, struct proc_thermal_pci *pci_info)
293{
294	int ret, i, irq, count;
295
296	count = pci_alloc_irq_vectors(pdev, 1, MSI_THERMAL_MAX, PCI_IRQ_MSI | PCI_IRQ_MSIX);
297	if (count < 0) {
298		dev_err(&pdev->dev, "Failed to allocate vectors!\n");
299		return count;
300	}
301
302	dev_info(&pdev->dev, "msi enabled:%d msix enabled:%d\n", pdev->msi_enabled,
303		 pdev->msix_enabled);
304
305	for (i = 0; i < count; i++) {
306		irq =  pci_irq_vector(pdev, i);
307
308		ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
309						proc_thermal_irq_thread_handler,
310						0, KBUILD_MODNAME, pci_info);
311		if (ret) {
312			dev_err(&pdev->dev, "Request IRQ %d failed\n", irq);
313			goto err_free_msi_vectors;
314		}
315
316		proc_thermal_msi_map[i] = irq;
317	}
318
319	msi_irq = true;
320
321	return 0;
322
323err_free_msi_vectors:
324	proc_thermal_free_msi(pdev, pci_info);
325
326	return ret;
327}
328
329static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
330{
331	struct proc_thermal_device *proc_priv;
332	struct proc_thermal_pci *pci_info;
333	struct thermal_trip psv_trip = {
334		.type = THERMAL_TRIP_PASSIVE,
335		.flags = THERMAL_TRIP_FLAG_RW_TEMP,
336	};
337	int irq_flag = 0, irq, ret;
338
339	proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
340	if (!proc_priv)
341		return -ENOMEM;
342
343	pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL);
344	if (!pci_info)
345		return -ENOMEM;
346
347	pci_info->pdev = pdev;
348	ret = pcim_enable_device(pdev);
349	if (ret < 0) {
350		dev_err(&pdev->dev, "error: could not enable device\n");
351		return ret;
352	}
353
354	pci_set_master(pdev);
355
356	INIT_DELAYED_WORK(&pci_info->work, proc_thermal_threshold_work_fn);
357
358	proc_priv->priv_data = pci_info;
359	pci_info->proc_priv = proc_priv;
360	pci_set_drvdata(pdev, proc_priv);
361
362	ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
363	if (ret)
364		return ret;
365
366	ret = proc_thermal_add(&pdev->dev, proc_priv);
367	if (ret) {
368		dev_err(&pdev->dev, "error: proc_thermal_add, will continue\n");
369		pci_info->no_legacy = 1;
370	}
371
372	psv_trip.temperature = get_trip_temp(pci_info);
373
374	pci_info->tzone = thermal_zone_device_register_with_trips("TCPU_PCI", &psv_trip,
375							1, pci_info,
376							&tzone_ops,
377							&tzone_params, 0, 0);
378	if (IS_ERR(pci_info->tzone)) {
379		ret = PTR_ERR(pci_info->tzone);
380		goto err_del_legacy;
381	}
382
383	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MSI_SUPPORT)
384		use_msi = true;
385
386	if (use_msi) {
387		ret = proc_thermal_setup_msi(pdev, pci_info);
388		if (ret)
389			goto err_ret_tzone;
390	} else {
391		irq_flag = IRQF_SHARED;
392		irq = pdev->irq;
393
394		ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
395						proc_thermal_irq_thread_handler, irq_flag,
396						KBUILD_MODNAME, pci_info);
397		if (ret) {
398			dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
399			goto err_ret_tzone;
400		}
401	}
402
403	ret = thermal_zone_device_enable(pci_info->tzone);
404	if (ret)
405		goto err_free_vectors;
406
407	return 0;
408
409err_free_vectors:
410	if (msi_irq)
411		proc_thermal_free_msi(pdev, pci_info);
412err_ret_tzone:
413	thermal_zone_device_unregister(pci_info->tzone);
414err_del_legacy:
415	if (!pci_info->no_legacy)
416		proc_thermal_remove(proc_priv);
417	proc_thermal_mmio_remove(pdev, proc_priv);
418
419	return ret;
420}
421
422static void proc_thermal_pci_remove(struct pci_dev *pdev)
423{
424	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
425	struct proc_thermal_pci *pci_info = proc_priv->priv_data;
426
427	cancel_delayed_work_sync(&pci_info->work);
428
429	proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0);
430	proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
431
432	if (msi_irq)
433		proc_thermal_free_msi(pdev, pci_info);
434
435	thermal_zone_device_unregister(pci_info->tzone);
436	proc_thermal_mmio_remove(pdev, pci_info->proc_priv);
437	if (!pci_info->no_legacy)
438		proc_thermal_remove(proc_priv);
439}
440
441#ifdef CONFIG_PM_SLEEP
442static int proc_thermal_pci_suspend(struct device *dev)
443{
444	struct pci_dev *pdev = to_pci_dev(dev);
445	struct proc_thermal_device *proc_priv;
446	struct proc_thermal_pci *pci_info;
447
448	proc_priv = pci_get_drvdata(pdev);
449	pci_info = proc_priv->priv_data;
450
451	if (!pci_info->no_legacy)
452		return proc_thermal_suspend(dev);
453
454	return 0;
455}
456static int proc_thermal_pci_resume(struct device *dev)
457{
458	struct pci_dev *pdev = to_pci_dev(dev);
459	struct proc_thermal_device *proc_priv;
460	struct proc_thermal_pci *pci_info;
461
462	proc_priv = pci_get_drvdata(pdev);
463	pci_info = proc_priv->priv_data;
464
465	if (pci_info->stored_thres) {
466		proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0,
467					 pci_info->stored_thres / 1000);
468		proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
469	}
470
471	if (!pci_info->no_legacy)
472		return proc_thermal_resume(dev);
473
474	return 0;
475}
476#else
477#define proc_thermal_pci_suspend NULL
478#define proc_thermal_pci_resume NULL
479#endif
480
481static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
482			 proc_thermal_pci_resume);
483
484static const struct pci_device_id proc_thermal_pci_ids[] = {
485	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
486	  PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_REQ) },
487	{ PCI_DEVICE_DATA(INTEL, LNLM_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT |
488	  PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS |
489	  PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR |
490	  PROC_THERMAL_FEATURE_PTC) },
491	{ PCI_DEVICE_DATA(INTEL, MTLP_THERMAL, PROC_THERMAL_FEATURE_RAPL |
492	  PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR |
493	  PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR) },
494	{ PCI_DEVICE_DATA(INTEL, ARL_S_THERMAL, PROC_THERMAL_FEATURE_RAPL |
495	  PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_WT_HINT) },
496	{ PCI_DEVICE_DATA(INTEL, RPL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
497	  PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_REQ) },
498	{ PCI_DEVICE_DATA(INTEL, PTL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
499	  PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS |
500	  PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT |
501	  PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC |
502	  PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) },
503	{ PCI_DEVICE_DATA(INTEL, WCL_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT |
504	  PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR |
505	  PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_HINT |
506	  PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC |
507	  PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) },
508	{ PCI_DEVICE_DATA(INTEL, NVL_H_THERMAL, PROC_THERMAL_FEATURE_RAPL |
509	  PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS |
510	  PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT |
511	  PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC |
512	  PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) },
513	{ PCI_DEVICE_DATA(INTEL, NVL_S_THERMAL, PROC_THERMAL_FEATURE_RAPL |
514	  PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS |
515	  PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT |
516	  PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC |
517	  PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) },
518	{ },
519};
520
521MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
522
523static struct pci_driver proc_thermal_pci_driver = {
524	.name		= DRV_NAME,
525	.probe		= proc_thermal_pci_probe,
526	.remove	= proc_thermal_pci_remove,
527	.id_table	= proc_thermal_pci_ids,
528	.driver.pm	= &proc_thermal_pci_pm,
529};
530
531module_pci_driver(proc_thermal_pci_driver);
532
533MODULE_IMPORT_NS("INT340X_THERMAL");
534
535MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
536MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
537MODULE_LICENSE("GPL v2");
~/ Read-only file preview.