xref: /linux/drivers/hid/intel-ish-hid/ipc/pci-ish.c (revision e6a901a00822659181c93c86d8bbc2a17779fddc)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * PCI glue for ISHTP provider device (ISH) driver
4  *
5  * Copyright (c) 2014-2016, Intel Corporation.
6  */
7 
8 #include <linux/acpi.h>
9 #include <linux/module.h>
10 #include <linux/moduleparam.h>
11 #include <linux/kernel.h>
12 #include <linux/device.h>
13 #include <linux/fs.h>
14 #include <linux/errno.h>
15 #include <linux/types.h>
16 #include <linux/pci.h>
17 #include <linux/sched.h>
18 #include <linux/suspend.h>
19 #include <linux/interrupt.h>
20 #include <linux/workqueue.h>
21 #define CREATE_TRACE_POINTS
22 #include <trace/events/intel_ish.h>
23 #include "ishtp-dev.h"
24 #include "hw-ish.h"
25 
26 static const struct pci_device_id ish_pci_tbl[] = {
27 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CHV_DEVICE_ID)},
28 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, BXT_Ax_DEVICE_ID)},
29 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, BXT_Bx_DEVICE_ID)},
30 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, APL_Ax_DEVICE_ID)},
31 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_Ax_DEVICE_ID)},
32 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_Ax_DEVICE_ID)},
33 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, GLK_Ax_DEVICE_ID)},
34 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_H_DEVICE_ID)},
35 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ICL_MOBILE_DEVICE_ID)},
36 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_H_DEVICE_ID)},
37 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CML_LP_DEVICE_ID)},
38 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CMP_H_DEVICE_ID)},
39 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, EHL_Ax_DEVICE_ID)},
40 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, TGL_LP_DEVICE_ID)},
41 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, TGL_H_DEVICE_ID)},
42 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_S_DEVICE_ID)},
43 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_P_DEVICE_ID)},
44 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_N_DEVICE_ID)},
45 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, RPL_S_DEVICE_ID)},
46 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MTL_P_DEVICE_ID)},
47 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ARL_H_DEVICE_ID)},
48 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ARL_S_DEVICE_ID)},
49 	{0, }
50 };
51 MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
52 
53 /**
54  * ish_event_tracer() - Callback function to dump trace messages
55  * @dev:	ishtp device
56  * @format:	printf style format
57  *
58  * Callback to direct log messages to Linux trace buffers
59  */
60 static __printf(2, 3)
61 void ish_event_tracer(struct ishtp_device *dev, const char *format, ...)
62 {
63 	if (trace_ishtp_dump_enabled()) {
64 		va_list args;
65 		char tmp_buf[100];
66 
67 		va_start(args, format);
68 		vsnprintf(tmp_buf, sizeof(tmp_buf), format, args);
69 		va_end(args);
70 
71 		trace_ishtp_dump(tmp_buf);
72 	}
73 }
74 
75 /**
76  * ish_init() - Init function
77  * @dev:	ishtp device
78  *
79  * This function initialize wait queues for suspend/resume and call
80  * calls hadware initialization function. This will initiate
81  * startup sequence
82  *
83  * Return: 0 for success or error code for failure
84  */
85 static int ish_init(struct ishtp_device *dev)
86 {
87 	int ret;
88 
89 	/* Set the state of ISH HW to start */
90 	ret = ish_hw_start(dev);
91 	if (ret) {
92 		dev_err(dev->devc, "ISH: hw start failed.\n");
93 		return ret;
94 	}
95 
96 	/* Start the inter process communication to ISH processor */
97 	ret = ishtp_start(dev);
98 	if (ret) {
99 		dev_err(dev->devc, "ISHTP: Protocol init failed.\n");
100 		return ret;
101 	}
102 
103 	return 0;
104 }
105 
106 static const struct pci_device_id ish_invalid_pci_ids[] = {
107 	/* Mehlow platform special pci ids */
108 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xA309)},
109 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xA30A)},
110 	{}
111 };
112 
113 static inline bool ish_should_enter_d0i3(struct pci_dev *pdev)
114 {
115 	return !pm_suspend_via_firmware() || pdev->device == CHV_DEVICE_ID;
116 }
117 
118 static inline bool ish_should_leave_d0i3(struct pci_dev *pdev)
119 {
120 	return !pm_resume_via_firmware() || pdev->device == CHV_DEVICE_ID;
121 }
122 
123 /**
124  * ish_probe() - PCI driver probe callback
125  * @pdev:	pci device
126  * @ent:	pci device id
127  *
128  * Initialize PCI function, setup interrupt and call for ISH initialization
129  *
130  * Return: 0 for success or error code for failure
131  */
132 static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
133 {
134 	int ret;
135 	struct ish_hw *hw;
136 	unsigned long irq_flag = 0;
137 	struct ishtp_device *ishtp;
138 	struct device *dev = &pdev->dev;
139 
140 	/* Check for invalid platforms for ISH support */
141 	if (pci_dev_present(ish_invalid_pci_ids))
142 		return -ENODEV;
143 
144 	/* enable pci dev */
145 	ret = pcim_enable_device(pdev);
146 	if (ret) {
147 		dev_err(dev, "ISH: Failed to enable PCI device\n");
148 		return ret;
149 	}
150 
151 	/* set PCI host mastering */
152 	pci_set_master(pdev);
153 
154 	/* pci request regions for ISH driver */
155 	ret = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
156 	if (ret) {
157 		dev_err(dev, "ISH: Failed to get PCI regions\n");
158 		return ret;
159 	}
160 
161 	/* allocates and initializes the ISH dev structure */
162 	ishtp = ish_dev_init(pdev);
163 	if (!ishtp) {
164 		ret = -ENOMEM;
165 		return ret;
166 	}
167 	hw = to_ish_hw(ishtp);
168 	ishtp->print_log = ish_event_tracer;
169 
170 	/* mapping IO device memory */
171 	hw->mem_addr = pcim_iomap_table(pdev)[0];
172 	ishtp->pdev = pdev;
173 
174 	/* request and enable interrupt */
175 	ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
176 	if (!pdev->msi_enabled && !pdev->msix_enabled)
177 		irq_flag = IRQF_SHARED;
178 
179 	ret = devm_request_irq(dev, pdev->irq, ish_irq_handler,
180 			       irq_flag, KBUILD_MODNAME, ishtp);
181 	if (ret) {
182 		dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq);
183 		return ret;
184 	}
185 
186 	dev_set_drvdata(ishtp->devc, ishtp);
187 
188 	init_waitqueue_head(&ishtp->suspend_wait);
189 	init_waitqueue_head(&ishtp->resume_wait);
190 
191 	/* Enable PME for EHL */
192 	if (pdev->device == EHL_Ax_DEVICE_ID)
193 		device_init_wakeup(dev, true);
194 
195 	ret = ish_init(ishtp);
196 	if (ret)
197 		return ret;
198 
199 	return 0;
200 }
201 
202 /**
203  * ish_remove() - PCI driver remove callback
204  * @pdev:	pci device
205  *
206  * This function does cleanup of ISH on pci remove callback
207  */
208 static void ish_remove(struct pci_dev *pdev)
209 {
210 	struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
211 
212 	ishtp_bus_remove_all_clients(ishtp_dev, false);
213 	ish_device_disable(ishtp_dev);
214 }
215 
216 
217 /**
218  * ish_shutdown() - PCI driver shutdown callback
219  * @pdev:	pci device
220  *
221  * This function sets up wakeup for S5
222  */
223 static void ish_shutdown(struct pci_dev *pdev)
224 {
225 	if (pdev->device == EHL_Ax_DEVICE_ID)
226 		pci_prepare_to_sleep(pdev);
227 }
228 
229 static struct device __maybe_unused *ish_resume_device;
230 
231 /* 50ms to get resume response */
232 #define WAIT_FOR_RESUME_ACK_MS		50
233 
234 /**
235  * ish_resume_handler() - Work function to complete resume
236  * @work:	work struct
237  *
238  * The resume work function to complete resume function asynchronously.
239  * There are two resume paths, one where ISH is not powered off,
240  * in that case a simple resume message is enough, others we need
241  * a reset sequence.
242  */
243 static void __maybe_unused ish_resume_handler(struct work_struct *work)
244 {
245 	struct pci_dev *pdev = to_pci_dev(ish_resume_device);
246 	struct ishtp_device *dev = pci_get_drvdata(pdev);
247 	uint32_t fwsts = dev->ops->get_fw_status(dev);
248 
249 	if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag
250 			&& IPC_IS_ISH_ILUP(fwsts)) {
251 		if (device_may_wakeup(&pdev->dev))
252 			disable_irq_wake(pdev->irq);
253 
254 		ish_set_host_ready(dev);
255 
256 		ishtp_send_resume(dev);
257 
258 		/* Waiting to get resume response */
259 		if (dev->resume_flag)
260 			wait_event_interruptible_timeout(dev->resume_wait,
261 				!dev->resume_flag,
262 				msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
263 
264 		/*
265 		 * If the flag is not cleared, something is wrong with ISH FW.
266 		 * So on resume, need to go through init sequence again.
267 		 */
268 		if (dev->resume_flag)
269 			ish_init(dev);
270 	} else {
271 		/*
272 		 * Resume from the D3, full reboot of ISH processor will happen,
273 		 * so need to go through init sequence again.
274 		 */
275 		ish_init(dev);
276 	}
277 }
278 
279 /**
280  * ish_suspend() - ISH suspend callback
281  * @device:	device pointer
282  *
283  * ISH suspend callback
284  *
285  * Return: 0 to the pm core
286  */
287 static int __maybe_unused ish_suspend(struct device *device)
288 {
289 	struct pci_dev *pdev = to_pci_dev(device);
290 	struct ishtp_device *dev = pci_get_drvdata(pdev);
291 
292 	if (ish_should_enter_d0i3(pdev)) {
293 		/*
294 		 * If previous suspend hasn't been asnwered then ISH is likely
295 		 * dead, don't attempt nested notification
296 		 */
297 		if (dev->suspend_flag)
298 			return	0;
299 
300 		dev->resume_flag = 0;
301 		dev->suspend_flag = 1;
302 		ishtp_send_suspend(dev);
303 
304 		/* 25 ms should be enough for live ISH to flush all IPC buf */
305 		if (dev->suspend_flag)
306 			wait_event_interruptible_timeout(dev->suspend_wait,
307 					!dev->suspend_flag,
308 					msecs_to_jiffies(25));
309 
310 		if (dev->suspend_flag) {
311 			/*
312 			 * It looks like FW halt, clear the DMA bit, and put
313 			 * ISH into D3, and FW would reset on resume.
314 			 */
315 			ish_disable_dma(dev);
316 		} else {
317 			/*
318 			 * Save state so PCI core will keep the device at D0,
319 			 * the ISH would enter D0i3
320 			 */
321 			pci_save_state(pdev);
322 
323 			if (device_may_wakeup(&pdev->dev))
324 				enable_irq_wake(pdev->irq);
325 		}
326 	} else {
327 		/*
328 		 * Clear the DMA bit before putting ISH into D3,
329 		 * or ISH FW would reset automatically.
330 		 */
331 		ish_disable_dma(dev);
332 	}
333 
334 	return 0;
335 }
336 
337 static __maybe_unused DECLARE_WORK(resume_work, ish_resume_handler);
338 /**
339  * ish_resume() - ISH resume callback
340  * @device:	device pointer
341  *
342  * ISH resume callback
343  *
344  * Return: 0 to the pm core
345  */
346 static int __maybe_unused ish_resume(struct device *device)
347 {
348 	struct pci_dev *pdev = to_pci_dev(device);
349 	struct ishtp_device *dev = pci_get_drvdata(pdev);
350 
351 	ish_resume_device = device;
352 	dev->resume_flag = 1;
353 
354 	schedule_work(&resume_work);
355 
356 	return 0;
357 }
358 
359 static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume);
360 
361 static struct pci_driver ish_driver = {
362 	.name = KBUILD_MODNAME,
363 	.id_table = ish_pci_tbl,
364 	.probe = ish_probe,
365 	.remove = ish_remove,
366 	.shutdown = ish_shutdown,
367 	.driver.pm = &ish_pm_ops,
368 };
369 
370 module_pci_driver(ish_driver);
371 
372 /* Original author */
373 MODULE_AUTHOR("Daniel Drubin <daniel.drubin@intel.com>");
374 /* Adoption to upstream Linux kernel */
375 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
376 
377 MODULE_DESCRIPTION("Intel(R) Integrated Sensor Hub PCI Device Driver");
378 MODULE_LICENSE("GPL");
379