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