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 enum ishtp_driver_data_index {
27 ISHTP_DRIVER_DATA_NONE,
28 ISHTP_DRIVER_DATA_LNL_M,
29 ISHTP_DRIVER_DATA_PTL,
30 ISHTP_DRIVER_DATA_WCL,
31 };
32
33 #define ISH_FW_GEN_LNL_M "lnlm"
34 #define ISH_FW_GEN_PTL "ptl"
35 #define ISH_FW_GEN_WCL "wcl"
36
37 #define ISH_FIRMWARE_PATH(gen) "intel/ish/ish_" gen ".bin"
38 #define ISH_FIRMWARE_PATH_ALL "intel/ish/ish_*.bin"
39
40 static struct ishtp_driver_data ishtp_driver_data[] = {
41 [ISHTP_DRIVER_DATA_LNL_M] = {
42 .fw_generation = ISH_FW_GEN_LNL_M,
43 },
44 [ISHTP_DRIVER_DATA_PTL] = {
45 .fw_generation = ISH_FW_GEN_PTL,
46 },
47 [ISHTP_DRIVER_DATA_WCL] = {
48 .fw_generation = ISH_FW_GEN_WCL,
49 },
50 };
51
52 static const struct pci_device_id ish_pci_tbl[] = {
53 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CHV)},
54 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_BXT_Ax)},
55 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_BXT_Bx)},
56 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_APL_Ax)},
57 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_SPT_Ax)},
58 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CNL_Ax)},
59 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_GLK_Ax)},
60 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CNL_H)},
61 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ICL_MOBILE)},
62 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_SPT_H)},
63 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CML_LP)},
64 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CMP_H)},
65 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_EHL_Ax)},
66 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_TGL_LP)},
67 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_TGL_H)},
68 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ADL_S)},
69 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ADL_P)},
70 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ADL_N)},
71 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_RPL_S)},
72 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_MTL_P)},
73 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ARL_H)},
74 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ARL_S)},
75 {PCI_DEVICE_DATA(INTEL, ISH_LNL_M, ISHTP_DRIVER_DATA_LNL_M)},
76 {PCI_DEVICE_DATA(INTEL, ISH_PTL_H, ISHTP_DRIVER_DATA_PTL)},
77 {PCI_DEVICE_DATA(INTEL, ISH_PTL_P, ISHTP_DRIVER_DATA_PTL)},
78 {PCI_DEVICE_DATA(INTEL, ISH_WCL, ISHTP_DRIVER_DATA_WCL)},
79 {}
80 };
81 MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
82
83 /**
84 * ish_event_tracer() - Callback function to dump trace messages
85 * @dev: ishtp device
86 * @format: printf style format
87 *
88 * Callback to direct log messages to Linux trace buffers
89 */
90 static __printf(2, 3)
ish_event_tracer(struct ishtp_device * dev,const char * format,...)91 void ish_event_tracer(struct ishtp_device *dev, const char *format, ...)
92 {
93 if (trace_ishtp_dump_enabled()) {
94 va_list args;
95 char tmp_buf[100];
96
97 va_start(args, format);
98 vsnprintf(tmp_buf, sizeof(tmp_buf), format, args);
99 va_end(args);
100
101 trace_ishtp_dump(tmp_buf);
102 }
103 }
104
105 /**
106 * ish_init() - Init function
107 * @dev: ishtp device
108 *
109 * This function initialize wait queues for suspend/resume and call
110 * calls hadware initialization function. This will initiate
111 * startup sequence
112 *
113 * Return: 0 for success or error code for failure
114 */
ish_init(struct ishtp_device * dev)115 static int ish_init(struct ishtp_device *dev)
116 {
117 int ret;
118
119 /* Set the state of ISH HW to start */
120 ret = ish_hw_start(dev);
121 if (ret) {
122 dev_err(dev->devc, "ISH: hw start failed.\n");
123 return ret;
124 }
125
126 /* Start the inter process communication to ISH processor */
127 ret = ishtp_start(dev);
128 if (ret) {
129 dev_err(dev->devc, "ISHTP: Protocol init failed.\n");
130 return ret;
131 }
132
133 return 0;
134 }
135
136 static const struct pci_device_id ish_invalid_pci_ids[] = {
137 /* Mehlow platform special pci ids */
138 {PCI_VDEVICE(INTEL, 0xA309)},
139 {PCI_VDEVICE(INTEL, 0xA30A)},
140 {}
141 };
142
ish_should_enter_d0i3(struct pci_dev * pdev)143 static inline bool ish_should_enter_d0i3(struct pci_dev *pdev)
144 {
145 return !pm_suspend_via_firmware() || pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV;
146 }
147
ish_should_leave_d0i3(struct pci_dev * pdev)148 static inline bool ish_should_leave_d0i3(struct pci_dev *pdev)
149 {
150 return !pm_resume_via_firmware() || pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV;
151 }
152
153 /**
154 * ish_probe() - PCI driver probe callback
155 * @pdev: pci device
156 * @ent: pci device id
157 *
158 * Initialize PCI function, setup interrupt and call for ISH initialization
159 *
160 * Return: 0 for success or error code for failure
161 */
ish_probe(struct pci_dev * pdev,const struct pci_device_id * ent)162 static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
163 {
164 int ret;
165 struct ish_hw *hw;
166 unsigned long irq_flag = 0;
167 struct ishtp_device *ishtp;
168 struct device *dev = &pdev->dev;
169
170 /* Check for invalid platforms for ISH support */
171 if (pci_dev_present(ish_invalid_pci_ids))
172 return -ENODEV;
173
174 /* enable pci dev */
175 ret = pcim_enable_device(pdev);
176 if (ret) {
177 dev_err(dev, "ISH: Failed to enable PCI device\n");
178 return ret;
179 }
180
181 /* set PCI host mastering */
182 pci_set_master(pdev);
183
184 /* pci request regions for ISH driver */
185 ret = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
186 if (ret) {
187 dev_err(dev, "ISH: Failed to get PCI regions\n");
188 return ret;
189 }
190
191 /* allocates and initializes the ISH dev structure */
192 ishtp = ish_dev_init(pdev);
193 if (!ishtp) {
194 ret = -ENOMEM;
195 return ret;
196 }
197 hw = to_ish_hw(ishtp);
198 ishtp->print_log = ish_event_tracer;
199 ishtp->driver_data = &ishtp_driver_data[ent->driver_data];
200
201 /* mapping IO device memory */
202 hw->mem_addr = pcim_iomap_table(pdev)[0];
203 ishtp->pdev = pdev;
204
205 /* request and enable interrupt */
206 ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
207 if (ret < 0) {
208 dev_err(dev, "ISH: Failed to allocate IRQ vectors\n");
209 return ret;
210 }
211
212 if (!pdev->msi_enabled && !pdev->msix_enabled)
213 irq_flag = IRQF_SHARED;
214
215 ret = devm_request_irq(dev, pdev->irq, ish_irq_handler,
216 irq_flag, KBUILD_MODNAME, ishtp);
217 if (ret) {
218 dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq);
219 return ret;
220 }
221
222 dev_set_drvdata(ishtp->devc, ishtp);
223
224 init_waitqueue_head(&ishtp->suspend_wait);
225 init_waitqueue_head(&ishtp->resume_wait);
226
227 /* Enable PME for EHL */
228 if (pdev->device == PCI_DEVICE_ID_INTEL_ISH_EHL_Ax)
229 device_init_wakeup(dev, true);
230
231 ret = ish_init(ishtp);
232 if (ret)
233 return ret;
234
235 return 0;
236 }
237
238 /**
239 * ish_remove() - PCI driver remove callback
240 * @pdev: pci device
241 *
242 * This function does cleanup of ISH on pci remove callback
243 */
ish_remove(struct pci_dev * pdev)244 static void ish_remove(struct pci_dev *pdev)
245 {
246 struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
247
248 ishtp_bus_remove_all_clients(ishtp_dev, false);
249 ish_device_disable(ishtp_dev);
250 }
251
252
253 /**
254 * ish_shutdown() - PCI driver shutdown callback
255 * @pdev: pci device
256 *
257 * This function sets up wakeup for S5
258 */
ish_shutdown(struct pci_dev * pdev)259 static void ish_shutdown(struct pci_dev *pdev)
260 {
261 if (pdev->device == PCI_DEVICE_ID_INTEL_ISH_EHL_Ax)
262 pci_prepare_to_sleep(pdev);
263 }
264
265 static struct device __maybe_unused *ish_resume_device;
266
267 /* 50ms to get resume response */
268 #define WAIT_FOR_RESUME_ACK_MS 50
269
270 /**
271 * ish_resume_handler() - Work function to complete resume
272 * @work: work struct
273 *
274 * The resume work function to complete resume function asynchronously.
275 * There are two resume paths, one where ISH is not powered off,
276 * in that case a simple resume message is enough, others we need
277 * a reset sequence.
278 */
ish_resume_handler(struct work_struct * work)279 static void __maybe_unused ish_resume_handler(struct work_struct *work)
280 {
281 struct pci_dev *pdev = to_pci_dev(ish_resume_device);
282 struct ishtp_device *dev = pci_get_drvdata(pdev);
283 uint32_t fwsts = dev->ops->get_fw_status(dev);
284
285 if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag
286 && IPC_IS_ISH_ILUP(fwsts)) {
287 if (device_may_wakeup(&pdev->dev))
288 disable_irq_wake(pdev->irq);
289
290 ish_set_host_ready(dev);
291
292 ishtp_send_resume(dev);
293
294 /* Waiting to get resume response */
295 if (dev->resume_flag)
296 wait_event_interruptible_timeout(dev->resume_wait,
297 !dev->resume_flag,
298 msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
299
300 /*
301 * If the flag is not cleared, something is wrong with ISH FW.
302 * So on resume, need to go through init sequence again.
303 */
304 if (dev->resume_flag)
305 ish_init(dev);
306 } else {
307 /*
308 * Resume from the D3, full reboot of ISH processor will happen,
309 * so need to go through init sequence again.
310 */
311 ish_init(dev);
312 }
313 }
314
315 /**
316 * ish_suspend() - ISH suspend callback
317 * @device: device pointer
318 *
319 * ISH suspend callback
320 *
321 * Return: 0 to the pm core
322 */
ish_suspend(struct device * device)323 static int __maybe_unused ish_suspend(struct device *device)
324 {
325 struct pci_dev *pdev = to_pci_dev(device);
326 struct ishtp_device *dev = pci_get_drvdata(pdev);
327
328 if (ish_should_enter_d0i3(pdev)) {
329 /*
330 * If previous suspend hasn't been asnwered then ISH is likely
331 * dead, don't attempt nested notification
332 */
333 if (dev->suspend_flag)
334 return 0;
335
336 dev->resume_flag = 0;
337 dev->suspend_flag = 1;
338 ishtp_send_suspend(dev);
339
340 /* 25 ms should be enough for live ISH to flush all IPC buf */
341 if (dev->suspend_flag)
342 wait_event_interruptible_timeout(dev->suspend_wait,
343 !dev->suspend_flag,
344 msecs_to_jiffies(25));
345
346 if (dev->suspend_flag) {
347 /*
348 * It looks like FW halt, clear the DMA bit, and put
349 * ISH into D3, and FW would reset on resume.
350 */
351 ish_disable_dma(dev);
352 } else {
353 /*
354 * Save state so PCI core will keep the device at D0,
355 * the ISH would enter D0i3
356 */
357 pci_save_state(pdev);
358
359 if (device_may_wakeup(&pdev->dev))
360 enable_irq_wake(pdev->irq);
361 }
362 } else {
363 /*
364 * Clear the DMA bit before putting ISH into D3,
365 * or ISH FW would reset automatically.
366 */
367 ish_disable_dma(dev);
368 }
369
370 return 0;
371 }
372
373 static __maybe_unused DECLARE_WORK(resume_work, ish_resume_handler);
374 /**
375 * ish_resume() - ISH resume callback
376 * @device: device pointer
377 *
378 * ISH resume callback
379 *
380 * Return: 0 to the pm core
381 */
ish_resume(struct device * device)382 static int __maybe_unused ish_resume(struct device *device)
383 {
384 struct pci_dev *pdev = to_pci_dev(device);
385 struct ishtp_device *dev = pci_get_drvdata(pdev);
386
387 ish_resume_device = device;
388 dev->resume_flag = 1;
389
390 schedule_work(&resume_work);
391
392 return 0;
393 }
394
395 static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume);
396
base_version_show(struct device * cdev,struct device_attribute * attr,char * buf)397 static ssize_t base_version_show(struct device *cdev,
398 struct device_attribute *attr, char *buf)
399 {
400 struct ishtp_device *dev = dev_get_drvdata(cdev);
401
402 return sysfs_emit(buf, "%u.%u.%u.%u\n", dev->base_ver.major,
403 dev->base_ver.minor, dev->base_ver.hotfix,
404 dev->base_ver.build);
405 }
406 static DEVICE_ATTR_RO(base_version);
407
project_version_show(struct device * cdev,struct device_attribute * attr,char * buf)408 static ssize_t project_version_show(struct device *cdev,
409 struct device_attribute *attr, char *buf)
410 {
411 struct ishtp_device *dev = dev_get_drvdata(cdev);
412
413 return sysfs_emit(buf, "%u.%u.%u.%u\n", dev->prj_ver.major,
414 dev->prj_ver.minor, dev->prj_ver.hotfix,
415 dev->prj_ver.build);
416 }
417 static DEVICE_ATTR_RO(project_version);
418
419 static struct attribute *ish_firmware_attrs[] = {
420 &dev_attr_base_version.attr,
421 &dev_attr_project_version.attr,
422 NULL
423 };
424
firmware_is_visible(struct kobject * kobj,struct attribute * attr,int i)425 static umode_t firmware_is_visible(struct kobject *kobj, struct attribute *attr,
426 int i)
427 {
428 struct ishtp_device *dev = dev_get_drvdata(kobj_to_dev(kobj));
429
430 return dev->driver_data->fw_generation ? attr->mode : 0;
431 }
432
433 static const struct attribute_group ish_firmware_group = {
434 .name = "firmware",
435 .attrs = ish_firmware_attrs,
436 .is_visible = firmware_is_visible,
437 };
438
439 __ATTRIBUTE_GROUPS(ish_firmware);
440
441 static struct pci_driver ish_driver = {
442 .name = KBUILD_MODNAME,
443 .id_table = ish_pci_tbl,
444 .probe = ish_probe,
445 .remove = ish_remove,
446 .shutdown = ish_shutdown,
447 .driver.pm = &ish_pm_ops,
448 .dev_groups = ish_firmware_groups,
449 };
450
451 module_pci_driver(ish_driver);
452
453 /* Original author */
454 MODULE_AUTHOR("Daniel Drubin <daniel.drubin@intel.com>");
455 /* Adoption to upstream Linux kernel */
456 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
457
458 MODULE_DESCRIPTION("Intel(R) Integrated Sensor Hub PCI Device Driver");
459 MODULE_LICENSE("GPL");
460
461 MODULE_FIRMWARE(ISH_FIRMWARE_PATH(ISH_FW_GEN_LNL_M));
462 MODULE_FIRMWARE(ISH_FIRMWARE_PATH_ALL);
463