xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/dispatcher/multibus.c (revision 97f44cd39e4ff816eaa1710279d28cf6b9e65ad9)
1 /*
2  * Copyright (c) 2016-2018, 2020 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* this file dispatches functions to bus specific definitions */
20 #include "hif_debug.h"
21 #include "hif.h"
22 #include "hif_main.h"
23 #include "hif_io32.h"
24 #include "multibus.h"
25 #include "dummy.h"
26 #if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) || \
27     defined(HIF_IPCI)
28 #include "ce_main.h"
29 #include "ce_api.h"
30 #include "ce_internal.h"
31 #endif
32 #include "htc_services.h"
33 #include "a_types.h"
34 #include "dummy.h"
35 #include "qdf_module.h"
36 
37 /**
38  * hif_initialize_default_ops() - initializes default operations values
39  *
40  * bus specific features should assign their dummy implementations here.
41  */
42 static void hif_initialize_default_ops(struct hif_softc *hif_sc)
43 {
44 	struct hif_bus_ops *bus_ops = &hif_sc->bus_ops;
45 
46 	/* must be filled in by hif_bus_open */
47 	bus_ops->hif_bus_close = NULL;
48 	/* dummy implementations */
49 	bus_ops->hif_display_stats =
50 		&hif_dummy_display_stats;
51 	bus_ops->hif_clear_stats =
52 		&hif_dummy_clear_stats;
53 	bus_ops->hif_set_bundle_mode = &hif_dummy_set_bundle_mode;
54 	bus_ops->hif_bus_reset_resume = &hif_dummy_bus_reset_resume;
55 	bus_ops->hif_bus_suspend_noirq = &hif_dummy_bus_suspend_noirq;
56 	bus_ops->hif_bus_resume_noirq = &hif_dummy_bus_resume_noirq;
57 	bus_ops->hif_bus_early_suspend = &hif_dummy_bus_suspend;
58 	bus_ops->hif_bus_late_resume = &hif_dummy_bus_resume;
59 	bus_ops->hif_map_ce_to_irq = &hif_dummy_map_ce_to_irq;
60 	bus_ops->hif_grp_irq_configure = &hif_dummy_grp_irq_configure;
61 	bus_ops->hif_config_irq_affinity =
62 		&hif_dummy_config_irq_affinity;
63 	bus_ops->hif_config_irq_by_ceid = &hif_dummy_config_irq_by_ceid;
64 }
65 
66 #define NUM_OPS (sizeof(struct hif_bus_ops) / sizeof(void *))
67 
68 /**
69  * hif_verify_basic_ops() - ensure required bus apis are defined
70  *
71  * all bus operations must be defined to avoid crashes
72  * itterate over the structure and ensure all function pointers
73  * are non null.
74  *
75  * Return: QDF_STATUS_SUCCESS if all the operations are defined
76  */
77 static QDF_STATUS hif_verify_basic_ops(struct hif_softc *hif_sc)
78 {
79 	struct hif_bus_ops *bus_ops = &hif_sc->bus_ops;
80 	void **ops_array = (void *)bus_ops;
81 	QDF_STATUS status = QDF_STATUS_SUCCESS;
82 	int i;
83 
84 	for (i = 0; i < NUM_OPS; i++) {
85 		if (!ops_array[i]) {
86 			hif_err("ops_array[%d] is null", i);
87 			status = QDF_STATUS_E_NOSUPPORT;
88 		}
89 	}
90 	return status;
91 }
92 
93 /**
94  * hif_bus_get_context_size - API to return size of the bus specific structure
95  *
96  * Return: sizeof of hif_pci_softc
97  */
98 int hif_bus_get_context_size(enum qdf_bus_type bus_type)
99 {
100 	switch (bus_type) {
101 	case QDF_BUS_TYPE_PCI:
102 		return hif_pci_get_context_size();
103 	case QDF_BUS_TYPE_IPCI:
104 		return hif_ipci_get_context_size();
105 	case QDF_BUS_TYPE_AHB:
106 		return hif_ahb_get_context_size();
107 	case QDF_BUS_TYPE_SNOC:
108 		return hif_snoc_get_context_size();
109 	case QDF_BUS_TYPE_SDIO:
110 		return hif_sdio_get_context_size();
111 	case QDF_BUS_TYPE_USB:
112 		return hif_usb_get_context_size();
113 	default:
114 		return 0;
115 	}
116 }
117 
118 /**
119  * hif_bus_open() - initialize the bus_ops and call the bus specific open
120  * hif_sc: hif_context
121  * bus_type: type of bus being enumerated
122  *
123  * Return: QDF_STATUS_SUCCESS or error
124  */
125 QDF_STATUS hif_bus_open(struct hif_softc *hif_sc,
126 			enum qdf_bus_type bus_type)
127 {
128 	QDF_STATUS status = QDF_STATUS_E_INVAL;
129 
130 	hif_initialize_default_ops(hif_sc);
131 
132 	switch (bus_type) {
133 	case QDF_BUS_TYPE_PCI:
134 		status = hif_initialize_pci_ops(hif_sc);
135 		break;
136 	case QDF_BUS_TYPE_IPCI:
137 		status = hif_initialize_ipci_ops(hif_sc);
138 		break;
139 	case QDF_BUS_TYPE_SNOC:
140 		status = hif_initialize_snoc_ops(&hif_sc->bus_ops);
141 		break;
142 	case QDF_BUS_TYPE_AHB:
143 		status = hif_initialize_ahb_ops(&hif_sc->bus_ops);
144 		break;
145 	case QDF_BUS_TYPE_SDIO:
146 		status = hif_initialize_sdio_ops(hif_sc);
147 		break;
148 	case QDF_BUS_TYPE_USB:
149 		status = hif_initialize_usb_ops(&hif_sc->bus_ops);
150 		break;
151 	default:
152 		status = QDF_STATUS_E_NOSUPPORT;
153 		break;
154 	}
155 
156 	if (status != QDF_STATUS_SUCCESS) {
157 		hif_err("bus_type: %d not supported", bus_type);
158 		return status;
159 	}
160 
161 	status = hif_verify_basic_ops(hif_sc);
162 	if (status != QDF_STATUS_SUCCESS)
163 		return status;
164 
165 	return hif_sc->bus_ops.hif_bus_open(hif_sc, bus_type);
166 }
167 
168 /**
169  * hif_bus_close() - close the bus
170  * @hif_sc: hif_context
171  */
172 void hif_bus_close(struct hif_softc *hif_sc)
173 {
174 	hif_sc->bus_ops.hif_bus_close(hif_sc);
175 }
176 
177 /**
178  * hif_bus_prevent_linkdown() - prevent linkdown
179  * @hif_ctx: hif context
180  * @flag: true = keep bus alive false = let bus go to sleep
181  *
182  * Keeps the bus awake durring suspend.
183  */
184 void hif_bus_prevent_linkdown(struct hif_softc *hif_sc, bool flag)
185 {
186 	hif_sc->bus_ops.hif_bus_prevent_linkdown(hif_sc, flag);
187 }
188 
189 
190 void hif_reset_soc(struct hif_opaque_softc *hif_ctx)
191 {
192 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
193 
194 	hif_sc->bus_ops.hif_reset_soc(hif_sc);
195 }
196 
197 int hif_bus_early_suspend(struct hif_opaque_softc *hif_ctx)
198 {
199 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
200 
201 	return hif_sc->bus_ops.hif_bus_early_suspend(hif_sc);
202 }
203 
204 int hif_bus_late_resume(struct hif_opaque_softc *hif_ctx)
205 {
206 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
207 
208 	return hif_sc->bus_ops.hif_bus_late_resume(hif_sc);
209 }
210 
211 int hif_bus_suspend(struct hif_opaque_softc *hif_ctx)
212 {
213 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
214 
215 	return hif_sc->bus_ops.hif_bus_suspend(hif_sc);
216 }
217 
218 int hif_bus_resume(struct hif_opaque_softc *hif_ctx)
219 {
220 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
221 
222 	return hif_sc->bus_ops.hif_bus_resume(hif_sc);
223 }
224 
225 int hif_bus_suspend_noirq(struct hif_opaque_softc *hif_ctx)
226 {
227 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
228 
229 	return hif_sc->bus_ops.hif_bus_suspend_noirq(hif_sc);
230 }
231 
232 int hif_bus_resume_noirq(struct hif_opaque_softc *hif_ctx)
233 {
234 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
235 
236 	return hif_sc->bus_ops.hif_bus_resume_noirq(hif_sc);
237 }
238 
239 int hif_target_sleep_state_adjust(struct hif_softc *hif_sc,
240 			      bool sleep_ok, bool wait_for_it)
241 {
242 	return hif_sc->bus_ops.hif_target_sleep_state_adjust(hif_sc,
243 			sleep_ok, wait_for_it);
244 }
245 qdf_export_symbol(hif_target_sleep_state_adjust);
246 
247 void hif_disable_isr(struct hif_opaque_softc *hif_hdl)
248 {
249 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
250 
251 	hif_sc->bus_ops.hif_disable_isr(hif_sc);
252 }
253 
254 void hif_nointrs(struct hif_softc *hif_sc)
255 {
256 	hif_sc->bus_ops.hif_nointrs(hif_sc);
257 }
258 
259 QDF_STATUS hif_enable_bus(struct hif_softc *hif_sc, struct device *dev,
260 			  void *bdev, const struct hif_bus_id *bid,
261 			  enum hif_enable_type type)
262 {
263 	return hif_sc->bus_ops.hif_enable_bus(hif_sc, dev, bdev, bid, type);
264 }
265 
266 void hif_disable_bus(struct hif_softc *hif_sc)
267 {
268 	hif_sc->bus_ops.hif_disable_bus(hif_sc);
269 }
270 
271 #ifdef FEATURE_RUNTIME_PM
272 struct hif_runtime_pm_ctx *hif_bus_get_rpm_ctx(struct hif_softc *hif_sc)
273 {
274 	return hif_sc->bus_ops.hif_bus_get_rpm_ctx(hif_sc);
275 }
276 
277 struct device *hif_bus_get_dev(struct hif_softc *hif_sc)
278 {
279 	return hif_sc->bus_ops.hif_bus_get_dev(hif_sc);
280 }
281 #endif
282 
283 int hif_bus_configure(struct hif_softc *hif_sc)
284 {
285 	return hif_sc->bus_ops.hif_bus_configure(hif_sc);
286 }
287 
288 QDF_STATUS hif_get_config_item(struct hif_opaque_softc *hif_ctx,
289 		     int opcode, void *config, uint32_t config_len)
290 {
291 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
292 
293 	return hif_sc->bus_ops.hif_get_config_item(hif_sc, opcode, config,
294 						 config_len);
295 }
296 
297 void hif_set_mailbox_swap(struct hif_opaque_softc *hif_ctx)
298 {
299 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
300 
301 	hif_sc->bus_ops.hif_set_mailbox_swap(hif_sc);
302 }
303 
304 void hif_claim_device(struct hif_opaque_softc *hif_ctx)
305 {
306 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
307 
308 	hif_sc->bus_ops.hif_claim_device(hif_sc);
309 }
310 
311 void hif_shutdown_device(struct hif_opaque_softc *hif_ctx)
312 {
313 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
314 
315 	hif_sc->bus_ops.hif_shutdown_device(hif_sc);
316 }
317 
318 void hif_stop(struct hif_opaque_softc *hif_ctx)
319 {
320 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
321 
322 	hif_sc->bus_ops.hif_stop(hif_sc);
323 }
324 
325 void hif_cancel_deferred_target_sleep(struct hif_softc *hif_sc)
326 {
327 	return hif_sc->bus_ops.hif_cancel_deferred_target_sleep(hif_sc);
328 }
329 
330 void hif_irq_enable(struct hif_softc *hif_sc, int irq_id)
331 {
332 	hif_sc->bus_ops.hif_irq_enable(hif_sc, irq_id);
333 }
334 qdf_export_symbol(hif_irq_enable);
335 
336 void hif_irq_disable(struct hif_softc *hif_sc, int irq_id)
337 {
338 	hif_sc->bus_ops.hif_irq_disable(hif_sc, irq_id);
339 }
340 
341 int hif_grp_irq_configure(struct hif_softc *hif_sc,
342 			  struct hif_exec_context *hif_exec)
343 {
344 	return hif_sc->bus_ops.hif_grp_irq_configure(hif_sc, hif_exec);
345 }
346 
347 int hif_dump_registers(struct hif_opaque_softc *hif_hdl)
348 {
349 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
350 
351 	return hif_sc->bus_ops.hif_dump_registers(hif_sc);
352 }
353 
354 void hif_dump_target_memory(struct hif_opaque_softc *hif_hdl,
355 			    void *ramdump_base,
356 			    uint32_t address, uint32_t size)
357 {
358 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
359 
360 	hif_sc->bus_ops.hif_dump_target_memory(hif_sc, ramdump_base,
361 					       address, size);
362 }
363 
364 void hif_ipa_get_ce_resource(struct hif_opaque_softc *hif_hdl,
365 			     qdf_shared_mem_t **ce_sr,
366 			     uint32_t *ce_sr_ring_size,
367 			     qdf_dma_addr_t *ce_reg_paddr)
368 {
369 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
370 
371 	hif_sc->bus_ops.hif_ipa_get_ce_resource(hif_sc, ce_sr,
372 			ce_sr_ring_size, ce_reg_paddr);
373 }
374 
375 void hif_mask_interrupt_call(struct hif_opaque_softc *hif_hdl)
376 {
377 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
378 
379 	hif_sc->bus_ops.hif_mask_interrupt_call(hif_sc);
380 }
381 
382 void hif_display_bus_stats(struct hif_opaque_softc *scn)
383 {
384 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
385 
386 	hif_sc->bus_ops.hif_display_stats(hif_sc);
387 }
388 
389 void hif_clear_bus_stats(struct hif_opaque_softc *scn)
390 {
391 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
392 
393 	hif_sc->bus_ops.hif_clear_stats(hif_sc);
394 }
395 
396 /**
397  * hif_enable_power_management() - enable power management after driver load
398  * @hif_hdl: opaque pointer to the hif context
399  * is_packet_log_enabled: true if packet log is enabled
400  *
401  * Driver load and firmware download are done in a high performance mode.
402  * Enable power management after the driver is loaded.
403  * packet log can require fewer power management features to be enabled.
404  */
405 void hif_enable_power_management(struct hif_opaque_softc *hif_hdl,
406 				 bool is_packet_log_enabled)
407 {
408 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
409 
410 	hif_sc->bus_ops.hif_enable_power_management(hif_sc,
411 				    is_packet_log_enabled);
412 }
413 
414 /**
415  * hif_disable_power_management() - reset the bus power management
416  * @hif_hdl: opaque pointer to the hif context
417  *
418  * return the power management of the bus to its default state.
419  * This isn't necessarily a complete reversal of its counterpart.
420  * This should be called when unloading the driver.
421  */
422 void hif_disable_power_management(struct hif_opaque_softc *hif_hdl)
423 {
424 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
425 
426 	hif_sc->bus_ops.hif_disable_power_management(hif_sc);
427 }
428 
429 /**
430  * hif_set_bundle_mode() - enable bundling and set default rx bundle cnt
431  * @scn: pointer to hif_opaque_softc structure
432  * @enabled: flag to enable/disable bundling
433  * @rx_bundle_cnt: bundle count to be used for RX
434  *
435  * Return: none
436  */
437 void hif_set_bundle_mode(struct hif_opaque_softc *scn, bool enabled,
438 				int rx_bundle_cnt)
439 {
440 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
441 
442 	hif_sc->bus_ops.hif_set_bundle_mode(hif_sc, enabled, rx_bundle_cnt);
443 }
444 
445 /**
446  * hif_bus_reset_resume() - resume the bus after reset
447  * @scn: struct hif_opaque_softc
448  *
449  * This function is called to tell the driver that USB device has been resumed
450  * and it has also been reset. The driver should redo any necessary
451  * initialization. This function resets WLAN SOC.
452  *
453  * Return: int 0 for success, non zero for failure
454  */
455 int hif_bus_reset_resume(struct hif_opaque_softc *scn)
456 {
457 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
458 
459 	return hif_sc->bus_ops.hif_bus_reset_resume(hif_sc);
460 }
461 
462 int hif_apps_irqs_disable(struct hif_opaque_softc *hif_ctx)
463 {
464 	struct hif_softc *scn;
465 	int i;
466 
467 	QDF_BUG(hif_ctx);
468 	scn = HIF_GET_SOFTC(hif_ctx);
469 	if (!scn)
470 		return -EINVAL;
471 
472 	/* if the wake_irq is shared, don't disable it twice */
473 	disable_irq(scn->wake_irq);
474 	for (i = 0; i < scn->ce_count; ++i) {
475 		int irq = scn->bus_ops.hif_map_ce_to_irq(scn, i);
476 
477 		if (irq != scn->wake_irq)
478 			disable_irq(irq);
479 	}
480 
481 	return 0;
482 }
483 
484 int hif_apps_irqs_enable(struct hif_opaque_softc *hif_ctx)
485 {
486 	struct hif_softc *scn;
487 	int i;
488 
489 	QDF_BUG(hif_ctx);
490 	scn = HIF_GET_SOFTC(hif_ctx);
491 	if (!scn)
492 		return -EINVAL;
493 
494 	/* if the wake_irq is shared, don't enable it twice */
495 	enable_irq(scn->wake_irq);
496 	for (i = 0; i < scn->ce_count; ++i) {
497 		int irq = scn->bus_ops.hif_map_ce_to_irq(scn, i);
498 
499 		if (irq != scn->wake_irq)
500 			enable_irq(irq);
501 	}
502 
503 	return 0;
504 }
505 
506 int hif_apps_wake_irq_disable(struct hif_opaque_softc *hif_ctx)
507 {
508 	struct hif_softc *scn;
509 
510 	QDF_BUG(hif_ctx);
511 	scn = HIF_GET_SOFTC(hif_ctx);
512 	if (!scn)
513 		return -EINVAL;
514 
515 	disable_irq(scn->wake_irq);
516 
517 	return 0;
518 }
519 
520 int hif_apps_wake_irq_enable(struct hif_opaque_softc *hif_ctx)
521 {
522 	struct hif_softc *scn;
523 
524 	QDF_BUG(hif_ctx);
525 	scn = HIF_GET_SOFTC(hif_ctx);
526 	if (!scn)
527 		return -EINVAL;
528 
529 	enable_irq(scn->wake_irq);
530 
531 	return 0;
532 }
533 
534 int hif_apps_disable_irq_wake(struct hif_opaque_softc *hif_ctx)
535 {
536 	struct hif_softc *scn;
537 
538 	QDF_BUG(hif_ctx);
539 	scn = HIF_GET_SOFTC(hif_ctx);
540 	if (!scn)
541 		return -EINVAL;
542 
543 	return disable_irq_wake(scn->wake_irq);
544 }
545 
546 int hif_apps_enable_irq_wake(struct hif_opaque_softc *hif_ctx)
547 {
548 	struct hif_softc *scn;
549 
550 	QDF_BUG(hif_ctx);
551 	scn = HIF_GET_SOFTC(hif_ctx);
552 	if (!scn)
553 		return -EINVAL;
554 
555 	return enable_irq_wake(scn->wake_irq);
556 }
557 
558 #ifdef WLAN_FEATURE_BMI
559 bool hif_needs_bmi(struct hif_opaque_softc *scn)
560 {
561 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
562 
563 	return hif_sc->bus_ops.hif_needs_bmi(hif_sc);
564 }
565 qdf_export_symbol(hif_needs_bmi);
566 #endif /* WLAN_FEATURE_BMI */
567 
568 void hif_config_irq_affinity(struct hif_softc *hif_sc)
569 {
570 	hif_sc->bus_ops.hif_config_irq_affinity(hif_sc);
571 }
572 
573 int hif_config_irq_by_ceid(struct hif_softc *hif_sc, int ce_id)
574 {
575 	return hif_sc->bus_ops.hif_config_irq_by_ceid(hif_sc, ce_id);
576 }
577 
578 #ifdef HIF_BUS_LOG_INFO
579 bool hif_log_bus_info(struct hif_softc *hif_sc, uint8_t *data,
580 		      unsigned int *offset)
581 {
582 	if (hif_sc->bus_ops.hif_log_bus_info)
583 		return hif_sc->bus_ops.hif_log_bus_info(hif_sc, data, offset);
584 
585 	return false;
586 }
587 #endif
588