1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Intel(R) Trace Hub pci driver
4 *
5 * Copyright (C) 2014-2015 Intel Corporation.
6 */
7
8#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
9
10#include <linux/types.h>
11#include <linux/module.h>
12#include <linux/device.h>
13#include <linux/sysfs.h>
14#include <linux/pci.h>
15
16#include "intel_th.h"
17
18#define DRIVER_NAME "intel_th_pci"
19
20enum {
21	TH_PCI_CONFIG_BAR	= 0,
22	TH_PCI_STH_SW_BAR	= 2,
23	TH_PCI_RTIT_BAR		= 4,
24};
25
26#define BAR_MASK (BIT(TH_PCI_CONFIG_BAR) | BIT(TH_PCI_STH_SW_BAR))
27
28#define PCI_REG_NPKDSC	0x80
29#define NPKDSC_TSACT	BIT(5)
30
31static int intel_th_pci_activate(struct intel_th *th)
32{
33	struct pci_dev *pdev = to_pci_dev(th->dev);
34	u32 npkdsc;
35	int err;
36
37	if (!INTEL_TH_CAP(th, tscu_enable))
38		return 0;
39
40	err = pci_read_config_dword(pdev, PCI_REG_NPKDSC, &npkdsc);
41	if (!err) {
42		npkdsc |= NPKDSC_TSACT;
43		err = pci_write_config_dword(pdev, PCI_REG_NPKDSC, npkdsc);
44	}
45
46	if (err)
47		dev_err(&pdev->dev, "failed to read NPKDSC register\n");
48
49	return err;
50}
51
52static void intel_th_pci_deactivate(struct intel_th *th)
53{
54	struct pci_dev *pdev = to_pci_dev(th->dev);
55	u32 npkdsc;
56	int err;
57
58	if (!INTEL_TH_CAP(th, tscu_enable))
59		return;
60
61	err = pci_read_config_dword(pdev, PCI_REG_NPKDSC, &npkdsc);
62	if (!err) {
63		npkdsc |= NPKDSC_TSACT;
64		err = pci_write_config_dword(pdev, PCI_REG_NPKDSC, npkdsc);
65	}
66
67	if (err)
68		dev_err(&pdev->dev, "failed to read NPKDSC register\n");
69}
70
71static int intel_th_pci_probe(struct pci_dev *pdev,
72			      const struct pci_device_id *id)
73{
74	const struct intel_th_drvdata *drvdata = (void *)id->driver_data;
75	struct resource resource[TH_MMIO_END + TH_NVEC_MAX] = {
76		[TH_MMIO_CONFIG]	= pdev->resource[TH_PCI_CONFIG_BAR],
77		[TH_MMIO_SW]		= pdev->resource[TH_PCI_STH_SW_BAR],
78	};
79	int err, r = TH_MMIO_SW + 1, i;
80	struct intel_th *th;
81
82	err = pcim_enable_device(pdev);
83	if (err)
84		return err;
85
86	err = pcim_iomap_regions_request_all(pdev, BAR_MASK, DRIVER_NAME);
87	if (err)
88		return err;
89
90	if (pdev->resource[TH_PCI_RTIT_BAR].start) {
91		resource[TH_MMIO_RTIT] = pdev->resource[TH_PCI_RTIT_BAR];
92		r++;
93	}
94
95	err = pci_alloc_irq_vectors(pdev, 1, 8, PCI_IRQ_ALL_TYPES);
96	if (err > 0)
97		for (i = 0; i < err; i++, r++) {
98			resource[r].flags = IORESOURCE_IRQ;
99			resource[r].start = pci_irq_vector(pdev, i);
100		}
101
102	th = intel_th_alloc(&pdev->dev, drvdata, resource, r);
103	if (IS_ERR(th)) {
104		err = PTR_ERR(th);
105		goto err_free_irq;
106	}
107
108	th->activate   = intel_th_pci_activate;
109	th->deactivate = intel_th_pci_deactivate;
110
111	pci_set_master(pdev);
112
113	return 0;
114
115err_free_irq:
116	pci_free_irq_vectors(pdev);
117	return err;
118}
119
120static void intel_th_pci_remove(struct pci_dev *pdev)
121{
122	struct intel_th *th = pci_get_drvdata(pdev);
123
124	intel_th_free(th);
125
126	pci_free_irq_vectors(pdev);
127}
128
129static const struct intel_th_drvdata intel_th_1x_multi_is_broken = {
130	.multi_is_broken	= 1,
131};
132
133static const struct intel_th_drvdata intel_th_2x = {
134	.tscu_enable	= 1,
135	.has_mintctl	= 1,
136};
137
138static const struct pci_device_id intel_th_pci_id_table[] = {
139	{
140		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9d26),
141		.driver_data = (kernel_ulong_t)0,
142	},
143	{
144		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa126),
145		.driver_data = (kernel_ulong_t)0,
146	},
147	{
148		/* Apollo Lake */
149		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a8e),
150		.driver_data = (kernel_ulong_t)0,
151	},
152	{
153		/* Broxton */
154		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0a80),
155		.driver_data = (kernel_ulong_t)0,
156	},
157	{
158		/* Broxton B-step */
159		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1a8e),
160		.driver_data = (kernel_ulong_t)0,
161	},
162	{
163		/* Kaby Lake PCH-H */
164		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa2a6),
165		.driver_data = (kernel_ulong_t)&intel_th_1x_multi_is_broken,
166	},
167	{
168		/* Denverton */
169		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x19e1),
170		.driver_data = (kernel_ulong_t)0,
171	},
172	{
173		/* Lewisburg PCH */
174		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa1a6),
175		.driver_data = (kernel_ulong_t)0,
176	},
177	{
178		/* Lewisburg PCH */
179		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa226),
180		.driver_data = (kernel_ulong_t)0,
181	},
182	{
183		/* Gemini Lake */
184		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x318e),
185		.driver_data = (kernel_ulong_t)&intel_th_2x,
186	},
187	{
188		/* Cannon Lake H */
189		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa326),
190		.driver_data = (kernel_ulong_t)&intel_th_2x,
191	},
192	{
193		/* Cannon Lake LP */
194		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9da6),
195		.driver_data = (kernel_ulong_t)&intel_th_2x,
196	},
197	{
198		/* Cedar Fork PCH */
199		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x18e1),
200		.driver_data = (kernel_ulong_t)&intel_th_2x,
201	},
202	{
203		/* Ice Lake PCH */
204		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x34a6),
205		.driver_data = (kernel_ulong_t)&intel_th_2x,
206	},
207	{
208		/* Comet Lake */
209		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x02a6),
210		.driver_data = (kernel_ulong_t)&intel_th_2x,
211	},
212	{
213		/* Comet Lake PCH */
214		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x06a6),
215		.driver_data = (kernel_ulong_t)&intel_th_2x,
216	},
217	{
218		/* Comet Lake PCH-V */
219		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa3a6),
220		.driver_data = (kernel_ulong_t)&intel_th_1x_multi_is_broken,
221	},
222	{
223		/* Ice Lake NNPI */
224		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x45c5),
225		.driver_data = (kernel_ulong_t)&intel_th_2x,
226	},
227	{
228		/* Ice Lake CPU */
229		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8a29),
230		.driver_data = (kernel_ulong_t)&intel_th_2x,
231	},
232	{
233		/* Tiger Lake CPU */
234		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9a33),
235		.driver_data = (kernel_ulong_t)&intel_th_2x,
236	},
237	{
238		/* Tiger Lake PCH */
239		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa0a6),
240		.driver_data = (kernel_ulong_t)&intel_th_2x,
241	},
242	{
243		/* Tiger Lake PCH-H */
244		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x43a6),
245		.driver_data = (kernel_ulong_t)&intel_th_2x,
246	},
247	{
248		/* Jasper Lake PCH */
249		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4da6),
250		.driver_data = (kernel_ulong_t)&intel_th_2x,
251	},
252	{
253		/* Jasper Lake CPU */
254		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4e29),
255		.driver_data = (kernel_ulong_t)&intel_th_2x,
256	},
257	{
258		/* Elkhart Lake CPU */
259		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4529),
260		.driver_data = (kernel_ulong_t)&intel_th_2x,
261	},
262	{
263		/* Elkhart Lake */
264		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4b26),
265		.driver_data = (kernel_ulong_t)&intel_th_2x,
266	},
267	{
268		/* Emmitsburg PCH */
269		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1bcc),
270		.driver_data = (kernel_ulong_t)&intel_th_2x,
271	},
272	{
273		/* Alder Lake */
274		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7aa6),
275		.driver_data = (kernel_ulong_t)&intel_th_2x,
276	},
277	{
278		/* Alder Lake-P */
279		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x51a6),
280		.driver_data = (kernel_ulong_t)&intel_th_2x,
281	},
282	{
283		/* Alder Lake-M */
284		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x54a6),
285		.driver_data = (kernel_ulong_t)&intel_th_2x,
286	},
287	{
288		/* Meteor Lake-P */
289		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7e24),
290		.driver_data = (kernel_ulong_t)&intel_th_2x,
291	},
292	{
293		/* Raptor Lake-S */
294		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7a26),
295		.driver_data = (kernel_ulong_t)&intel_th_2x,
296	},
297	{
298		/* Raptor Lake-S CPU */
299		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa76f),
300		.driver_data = (kernel_ulong_t)&intel_th_2x,
301	},
302	{
303		/* Alder Lake CPU */
304		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x466f),
305		.driver_data = (kernel_ulong_t)&intel_th_2x,
306	},
307	{
308		/* Rocket Lake CPU */
309		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c19),
310		.driver_data = (kernel_ulong_t)&intel_th_2x,
311	},
312	{ 0 },
313};
314
315MODULE_DEVICE_TABLE(pci, intel_th_pci_id_table);
316
317static struct pci_driver intel_th_pci_driver = {
318	.name		= DRIVER_NAME,
319	.id_table	= intel_th_pci_id_table,
320	.probe		= intel_th_pci_probe,
321	.remove		= intel_th_pci_remove,
322};
323
324module_pci_driver(intel_th_pci_driver);
325
326MODULE_LICENSE("GPL v2");
327MODULE_DESCRIPTION("Intel(R) Trace Hub PCI controller driver");
328MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@intel.com>");
329