blob: 05f938507a477545095685e5312000c1f2c86088 [file] [log] [blame]
Houston Hoffman32bc8eb2016-03-14 21:11:34 -07001/*
Yu Wang1e487a52017-02-07 20:10:42 +08002 * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
Houston Hoffman32bc8eb2016-03-14 21:11:34 -07003 *
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"
Jeff Johnson6950fdb2016-10-07 13:00:59 -070033#include "hif_io32.h"
Houston Hoffman32bc8eb2016-03-14 21:11:34 -070034#include "multibus.h"
Mohit Khanna1957ba92016-05-11 11:17:01 -070035#include "dummy.h"
Nirav Shah3573f952016-05-12 18:37:03 +053036#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB)
Houston Hoffman162164c2016-03-14 21:12:10 -070037#include "ce_main.h"
Dustin Brown6834d322017-03-20 15:02:48 -070038#include "ce_api.h"
39#include "ce_internal.h"
Nirav Shah3573f952016-05-12 18:37:03 +053040#endif
Komal Seelam6ee55902016-04-11 17:11:07 +053041#include "htc_services.h"
42#include "a_types.h"
Nirav Shahb70bd732016-05-25 14:31:51 +053043#include "dummy.h"
44
Houston Hoffman32bc8eb2016-03-14 21:11:34 -070045/**
46 * hif_intialize_default_ops() - intializes default operations values
47 *
48 * bus specific features should assign their dummy implementations here.
49 */
50static void hif_intialize_default_ops(struct hif_softc *hif_sc)
51{
52 struct hif_bus_ops *bus_ops = &hif_sc->bus_ops;
53
54 /* must be filled in by hif_bus_open */
55 bus_ops->hif_bus_close = NULL;
Houston Hoffman32bc8eb2016-03-14 21:11:34 -070056 /* dummy implementations */
Nirav Shahb70bd732016-05-25 14:31:51 +053057 bus_ops->hif_display_stats =
58 &hif_dummy_display_stats;
59 bus_ops->hif_clear_stats =
60 &hif_dummy_clear_stats;
Houston Hoffman7fdff0c2016-08-29 12:31:58 -070061 bus_ops->hif_set_bundle_mode = &hif_dummy_set_bundle_mode;
62 bus_ops->hif_bus_reset_resume = &hif_dummy_bus_reset_resume;
63 bus_ops->hif_bus_suspend_noirq = &hif_dummy_bus_suspend_noirq;
64 bus_ops->hif_bus_resume_noirq = &hif_dummy_bus_resume_noirq;
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +053065 bus_ops->hif_grp_irq_disable = &hif_dummy_grp_irq_disable;
66 bus_ops->hif_grp_irq_enable = &hif_dummy_grp_irq_enable;
Houston Hoffman32bc8eb2016-03-14 21:11:34 -070067}
68
69#define NUM_OPS (sizeof(struct hif_bus_ops) / sizeof(void *))
70
71/**
72 * hif_verify_basic_ops() - ensure required bus apis are defined
73 *
74 * all bus operations must be defined to avoid crashes
75 * itterate over the structure and ensure all function pointers
76 * are non null.
77 *
78 * Return: QDF_STATUS_SUCCESS if all the operations are defined
79 */
80static QDF_STATUS hif_verify_basic_ops(struct hif_softc *hif_sc)
81{
82 struct hif_bus_ops *bus_ops = &hif_sc->bus_ops;
83 void **ops_array = (void *)bus_ops;
84 QDF_STATUS status = QDF_STATUS_SUCCESS;
85 int i;
86
87 for (i = 0; i < NUM_OPS; i++) {
88 if (!ops_array[i]) {
89 HIF_ERROR("%s: function %d is null", __func__, i);
90 status = QDF_STATUS_E_NOSUPPORT;
91 }
92 }
93 return status;
94}
95
96/**
Houston Hoffman162164c2016-03-14 21:12:10 -070097 * hif_bus_get_context_size - API to return size of the bus specific structure
98 *
99 * Return: sizeof of hif_pci_softc
100 */
101int hif_bus_get_context_size(enum qdf_bus_type bus_type)
102{
103 switch (bus_type) {
104 case QDF_BUS_TYPE_PCI:
105 return hif_pci_get_context_size();
Houston Hoffman3db96a42016-05-05 19:54:39 -0700106 case QDF_BUS_TYPE_AHB:
107 return hif_ahb_get_context_size();
Houston Hoffman162164c2016-03-14 21:12:10 -0700108 case QDF_BUS_TYPE_SNOC:
109 return hif_snoc_get_context_size();
Nirav Shah3573f952016-05-12 18:37:03 +0530110 case QDF_BUS_TYPE_SDIO:
111 return hif_sdio_get_context_size();
Mohit Khanna1957ba92016-05-11 11:17:01 -0700112 case QDF_BUS_TYPE_USB:
113 return hif_usb_get_context_size();
Houston Hoffman162164c2016-03-14 21:12:10 -0700114 default:
115 return 0;
116 }
117}
118
119/**
Houston Hoffman32bc8eb2016-03-14 21:11:34 -0700120 * hif_bus_open() - initialize the bus_ops and call the bus specific open
121 * hif_sc: hif_context
122 * bus_type: type of bus being enumerated
123 *
124 * Return: QDF_STATUS_SUCCESS or error
125 */
126QDF_STATUS hif_bus_open(struct hif_softc *hif_sc,
127 enum qdf_bus_type bus_type)
128{
129 QDF_STATUS status = QDF_STATUS_E_INVAL;
130
131 hif_intialize_default_ops(hif_sc);
132
133 switch (bus_type) {
134 case QDF_BUS_TYPE_PCI:
Houston Hoffman54ef87d2016-03-14 21:11:58 -0700135 status = hif_initialize_pci_ops(hif_sc);
Houston Hoffman32bc8eb2016-03-14 21:11:34 -0700136 break;
137 case QDF_BUS_TYPE_SNOC:
138 status = hif_initialize_snoc_ops(&hif_sc->bus_ops);
139 break;
Houston Hoffman3db96a42016-05-05 19:54:39 -0700140 case QDF_BUS_TYPE_AHB:
141 status = hif_initialize_ahb_ops(&hif_sc->bus_ops);
142 break;
Nirav Shah3573f952016-05-12 18:37:03 +0530143 case QDF_BUS_TYPE_SDIO:
144 status = hif_initialize_sdio_ops(hif_sc);
Yu Wang1e487a52017-02-07 20:10:42 +0800145 break;
Mohit Khanna1957ba92016-05-11 11:17:01 -0700146 case QDF_BUS_TYPE_USB:
147 status = hif_initialize_usb_ops(&hif_sc->bus_ops);
Nirav Shah3573f952016-05-12 18:37:03 +0530148 break;
Houston Hoffman32bc8eb2016-03-14 21:11:34 -0700149 default:
150 status = QDF_STATUS_E_NOSUPPORT;
151 break;
152 }
153
154 if (status != QDF_STATUS_SUCCESS) {
155 HIF_ERROR("%s: %d not supported", __func__, bus_type);
156 return status;
157 }
158
159 status = hif_verify_basic_ops(hif_sc);
160 if (status != QDF_STATUS_SUCCESS)
161 return status;
162
163 return hif_sc->bus_ops.hif_bus_open(hif_sc, bus_type);
164}
165
166/**
167 * hif_bus_close() - close the bus
168 * @hif_sc: hif_context
169 */
170void hif_bus_close(struct hif_softc *hif_sc)
171{
172 hif_sc->bus_ops.hif_bus_close(hif_sc);
173}
Houston Hoffman4ca03b62016-03-14 21:11:51 -0700174
175/**
176 * hif_bus_prevent_linkdown() - prevent linkdown
177 * @hif_ctx: hif context
178 * @flag: true = keep bus alive false = let bus go to sleep
179 *
180 * Keeps the bus awake durring suspend.
181 */
182void hif_bus_prevent_linkdown(struct hif_softc *hif_sc, bool flag)
183{
184 hif_sc->bus_ops.hif_bus_prevent_linkdown(hif_sc, flag);
185}
186
187
188void hif_reset_soc(struct hif_opaque_softc *hif_ctx)
189{
190 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
191 hif_sc->bus_ops.hif_reset_soc(hif_sc);
192}
193
194int hif_bus_suspend(struct hif_opaque_softc *hif_ctx)
195{
196 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
197 return hif_sc->bus_ops.hif_bus_suspend(hif_sc);
198}
199
200int hif_bus_resume(struct hif_opaque_softc *hif_ctx)
201{
202 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
203 return hif_sc->bus_ops.hif_bus_resume(hif_sc);
204}
205
Houston Hoffman7fdff0c2016-08-29 12:31:58 -0700206int hif_bus_suspend_noirq(struct hif_opaque_softc *hif_ctx)
207{
208 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
209 return hif_sc->bus_ops.hif_bus_suspend_noirq(hif_sc);
210}
211
212int hif_bus_resume_noirq(struct hif_opaque_softc *hif_ctx)
213{
214 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
215 return hif_sc->bus_ops.hif_bus_resume_noirq(hif_sc);
216}
217
Houston Hoffman4ca03b62016-03-14 21:11:51 -0700218int hif_target_sleep_state_adjust(struct hif_softc *hif_sc,
219 bool sleep_ok, bool wait_for_it)
220{
221 return hif_sc->bus_ops.hif_target_sleep_state_adjust(hif_sc,
222 sleep_ok, wait_for_it);
223}
Houston Hoffman8f239f62016-03-14 21:12:05 -0700224
225void hif_disable_isr(struct hif_opaque_softc *hif_hdl)
226{
227 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
228 hif_sc->bus_ops.hif_disable_isr(hif_sc);
229}
230
231void hif_nointrs(struct hif_softc *hif_sc)
232{
233 hif_sc->bus_ops.hif_nointrs(hif_sc);
234}
235
236QDF_STATUS hif_enable_bus(struct hif_softc *hif_sc, struct device *dev,
237 void *bdev, const hif_bus_id *bid,
238 enum hif_enable_type type)
239{
240 return hif_sc->bus_ops.hif_enable_bus(hif_sc, dev, bdev, bid, type);
241}
242
243void hif_disable_bus(struct hif_softc *hif_sc)
244{
245 hif_sc->bus_ops.hif_disable_bus(hif_sc);
246}
247
248int hif_bus_configure(struct hif_softc *hif_sc)
249{
250 return hif_sc->bus_ops.hif_bus_configure(hif_sc);
251}
252
Nirav Shah3573f952016-05-12 18:37:03 +0530253QDF_STATUS hif_get_config_item(struct hif_opaque_softc *hif_ctx,
254 int opcode, void *config, uint32_t config_len)
255{
256 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
257 return hif_sc->bus_ops.hif_get_config_item(hif_sc, opcode, config,
258 config_len);
259}
260
261void hif_set_mailbox_swap(struct hif_opaque_softc *hif_ctx)
262{
263 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
264 hif_sc->bus_ops.hif_set_mailbox_swap(hif_sc);
265}
266
267void hif_claim_device(struct hif_opaque_softc *hif_ctx)
268{
269 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
270 hif_sc->bus_ops.hif_claim_device(hif_sc);
271}
272
273void hif_shutdown_device(struct hif_opaque_softc *hif_ctx)
274{
275 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
276 hif_sc->bus_ops.hif_shutdown_device(hif_sc);
277}
278
279void hif_stop(struct hif_opaque_softc *hif_ctx)
280{
281 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
282 hif_sc->bus_ops.hif_stop(hif_sc);
283}
284
Nirav Shah3573f952016-05-12 18:37:03 +0530285void hif_cancel_deferred_target_sleep(struct hif_softc *hif_sc)
286{
287 return hif_sc->bus_ops.hif_cancel_deferred_target_sleep(hif_sc);
288}
289
Houston Hoffman8f239f62016-03-14 21:12:05 -0700290void hif_irq_enable(struct hif_softc *hif_sc, int irq_id)
291{
292 hif_sc->bus_ops.hif_irq_enable(hif_sc, irq_id);
293}
294
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530295void hif_grp_irq_enable(struct hif_softc *hif_sc, uint32_t grp_id)
296{
297 hif_sc->bus_ops.hif_grp_irq_enable(hif_sc, grp_id);
298}
299
Houston Hoffman8f239f62016-03-14 21:12:05 -0700300void hif_irq_disable(struct hif_softc *hif_sc, int irq_id)
301{
302 hif_sc->bus_ops.hif_irq_disable(hif_sc, irq_id);
303}
Houston Hoffman3c017e72016-03-14 21:12:11 -0700304
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530305void hif_grp_irq_disable(struct hif_softc *hif_sc, uint32_t grp_id)
306{
307 hif_sc->bus_ops.hif_grp_irq_disable(hif_sc, grp_id);
308}
309
Houston Hoffman3c017e72016-03-14 21:12:11 -0700310int hif_dump_registers(struct hif_opaque_softc *hif_hdl)
311{
312 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
313 return hif_sc->bus_ops.hif_dump_registers(hif_sc);
314}
Houston Hoffmanb4149dd2016-03-23 15:55:41 -0700315
Nirav Shah3573f952016-05-12 18:37:03 +0530316void hif_dump_target_memory(struct hif_opaque_softc *hif_hdl,
317 void *ramdump_base,
318 uint32_t address, uint32_t size)
319{
320 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
321 hif_sc->bus_ops.hif_dump_target_memory(hif_sc, ramdump_base,
322 address, size);
323}
324
325void hif_ipa_get_ce_resource(struct hif_opaque_softc *hif_hdl,
326 qdf_dma_addr_t *ce_sr_base_paddr,
327 uint32_t *ce_sr_ring_size,
328 qdf_dma_addr_t *ce_reg_paddr)
329{
330 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
331 hif_sc->bus_ops.hif_ipa_get_ce_resource(hif_sc, ce_sr_base_paddr,
332 ce_sr_ring_size, ce_reg_paddr);
333}
334
335void hif_mask_interrupt_call(struct hif_opaque_softc *hif_hdl)
336{
337 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
338 hif_sc->bus_ops.hif_mask_interrupt_call(hif_sc);
339}
340
Nirav Shahb70bd732016-05-25 14:31:51 +0530341void hif_display_bus_stats(struct hif_opaque_softc *scn)
342{
343 struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
344
345 hif_sc->bus_ops.hif_display_stats(hif_sc);
346}
347
348void hif_clear_bus_stats(struct hif_opaque_softc *scn)
349{
350 struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
351
352 hif_sc->bus_ops.hif_clear_stats(hif_sc);
353}
354
Houston Hoffmanb4149dd2016-03-23 15:55:41 -0700355/**
356 * hif_enable_power_management() - enable power management after driver load
357 * @hif_hdl: opaque pointer to the hif context
358 * is_packet_log_enabled: true if packet log is enabled
359 *
360 * Driver load and firmware download are done in a high performance mode.
361 * Enable power management after the driver is loaded.
362 * packet log can require fewer power management features to be enabled.
363 */
364void hif_enable_power_management(struct hif_opaque_softc *hif_hdl,
365 bool is_packet_log_enabled)
366{
367 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
368 hif_sc->bus_ops.hif_enable_power_management(hif_sc,
369 is_packet_log_enabled);
370}
371
372/**
373 * hif_disable_power_management() - reset the bus power management
374 * @hif_hdl: opaque pointer to the hif context
375 *
376 * return the power management of the bus to its default state.
377 * This isn't necessarily a complete reversal of its counterpart.
378 * This should be called when unloading the driver.
379 */
380void hif_disable_power_management(struct hif_opaque_softc *hif_hdl)
381{
382 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
383 hif_sc->bus_ops.hif_disable_power_management(hif_sc);
384}
385
Mohit Khanna1957ba92016-05-11 11:17:01 -0700386/**
387 * hif_set_bundle_mode() - enable bundling and set default rx bundle cnt
388 * @scn: pointer to hif_opaque_softc structure
389 * @enabled: flag to enable/disable bundling
390 * @rx_bundle_cnt: bundle count to be used for RX
391 *
392 * Return: none
393 */
394void hif_set_bundle_mode(struct hif_opaque_softc *scn, bool enabled,
395 int rx_bundle_cnt)
396{
397 struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
398 hif_sc->bus_ops.hif_set_bundle_mode(hif_sc, enabled, rx_bundle_cnt);
399}
400
401/**
402 * hif_bus_reset_resume() - resume the bus after reset
403 * @scn: struct hif_opaque_softc
404 *
405 * This function is called to tell the driver that USB device has been resumed
406 * and it has also been reset. The driver should redo any necessary
407 * initialization. This function resets WLAN SOC.
408 *
409 * Return: int 0 for success, non zero for failure
410 */
411int hif_bus_reset_resume(struct hif_opaque_softc *scn)
412
413{
414 struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
415 return hif_sc->bus_ops.hif_bus_reset_resume(hif_sc);
416}
Dustin Brown6834d322017-03-20 15:02:48 -0700417
418int hif_apps_irqs_disable(struct hif_opaque_softc *hif_ctx)
419{
420 struct hif_softc *scn;
421 int i;
422
423 scn = HIF_GET_SOFTC(hif_ctx);
424 if (!scn) {
425 QDF_BUG(0);
426 return -EINVAL;
427 }
428
429 for (i = 0; i < scn->ce_count; ++i)
430 disable_irq(scn->bus_ops.hif_map_ce_to_irq(scn, i));
431
432 return 0;
433}
434
435int hif_apps_irqs_enable(struct hif_opaque_softc *hif_ctx)
436{
437 struct hif_softc *scn;
438 int i;
439
440 scn = HIF_GET_SOFTC(hif_ctx);
441 if (!scn) {
442 QDF_BUG(0);
443 return -EINVAL;
444 }
445
446 for (i = 0; i < scn->ce_count; ++i)
447 enable_irq(scn->bus_ops.hif_map_ce_to_irq(scn, i));
448
449 return 0;
450}
451
452int hif_apps_wake_irq_disable(struct hif_opaque_softc *hif_ctx)
453{
454 int errno;
455 struct hif_softc *scn;
456 uint8_t wake_ce_id;
457
458 scn = HIF_GET_SOFTC(hif_ctx);
459 if (!scn) {
460 QDF_BUG(0);
461 return -EINVAL;
462 }
463
464 errno = hif_get_wake_ce_id(scn, &wake_ce_id);
465 if (errno) {
466 HIF_ERROR("%s: failed to get wake CE Id: %d", __func__, errno);
467 return errno;
468 }
469
470 disable_irq(scn->bus_ops.hif_map_ce_to_irq(scn, wake_ce_id));
471
472 return 0;
473}
474
475int hif_apps_wake_irq_enable(struct hif_opaque_softc *hif_ctx)
476{
477 int errno;
478 struct hif_softc *scn;
479 uint8_t wake_ce_id;
480
481 scn = HIF_GET_SOFTC(hif_ctx);
482 if (!scn) {
483 QDF_BUG(0);
484 return -EINVAL;
485 }
486
487 errno = hif_get_wake_ce_id(scn, &wake_ce_id);
488 if (errno) {
489 HIF_ERROR("%s: failed to get wake CE Id: %d", __func__, errno);
490 return errno;
491 }
492
493 enable_irq(scn->bus_ops.hif_map_ce_to_irq(scn, wake_ce_id));
494
495 return 0;
496}