xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/dispatcher/multibus.c (revision 45a38684b07295822dc8eba39e293408f203eec8)
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 }
64 
65 #define NUM_OPS (sizeof(struct hif_bus_ops) / sizeof(void *))
66 
67 /**
68  * hif_verify_basic_ops() - ensure required bus apis are defined
69  *
70  * all bus operations must be defined to avoid crashes
71  * itterate over the structure and ensure all function pointers
72  * are non null.
73  *
74  * Return: QDF_STATUS_SUCCESS if all the operations are defined
75  */
76 static QDF_STATUS hif_verify_basic_ops(struct hif_softc *hif_sc)
77 {
78 	struct hif_bus_ops *bus_ops = &hif_sc->bus_ops;
79 	void **ops_array = (void *)bus_ops;
80 	QDF_STATUS status = QDF_STATUS_SUCCESS;
81 	int i;
82 
83 	for (i = 0; i < NUM_OPS; i++) {
84 		if (!ops_array[i]) {
85 			HIF_ERROR("%s: function %d is null", __func__, i);
86 			status = QDF_STATUS_E_NOSUPPORT;
87 		}
88 	}
89 	return status;
90 }
91 
92 /**
93  * hif_bus_get_context_size - API to return size of the bus specific structure
94  *
95  * Return: sizeof of hif_pci_softc
96  */
97 int hif_bus_get_context_size(enum qdf_bus_type bus_type)
98 {
99 	switch (bus_type) {
100 	case QDF_BUS_TYPE_PCI:
101 		return hif_pci_get_context_size();
102 	case QDF_BUS_TYPE_IPCI:
103 		return hif_ipci_get_context_size();
104 	case QDF_BUS_TYPE_AHB:
105 		return hif_ahb_get_context_size();
106 	case QDF_BUS_TYPE_SNOC:
107 		return hif_snoc_get_context_size();
108 	case QDF_BUS_TYPE_SDIO:
109 		return hif_sdio_get_context_size();
110 	case QDF_BUS_TYPE_USB:
111 		return hif_usb_get_context_size();
112 	default:
113 		return 0;
114 	}
115 }
116 
117 /**
118  * hif_bus_open() - initialize the bus_ops and call the bus specific open
119  * hif_sc: hif_context
120  * bus_type: type of bus being enumerated
121  *
122  * Return: QDF_STATUS_SUCCESS or error
123  */
124 QDF_STATUS hif_bus_open(struct hif_softc *hif_sc,
125 			enum qdf_bus_type bus_type)
126 {
127 	QDF_STATUS status = QDF_STATUS_E_INVAL;
128 
129 	hif_initialize_default_ops(hif_sc);
130 
131 	switch (bus_type) {
132 	case QDF_BUS_TYPE_PCI:
133 		status = hif_initialize_pci_ops(hif_sc);
134 		break;
135 	case QDF_BUS_TYPE_IPCI:
136 		status = hif_initialize_ipci_ops(hif_sc);
137 		break;
138 	case QDF_BUS_TYPE_SNOC:
139 		status = hif_initialize_snoc_ops(&hif_sc->bus_ops);
140 		break;
141 	case QDF_BUS_TYPE_AHB:
142 		status = hif_initialize_ahb_ops(&hif_sc->bus_ops);
143 		break;
144 	case QDF_BUS_TYPE_SDIO:
145 		status = hif_initialize_sdio_ops(hif_sc);
146 		break;
147 	case QDF_BUS_TYPE_USB:
148 		status = hif_initialize_usb_ops(&hif_sc->bus_ops);
149 		break;
150 	default:
151 		status = QDF_STATUS_E_NOSUPPORT;
152 		break;
153 	}
154 
155 	if (status != QDF_STATUS_SUCCESS) {
156 		HIF_ERROR("%s: %d not supported", __func__, bus_type);
157 		return status;
158 	}
159 
160 	status = hif_verify_basic_ops(hif_sc);
161 	if (status != QDF_STATUS_SUCCESS)
162 		return status;
163 
164 	return hif_sc->bus_ops.hif_bus_open(hif_sc, bus_type);
165 }
166 
167 /**
168  * hif_bus_close() - close the bus
169  * @hif_sc: hif_context
170  */
171 void hif_bus_close(struct hif_softc *hif_sc)
172 {
173 	hif_sc->bus_ops.hif_bus_close(hif_sc);
174 }
175 
176 /**
177  * hif_bus_prevent_linkdown() - prevent linkdown
178  * @hif_ctx: hif context
179  * @flag: true = keep bus alive false = let bus go to sleep
180  *
181  * Keeps the bus awake durring suspend.
182  */
183 void hif_bus_prevent_linkdown(struct hif_softc *hif_sc, bool flag)
184 {
185 	hif_sc->bus_ops.hif_bus_prevent_linkdown(hif_sc, flag);
186 }
187 
188 
189 void hif_reset_soc(struct hif_opaque_softc *hif_ctx)
190 {
191 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
192 
193 	hif_sc->bus_ops.hif_reset_soc(hif_sc);
194 }
195 
196 int hif_bus_early_suspend(struct hif_opaque_softc *hif_ctx)
197 {
198 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
199 
200 	return hif_sc->bus_ops.hif_bus_early_suspend(hif_sc);
201 }
202 
203 int hif_bus_late_resume(struct hif_opaque_softc *hif_ctx)
204 {
205 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
206 
207 	return hif_sc->bus_ops.hif_bus_late_resume(hif_sc);
208 }
209 
210 int hif_bus_suspend(struct hif_opaque_softc *hif_ctx)
211 {
212 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
213 
214 	return hif_sc->bus_ops.hif_bus_suspend(hif_sc);
215 }
216 
217 int hif_bus_resume(struct hif_opaque_softc *hif_ctx)
218 {
219 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
220 
221 	return hif_sc->bus_ops.hif_bus_resume(hif_sc);
222 }
223 
224 int hif_bus_suspend_noirq(struct hif_opaque_softc *hif_ctx)
225 {
226 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
227 
228 	return hif_sc->bus_ops.hif_bus_suspend_noirq(hif_sc);
229 }
230 
231 int hif_bus_resume_noirq(struct hif_opaque_softc *hif_ctx)
232 {
233 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
234 
235 	return hif_sc->bus_ops.hif_bus_resume_noirq(hif_sc);
236 }
237 
238 int hif_target_sleep_state_adjust(struct hif_softc *hif_sc,
239 			      bool sleep_ok, bool wait_for_it)
240 {
241 	return hif_sc->bus_ops.hif_target_sleep_state_adjust(hif_sc,
242 			sleep_ok, wait_for_it);
243 }
244 qdf_export_symbol(hif_target_sleep_state_adjust);
245 
246 void hif_disable_isr(struct hif_opaque_softc *hif_hdl)
247 {
248 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
249 
250 	hif_sc->bus_ops.hif_disable_isr(hif_sc);
251 }
252 
253 void hif_nointrs(struct hif_softc *hif_sc)
254 {
255 	hif_sc->bus_ops.hif_nointrs(hif_sc);
256 }
257 
258 QDF_STATUS hif_enable_bus(struct hif_softc *hif_sc, struct device *dev,
259 			  void *bdev, const struct hif_bus_id *bid,
260 			  enum hif_enable_type type)
261 {
262 	return hif_sc->bus_ops.hif_enable_bus(hif_sc, dev, bdev, bid, type);
263 }
264 
265 void hif_disable_bus(struct hif_softc *hif_sc)
266 {
267 	hif_sc->bus_ops.hif_disable_bus(hif_sc);
268 }
269 
270 #ifdef FEATURE_RUNTIME_PM
271 struct hif_runtime_pm_ctx *hif_bus_get_rpm_ctx(struct hif_softc *hif_sc)
272 {
273 	return hif_sc->bus_ops.hif_bus_get_rpm_ctx(hif_sc);
274 }
275 
276 struct device *hif_bus_get_dev(struct hif_softc *hif_sc)
277 {
278 	return hif_sc->bus_ops.hif_bus_get_dev(hif_sc);
279 }
280 #endif
281 
282 int hif_bus_configure(struct hif_softc *hif_sc)
283 {
284 	return hif_sc->bus_ops.hif_bus_configure(hif_sc);
285 }
286 
287 QDF_STATUS hif_get_config_item(struct hif_opaque_softc *hif_ctx,
288 		     int opcode, void *config, uint32_t config_len)
289 {
290 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
291 
292 	return hif_sc->bus_ops.hif_get_config_item(hif_sc, opcode, config,
293 						 config_len);
294 }
295 
296 void hif_set_mailbox_swap(struct hif_opaque_softc *hif_ctx)
297 {
298 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
299 
300 	hif_sc->bus_ops.hif_set_mailbox_swap(hif_sc);
301 }
302 
303 void hif_claim_device(struct hif_opaque_softc *hif_ctx)
304 {
305 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
306 
307 	hif_sc->bus_ops.hif_claim_device(hif_sc);
308 }
309 
310 void hif_shutdown_device(struct hif_opaque_softc *hif_ctx)
311 {
312 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
313 
314 	hif_sc->bus_ops.hif_shutdown_device(hif_sc);
315 }
316 
317 void hif_stop(struct hif_opaque_softc *hif_ctx)
318 {
319 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
320 
321 	hif_sc->bus_ops.hif_stop(hif_sc);
322 }
323 
324 void hif_cancel_deferred_target_sleep(struct hif_softc *hif_sc)
325 {
326 	return hif_sc->bus_ops.hif_cancel_deferred_target_sleep(hif_sc);
327 }
328 
329 void hif_irq_enable(struct hif_softc *hif_sc, int irq_id)
330 {
331 	hif_sc->bus_ops.hif_irq_enable(hif_sc, irq_id);
332 }
333 qdf_export_symbol(hif_irq_enable);
334 
335 void hif_irq_disable(struct hif_softc *hif_sc, int irq_id)
336 {
337 	hif_sc->bus_ops.hif_irq_disable(hif_sc, irq_id);
338 }
339 
340 int hif_grp_irq_configure(struct hif_softc *hif_sc,
341 			  struct hif_exec_context *hif_exec)
342 {
343 	return hif_sc->bus_ops.hif_grp_irq_configure(hif_sc, hif_exec);
344 }
345 
346 int hif_dump_registers(struct hif_opaque_softc *hif_hdl)
347 {
348 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
349 
350 	return hif_sc->bus_ops.hif_dump_registers(hif_sc);
351 }
352 
353 void hif_dump_target_memory(struct hif_opaque_softc *hif_hdl,
354 			    void *ramdump_base,
355 			    uint32_t address, uint32_t size)
356 {
357 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
358 
359 	hif_sc->bus_ops.hif_dump_target_memory(hif_sc, ramdump_base,
360 					       address, size);
361 }
362 
363 void hif_ipa_get_ce_resource(struct hif_opaque_softc *hif_hdl,
364 			     qdf_shared_mem_t **ce_sr,
365 			     uint32_t *ce_sr_ring_size,
366 			     qdf_dma_addr_t *ce_reg_paddr)
367 {
368 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
369 
370 	hif_sc->bus_ops.hif_ipa_get_ce_resource(hif_sc, ce_sr,
371 			ce_sr_ring_size, ce_reg_paddr);
372 }
373 
374 void hif_mask_interrupt_call(struct hif_opaque_softc *hif_hdl)
375 {
376 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
377 
378 	hif_sc->bus_ops.hif_mask_interrupt_call(hif_sc);
379 }
380 
381 void hif_display_bus_stats(struct hif_opaque_softc *scn)
382 {
383 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
384 
385 	hif_sc->bus_ops.hif_display_stats(hif_sc);
386 }
387 
388 void hif_clear_bus_stats(struct hif_opaque_softc *scn)
389 {
390 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
391 
392 	hif_sc->bus_ops.hif_clear_stats(hif_sc);
393 }
394 
395 /**
396  * hif_enable_power_management() - enable power management after driver load
397  * @hif_hdl: opaque pointer to the hif context
398  * is_packet_log_enabled: true if packet log is enabled
399  *
400  * Driver load and firmware download are done in a high performance mode.
401  * Enable power management after the driver is loaded.
402  * packet log can require fewer power management features to be enabled.
403  */
404 void hif_enable_power_management(struct hif_opaque_softc *hif_hdl,
405 				 bool is_packet_log_enabled)
406 {
407 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
408 
409 	hif_sc->bus_ops.hif_enable_power_management(hif_sc,
410 				    is_packet_log_enabled);
411 }
412 
413 /**
414  * hif_disable_power_management() - reset the bus power management
415  * @hif_hdl: opaque pointer to the hif context
416  *
417  * return the power management of the bus to its default state.
418  * This isn't necessarily a complete reversal of its counterpart.
419  * This should be called when unloading the driver.
420  */
421 void hif_disable_power_management(struct hif_opaque_softc *hif_hdl)
422 {
423 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
424 
425 	hif_sc->bus_ops.hif_disable_power_management(hif_sc);
426 }
427 
428 /**
429  * hif_set_bundle_mode() - enable bundling and set default rx bundle cnt
430  * @scn: pointer to hif_opaque_softc structure
431  * @enabled: flag to enable/disable bundling
432  * @rx_bundle_cnt: bundle count to be used for RX
433  *
434  * Return: none
435  */
436 void hif_set_bundle_mode(struct hif_opaque_softc *scn, bool enabled,
437 				int rx_bundle_cnt)
438 {
439 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
440 
441 	hif_sc->bus_ops.hif_set_bundle_mode(hif_sc, enabled, rx_bundle_cnt);
442 }
443 
444 /**
445  * hif_bus_reset_resume() - resume the bus after reset
446  * @scn: struct hif_opaque_softc
447  *
448  * This function is called to tell the driver that USB device has been resumed
449  * and it has also been reset. The driver should redo any necessary
450  * initialization. This function resets WLAN SOC.
451  *
452  * Return: int 0 for success, non zero for failure
453  */
454 int hif_bus_reset_resume(struct hif_opaque_softc *scn)
455 {
456 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
457 
458 	return hif_sc->bus_ops.hif_bus_reset_resume(hif_sc);
459 }
460 
461 int hif_apps_irqs_disable(struct hif_opaque_softc *hif_ctx)
462 {
463 	struct hif_softc *scn;
464 	int i;
465 
466 	QDF_BUG(hif_ctx);
467 	scn = HIF_GET_SOFTC(hif_ctx);
468 	if (!scn)
469 		return -EINVAL;
470 
471 	/* if the wake_irq is shared, don't disable it twice */
472 	disable_irq(scn->wake_irq);
473 	for (i = 0; i < scn->ce_count; ++i) {
474 		int irq = scn->bus_ops.hif_map_ce_to_irq(scn, i);
475 
476 		if (irq != scn->wake_irq)
477 			disable_irq(irq);
478 	}
479 
480 	return 0;
481 }
482 
483 int hif_apps_irqs_enable(struct hif_opaque_softc *hif_ctx)
484 {
485 	struct hif_softc *scn;
486 	int i;
487 
488 	QDF_BUG(hif_ctx);
489 	scn = HIF_GET_SOFTC(hif_ctx);
490 	if (!scn)
491 		return -EINVAL;
492 
493 	/* if the wake_irq is shared, don't enable it twice */
494 	enable_irq(scn->wake_irq);
495 	for (i = 0; i < scn->ce_count; ++i) {
496 		int irq = scn->bus_ops.hif_map_ce_to_irq(scn, i);
497 
498 		if (irq != scn->wake_irq)
499 			enable_irq(irq);
500 	}
501 
502 	return 0;
503 }
504 
505 int hif_apps_wake_irq_disable(struct hif_opaque_softc *hif_ctx)
506 {
507 	struct hif_softc *scn;
508 
509 	QDF_BUG(hif_ctx);
510 	scn = HIF_GET_SOFTC(hif_ctx);
511 	if (!scn)
512 		return -EINVAL;
513 
514 	disable_irq(scn->wake_irq);
515 
516 	return 0;
517 }
518 
519 int hif_apps_wake_irq_enable(struct hif_opaque_softc *hif_ctx)
520 {
521 	struct hif_softc *scn;
522 
523 	QDF_BUG(hif_ctx);
524 	scn = HIF_GET_SOFTC(hif_ctx);
525 	if (!scn)
526 		return -EINVAL;
527 
528 	enable_irq(scn->wake_irq);
529 
530 	return 0;
531 }
532 
533 int hif_apps_disable_irq_wake(struct hif_opaque_softc *hif_ctx)
534 {
535 	struct hif_softc *scn;
536 
537 	QDF_BUG(hif_ctx);
538 	scn = HIF_GET_SOFTC(hif_ctx);
539 	if (!scn)
540 		return -EINVAL;
541 
542 	return disable_irq_wake(scn->wake_irq);
543 }
544 
545 int hif_apps_enable_irq_wake(struct hif_opaque_softc *hif_ctx)
546 {
547 	struct hif_softc *scn;
548 
549 	QDF_BUG(hif_ctx);
550 	scn = HIF_GET_SOFTC(hif_ctx);
551 	if (!scn)
552 		return -EINVAL;
553 
554 	return enable_irq_wake(scn->wake_irq);
555 }
556 
557 #ifdef WLAN_FEATURE_BMI
558 bool hif_needs_bmi(struct hif_opaque_softc *scn)
559 {
560 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
561 
562 	return hif_sc->bus_ops.hif_needs_bmi(hif_sc);
563 }
564 qdf_export_symbol(hif_needs_bmi);
565 #endif /* WLAN_FEATURE_BMI */
566 
567 void hif_config_irq_affinity(struct hif_softc *hif_sc)
568 {
569 	hif_sc->bus_ops.hif_config_irq_affinity(hif_sc);
570 }
571