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/list.h>
23 #include <linux/slab.h>
24
25 #ifdef CONFIG_PLD_IPCI_ICNSS
26 #ifdef CONFIG_CNSS_OUT_OF_TREE
27 #include "icnss2.h"
28 #else
29 #include <soc/qcom/icnss2.h>
30 #endif
31 #endif
32
33 #include "pld_internal.h"
34 #include "pld_ipci.h"
35 #include "osif_psoc_sync.h"
36
37 #ifdef CONFIG_PLD_IPCI_ICNSS
38
39 #define WCN6750_DEVICE_ID 0x6750
40 #define WCN6450_DEVICE_ID 0x6450
41 /**
42 * pld_ipci_probe() - Probe function for platform driver
43 * @dev: device
44 *
45 * The probe function will be called when platform device
46 * is detected.
47 *
48 * Return: int
49 */
pld_ipci_probe(struct device * dev)50 static int pld_ipci_probe(struct device *dev)
51 {
52 struct pld_context *pld_context;
53 int ret = 0;
54
55 pld_context = pld_get_global_context();
56 if (!pld_context) {
57 ret = -ENODEV;
58 goto out;
59 }
60
61 ret = pld_add_dev(pld_context, dev, NULL, PLD_BUS_TYPE_IPCI);
62 if (ret)
63 goto out;
64
65 return pld_context->ops->probe(dev, PLD_BUS_TYPE_IPCI,
66 NULL, NULL);
67
68 out:
69 return ret;
70 }
71
72 /**
73 * pld_ipci_remove() - Remove function for platform device
74 * @dev: device
75 *
76 * The remove function will be called when platform device
77 * is disconnected
78 *
79 * Return: void
80 */
pld_ipci_remove(struct device * dev)81 static void pld_ipci_remove(struct device *dev)
82 {
83 struct pld_context *pld_context;
84 int errno;
85 struct osif_psoc_sync *psoc_sync;
86
87 errno = osif_psoc_sync_trans_start_wait(dev, &psoc_sync);
88 if (errno)
89 return;
90
91 osif_psoc_sync_unregister(dev);
92 osif_psoc_sync_wait_for_ops(psoc_sync);
93
94 pld_context = pld_get_global_context();
95
96 if (!pld_context)
97 goto out;
98
99 pld_context->ops->remove(dev, PLD_BUS_TYPE_SNOC);
100
101 pld_del_dev(pld_context, dev);
102
103 out:
104 osif_psoc_sync_trans_stop(psoc_sync);
105 osif_psoc_sync_destroy(psoc_sync);
106 }
107
108 /**
109 * pld_ipci_reinit() - SSR re-initialize function for platform device
110 * @dev: device
111 *
112 * During subsystem restart(SSR), this function will be called to
113 * re-initialize platform device.
114 *
115 * Return: int
116 */
pld_ipci_reinit(struct device * dev)117 static int pld_ipci_reinit(struct device *dev)
118 {
119 struct pld_context *pld_context;
120
121 pld_context = pld_get_global_context();
122 if (pld_context->ops->reinit)
123 return pld_context->ops->reinit(dev, PLD_BUS_TYPE_IPCI,
124 NULL, NULL);
125
126 return -ENODEV;
127 }
128
129 /**
130 * pld_ipci_shutdown() - SSR shutdown function for platform device
131 * @dev: device
132 *
133 * During SSR, this function will be called to shutdown platform device.
134 *
135 * Return: void
136 */
pld_ipci_shutdown(struct device * dev)137 static void pld_ipci_shutdown(struct device *dev)
138 {
139 struct pld_context *pld_context;
140
141 pld_context = pld_get_global_context();
142 if (pld_context->ops->shutdown)
143 pld_context->ops->shutdown(dev, PLD_BUS_TYPE_IPCI);
144 }
145
146 /**
147 * pld_ipci_crash_shutdown() - Crash shutdown function for platform device
148 * @dev: device
149 *
150 * This function will be called when a crash is detected, it will shutdown
151 * platform device.
152 *
153 * Return: void
154 */
pld_ipci_crash_shutdown(void * dev)155 static void pld_ipci_crash_shutdown(void *dev)
156 {
157 struct pld_context *pld_context;
158
159 pld_context = pld_get_global_context();
160 if (pld_context->ops->crash_shutdown)
161 pld_context->ops->crash_shutdown(dev, PLD_BUS_TYPE_IPCI);
162 }
163
164 /**
165 * pld_ipci_pm_suspend() - PM suspend callback function for power management
166 * @dev: device
167 *
168 * This function is to suspend the platform device when power management
169 * is enabled.
170 *
171 * Return: void
172 */
pld_ipci_pm_suspend(struct device * dev)173 static int pld_ipci_pm_suspend(struct device *dev)
174 {
175 struct pld_context *pld_context;
176 pm_message_t state;
177
178 state.event = PM_EVENT_SUSPEND;
179 pld_context = pld_get_global_context();
180 return pld_context->ops->suspend(dev, PLD_BUS_TYPE_IPCI, state);
181 }
182
183 /**
184 * pld_ipci_pm_resume() - PM resume callback function for power management
185 * @dev: device
186 *
187 * This function is to resume the platform device when power management
188 * is enabled.
189 *
190 * Return: void
191 */
pld_ipci_pm_resume(struct device * dev)192 static int pld_ipci_pm_resume(struct device *dev)
193 {
194 struct pld_context *pld_context;
195
196 pld_context = pld_get_global_context();
197 return pld_context->ops->resume(dev, PLD_BUS_TYPE_IPCI);
198 }
199
200 /**
201 * pld_ipci_suspend_noirq() - Complete the actions started by suspend()
202 * @dev: device
203 *
204 * Complete the actions started by suspend(). Carry out any
205 * additional operations required for suspending the device that might be
206 * racing with its driver's interrupt handler, which is guaranteed not to
207 * run while suspend_noirq() is being executed.
208 *
209 * Return: 0 for success
210 * Non zero failure code for errors
211 */
pld_ipci_suspend_noirq(struct device * dev)212 static int pld_ipci_suspend_noirq(struct device *dev)
213 {
214 struct pld_context *pld_context;
215
216 pld_context = pld_get_global_context();
217 if (!pld_context)
218 return -EINVAL;
219
220 if (pld_context->ops->suspend_noirq)
221 return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_IPCI);
222 return 0;
223 }
224
225 /**
226 * pld_ipci_resume_noirq() - Prepare for the execution of resume()
227 * @dev: device
228 *
229 * Prepare for the execution of resume() by carrying out any
230 * operations required for resuming the device that might be racing with
231 * its driver's interrupt handler, which is guaranteed not to run while
232 * resume_noirq() is being executed.
233 *
234 * Return: 0 for success
235 * Non zero failure code for errors
236 */
pld_ipci_resume_noirq(struct device * dev)237 static int pld_ipci_resume_noirq(struct device *dev)
238 {
239 struct pld_context *pld_context;
240
241 pld_context = pld_get_global_context();
242 if (!pld_context)
243 return -EINVAL;
244
245 if (pld_context->ops->resume_noirq)
246 return pld_context->ops->resume_noirq(dev, PLD_BUS_TYPE_IPCI);
247
248 return 0;
249 }
250
251 /**
252 * pld_ipci_runtime_suspend() - Runtime suspend callback for power management
253 * @dev: device
254 *
255 * This function is to runtime suspend the platform device when power management
256 * is enabled.
257 *
258 * Return: status
259 */
pld_ipci_runtime_suspend(struct device * dev)260 static int pld_ipci_runtime_suspend(struct device *dev)
261 {
262 struct pld_context *pld_context;
263
264 pld_context = pld_get_global_context();
265 if (!pld_context)
266 return -EINVAL;
267
268 if (pld_context->ops && pld_context->ops->runtime_suspend)
269 return pld_context->ops->runtime_suspend(dev,
270 PLD_BUS_TYPE_IPCI);
271
272 return 0;
273 }
274
275 /**
276 * pld_ipci_runtime_resume() - Runtime resume callback for power management
277 * @dev: device
278 *
279 * This function is to runtime resume the platform device when power management
280 * is enabled.
281 *
282 * Return: status
283 */
pld_ipci_runtime_resume(struct device * dev)284 static int pld_ipci_runtime_resume(struct device *dev)
285 {
286 struct pld_context *pld_context;
287
288 pld_context = pld_get_global_context();
289 if (!pld_context)
290 return -EINVAL;
291
292 if (pld_context->ops && pld_context->ops->runtime_resume)
293 return pld_context->ops->runtime_resume(dev, PLD_BUS_TYPE_IPCI);
294
295 return 0;
296 }
297
298 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
pld_update_hang_evt_data(struct icnss_uevent_hang_data * evt_data,struct pld_uevent_data * data)299 static int pld_update_hang_evt_data(struct icnss_uevent_hang_data *evt_data,
300 struct pld_uevent_data *data)
301 {
302 if (!evt_data || !data)
303 return -EINVAL;
304
305 data->hang_data.hang_event_data = evt_data->hang_event_data;
306 data->hang_data.hang_event_data_len = evt_data->hang_event_data_len;
307 return 0;
308 }
309
pld_ipci_uevent(struct device * dev,struct icnss_uevent_data * uevent)310 static int pld_ipci_uevent(struct device *dev,
311 struct icnss_uevent_data *uevent)
312 {
313 struct pld_context *pld_context;
314 struct icnss_uevent_fw_down_data *uevent_data = NULL;
315 struct pld_uevent_data data = {0};
316 struct icnss_uevent_hang_data *hang_data = NULL;
317
318 pld_context = pld_get_global_context();
319 if (!pld_context)
320 return -EINVAL;
321
322 if (!pld_context->ops->uevent)
323 goto out;
324
325 if (!uevent)
326 return -EINVAL;
327
328 switch (uevent->uevent) {
329 case ICNSS_UEVENT_FW_CRASHED:
330 data.uevent = PLD_FW_CRASHED;
331 break;
332 case ICNSS_UEVENT_FW_DOWN:
333 if (!uevent->data)
334 return -EINVAL;
335 uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data;
336 data.uevent = PLD_FW_DOWN;
337 data.fw_down.crashed = uevent_data->crashed;
338 break;
339 case ICNSS_UEVENT_HANG_DATA:
340 if (!uevent->data)
341 return -EINVAL;
342 hang_data = (struct icnss_uevent_hang_data *)uevent->data;
343 data.uevent = PLD_FW_HANG_EVENT;
344 pld_update_hang_evt_data(hang_data, &data);
345 break;
346 case ICNSS_UEVENT_SMMU_FAULT:
347 if (!uevent->data)
348 return -EINVAL;
349 uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data;
350 data.uevent = PLD_SMMU_FAULT;
351 data.fw_down.crashed = uevent_data->crashed;
352 break;
353 default:
354 goto out;
355 }
356
357 pld_context->ops->uevent(dev, &data);
358 out:
359 return 0;
360 }
361 #else
pld_ipci_uevent(struct device * dev,struct icnss_uevent_data * uevent)362 static int pld_ipci_uevent(struct device *dev,
363 struct icnss_uevent_data *uevent)
364 {
365 struct pld_context *pld_context;
366 struct icnss_uevent_fw_down_data *uevent_data = NULL;
367 struct pld_uevent_data data = {0};
368
369 pld_context = pld_get_global_context();
370 if (!pld_context)
371 return -EINVAL;
372
373 if (!pld_context->ops->uevent)
374 goto out;
375
376 if (!uevent)
377 return -EINVAL;
378
379 switch (uevent->uevent) {
380 case ICNSS_UEVENT_FW_CRASHED:
381 data.uevent = PLD_FW_CRASHED;
382 break;
383 case ICNSS_UEVENT_FW_DOWN:
384 if (!uevent->data)
385 return -EINVAL;
386 uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data;
387 data.uevent = PLD_FW_DOWN;
388 data.fw_down.crashed = uevent_data->crashed;
389 break;
390 default:
391 goto out;
392 }
393
394 pld_context->ops->uevent(dev, &data);
395 out:
396 return 0;
397 }
398 #endif
399
400 /**
401 * pld_ipci_idle_restart_cb() - Perform idle restart
402 * @dev: platform device
403 *
404 * This function will be called if there is an idle restart request
405 *
406 * Return: int
407 */
pld_ipci_idle_restart_cb(struct device * dev)408 static int pld_ipci_idle_restart_cb(struct device *dev)
409 {
410 struct pld_context *pld_context;
411
412 pld_context = pld_get_global_context();
413
414 if (!pld_context)
415 return -EINVAL;
416
417 if (pld_context->ops->idle_restart)
418 return pld_context->ops->idle_restart(dev,
419 PLD_BUS_TYPE_IPCI);
420
421 return -ENODEV;
422 }
423
424 /**
425 * pld_ipci_idle_shutdown_cb() - Perform idle shutdown
426 * @dev: PCIE device
427 *
428 * This function will be called if there is an idle shutdown request
429 *
430 * Return: int
431 */
pld_ipci_idle_shutdown_cb(struct device * dev)432 static int pld_ipci_idle_shutdown_cb(struct device *dev)
433 {
434 struct pld_context *pld_context;
435
436 pld_context = pld_get_global_context();
437
438 if (!pld_context)
439 return -EINVAL;
440
441 if (pld_context->ops->shutdown)
442 return pld_context->ops->idle_shutdown(dev,
443 PLD_BUS_TYPE_IPCI);
444
445 return -ENODEV;
446 }
447
448 /**
449 * pld_ipci_set_thermal_state() - Set thermal state for thermal mitigation
450 * @dev: device
451 * @thermal_state: Thermal state set by thermal subsystem
452 * @mon_id: Thermal cooling device ID
453 *
454 * This function will be called when thermal subsystem notifies platform
455 * driver about change in thermal state.
456 *
457 * Return: 0 for success
458 * Non zero failure code for errors
459 */
pld_ipci_set_thermal_state(struct device * dev,unsigned long thermal_state,int mon_id)460 static int pld_ipci_set_thermal_state(struct device *dev,
461 unsigned long thermal_state,
462 int mon_id)
463 {
464 struct pld_context *pld_context;
465
466 pld_context = pld_get_global_context();
467 if (!pld_context)
468 return -EINVAL;
469
470 if (pld_context->ops->set_curr_therm_cdev_state)
471 return pld_context->ops->set_curr_therm_cdev_state(dev,
472 thermal_state,
473 mon_id);
474
475 return -ENOTSUPP;
476 }
477
478 #ifdef MULTI_IF_NAME
479 #define PLD_IPCI_OPS_NAME "pld_ipci_" MULTI_IF_NAME
480 #else
481 #define PLD_IPCI_OPS_NAME "pld_ipci"
482 #endif
483
484 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
485 static struct device_info pld_ipci_dev_info[] = {
486 #ifdef QCA_WIFI_QCA6750
487 { "wcn6750", WCN6750_DEVICE_ID },
488 #elif defined(QCA_WIFI_WCN6450)
489 { "wcn6450", WCN6450_DEVICE_ID },
490 #endif
491 { { 0 } }
492 };
493 #endif
494
495 struct icnss_driver_ops pld_ipci_ops = {
496 .name = PLD_IPCI_OPS_NAME,
497 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
498 .dev_info = pld_ipci_dev_info,
499 #endif
500 .probe = pld_ipci_probe,
501 .remove = pld_ipci_remove,
502 .shutdown = pld_ipci_shutdown,
503 .reinit = pld_ipci_reinit,
504 .crash_shutdown = pld_ipci_crash_shutdown,
505 .pm_suspend = pld_ipci_pm_suspend,
506 .pm_resume = pld_ipci_pm_resume,
507 .suspend_noirq = pld_ipci_suspend_noirq,
508 .resume_noirq = pld_ipci_resume_noirq,
509 .runtime_suspend = pld_ipci_runtime_suspend,
510 .runtime_resume = pld_ipci_runtime_resume,
511 .uevent = pld_ipci_uevent,
512 .idle_restart = pld_ipci_idle_restart_cb,
513 .idle_shutdown = pld_ipci_idle_shutdown_cb,
514 .set_therm_cdev_state = pld_ipci_set_thermal_state,
515 };
516
pld_ipci_register_driver(void)517 int pld_ipci_register_driver(void)
518 {
519 return icnss_register_driver(&pld_ipci_ops);
520 }
521
pld_ipci_unregister_driver(void)522 void pld_ipci_unregister_driver(void)
523 {
524 icnss_unregister_driver(&pld_ipci_ops);
525 }
526
527 #ifdef CONFIG_SHADOW_V3
528 static inline void
pld_ipci_populate_shadow_v3_cfg(struct icnss_wlan_enable_cfg * cfg,struct pld_wlan_enable_cfg * config)529 pld_ipci_populate_shadow_v3_cfg(struct icnss_wlan_enable_cfg *cfg,
530 struct pld_wlan_enable_cfg *config)
531 {
532 cfg->num_shadow_reg_v3_cfg = config->num_shadow_reg_v3_cfg;
533 cfg->shadow_reg_v3_cfg = (struct icnss_shadow_reg_v3_cfg *)
534 config->shadow_reg_v3_cfg;
535 }
536 #else
537 static inline void
pld_ipci_populate_shadow_v3_cfg(struct icnss_wlan_enable_cfg * cfg,struct pld_wlan_enable_cfg * config)538 pld_ipci_populate_shadow_v3_cfg(struct icnss_wlan_enable_cfg *cfg,
539 struct pld_wlan_enable_cfg *config)
540 {
541 }
542 #endif
543
pld_ipci_wlan_enable(struct device * dev,struct pld_wlan_enable_cfg * config,enum pld_driver_mode mode,const char * host_version)544 int pld_ipci_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
545 enum pld_driver_mode mode, const char *host_version)
546 {
547 struct icnss_wlan_enable_cfg cfg;
548 enum icnss_driver_mode icnss_mode;
549
550 if (!dev)
551 return -ENODEV;
552
553 cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg;
554 cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *)
555 config->ce_tgt_cfg;
556 cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg;
557 cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *)
558 config->ce_svc_cfg;
559 cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg;
560 cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *)
561 config->shadow_reg_cfg;
562 cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg;
563 cfg.shadow_reg_v2_cfg = (struct icnss_shadow_reg_v2_cfg *)
564 config->shadow_reg_v2_cfg;
565 cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid;
566 if (config->rri_over_ddr_cfg_valid) {
567 cfg.rri_over_ddr_cfg.base_addr_low =
568 config->rri_over_ddr_cfg.base_addr_low;
569 cfg.rri_over_ddr_cfg.base_addr_high =
570 config->rri_over_ddr_cfg.base_addr_high;
571 }
572
573 pld_ipci_populate_shadow_v3_cfg(&cfg, config);
574
575 switch (mode) {
576 case PLD_FTM:
577 icnss_mode = ICNSS_FTM;
578 break;
579 case PLD_EPPING:
580 icnss_mode = ICNSS_EPPING;
581 break;
582 default:
583 icnss_mode = ICNSS_MISSION;
584 break;
585 }
586
587 return icnss_wlan_enable(dev, &cfg, icnss_mode, host_version);
588 }
589
pld_ipci_wlan_disable(struct device * dev,enum pld_driver_mode mode)590 int pld_ipci_wlan_disable(struct device *dev, enum pld_driver_mode mode)
591 {
592 if (!dev)
593 return -ENODEV;
594
595 return icnss_wlan_disable(dev, ICNSS_OFF);
596 }
597
598 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0))
pld_ipci_populate_hw_cap_info(struct icnss_soc_info * icnss_info,struct pld_soc_info * info)599 static void pld_ipci_populate_hw_cap_info(struct icnss_soc_info *icnss_info,
600 struct pld_soc_info *info)
601 {
602 /*WLAN HW cap info*/
603 info->hw_cap_info.nss =
604 (enum pld_wlan_hw_nss_info)icnss_info->rd_card_chain_cap;
605 info->hw_cap_info.bw =
606 (enum pld_wlan_hw_channel_bw_info)icnss_info->phy_he_channel_width_cap;
607 info->hw_cap_info.qam =
608 (enum pld_wlan_hw_qam_info)icnss_info->phy_qam_cap;
609 }
610 #else
pld_ipci_populate_hw_cap_info(struct icnss_soc_info * icnss_info,struct pld_soc_info * info)611 static void pld_ipci_populate_hw_cap_info(struct icnss_soc_info *icnss_info,
612 struct pld_soc_info *info)
613 {
614 }
615 #endif
616
pld_ipci_get_soc_info(struct device * dev,struct pld_soc_info * info)617 int pld_ipci_get_soc_info(struct device *dev, struct pld_soc_info *info)
618 {
619 int errno;
620 struct icnss_soc_info icnss_info = {0};
621
622 if (!info || !dev)
623 return -ENODEV;
624
625 errno = icnss_get_soc_info(dev, &icnss_info);
626 if (errno)
627 return errno;
628
629 info->v_addr = icnss_info.v_addr;
630 info->p_addr = icnss_info.p_addr;
631 info->chip_id = icnss_info.chip_id;
632 info->chip_family = icnss_info.chip_family;
633 info->board_id = icnss_info.board_id;
634 info->soc_id = icnss_info.soc_id;
635 info->fw_version = icnss_info.fw_version;
636 strlcpy(info->fw_build_timestamp, icnss_info.fw_build_timestamp,
637 sizeof(info->fw_build_timestamp));
638 strlcpy(info->fw_build_id, icnss_info.fw_build_id,
639 sizeof(info->fw_build_id));
640
641 pld_ipci_populate_hw_cap_info(&icnss_info, info);
642
643 return 0;
644 }
645
646 /*
647 * pld_ipci_get_irq() - Get irq by ce_id
648 * @dev: device
649 * @ce_id: CE id for which irq is requested
650 *
651 * Return irq number.
652 *
653 * Return: irq number for success
654 * Non zero failure code for errors
655 */
pld_ipci_get_irq(struct device * dev,int ce_id)656 int pld_ipci_get_irq(struct device *dev, int ce_id)
657 {
658 uint32_t msi_data_start;
659 uint32_t msi_data_count;
660 uint32_t msi_irq_start;
661 uint32_t msi_data;
662 int ret;
663
664 ret = icnss_get_user_msi_assignment(dev, "CE", &msi_data_count,
665 &msi_data_start, &msi_irq_start);
666 if (ret)
667 return ret;
668
669 msi_data = (ce_id % msi_data_count) + msi_irq_start;
670 ret = icnss_get_msi_irq(dev, msi_data);
671
672 return ret;
673 }
674 #endif
675