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