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