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