1 /*
2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <linux/platform_device.h>
21 #include <linux/err.h>
22 #include <linux/pci.h>
23 #include <linux/list.h>
24 #include <linux/slab.h>
25
26 #ifdef CONFIG_PLD_PCIE_CNSS
27 #ifdef CONFIG_CNSS_OUT_OF_TREE
28 #include "cnss2.h"
29 #else
30 #include <net/cnss2.h>
31 #endif
32 #endif
33
34 #include "pld_internal.h"
35 #include "pld_pcie.h"
36 #include "osif_psoc_sync.h"
37
38 #ifdef CONFIG_PCI
39
40 #ifdef QCA_WIFI_3_0_ADRASTEA
41 #define CE_COUNT_MAX 12
42 #else
43 #define CE_COUNT_MAX 8
44 #endif
45
46 #if defined(CONFIG_PLD_PCIE_CNSS) && \
47 (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
48 #ifndef CHIP_VERSION
49 #define CHIP_VERSION CNSS_CHIP_VER_ANY
50 #endif
51 #endif
52
53 /**
54 * pld_pcie_probe() - Probe function for PCIE platform driver
55 * @pdev: PCIE device
56 * @id: PCIE device ID table
57 *
58 * The probe function will be called when PCIE device provided
59 * in the ID table is detected.
60 *
61 * Return: int
62 */
pld_pcie_probe(struct pci_dev * pdev,const struct pci_device_id * id)63 static int pld_pcie_probe(struct pci_dev *pdev,
64 const struct pci_device_id *id)
65 {
66 struct pld_context *pld_context;
67 int ret = 0;
68
69 pld_context = pld_get_global_context();
70 if (!pld_context) {
71 ret = -ENODEV;
72 goto out;
73 }
74
75 ret = pld_add_dev(pld_context, &pdev->dev, NULL, PLD_BUS_TYPE_PCIE);
76 if (ret)
77 goto out;
78
79 return pld_context->ops->probe(&pdev->dev,
80 PLD_BUS_TYPE_PCIE, pdev, (void *)id);
81
82 out:
83 return ret;
84 }
85
86
87 /**
88 * pld_pcie_remove() - Remove function for PCIE device
89 * @pdev: PCIE device
90 *
91 * The remove function will be called when PCIE device is disconnected
92 *
93 * Return: void
94 */
pld_pcie_remove(struct pci_dev * pdev)95 static void pld_pcie_remove(struct pci_dev *pdev)
96 {
97 struct pld_context *pld_context;
98 int errno;
99 struct osif_psoc_sync *psoc_sync;
100
101 errno = osif_psoc_sync_trans_start_wait(&pdev->dev, &psoc_sync);
102
103 #ifdef ENFORCE_PLD_REMOVE
104 if (errno && errno != -EINVAL)
105 return;
106 #else
107 if (errno)
108 return;
109 #endif
110
111 osif_psoc_sync_unregister(&pdev->dev);
112
113 if (psoc_sync)
114 osif_psoc_sync_wait_for_ops(psoc_sync);
115
116 pld_context = pld_get_global_context();
117
118 if (!pld_context)
119 goto out;
120
121 pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE);
122
123 pld_del_dev(pld_context, &pdev->dev);
124
125 out:
126 if (psoc_sync) {
127 osif_psoc_sync_trans_stop(psoc_sync);
128 osif_psoc_sync_destroy(psoc_sync);
129 }
130 }
131
132 /**
133 * pld_pcie_set_thermal_state() - Set thermal state for thermal mitigation
134 * @pdev: PCIE device
135 * @thermal_state: Thermal state set by thermal subsystem
136 * @mon_id: Thermal cooling device ID
137 *
138 * This function will be called when thermal subsystem notifies platform
139 * driver about change in thermal state.
140 *
141 * Return: 0 for success
142 * Non zero failure code for errors
143 */
pld_pcie_set_thermal_state(struct pci_dev * pdev,unsigned long thermal_state,int mon_id)144 static int pld_pcie_set_thermal_state(struct pci_dev *pdev,
145 unsigned long thermal_state,
146 int mon_id)
147 {
148 struct pld_context *pld_context;
149
150 pld_context = pld_get_global_context();
151 if (!pld_context)
152 return -EINVAL;
153
154 if (pld_context->ops->set_curr_therm_cdev_state)
155 return pld_context->ops->set_curr_therm_cdev_state(&pdev->dev,
156 thermal_state,
157 mon_id);
158
159 return -ENOTSUPP;
160 }
161
162 #ifdef CONFIG_PLD_PCIE_CNSS
163 /**
164 * pld_pcie_idle_restart_cb() - Perform idle restart
165 * @pdev: PCIE device
166 * @id: PCIE device ID
167 *
168 * This function will be called if there is an idle restart request
169 *
170 * Return: int
171 */
pld_pcie_idle_restart_cb(struct pci_dev * pdev,const struct pci_device_id * id)172 static int pld_pcie_idle_restart_cb(struct pci_dev *pdev,
173 const struct pci_device_id *id)
174 {
175 struct pld_context *pld_context;
176
177 pld_context = pld_get_global_context();
178 if (pld_context->ops->idle_restart)
179 return pld_context->ops->idle_restart(&pdev->dev,
180 PLD_BUS_TYPE_PCIE);
181
182 return -ENODEV;
183 }
184
185 /**
186 * pld_pcie_idle_shutdown_cb() - Perform idle shutdown
187 * @pdev: PCIE device
188 *
189 * This function will be called if there is an idle shutdown request
190 *
191 * Return: int
192 */
pld_pcie_idle_shutdown_cb(struct pci_dev * pdev)193 static int pld_pcie_idle_shutdown_cb(struct pci_dev *pdev)
194 {
195 struct pld_context *pld_context;
196
197 pld_context = pld_get_global_context();
198 if (pld_context->ops->shutdown)
199 return pld_context->ops->idle_shutdown(&pdev->dev,
200 PLD_BUS_TYPE_PCIE);
201
202 return -ENODEV;
203 }
204
205 /**
206 * pld_pcie_reinit() - SSR re-initialize function for PCIE device
207 * @pdev: PCIE device
208 * @id: PCIE device ID
209 *
210 * During subsystem restart(SSR), this function will be called to
211 * re-initialize PCIE device.
212 *
213 * Return: int
214 */
pld_pcie_reinit(struct pci_dev * pdev,const struct pci_device_id * id)215 static int pld_pcie_reinit(struct pci_dev *pdev,
216 const struct pci_device_id *id)
217 {
218 struct pld_context *pld_context;
219
220 pld_context = pld_get_global_context();
221 if (pld_context->ops->reinit)
222 return pld_context->ops->reinit(&pdev->dev,
223 PLD_BUS_TYPE_PCIE, pdev, (void *)id);
224
225 return -ENODEV;
226 }
227
228 /**
229 * pld_pcie_shutdown() - SSR shutdown function for PCIE device
230 * @pdev: PCIE device
231 *
232 * During SSR, this function will be called to shutdown PCIE device.
233 *
234 * Return: void
235 */
pld_pcie_shutdown(struct pci_dev * pdev)236 static void pld_pcie_shutdown(struct pci_dev *pdev)
237 {
238 struct pld_context *pld_context;
239
240 pld_context = pld_get_global_context();
241 if (pld_context->ops->shutdown)
242 pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
243 }
244
245 /**
246 * pld_pcie_crash_shutdown() - Crash shutdown function for PCIE device
247 * @pdev: PCIE device
248 *
249 * This function will be called when a crash is detected, it will shutdown
250 * the PCIE device.
251 *
252 * Return: void
253 */
pld_pcie_crash_shutdown(struct pci_dev * pdev)254 static void pld_pcie_crash_shutdown(struct pci_dev *pdev)
255 {
256 struct pld_context *pld_context;
257
258 pld_context = pld_get_global_context();
259 if (pld_context->ops->crash_shutdown)
260 pld_context->ops->crash_shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
261 }
262
263 /**
264 * pld_pcie_notify_handler() - Modem state notification callback function
265 * @pdev: PCIE device
266 * @state: modem power state
267 *
268 * This function will be called when there's a modem power state change.
269 *
270 * Return: void
271 */
pld_pcie_notify_handler(struct pci_dev * pdev,int state)272 static void pld_pcie_notify_handler(struct pci_dev *pdev, int state)
273 {
274 struct pld_context *pld_context;
275
276 pld_context = pld_get_global_context();
277 if (pld_context->ops->modem_status)
278 pld_context->ops->modem_status(&pdev->dev,
279 PLD_BUS_TYPE_PCIE, state);
280 }
281
282 /**
283 * pld_pcie_uevent() - update wlan driver status callback function
284 * @pdev: PCIE device
285 * @status: driver uevent status
286 *
287 * This function will be called when platform driver wants to update wlan
288 * driver's status.
289 *
290 * Return: void
291 */
pld_pcie_uevent(struct pci_dev * pdev,uint32_t status)292 static void pld_pcie_uevent(struct pci_dev *pdev, uint32_t status)
293 {
294 struct pld_context *pld_context;
295 struct pld_uevent_data data = {0};
296
297 pld_context = pld_get_global_context();
298 if (!pld_context)
299 return;
300
301 switch (status) {
302 case CNSS_RECOVERY:
303 data.uevent = PLD_FW_RECOVERY_START;
304 break;
305 case CNSS_FW_DOWN:
306 data.uevent = PLD_FW_DOWN;
307 break;
308 case CNSS_SYS_REBOOT:
309 data.uevent = PLD_SYS_REBOOT;
310 break;
311 default:
312 goto out;
313 }
314
315 if (pld_context->ops->uevent)
316 pld_context->ops->uevent(&pdev->dev, &data);
317
318 out:
319 return;
320 }
321
322 #ifdef WLAN_FEATURE_SSR_DRIVER_DUMP
323 static int
pld_pcie_collect_driver_dump(struct pci_dev * pdev,struct cnss_ssr_driver_dump_entry * input_array,size_t * num_entries)324 pld_pcie_collect_driver_dump(struct pci_dev *pdev,
325 struct cnss_ssr_driver_dump_entry *input_array,
326 size_t *num_entries)
327 {
328 struct pld_context *pld_context;
329 struct pld_driver_ops *ops;
330 int ret = -EINVAL;
331
332 pld_context = pld_get_global_context();
333 ops = pld_context->ops;
334 if (ops->collect_driver_dump) {
335 ret = ops->collect_driver_dump(&pdev->dev,
336 PLD_BUS_TYPE_PCIE,
337 input_array,
338 num_entries);
339 }
340 return ret;
341 }
342 #endif
343
344 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
345 /**
346 * pld_bus_event_type_convert() - Convert enum cnss_bus_event_type
347 * to enum pld_bus_event
348 * @etype: enum cnss_bus_event_type value
349 *
350 * This function will convert enum cnss_bus_event_type to
351 * enum pld_bus_event.
352 *
353 * Return: enum pld_bus_event
354 */
355 static inline
pld_bus_event_type_convert(enum cnss_bus_event_type etype)356 enum pld_bus_event pld_bus_event_type_convert(enum cnss_bus_event_type etype)
357 {
358 enum pld_bus_event pld_etype = PLD_BUS_EVENT_INVALID;
359
360 switch (etype) {
361 case BUS_EVENT_PCI_LINK_DOWN:
362 pld_etype = PLD_BUS_EVENT_PCIE_LINK_DOWN;
363 break;
364 default:
365 break;
366 }
367
368 return pld_etype;
369 }
370
371 /**
372 * pld_pcie_update_event() - update wlan driver status callback function
373 * @pdev: PCIE device
374 * @uevent_data: driver uevent data
375 *
376 * This function will be called when platform driver wants to update wlan
377 * driver's status.
378 *
379 * Return: 0 for success, non zero for error code
380 */
pld_pcie_update_event(struct pci_dev * pdev,struct cnss_uevent_data * uevent_data)381 static int pld_pcie_update_event(struct pci_dev *pdev,
382 struct cnss_uevent_data *uevent_data)
383 {
384 struct pld_context *pld_context;
385 struct pld_uevent_data data = {0};
386 struct cnss_hang_event *hang_event;
387
388 pld_context = pld_get_global_context();
389
390 if (!pld_context || !uevent_data)
391 return -EINVAL;
392
393 switch (uevent_data->status) {
394 case CNSS_HANG_EVENT:
395 if (!uevent_data->data)
396 return -EINVAL;
397 hang_event = (struct cnss_hang_event *)uevent_data->data;
398 data.uevent = PLD_FW_HANG_EVENT;
399 data.hang_data.hang_event_data = hang_event->hang_event_data;
400 data.hang_data.hang_event_data_len =
401 hang_event->hang_event_data_len;
402 break;
403 case CNSS_BUS_EVENT:
404 {
405 struct cnss_bus_event *bus_evt = uevent_data->data;
406
407 if (!bus_evt)
408 return -EINVAL;
409
410 data.uevent = PLD_BUS_EVENT;
411
412 /* Process uevent_data->data if any */
413 data.bus_data.etype =
414 pld_bus_event_type_convert(bus_evt->etype);
415 data.bus_data.event_data = bus_evt->event_data;
416 break;
417 }
418 default:
419 return 0;
420 }
421
422 if (pld_context->ops->uevent)
423 pld_context->ops->uevent(&pdev->dev, &data);
424
425 return 0;
426 }
427 #endif
428
429 #ifdef FEATURE_RUNTIME_PM
430 /**
431 * pld_pcie_runtime_suspend() - PM runtime suspend
432 * @pdev: PCIE device
433 *
434 * PM runtime suspend callback function.
435 *
436 * Return: int
437 */
pld_pcie_runtime_suspend(struct pci_dev * pdev)438 static int pld_pcie_runtime_suspend(struct pci_dev *pdev)
439 {
440 struct pld_context *pld_context;
441
442 pld_context = pld_get_global_context();
443 if (pld_context->ops->runtime_suspend)
444 return pld_context->ops->runtime_suspend(&pdev->dev,
445 PLD_BUS_TYPE_PCIE);
446
447 return -ENODEV;
448 }
449
450 /**
451 * pld_pcie_runtime_resume() - PM runtime resume
452 * @pdev: PCIE device
453 *
454 * PM runtime resume callback function.
455 *
456 * Return: int
457 */
pld_pcie_runtime_resume(struct pci_dev * pdev)458 static int pld_pcie_runtime_resume(struct pci_dev *pdev)
459 {
460 struct pld_context *pld_context;
461
462 pld_context = pld_get_global_context();
463 if (pld_context->ops->runtime_resume)
464 return pld_context->ops->runtime_resume(&pdev->dev,
465 PLD_BUS_TYPE_PCIE);
466
467 return -ENODEV;
468 }
469 #endif
470
471 #ifdef FEATURE_GET_DRIVER_MODE
472 /**
473 * pld_pcie_get_mode() - Get current WLAN driver mode
474 *
475 * This function is to get current driver mode
476 *
477 * Return: mission mode or ftm mode
478 */
479 static
pld_pcie_get_mode(void)480 enum cnss_driver_mode pld_pcie_get_mode(void)
481 {
482 struct pld_context *pld_ctx = pld_get_global_context();
483 enum cnss_driver_mode cnss_mode = CNSS_MISSION;
484
485 if (!pld_ctx)
486 return cnss_mode;
487
488 switch (pld_ctx->mode) {
489 case QDF_GLOBAL_MISSION_MODE:
490 cnss_mode = CNSS_MISSION;
491 break;
492 case QDF_GLOBAL_WALTEST_MODE:
493 cnss_mode = CNSS_WALTEST;
494 break;
495 case QDF_GLOBAL_FTM_MODE:
496 cnss_mode = CNSS_FTM;
497 break;
498 case QDF_GLOBAL_COLDBOOT_CALIB_MODE:
499 cnss_mode = CNSS_CALIBRATION;
500 break;
501 case QDF_GLOBAL_EPPING_MODE:
502 cnss_mode = CNSS_EPPING;
503 break;
504 case QDF_GLOBAL_QVIT_MODE:
505 cnss_mode = CNSS_QVIT;
506 break;
507 default:
508 cnss_mode = CNSS_MISSION;
509 break;
510 }
511 return cnss_mode;
512 }
513 #endif
514 #endif
515
516 #ifdef CONFIG_PM
517 #ifdef CONFIG_PLD_PCIE_CNSS
518 /**
519 * pld_pcie_suspend() - Suspend callback function for power management
520 * @pdev: PCIE device
521 * @state: power state
522 *
523 * This function is to suspend the PCIE device when power management is
524 * enabled.
525 *
526 * Return: void
527 */
pld_pcie_suspend(struct pci_dev * pdev,pm_message_t state)528 static int pld_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
529 {
530 struct pld_context *pld_context;
531
532 pld_context = pld_get_global_context();
533 return pld_context->ops->suspend(&pdev->dev,
534 PLD_BUS_TYPE_PCIE, state);
535 }
536
537 /**
538 * pld_pcie_resume() - Resume callback function for power management
539 * @pdev: PCIE device
540 *
541 * This function is to resume the PCIE device when power management is
542 * enabled.
543 *
544 * Return: void
545 */
pld_pcie_resume(struct pci_dev * pdev)546 static int pld_pcie_resume(struct pci_dev *pdev)
547 {
548 struct pld_context *pld_context;
549
550 pld_context = pld_get_global_context();
551 return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_PCIE);
552 }
553
554 /**
555 * pld_pcie_suspend_noirq() - Complete the actions started by suspend()
556 * @pdev: PCI device
557 *
558 * Complete the actions started by suspend(). Carry out any additional
559 * operations required for suspending the device that might be racing
560 * with its driver's interrupt handler, which is guaranteed not to run
561 * while suspend_noirq() is being executed.
562 *
563 * Return: 0 for success
564 * Non zero failure code for errors
565 */
pld_pcie_suspend_noirq(struct pci_dev * pdev)566 static int pld_pcie_suspend_noirq(struct pci_dev *pdev)
567 {
568 struct pld_context *pld_context;
569
570 pld_context = pld_get_global_context();
571 if (!pld_context)
572 return -EINVAL;
573
574 if (pld_context->ops->suspend_noirq)
575 return pld_context->ops->
576 suspend_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE);
577 return 0;
578 }
579
580 /**
581 * pld_pcie_resume_noirq() - Prepare for the execution of resume()
582 * @pdev: PCI device
583 *
584 * Prepare for the execution of resume() by carrying out any additional
585 * operations required for resuming the device that might be racing with
586 * its driver's interrupt handler, which is guaranteed not to run while
587 * resume_noirq() is being executed.
588 *
589 * Return: 0 for success
590 * Non zero failure code for errors
591 */
pld_pcie_resume_noirq(struct pci_dev * pdev)592 static int pld_pcie_resume_noirq(struct pci_dev *pdev)
593 {
594 struct pld_context *pld_context;
595
596 pld_context = pld_get_global_context();
597 if (!pld_context)
598 return -EINVAL;
599
600 if (pld_context->ops->resume_noirq)
601 return pld_context->ops->
602 resume_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE);
603 return 0;
604 }
605 #else
606 /**
607 * pld_pcie_pm_suspend() - Suspend callback function for power management
608 * @dev: device
609 *
610 * This function is to suspend the PCIE device when power management is
611 * enabled.
612 *
613 * Return: 0 for success
614 * Non zero failure code for errors
615 */
pld_pcie_pm_suspend(struct device * dev)616 static int pld_pcie_pm_suspend(struct device *dev)
617 {
618 struct pld_context *pld_context;
619
620 pm_message_t state = { .event = PM_EVENT_SUSPEND };
621
622 pld_context = pld_get_global_context();
623 return pld_context->ops->suspend(dev, PLD_BUS_TYPE_PCIE, state);
624 }
625
626 /**
627 * pld_pcie_pm_resume() - Resume callback function for power management
628 * @dev: device
629 *
630 * This function is to resume the PCIE device when power management is
631 * enabled.
632 *
633 * Return: 0 for success
634 * Non zero failure code for errors
635 */
pld_pcie_pm_resume(struct device * dev)636 static int pld_pcie_pm_resume(struct device *dev)
637 {
638 struct pld_context *pld_context;
639
640 pld_context = pld_get_global_context();
641 return pld_context->ops->resume(dev, PLD_BUS_TYPE_PCIE);
642 }
643
644 /**
645 * pld_pcie_pm_suspend_noirq() - Complete the actions started by suspend()
646 * @dev: device
647 *
648 * Complete the actions started by suspend(). Carry out any additional
649 * operations required for suspending the device that might be racing
650 * with its driver's interrupt handler, which is guaranteed not to run
651 * while suspend_noirq() is being executed.
652 *
653 * Return: 0 for success
654 * Non zero failure code for errors
655 */
pld_pcie_pm_suspend_noirq(struct device * dev)656 static int pld_pcie_pm_suspend_noirq(struct device *dev)
657 {
658 struct pld_context *pld_context;
659
660 pld_context = pld_get_global_context();
661 if (!pld_context)
662 return -EINVAL;
663
664 if (pld_context->ops->suspend_noirq)
665 return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_PCIE);
666 return 0;
667 }
668
669 /**
670 * pld_pcie_pm_resume_noirq() - Prepare for the execution of resume()
671 * @dev: device
672 *
673 * Prepare for the execution of resume() by carrying out any additional
674 * operations required for resuming the device that might be racing with
675 * its driver's interrupt handler, which is guaranteed not to run while
676 * resume_noirq() is being executed.
677 *
678 * Return: 0 for success
679 * Non zero failure code for errors
680 */
pld_pcie_pm_resume_noirq(struct device * dev)681 static int pld_pcie_pm_resume_noirq(struct device *dev)
682 {
683 struct pld_context *pld_context;
684
685 pld_context = pld_get_global_context();
686 if (!pld_context)
687 return -EINVAL;
688
689 if (pld_context->ops->resume_noirq)
690 return pld_context->ops->
691 resume_noirq(dev, PLD_BUS_TYPE_PCIE);
692 return 0;
693 }
694 #endif
695 #endif
696
697 static struct pci_device_id pld_pcie_id_table[] = {
698 #ifdef CONFIG_AR6320_SUPPORT
699 { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID },
700 #elif defined(QCA_WIFI_QCA6290)
701 { 0x17cb, 0x1100, PCI_ANY_ID, PCI_ANY_ID },
702 #elif defined(QCA_WIFI_QCA6390)
703 { 0x17cb, 0x1101, PCI_ANY_ID, PCI_ANY_ID },
704 #elif defined(QCA_WIFI_QCA6490)
705 { 0x17cb, 0x1103, PCI_ANY_ID, PCI_ANY_ID },
706 #elif defined(QCA_WIFI_KIWI)
707 #if defined(QCA_WIFI_PEACH)
708 { 0x17cb, 0x110E, PCI_ANY_ID, PCI_ANY_ID },
709 #elif defined(QCA_WIFI_MANGO)
710 { 0x17cb, 0x110A, PCI_ANY_ID, PCI_ANY_ID },
711 #else
712 { 0x17cb, 0x1107, PCI_ANY_ID, PCI_ANY_ID },
713 #endif
714 #elif defined(QCN7605_SUPPORT)
715 { 0x17cb, 0x1102, PCI_ANY_ID, PCI_ANY_ID },
716 #else
717 { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID },
718 { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID },
719 { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID },
720 { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID },
721 #endif
722 { 0 }
723 };
724
725 #ifdef MULTI_IF_NAME
726 #define PLD_PCIE_OPS_NAME "pld_pcie_" MULTI_IF_NAME
727 #else
728 #define PLD_PCIE_OPS_NAME "pld_pcie"
729 #endif
730
731 #ifdef CONFIG_PLD_PCIE_CNSS
732 #ifdef FEATURE_RUNTIME_PM
733 struct cnss_wlan_runtime_ops runtime_pm_ops = {
734 .runtime_suspend = pld_pcie_runtime_suspend,
735 .runtime_resume = pld_pcie_runtime_resume,
736 };
737 #endif
738
739 struct cnss_wlan_driver pld_pcie_ops = {
740 .name = PLD_PCIE_OPS_NAME,
741 .id_table = pld_pcie_id_table,
742 .probe = pld_pcie_probe,
743 .remove = pld_pcie_remove,
744 .idle_restart = pld_pcie_idle_restart_cb,
745 .idle_shutdown = pld_pcie_idle_shutdown_cb,
746 .reinit = pld_pcie_reinit,
747 .shutdown = pld_pcie_shutdown,
748 .crash_shutdown = pld_pcie_crash_shutdown,
749 .modem_status = pld_pcie_notify_handler,
750 .update_status = pld_pcie_uevent,
751 #ifdef WLAN_FEATURE_SSR_DRIVER_DUMP
752 .collect_driver_dump = pld_pcie_collect_driver_dump,
753 #endif
754 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
755 .update_event = pld_pcie_update_event,
756 #endif
757 #ifdef CONFIG_PM
758 .suspend = pld_pcie_suspend,
759 .resume = pld_pcie_resume,
760 .suspend_noirq = pld_pcie_suspend_noirq,
761 .resume_noirq = pld_pcie_resume_noirq,
762 #endif
763 #ifdef FEATURE_RUNTIME_PM
764 .runtime_ops = &runtime_pm_ops,
765 #endif
766 #ifdef FEATURE_GET_DRIVER_MODE
767 .get_driver_mode = pld_pcie_get_mode,
768 #endif
769 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
770 .chip_version = CHIP_VERSION,
771 #endif
772 .set_therm_cdev_state = pld_pcie_set_thermal_state,
773 };
774
pld_pcie_register_driver(void)775 int pld_pcie_register_driver(void)
776 {
777 return cnss_wlan_register_driver(&pld_pcie_ops);
778 }
779
pld_pcie_unregister_driver(void)780 void pld_pcie_unregister_driver(void)
781 {
782 cnss_wlan_unregister_driver(&pld_pcie_ops);
783 }
784 #else
785 #ifdef CONFIG_PM
786 static const struct dev_pm_ops pld_pm_ops = {
787 SET_SYSTEM_SLEEP_PM_OPS(pld_pcie_pm_suspend, pld_pcie_pm_resume)
788 .suspend_noirq = pld_pcie_pm_suspend_noirq,
789 .resume_noirq = pld_pcie_pm_resume_noirq,
790 };
791 #endif
792
793 struct pci_driver pld_pcie_ops = {
794 .name = PLD_PCIE_OPS_NAME,
795 .id_table = pld_pcie_id_table,
796 .probe = pld_pcie_probe,
797 .remove = pld_pcie_remove,
798 .driver = {
799 #ifdef CONFIG_PM
800 .pm = &pld_pm_ops,
801 #endif
802 },
803 };
804
pld_pcie_register_driver(void)805 int pld_pcie_register_driver(void)
806 {
807 return pci_register_driver(&pld_pcie_ops);
808 }
809
pld_pcie_unregister_driver(void)810 void pld_pcie_unregister_driver(void)
811 {
812 pci_unregister_driver(&pld_pcie_ops);
813 }
814 #endif
815
pld_pcie_get_ce_id(struct device * dev,int irq)816 int pld_pcie_get_ce_id(struct device *dev, int irq)
817 {
818 int ce_id = irq - 100;
819
820 if (ce_id < CE_COUNT_MAX && ce_id >= 0)
821 return ce_id;
822
823 return -EINVAL;
824 }
825
826 #ifdef CONFIG_PLD_PCIE_CNSS
827 #ifdef CONFIG_SHADOW_V3
828 static inline void
pld_pcie_populate_shadow_v3_cfg(struct cnss_wlan_enable_cfg * cfg,struct pld_wlan_enable_cfg * config)829 pld_pcie_populate_shadow_v3_cfg(struct cnss_wlan_enable_cfg *cfg,
830 struct pld_wlan_enable_cfg *config)
831 {
832 cfg->num_shadow_reg_v3_cfg = config->num_shadow_reg_v3_cfg;
833 cfg->shadow_reg_v3_cfg = (struct cnss_shadow_reg_v3_cfg *)
834 config->shadow_reg_v3_cfg;
835 }
836 #else
837 static inline void
pld_pcie_populate_shadow_v3_cfg(struct cnss_wlan_enable_cfg * cfg,struct pld_wlan_enable_cfg * config)838 pld_pcie_populate_shadow_v3_cfg(struct cnss_wlan_enable_cfg *cfg,
839 struct pld_wlan_enable_cfg *config)
840 {
841 }
842 #endif
pld_pcie_wlan_enable(struct device * dev,struct pld_wlan_enable_cfg * config,enum pld_driver_mode mode,const char * host_version)843 int pld_pcie_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
844 enum pld_driver_mode mode, const char *host_version)
845 {
846 struct cnss_wlan_enable_cfg cfg;
847 enum cnss_driver_mode cnss_mode;
848
849 cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg;
850 cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *)
851 config->ce_tgt_cfg;
852 cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg;
853 cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *)
854 config->ce_svc_cfg;
855 cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg;
856 cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *)
857 config->shadow_reg_cfg;
858 cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg;
859 cfg.shadow_reg_v2_cfg = (struct cnss_shadow_reg_v2_cfg *)
860 config->shadow_reg_v2_cfg;
861 cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid;
862 if (config->rri_over_ddr_cfg_valid) {
863 cfg.rri_over_ddr_cfg.base_addr_low =
864 config->rri_over_ddr_cfg.base_addr_low;
865 cfg.rri_over_ddr_cfg.base_addr_high =
866 config->rri_over_ddr_cfg.base_addr_high;
867 }
868
869 pld_pcie_populate_shadow_v3_cfg(&cfg, config);
870
871 switch (mode) {
872 case PLD_FTM:
873 cnss_mode = CNSS_FTM;
874 break;
875 case PLD_EPPING:
876 cnss_mode = CNSS_EPPING;
877 break;
878 default:
879 cnss_mode = CNSS_MISSION;
880 break;
881 }
882 return cnss_wlan_enable(dev, &cfg, cnss_mode, host_version);
883 }
884
pld_pcie_wlan_disable(struct device * dev,enum pld_driver_mode mode)885 int pld_pcie_wlan_disable(struct device *dev, enum pld_driver_mode mode)
886 {
887 return cnss_wlan_disable(dev, CNSS_OFF);
888 }
889
pld_pcie_get_fw_files_for_target(struct device * dev,struct pld_fw_files * pfw_files,u32 target_type,u32 target_version)890 int pld_pcie_get_fw_files_for_target(struct device *dev,
891 struct pld_fw_files *pfw_files,
892 u32 target_type, u32 target_version)
893 {
894 int ret = 0;
895 struct cnss_fw_files cnss_fw_files;
896
897 if (!pfw_files)
898 return -ENODEV;
899
900 memset(pfw_files, 0, sizeof(*pfw_files));
901
902 ret = cnss_get_fw_files_for_target(dev, &cnss_fw_files,
903 target_type, target_version);
904 if (ret)
905 return ret;
906
907 scnprintf(pfw_files->image_file, PLD_MAX_FILE_NAME, PREFIX "%s",
908 cnss_fw_files.image_file);
909 scnprintf(pfw_files->board_data, PLD_MAX_FILE_NAME, PREFIX "%s",
910 cnss_fw_files.board_data);
911 scnprintf(pfw_files->otp_data, PLD_MAX_FILE_NAME, PREFIX "%s",
912 cnss_fw_files.otp_data);
913 scnprintf(pfw_files->utf_file, PLD_MAX_FILE_NAME, PREFIX "%s",
914 cnss_fw_files.utf_file);
915 scnprintf(pfw_files->utf_board_data, PLD_MAX_FILE_NAME, PREFIX "%s",
916 cnss_fw_files.utf_board_data);
917 scnprintf(pfw_files->epping_file, PLD_MAX_FILE_NAME, PREFIX "%s",
918 cnss_fw_files.epping_file);
919 scnprintf(pfw_files->evicted_data, PLD_MAX_FILE_NAME, PREFIX "%s",
920 cnss_fw_files.evicted_data);
921
922 return 0;
923 }
924
pld_pcie_get_platform_cap(struct device * dev,struct pld_platform_cap * cap)925 int pld_pcie_get_platform_cap(struct device *dev, struct pld_platform_cap *cap)
926 {
927 int ret = 0;
928 struct cnss_platform_cap cnss_cap;
929
930 if (!cap)
931 return -ENODEV;
932
933 ret = cnss_get_platform_cap(dev, &cnss_cap);
934 if (ret)
935 return ret;
936
937 memcpy(cap, &cnss_cap, sizeof(*cap));
938 return 0;
939 }
940
pld_pcie_get_soc_info(struct device * dev,struct pld_soc_info * info)941 int pld_pcie_get_soc_info(struct device *dev, struct pld_soc_info *info)
942 {
943 int ret = 0, i;
944 struct cnss_soc_info cnss_info = {0};
945
946 if (!info)
947 return -ENODEV;
948
949 ret = cnss_get_soc_info(dev, &cnss_info);
950 if (ret)
951 return ret;
952
953 info->v_addr = cnss_info.va;
954 info->p_addr = cnss_info.pa;
955 info->chip_id = cnss_info.chip_id;
956 info->chip_family = cnss_info.chip_family;
957 info->board_id = cnss_info.board_id;
958 info->soc_id = cnss_info.soc_id;
959 info->fw_version = cnss_info.fw_version;
960 strlcpy(info->fw_build_timestamp, cnss_info.fw_build_timestamp,
961 sizeof(info->fw_build_timestamp));
962 info->device_version.family_number =
963 cnss_info.device_version.family_number;
964 info->device_version.device_number =
965 cnss_info.device_version.device_number;
966 info->device_version.major_version =
967 cnss_info.device_version.major_version;
968 info->device_version.minor_version =
969 cnss_info.device_version.minor_version;
970 for (i = 0; i < PLD_MAX_DEV_MEM_NUM; i++) {
971 info->dev_mem_info[i].start = cnss_info.dev_mem_info[i].start;
972 info->dev_mem_info[i].size = cnss_info.dev_mem_info[i].size;
973 }
974 strlcpy(info->fw_build_id, cnss_info.fw_build_id,
975 sizeof(info->fw_build_id));
976
977 return 0;
978 }
979
pld_pcie_schedule_recovery_work(struct device * dev,enum pld_recovery_reason reason)980 void pld_pcie_schedule_recovery_work(struct device *dev,
981 enum pld_recovery_reason reason)
982 {
983 enum cnss_recovery_reason cnss_reason;
984
985 switch (reason) {
986 case PLD_REASON_LINK_DOWN:
987 cnss_reason = CNSS_REASON_LINK_DOWN;
988 break;
989 default:
990 cnss_reason = CNSS_REASON_DEFAULT;
991 break;
992 }
993 cnss_schedule_recovery(dev, cnss_reason);
994 }
995
pld_pcie_device_self_recovery(struct device * dev,enum pld_recovery_reason reason)996 void pld_pcie_device_self_recovery(struct device *dev,
997 enum pld_recovery_reason reason)
998 {
999 enum cnss_recovery_reason cnss_reason;
1000
1001 switch (reason) {
1002 case PLD_REASON_LINK_DOWN:
1003 cnss_reason = CNSS_REASON_LINK_DOWN;
1004 break;
1005 default:
1006 cnss_reason = CNSS_REASON_DEFAULT;
1007 break;
1008 }
1009 cnss_self_recovery(dev, cnss_reason);
1010 }
1011
1012 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
pld_pcie_set_wfc_mode(struct device * dev,enum pld_wfc_mode wfc_mode)1013 int pld_pcie_set_wfc_mode(struct device *dev,
1014 enum pld_wfc_mode wfc_mode)
1015 {
1016 struct cnss_wfc_cfg cfg;
1017 int ret;
1018
1019 switch (wfc_mode) {
1020 case PLD_WFC_MODE_OFF:
1021 cfg.mode = CNSS_WFC_MODE_OFF;
1022 break;
1023 case PLD_WFC_MODE_ON:
1024 cfg.mode = CNSS_WFC_MODE_ON;
1025 break;
1026 default:
1027 ret = -EINVAL;
1028 goto out;
1029 }
1030
1031 ret = cnss_set_wfc_mode(dev, cfg);
1032 out:
1033 return ret;
1034 }
1035 #endif
1036 #endif
1037 #endif
1038