1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * B0D4 processor thermal device
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 #include "../intel_soc_dts_iosf.h"
16 
17 #define DRV_NAME "proc_thermal"
18 
19 static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid)
20 {
21 	struct proc_thermal_device *proc_priv;
22 	struct pci_dev *pdev = devid;
23 
24 	proc_priv = pci_get_drvdata(pdev);
25 
26 	intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts);
27 
28 	return IRQ_HANDLED;
29 }
30 
31 static int proc_thermal_pci_probe(struct pci_dev *pdev,
32 				  const struct pci_device_id *id)
33 {
34 	struct proc_thermal_device *proc_priv;
35 	int ret;
36 
37 	ret = pcim_enable_device(pdev);
38 	if (ret < 0) {
39 		dev_err(&pdev->dev, "error: could not enable device\n");
40 		return ret;
41 	}
42 
43 	proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
44 	if (!proc_priv)
45 		return -ENOMEM;
46 
47 	ret = proc_thermal_add(&pdev->dev, proc_priv);
48 	if (ret)
49 		return ret;
50 
51 	pci_set_drvdata(pdev, proc_priv);
52 
53 	if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) {
54 		/*
55 		 * Enumerate additional DTS sensors available via IOSF.
56 		 * But we are not treating as a failure condition, if
57 		 * there are no aux DTSs enabled or fails. This driver
58 		 * already exposes sensors, which can be accessed via
59 		 * ACPI/MSR. So we don't want to fail for auxiliary DTSs.
60 		 */
61 		proc_priv->soc_dts = intel_soc_dts_iosf_init(
62 					INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0);
63 
64 		if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) {
65 			ret = pci_enable_msi(pdev);
66 			if (!ret) {
67 				ret = request_threaded_irq(pdev->irq, NULL,
68 						proc_thermal_pci_msi_irq,
69 						IRQF_ONESHOT, "proc_thermal",
70 						pdev);
71 				if (ret) {
72 					intel_soc_dts_iosf_exit(
73 							proc_priv->soc_dts);
74 					pci_disable_msi(pdev);
75 					proc_priv->soc_dts = NULL;
76 				}
77 			}
78 		} else
79 			dev_err(&pdev->dev, "No auxiliary DTSs enabled\n");
80 	} else {
81 
82 	}
83 
84 	ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
85 	if (ret) {
86 		proc_thermal_remove(proc_priv);
87 		return ret;
88 	}
89 
90 	return 0;
91 }
92 
93 static void proc_thermal_pci_remove(struct pci_dev *pdev)
94 {
95 	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
96 
97 	if (proc_priv->soc_dts) {
98 		intel_soc_dts_iosf_exit(proc_priv->soc_dts);
99 		if (pdev->irq) {
100 			free_irq(pdev->irq, pdev);
101 			pci_disable_msi(pdev);
102 		}
103 	}
104 
105 	proc_thermal_mmio_remove(pdev, proc_priv);
106 	proc_thermal_remove(proc_priv);
107 }
108 
109 #ifdef CONFIG_PM_SLEEP
110 static int proc_thermal_pci_suspend(struct device *dev)
111 {
112 	return proc_thermal_suspend(dev);
113 }
114 static int proc_thermal_pci_resume(struct device *dev)
115 {
116 	return proc_thermal_resume(dev);
117 }
118 #else
119 #define proc_thermal_pci_suspend NULL
120 #define proc_thermal_pci_resume NULL
121 #endif
122 
123 static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
124 			 proc_thermal_pci_resume);
125 
126 static const struct pci_device_id proc_thermal_pci_ids[] = {
127 	{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
128 	{ PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
129 	{ PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
130 	{ PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) },
131 	{ PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) },
132 	{ PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) },
133 	{ PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) },
134 	{ PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) },
135 	{ PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) },
136 	{ PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) },
137 	{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
138 	{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
139 	{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
140 	{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) },
141 	{ },
142 };
143 
144 MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
145 
146 static struct pci_driver proc_thermal_pci_driver = {
147 	.name		= DRV_NAME,
148 	.probe		= proc_thermal_pci_probe,
149 	.remove		= proc_thermal_pci_remove,
150 	.id_table	= proc_thermal_pci_ids,
151 	.driver.pm	= &proc_thermal_pci_pm,
152 };
153 
154 module_pci_driver(proc_thermal_pci_driver);
155 
156 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
157 MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
158 MODULE_LICENSE("GPL v2");
159