• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 static bool use_msi;
19 module_param(use_msi, bool, 0644);
20 MODULE_PARM_DESC(use_msi,
21 	"Use PCI MSI based interrupts for processor thermal device.");
22 
23 struct 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 
32 enum 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 
46 struct proc_thermal_mmio_info {
47 	enum proc_thermal_mmio_type mmio_type;
48 	u64	mmio_addr;
49 	u64	shift;
50 	u64	mask;
51 };
52 
53 static 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) */
67 enum 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 */
76 static int proc_thermal_msi_map[MSI_THERMAL_MAX];
77 
78 #define B0D4_THERMAL_NOTIFY_DELAY	1000
79 static int notify_delay_ms = B0D4_THERMAL_NOTIFY_DELAY;
80 
proc_thermal_mmio_read(struct proc_thermal_pci * pci_info,enum proc_thermal_mmio_type type,u32 * value)81 static 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 
proc_thermal_mmio_write(struct proc_thermal_pci * pci_info,enum proc_thermal_mmio_type type,u32 value)91 static 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  */
proc_thermal_threshold_work_fn(struct work_struct * work)116 static 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 
pkg_thermal_schedule_work(struct delayed_work * work)130 static 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 
proc_thermal_clear_soc_int_status(struct proc_thermal_device * proc_priv)137 static 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 
proc_thermal_irq_thread_handler(int irq,void * devid)150 static 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 
proc_thermal_match_msi_irq(int irq)161 static 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 
173 msi_fail:
174 	return -EOPNOTSUPP;
175 }
176 
proc_thermal_irq_handler(int irq,void * devid)177 static 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 
sys_get_curr_temp(struct thermal_zone_device * tzd,int * temp)217 static 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 
sys_set_trip_temp(struct thermal_zone_device * tzd,const struct thermal_trip * trip,int temp)228 static 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 
get_trip_temp(struct proc_thermal_pci * pci_info)255 static 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 
269 static 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 
274 static struct thermal_zone_params tzone_params = {
275 	.governor_name = "user_space",
276 	.no_hwmon = true,
277 };
278 
279 static bool msi_irq;
280 
proc_thermal_free_msi(struct pci_dev * pdev,struct proc_thermal_pci * pci_info)281 static void proc_thermal_free_msi(struct pci_dev *pdev, struct proc_thermal_pci *pci_info)
282 {
283 	int i;
284 
285 	for (i = 0; i < MSI_THERMAL_MAX; i++) {
286 		if (proc_thermal_msi_map[i])
287 			devm_free_irq(&pdev->dev, proc_thermal_msi_map[i], pci_info);
288 	}
289 
290 	pci_free_irq_vectors(pdev);
291 }
292 
proc_thermal_setup_msi(struct pci_dev * pdev,struct proc_thermal_pci * pci_info)293 static int proc_thermal_setup_msi(struct pci_dev *pdev, struct proc_thermal_pci *pci_info)
294 {
295 	int ret, i, irq, count;
296 
297 	count = pci_alloc_irq_vectors(pdev, 1, MSI_THERMAL_MAX, PCI_IRQ_MSI | PCI_IRQ_MSIX);
298 	if (count < 0) {
299 		dev_err(&pdev->dev, "Failed to allocate vectors!\n");
300 		return count;
301 	}
302 
303 	dev_info(&pdev->dev, "msi enabled:%d msix enabled:%d\n", pdev->msi_enabled,
304 		 pdev->msix_enabled);
305 
306 	for (i = 0; i < count; i++) {
307 		irq =  pci_irq_vector(pdev, i);
308 
309 		ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
310 						proc_thermal_irq_thread_handler,
311 						0, KBUILD_MODNAME, pci_info);
312 		if (ret) {
313 			dev_err(&pdev->dev, "Request IRQ %d failed\n", irq);
314 			goto err_free_msi_vectors;
315 		}
316 
317 		proc_thermal_msi_map[i] = irq;
318 	}
319 
320 	msi_irq = true;
321 
322 	return 0;
323 
324 err_free_msi_vectors:
325 	proc_thermal_free_msi(pdev, pci_info);
326 
327 	return ret;
328 }
329 
proc_thermal_pci_probe(struct pci_dev * pdev,const struct pci_device_id * id)330 static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
331 {
332 	struct proc_thermal_device *proc_priv;
333 	struct proc_thermal_pci *pci_info;
334 	struct thermal_trip psv_trip = {
335 		.type = THERMAL_TRIP_PASSIVE,
336 		.flags = THERMAL_TRIP_FLAG_RW_TEMP,
337 	};
338 	int irq_flag = 0, irq, ret;
339 
340 	proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
341 	if (!proc_priv)
342 		return -ENOMEM;
343 
344 	pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL);
345 	if (!pci_info)
346 		return -ENOMEM;
347 
348 	pci_info->pdev = pdev;
349 	ret = pcim_enable_device(pdev);
350 	if (ret < 0) {
351 		dev_err(&pdev->dev, "error: could not enable device\n");
352 		return ret;
353 	}
354 
355 	pci_set_master(pdev);
356 
357 	INIT_DELAYED_WORK(&pci_info->work, proc_thermal_threshold_work_fn);
358 
359 	proc_priv->priv_data = pci_info;
360 	pci_info->proc_priv = proc_priv;
361 	pci_set_drvdata(pdev, proc_priv);
362 
363 	ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
364 	if (ret)
365 		return ret;
366 
367 	ret = proc_thermal_add(&pdev->dev, proc_priv);
368 	if (ret) {
369 		dev_err(&pdev->dev, "error: proc_thermal_add, will continue\n");
370 		pci_info->no_legacy = 1;
371 	}
372 
373 	psv_trip.temperature = get_trip_temp(pci_info);
374 
375 	pci_info->tzone = thermal_zone_device_register_with_trips("TCPU_PCI", &psv_trip,
376 							1, pci_info,
377 							&tzone_ops,
378 							&tzone_params, 0, 0);
379 	if (IS_ERR(pci_info->tzone)) {
380 		ret = PTR_ERR(pci_info->tzone);
381 		goto err_del_legacy;
382 	}
383 
384 	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MSI_SUPPORT)
385 		use_msi = true;
386 
387 	if (use_msi) {
388 		ret = proc_thermal_setup_msi(pdev, pci_info);
389 		if (ret)
390 			goto err_ret_tzone;
391 	} else {
392 		irq_flag = IRQF_SHARED;
393 		irq = pdev->irq;
394 
395 		ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
396 						proc_thermal_irq_thread_handler, irq_flag,
397 						KBUILD_MODNAME, pci_info);
398 		if (ret) {
399 			dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
400 			goto err_ret_tzone;
401 		}
402 	}
403 
404 	ret = thermal_zone_device_enable(pci_info->tzone);
405 	if (ret)
406 		goto err_free_vectors;
407 
408 	return 0;
409 
410 err_free_vectors:
411 	if (msi_irq)
412 		proc_thermal_free_msi(pdev, pci_info);
413 err_ret_tzone:
414 	thermal_zone_device_unregister(pci_info->tzone);
415 err_del_legacy:
416 	if (!pci_info->no_legacy)
417 		proc_thermal_remove(proc_priv);
418 	proc_thermal_mmio_remove(pdev, proc_priv);
419 
420 	return ret;
421 }
422 
proc_thermal_pci_remove(struct pci_dev * pdev)423 static void proc_thermal_pci_remove(struct pci_dev *pdev)
424 {
425 	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
426 	struct proc_thermal_pci *pci_info = proc_priv->priv_data;
427 
428 	cancel_delayed_work_sync(&pci_info->work);
429 
430 	proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0);
431 	proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
432 
433 	if (msi_irq)
434 		proc_thermal_free_msi(pdev, pci_info);
435 
436 	thermal_zone_device_unregister(pci_info->tzone);
437 	proc_thermal_mmio_remove(pdev, pci_info->proc_priv);
438 	if (!pci_info->no_legacy)
439 		proc_thermal_remove(proc_priv);
440 }
441 
442 #ifdef CONFIG_PM_SLEEP
proc_thermal_pci_suspend(struct device * dev)443 static int proc_thermal_pci_suspend(struct device *dev)
444 {
445 	struct pci_dev *pdev = to_pci_dev(dev);
446 	struct proc_thermal_device *proc_priv;
447 	struct proc_thermal_pci *pci_info;
448 
449 	proc_priv = pci_get_drvdata(pdev);
450 	pci_info = proc_priv->priv_data;
451 
452 	if (!pci_info->no_legacy)
453 		return proc_thermal_suspend(dev);
454 
455 	return 0;
456 }
proc_thermal_pci_resume(struct device * dev)457 static int proc_thermal_pci_resume(struct device *dev)
458 {
459 	struct pci_dev *pdev = to_pci_dev(dev);
460 	struct proc_thermal_device *proc_priv;
461 	struct proc_thermal_pci *pci_info;
462 
463 	proc_priv = pci_get_drvdata(pdev);
464 	pci_info = proc_priv->priv_data;
465 
466 	if (pci_info->stored_thres) {
467 		proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0,
468 					 pci_info->stored_thres / 1000);
469 		proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
470 	}
471 
472 	if (!pci_info->no_legacy)
473 		return proc_thermal_resume(dev);
474 
475 	return 0;
476 }
477 #else
478 #define proc_thermal_pci_suspend NULL
479 #define proc_thermal_pci_resume NULL
480 #endif
481 
482 static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
483 			 proc_thermal_pci_resume);
484 
485 static const struct pci_device_id proc_thermal_pci_ids[] = {
486 	{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
487 	  PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_REQ) },
488 	{ PCI_DEVICE_DATA(INTEL, LNLM_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT |
489 	  PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR |
490 	  PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR) },
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 	{ },
499 };
500 
501 MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
502 
503 static struct pci_driver proc_thermal_pci_driver = {
504 	.name		= DRV_NAME,
505 	.probe		= proc_thermal_pci_probe,
506 	.remove	= proc_thermal_pci_remove,
507 	.id_table	= proc_thermal_pci_ids,
508 	.driver.pm	= &proc_thermal_pci_pm,
509 };
510 
511 module_pci_driver(proc_thermal_pci_driver);
512 
513 MODULE_IMPORT_NS(INT340X_THERMAL);
514 
515 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
516 MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
517 MODULE_LICENSE("GPL v2");
518