blob: 0c69dbfe73af06b33307b0bf4683da5c5b022226 [file] [log] [blame]
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001/*
Houston Hoffmancceec342015-11-11 11:37:20 -08002 * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08003 *
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#include <osdep.h>
29#include "a_types.h"
30#include "athdefs.h"
31#include "osapi_linux.h"
32#include "targcfg.h"
33#include "cdf_lock.h"
34#include "cdf_status.h"
35#include <cdf_atomic.h> /* cdf_atomic_read */
36#include <targaddrs.h>
37#include <bmi_msg.h>
38#include "hif_io32.h"
39#include <hif.h>
40#include <htc_services.h>
41#include "regtable.h"
42#define ATH_MODULE_NAME hif
43#include <a_debug.h>
44#include "hif_main.h"
45#include "hif_hw_version.h"
46#include "ce_api.h"
47#include "ce_tasklet.h"
48#include "cdf_trace.h"
49#include "cdf_status.h"
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080050#ifdef CONFIG_CNSS
51#include <net/cnss.h>
52#endif
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080053#include "epping_main.h"
54#include "hif_debug.h"
55#include "mp_dev.h"
56#ifdef HIF_PCI
57#include "icnss_stub.h"
58#else
59#include <soc/qcom/icnss.h>
60#endif
61
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080062#define AGC_DUMP 1
63#define CHANINFO_DUMP 2
64#define BB_WATCHDOG_DUMP 3
65#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
66#define PCIE_ACCESS_DUMP 4
67#endif
68
Komal Seelam5584a7c2016-02-24 19:22:48 +053069void hif_dump(struct hif_opaque_softc *hif_ctx, uint8_t cmd_id, bool start)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080070{
Komal Seelam644263d2016-02-22 20:45:49 +053071 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080072 switch (cmd_id) {
73 case AGC_DUMP:
74 if (start)
75 priv_start_agc(scn);
76 else
77 priv_dump_agc(scn);
78 break;
79
80 case CHANINFO_DUMP:
81 if (start)
82 priv_start_cap_chaninfo(scn);
83 else
84 priv_dump_chaninfo(scn);
85 break;
86
87 case BB_WATCHDOG_DUMP:
88 priv_dump_bbwatchdog(scn);
89 break;
90
91#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
92 case PCIE_ACCESS_DUMP:
93 hif_target_dump_access_log();
94 break;
95#endif
96 default:
97 HIF_ERROR("%s: Invalid htc dump command", __func__);
98 break;
99 }
100}
101
102/**
103 * hif_shut_down_device() - hif_shut_down_device
104 *
105 * SThis fucntion shuts down the device
106 *
Komal Seelam5584a7c2016-02-24 19:22:48 +0530107 * @scn: hif_opaque_softc
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800108 *
109 * Return: void
110 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530111void hif_shut_down_device(struct hif_opaque_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800112{
Komal Seelam02cf2f82016-02-22 20:44:25 +0530113 hif_stop(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800114}
115
116
117
118/**
119 * hif_cancel_deferred_target_sleep() - cancel deferred target sleep
120 *
121 * This function cancels the defered target sleep
122 *
Komal Seelam5584a7c2016-02-24 19:22:48 +0530123 * @scn: hif_opaque_softc
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800124 *
125 * Return: void
126 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530127void hif_cancel_deferred_target_sleep(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800128{
Komal Seelam644263d2016-02-22 20:45:49 +0530129 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
130
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800131 hif_pci_cancel_deferred_target_sleep(scn);
132}
133
134/**
135 * hif_get_target_id(): hif_get_target_id
136 *
137 * Return the virtual memory base address to the caller
138 *
Komal Seelam644263d2016-02-22 20:45:49 +0530139 * @scn: hif_softc
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800140 *
141 * Return: A_target_id_t
142 */
Komal Seelam644263d2016-02-22 20:45:49 +0530143A_target_id_t hif_get_target_id(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800144{
145 return scn->mem;
146}
147
148/**
149 * hif_set_target_sleep(): hif_set_target_sleep
150 * @scn: scn
151 * @sleep_ok: sleep_ok
152 * @wait_for_it: wait
153 *
154 * Return: void
155 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530156void hif_set_target_sleep(struct hif_opaque_softc *hif_ctx,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800157 bool sleep_ok, bool wait_for_it)
158{
Komal Seelam644263d2016-02-22 20:45:49 +0530159 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800160 hif_target_sleep_state_adjust(scn,
161 sleep_ok, wait_for_it);
162}
163
164/**
165 * hif_target_forced_awake(): hif_target_forced_awake
166 * @scn: scn
167 *
168 * Return: bool
169 */
Komal Seelam644263d2016-02-22 20:45:49 +0530170bool hif_target_forced_awake(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800171{
172 A_target_id_t addr = scn->mem;
173 bool awake;
174 bool forced_awake;
175
176 awake = hif_targ_is_awake(scn, addr);
177
178 forced_awake =
179 !!(hif_read32_mb
180 (addr + PCIE_LOCAL_BASE_ADDRESS +
181 PCIE_SOC_WAKE_ADDRESS) & PCIE_SOC_WAKE_V_MASK);
182
183 return awake && forced_awake;
184}
185
Houston Hoffman0dad5092015-09-28 16:25:51 -0700186
187static inline void hif_fw_event_handler(struct HIF_CE_state *hif_state)
188{
189 struct hif_msg_callbacks *msg_callbacks =
190 &hif_state->msg_callbacks_current;
191
192 if (!msg_callbacks->fwEventHandler)
193 return;
194
195 msg_callbacks->fwEventHandler(msg_callbacks->Context,
196 CDF_STATUS_E_FAILURE);
197}
198
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800199/**
200 * hif_fw_interrupt_handler(): FW interrupt handler
201 *
202 * This function is the FW interrupt handlder
203 *
204 * @irq: irq number
205 * @arg: the user pointer
206 *
207 * Return: bool
208 */
209#ifndef QCA_WIFI_3_0
210irqreturn_t hif_fw_interrupt_handler(int irq, void *arg)
211{
Komal Seelam644263d2016-02-22 20:45:49 +0530212 struct hif_softc *scn = arg;
Komal Seelam02cf2f82016-02-22 20:44:25 +0530213 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800214 uint32_t fw_indicator_address, fw_indicator;
215
216 A_TARGET_ACCESS_BEGIN_RET(scn);
217
218 fw_indicator_address = hif_state->fw_indicator_address;
219 /* For sudden unplug this will return ~0 */
220 fw_indicator = A_TARGET_READ(scn, fw_indicator_address);
221
222 if ((fw_indicator != ~0) && (fw_indicator & FW_IND_EVENT_PENDING)) {
223 /* ACK: clear Target-side pending event */
224 A_TARGET_WRITE(scn, fw_indicator_address,
225 fw_indicator & ~FW_IND_EVENT_PENDING);
226 A_TARGET_ACCESS_END_RET(scn);
227
228 if (hif_state->started) {
Houston Hoffman0dad5092015-09-28 16:25:51 -0700229 hif_fw_event_handler(hif_state);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800230 } else {
231 /*
232 * Probable Target failure before we're prepared
233 * to handle it. Generally unexpected.
234 */
235 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
236 ("%s: Early firmware event indicated\n",
237 __func__));
238 }
239 } else {
240 A_TARGET_ACCESS_END_RET(scn);
241 }
242
243 return ATH_ISR_SCHED;
244}
245#else
246irqreturn_t hif_fw_interrupt_handler(int irq, void *arg)
247{
248 return ATH_ISR_SCHED;
249}
250#endif /* #ifdef QCA_WIFI_3_0 */
251
252/**
253 * hif_get_targetdef(): hif_get_targetdef
254 * @scn: scn
255 *
256 * Return: void *
257 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530258void *hif_get_targetdef(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800259{
Komal Seelam644263d2016-02-22 20:45:49 +0530260 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
261
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800262 return scn->targetdef;
263}
264
265/**
266 * hif_vote_link_down(): unvote for link up
267 *
268 * Call hif_vote_link_down to release a previous request made using
269 * hif_vote_link_up. A hif_vote_link_down call should only be made
270 * after a corresponding hif_vote_link_up, otherwise you could be
271 * negating a vote from another source. When no votes are present
272 * hif will not guarantee the linkstate after hif_bus_suspend.
273 *
274 * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread
275 * and initialization deinitialization sequencences.
276 *
277 * Return: n/a
278 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530279void hif_vote_link_down(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800280{
Komal Seelam644263d2016-02-22 20:45:49 +0530281 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800282 CDF_BUG(scn);
283
284 scn->linkstate_vote--;
285 if (scn->linkstate_vote == 0)
Houston Hoffmancceec342015-11-11 11:37:20 -0800286 hif_bus_prevent_linkdown(scn, false);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800287}
288
289/**
290 * hif_vote_link_up(): vote to prevent bus from suspending
291 *
292 * Makes hif guarantee that fw can message the host normally
293 * durring suspend.
294 *
295 * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread
296 * and initialization deinitialization sequencences.
297 *
298 * Return: n/a
299 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530300void hif_vote_link_up(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800301{
Komal Seelam644263d2016-02-22 20:45:49 +0530302 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800303 CDF_BUG(scn);
304
305 scn->linkstate_vote++;
306 if (scn->linkstate_vote == 1)
Houston Hoffmancceec342015-11-11 11:37:20 -0800307 hif_bus_prevent_linkdown(scn, true);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800308}
309
310/**
311 * hif_can_suspend_link(): query if hif is permitted to suspend the link
312 *
313 * Hif will ensure that the link won't be suspended if the upperlayers
314 * don't want it to.
315 *
316 * SYNCHRONIZATION: MC thread is stopped before bus suspend thus
317 * we don't need extra locking to ensure votes dont change while
318 * we are in the process of suspending or resuming.
319 *
320 * Return: false if hif will guarantee link up durring suspend.
321 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530322bool hif_can_suspend_link(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800323{
Komal Seelam644263d2016-02-22 20:45:49 +0530324 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800325 CDF_BUG(scn);
326
327 return scn->linkstate_vote == 0;
328}
329
330/**
331 * hif_hia_item_address(): hif_hia_item_address
332 * @target_type: target_type
333 * @item_offset: item_offset
334 *
335 * Return: n/a
336 */
337uint32_t hif_hia_item_address(uint32_t target_type, uint32_t item_offset)
338{
339 switch (target_type) {
340 case TARGET_TYPE_AR6002:
341 return AR6002_HOST_INTEREST_ADDRESS + item_offset;
342 case TARGET_TYPE_AR6003:
343 return AR6003_HOST_INTEREST_ADDRESS + item_offset;
344 case TARGET_TYPE_AR6004:
345 return AR6004_HOST_INTEREST_ADDRESS + item_offset;
346 case TARGET_TYPE_AR6006:
347 return AR6006_HOST_INTEREST_ADDRESS + item_offset;
348 case TARGET_TYPE_AR9888:
349 return AR9888_HOST_INTEREST_ADDRESS + item_offset;
350 case TARGET_TYPE_AR6320:
351 case TARGET_TYPE_AR6320V2:
352 return AR6320_HOST_INTEREST_ADDRESS + item_offset;
353 case TARGET_TYPE_QCA6180:
354 return QCA6180_HOST_INTEREST_ADDRESS + item_offset;
355 case TARGET_TYPE_ADRASTEA:
356 /* ADRASTEA doesn't have a host interest address */
357 ASSERT(0);
358 return 0;
359 default:
360 ASSERT(0);
361 return 0;
362 }
363}
364
365/**
366 * hif_max_num_receives_reached() - check max receive is reached
Komal Seelambd7c51d2016-02-24 10:27:30 +0530367 * @scn: HIF Context
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800368 * @count: unsigned int.
369 *
370 * Output check status as bool
371 *
372 * Return: bool
373 */
Komal Seelambd7c51d2016-02-24 10:27:30 +0530374bool hif_max_num_receives_reached(struct hif_softc *scn, unsigned int count)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800375{
Komal Seelambd7c51d2016-02-24 10:27:30 +0530376 if (WLAN_IS_EPPING_ENABLED(hif_get_conparam(scn)))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800377 return count > 120;
378 else
379 return count > MAX_NUM_OF_RECEIVES;
380}
381
382/**
383 * init_buffer_count() - initial buffer count
384 * @maxSize: cdf_size_t
385 *
386 * routine to modify the initial buffer count to be allocated on an os
387 * platform basis. Platform owner will need to modify this as needed
388 *
389 * Return: cdf_size_t
390 */
391cdf_size_t init_buffer_count(cdf_size_t maxSize)
392{
393 return maxSize;
394}
395
396/**
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800397 * hif_save_htc_htt_config_endpoint():
398 * hif_save_htc_htt_config_endpoint
399 * @htc_endpoint: htc_endpoint
400 *
401 * Return: void
402 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530403void hif_save_htc_htt_config_endpoint(struct hif_opaque_softc *hif_ctx,
404 int htc_endpoint)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800405{
Komal Seelam644263d2016-02-22 20:45:49 +0530406 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800407
408 if (!scn) {
409 HIF_ERROR("%s: error: scn or scn->hif_sc is NULL!",
410 __func__);
411 return;
412 }
413
414 scn->htc_endpoint = htc_endpoint;
415}
416
417/**
418 * hif_get_hw_name(): get a human readable name for the hardware
Komal Seelam91553ce2016-01-27 18:57:10 +0530419 * @info: Target Info
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800420 *
Komal Seelam91553ce2016-01-27 18:57:10 +0530421 * Return: human readable name for the underlying wifi hardware.
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800422 */
Komal Seelam91553ce2016-01-27 18:57:10 +0530423static const char *hif_get_hw_name(struct hif_target_info *info)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800424{
425 int i;
Komal Seelam91553ce2016-01-27 18:57:10 +0530426
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800427 for (i = 0; i < ARRAY_SIZE(qwlan_hw_list); i++) {
Komal Seelam91553ce2016-01-27 18:57:10 +0530428 if (info->target_version == qwlan_hw_list[i].id &&
429 info->target_revision == qwlan_hw_list[i].subid) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800430 return qwlan_hw_list[i].name;
431 }
432 }
433
434 return "Unknown Device";
435}
436
437/**
438 * hif_get_hw_info(): hif_get_hw_info
439 * @scn: scn
440 * @version: version
441 * @revision: revision
442 *
443 * Return: n/a
444 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530445void hif_get_hw_info(struct hif_opaque_softc *scn, u32 *version, u32 *revision,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800446 const char **target_name)
447{
Komal Seelam91553ce2016-01-27 18:57:10 +0530448 struct hif_target_info *info = hif_get_target_info_handle(scn);
449 *version = info->target_version;
450 *revision = info->target_revision;
451 *target_name = hif_get_hw_name(info);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800452}
453
454/**
455 * hif_open(): hif_open
Komal Seelambd7c51d2016-02-24 10:27:30 +0530456 * @cdf_ctx: CDF Context
457 * @mode: Driver Mode
458 * @bus_type: Bus Type
459 * @cbk: CDS Callbacks
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800460 *
Komal Seelambd7c51d2016-02-24 10:27:30 +0530461 * API to open HIF Context
462 *
463 * Return: HIF Opaque Pointer
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800464 */
Komal Seelambd7c51d2016-02-24 10:27:30 +0530465struct hif_opaque_softc *hif_open(cdf_device_t cdf_ctx, uint32_t mode,
466 enum ath_hal_bus_type bus_type,
467 struct hif_callbacks *cbk)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800468{
Komal Seelam644263d2016-02-22 20:45:49 +0530469 struct hif_softc *scn;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800470 CDF_STATUS status = CDF_STATUS_SUCCESS;
Komal Seelam43301de2016-02-02 18:20:48 +0530471 int bus_context_size = hif_bus_get_context_size();
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800472
Komal Seelambd7c51d2016-02-24 10:27:30 +0530473 scn = (struct hif_softc *)cdf_mem_malloc(bus_context_size);
474 if (!scn) {
475 HIF_ERROR("%s: cannot alloc memory for HIF context of size:%d",
476 __func__, bus_context_size);
477 return GET_HIF_OPAQUE_HDL(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800478 }
479
Komal Seelam43301de2016-02-02 18:20:48 +0530480 cdf_mem_zero(scn, bus_context_size);
Komal Seelambd7c51d2016-02-24 10:27:30 +0530481
Komal Seelamf8600682016-02-02 18:17:13 +0530482 scn->cdf_dev = cdf_ctx;
Komal Seelambd7c51d2016-02-24 10:27:30 +0530483 scn->hif_con_param = mode;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800484 cdf_atomic_init(&scn->active_tasklet_cnt);
485 cdf_atomic_init(&scn->link_suspended);
486 cdf_atomic_init(&scn->tasklet_from_intr);
Komal Seelambd7c51d2016-02-24 10:27:30 +0530487 cdf_mem_copy(&scn->callbacks, cbk, sizeof(struct hif_callbacks));
Houston Hoffman3cfe6862016-01-08 10:33:55 -0800488
489 status = hif_bus_open(scn, bus_type);
490 if (status != CDF_STATUS_SUCCESS) {
491 HIF_ERROR("%s: hif_bus_open error = %d, bus_type = %d",
492 __func__, status, bus_type);
Komal Seelambd7c51d2016-02-24 10:27:30 +0530493 cdf_mem_free(scn);
494 scn = NULL;
Houston Hoffman3cfe6862016-01-08 10:33:55 -0800495 }
496
Komal Seelambd7c51d2016-02-24 10:27:30 +0530497 return GET_HIF_OPAQUE_HDL(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800498}
499
500/**
501 * hif_close(): hif_close
502 * @hif_ctx: hif_ctx
503 *
504 * Return: n/a
505 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530506void hif_close(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800507{
Komal Seelam644263d2016-02-22 20:45:49 +0530508 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800509
510 if (scn == NULL) {
Komal Seelam5584a7c2016-02-24 19:22:48 +0530511 HIF_ERROR("%s: hif_opaque_softc is NULL", __func__);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800512 return;
513 }
514
515 if (scn->athdiag_procfs_inited) {
516 athdiag_procfs_remove();
517 scn->athdiag_procfs_inited = false;
518 }
519
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800520 hif_bus_close(scn);
Komal Seelambd7c51d2016-02-24 10:27:30 +0530521 cdf_mem_free(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800522}
523
524/**
525 * hif_enable(): hif_enable
526 * @hif_ctx: hif_ctx
527 * @dev: dev
528 * @bdev: bus dev
529 * @bid: bus ID
530 * @bus_type: bus type
531 * @type: enable type
532 *
533 * Return: CDF_STATUS
534 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530535CDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800536 void *bdev, const hif_bus_id *bid,
537 enum ath_hal_bus_type bus_type,
538 enum hif_enable_type type)
539{
540 CDF_STATUS status;
Komal Seelam644263d2016-02-22 20:45:49 +0530541 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800542
543 if (scn == NULL) {
544 HIF_ERROR("%s: hif_ctx = NULL", __func__);
545 return CDF_STATUS_E_NULL_VALUE;
546 }
547
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800548 status = hif_enable_bus(scn, dev, bdev, bid, type);
549 if (status != CDF_STATUS_SUCCESS) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800550 HIF_ERROR("%s: hif_enable_bus error = %d",
551 __func__, status);
552 return status;
553 }
554
555 if (ADRASTEA_BU)
Komal Seelamf8600682016-02-02 18:17:13 +0530556 hif_vote_link_up(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800557
558 if (hif_config_ce(scn)) {
559 HIF_ERROR("%s: Target probe failed.", __func__);
Vishwajith Upendra3f78aa62016-02-09 17:53:02 +0530560 hif_disable_bus(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800561 status = CDF_STATUS_E_FAILURE;
562 return status;
563 }
564 /*
565 * Flag to avoid potential unallocated memory access from MSI
566 * interrupt handler which could get scheduled as soon as MSI
567 * is enabled, i.e to take care of the race due to the order
568 * in where MSI is enabled before the memory, that will be
569 * in interrupt handlers, is allocated.
570 */
571
572#ifdef HIF_PCI
Komal Seelam644263d2016-02-22 20:45:49 +0530573 status = hif_configure_irq(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800574 if (status < 0) {
575 HIF_ERROR("%s: ERROR - configure_IRQ_and_CE failed, status = %d",
576 __func__, status);
577 return CDF_STATUS_E_FAILURE;
578 }
579#endif
580
581 scn->hif_init_done = true;
582
583 HIF_TRACE("%s: X OK", __func__);
584
585 return CDF_STATUS_SUCCESS;
586}
587
588/**
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800589 * hif_wlan_disable(): call the platform driver to disable wlan
Komal Seelambd7c51d2016-02-24 10:27:30 +0530590 * @scn: HIF Context
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800591 *
592 * This function passes the con_mode to platform driver to disable
593 * wlan.
594 *
595 * Return: void
596 */
Komal Seelambd7c51d2016-02-24 10:27:30 +0530597void hif_wlan_disable(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800598{
599 enum icnss_driver_mode mode;
Komal Seelambd7c51d2016-02-24 10:27:30 +0530600 uint32_t con_mode = hif_get_conparam(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800601
Peng Xu7b962532015-10-02 17:17:03 -0700602 if (CDF_GLOBAL_FTM_MODE == con_mode)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800603 mode = ICNSS_FTM;
Komal Seelambd7c51d2016-02-24 10:27:30 +0530604 else if (WLAN_IS_EPPING_ENABLED(con_mode))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800605 mode = ICNSS_EPPING;
Peng Xu7b962532015-10-02 17:17:03 -0700606 else
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800607 mode = ICNSS_MISSION;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800608
609 icnss_wlan_disable(mode);
610}
611
Komal Seelam5584a7c2016-02-24 19:22:48 +0530612void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800613{
Komal Seelam644263d2016-02-22 20:45:49 +0530614 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800615
616 if (!scn)
617 return;
618
619 hif_nointrs(scn);
620 if (scn->hif_init_done == false)
Komal Seelam644263d2016-02-22 20:45:49 +0530621 hif_shut_down_device(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800622 else
Komal Seelam644263d2016-02-22 20:45:49 +0530623 hif_stop(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800624
625 if (ADRASTEA_BU)
Komal Seelamf8600682016-02-02 18:17:13 +0530626 hif_vote_link_down(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800627
Vishwajith Upendra3f78aa62016-02-09 17:53:02 +0530628 hif_disable_bus(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800629
Komal Seelambd7c51d2016-02-24 10:27:30 +0530630 hif_wlan_disable(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800631
632 scn->notice_send = false;
633
634 HIF_INFO("%s: X", __func__);
635}
636
637
638/**
Govind Singh2443fb32016-01-13 17:44:48 +0530639 * hif_crash_shutdown_dump_bus_register() - dump bus registers
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800640 * @hif_ctx: hif_ctx
641 *
642 * Return: n/a
643 */
644#if defined(TARGET_RAMDUMP_AFTER_KERNEL_PANIC) \
645&& defined(HIF_PCI) && defined(DEBUG)
646
Govind Singh2443fb32016-01-13 17:44:48 +0530647static void hif_crash_shutdown_dump_bus_register(void *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800648{
Komal Seelam5584a7c2016-02-24 19:22:48 +0530649 struct hif_opaque_softc *scn = hif_ctx;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800650
Govind Singh2443fb32016-01-13 17:44:48 +0530651 if (hif_check_soc_status(scn))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800652 return;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800653
Govind Singh2443fb32016-01-13 17:44:48 +0530654 if (hif_dump_registers(scn))
655 HIF_ERROR("Failed to dump bus registers!");
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800656}
657
658/**
659 * hif_crash_shutdown(): hif_crash_shutdown
660 *
661 * This function is called by the platform driver to dump CE registers
662 *
663 * @hif_ctx: hif_ctx
664 *
665 * Return: n/a
666 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530667void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800668{
Komal Seelam644263d2016-02-22 20:45:49 +0530669 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Komal Seelam02cf2f82016-02-22 20:44:25 +0530670 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800671
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800672 if (!hif_state)
673 return;
674
675
676 if (OL_TRGET_STATUS_RESET == scn->target_status) {
677 HIF_INFO_MED("%s: Target is already asserted, ignore!",
678 __func__);
679 return;
680 }
681
Komal Seelambd7c51d2016-02-24 10:27:30 +0530682 if (hif_is_load_or_unload_in_progress(scn)) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800683 HIF_ERROR("%s: Load/unload is in progress, ignore!", __func__);
684 return;
685 }
686
Govind Singh2443fb32016-01-13 17:44:48 +0530687 hif_crash_shutdown_dump_bus_register(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800688
Komal Seelam644263d2016-02-22 20:45:49 +0530689 if (ol_copy_ramdump(hif_ctx))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800690 goto out;
691
692 HIF_INFO_MED("%s: RAM dump collecting completed!", __func__);
693
694out:
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800695 return;
696}
697#else
Komal Seelam5584a7c2016-02-24 19:22:48 +0530698void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800699{
700 HIF_INFO_MED("%s: Collecting target RAM dump disabled",
701 __func__);
702 return;
703}
704#endif /* TARGET_RAMDUMP_AFTER_KERNEL_PANIC */
705
706#ifdef QCA_WIFI_3_0
707/**
708 * hif_check_fw_reg(): hif_check_fw_reg
709 * @scn: scn
710 * @state:
711 *
712 * Return: int
713 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530714int hif_check_fw_reg(struct hif_opaque_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800715{
716 return 0;
717}
718#endif
719
720#ifdef IPA_OFFLOAD
721/**
722 * hif_read_phy_mem_base(): hif_read_phy_mem_base
723 * @scn: scn
724 * @phy_mem_base: physical mem base
725 *
726 * Return: n/a
727 */
Komal Seelam644263d2016-02-22 20:45:49 +0530728void hif_read_phy_mem_base(struct hif_softc *scn, cdf_dma_addr_t *phy_mem_base)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800729{
730 *phy_mem_base = scn->mem_pa;
731}
732#endif /* IPA_OFFLOAD */
733
734/**
735 * hif_get_device_type(): hif_get_device_type
736 * @device_id: device_id
737 * @revision_id: revision_id
738 * @hif_type: returned hif_type
739 * @target_type: returned target_type
740 *
741 * Return: int
742 */
743int hif_get_device_type(uint32_t device_id,
744 uint32_t revision_id,
745 uint32_t *hif_type, uint32_t *target_type)
746{
747 int ret = 0;
748
749 switch (device_id) {
750#ifdef QCA_WIFI_3_0_ADRASTEA
751 case ADRASTEA_DEVICE_ID:
752 case ADRASTEA_DEVICE_ID_P2_E12:
753
754 *hif_type = HIF_TYPE_ADRASTEA;
755 *target_type = TARGET_TYPE_ADRASTEA;
756 break;
757#else
758 case QCA6180_DEVICE_ID:
759 *hif_type = HIF_TYPE_QCA6180;
760 *target_type = TARGET_TYPE_QCA6180;
761 break;
762#endif
763
764 case AR9888_DEVICE_ID:
765 *hif_type = HIF_TYPE_AR9888;
766 *target_type = TARGET_TYPE_AR9888;
767 break;
768
769 case AR6320_DEVICE_ID:
770 switch (revision_id) {
771 case AR6320_FW_1_1:
772 case AR6320_FW_1_3:
773 *hif_type = HIF_TYPE_AR6320;
774 *target_type = TARGET_TYPE_AR6320;
775 break;
776
777 case AR6320_FW_2_0:
778 case AR6320_FW_3_0:
779 case AR6320_FW_3_2:
780 *hif_type = HIF_TYPE_AR6320V2;
781 *target_type = TARGET_TYPE_AR6320V2;
782 break;
783
784 default:
785 HIF_ERROR("%s: error - dev_id = 0x%x, rev_id = 0x%x",
786 __func__, device_id, revision_id);
787 ret = -ENODEV;
788 goto end;
789 }
790 break;
791
792 default:
793 HIF_ERROR("%s: Unsupported device ID!", __func__);
794 ret = -ENODEV;
795 break;
796 }
797end:
798 return ret;
799}
Komal Seelam91553ce2016-01-27 18:57:10 +0530800
801/**
802 * Target info and ini parameters are global to the driver
803 * Hence these structures are exposed to all the modules in
804 * the driver and they don't need to maintains multiple copies
805 * of the same info, instead get the handle from hif and
806 * modify them in hif
807 */
808
809/**
810 * hif_get_ini_handle() - API to get hif_config_param handle
Komal Seelam644263d2016-02-22 20:45:49 +0530811 * @hif_ctx: HIF Context
Komal Seelam91553ce2016-01-27 18:57:10 +0530812 *
813 * Return: pointer to hif_config_info
814 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530815struct hif_config_info *hif_get_ini_handle(struct hif_opaque_softc *hif_ctx)
Komal Seelam91553ce2016-01-27 18:57:10 +0530816{
Komal Seelam644263d2016-02-22 20:45:49 +0530817 struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx);
818
819 return &sc->hif_config;
Komal Seelam91553ce2016-01-27 18:57:10 +0530820}
821
822/**
823 * hif_get_target_info_handle() - API to get hif_target_info handle
Komal Seelam644263d2016-02-22 20:45:49 +0530824 * @hif_ctx: HIF context
Komal Seelam91553ce2016-01-27 18:57:10 +0530825 *
826 * Return: Pointer to hif_target_info
827 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530828struct hif_target_info *hif_get_target_info_handle(
829 struct hif_opaque_softc *hif_ctx)
Komal Seelam91553ce2016-01-27 18:57:10 +0530830{
Komal Seelam644263d2016-02-22 20:45:49 +0530831 struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx);
832
833 return &sc->target_info;
834
Komal Seelam91553ce2016-01-27 18:57:10 +0530835}
Komal Seelamc92a0cf2016-02-22 20:43:52 +0530836
837#if defined(FEATURE_LRO)
838/**
839 * hif_lro_flush_cb_register - API to register for LRO Flush Callback
840 * @scn: HIF Context
841 * @handler: Function pointer to be called by HIF
842 * @data: Private data to be used by the module registering to HIF
843 *
844 * Return: void
845 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530846void hif_lro_flush_cb_register(struct hif_opaque_softc *scn,
847 void (handler)(void *), void *data)
Komal Seelamc92a0cf2016-02-22 20:43:52 +0530848{
849 ce_lro_flush_cb_register(scn, handler, data);
850}
851
852/**
853 * hif_lro_flush_cb_deregister - API to deregister for LRO Flush Callbacks
854 * @scn: HIF Context
855 *
856 * Return: void
857 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530858void hif_lro_flush_cb_deregister(struct hif_opaque_softc *scn)
Komal Seelamc92a0cf2016-02-22 20:43:52 +0530859{
860 ce_lro_flush_cb_deregister(scn);
861}
862#endif
Komal Seelam644263d2016-02-22 20:45:49 +0530863
864/**
865 * hif_get_target_status - API to get target status
866 * @hif_ctx: HIF Context
867 *
868 * Return: enum ol_target_status
869 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530870ol_target_status hif_get_target_status(struct hif_opaque_softc *hif_ctx)
Komal Seelam644263d2016-02-22 20:45:49 +0530871{
872 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
873
874 return scn->target_status;
875}
876
877/**
Komal Seelama5911d32016-02-24 19:21:59 +0530878 * hif_set_target_status() - API to set target status
Komal Seelam644263d2016-02-22 20:45:49 +0530879 * @hif_ctx: HIF Context
880 * @status: Target Status
881 *
882 * Return: void
883 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530884void hif_set_target_status(struct hif_opaque_softc *hif_ctx,
885 ol_target_status status)
Komal Seelam644263d2016-02-22 20:45:49 +0530886{
887 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
888
889 scn->target_status = status;
890}
Komal Seelama5911d32016-02-24 19:21:59 +0530891
892/**
893 * hif_init_ini_config() - API to initialize HIF configuration parameters
894 * @hif_ctx: HIF Context
895 * @cfg: HIF Configuration
896 *
897 * Return: void
898 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530899void hif_init_ini_config(struct hif_opaque_softc *hif_ctx,
900 struct hif_config_info *cfg)
Komal Seelama5911d32016-02-24 19:21:59 +0530901{
902 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
903
904 cdf_mem_copy(&scn->hif_config, cfg, sizeof(struct hif_config_info));
905}
Komal Seelambd7c51d2016-02-24 10:27:30 +0530906
907/**
908 * hif_get_conparam() - API to get driver mode in HIF
909 * @scn: HIF Context
910 *
911 * Return: driver mode of operation
912 */
913uint32_t hif_get_conparam(struct hif_softc *scn)
914{
915 if (!scn)
916 return 0;
917
918 return scn->hif_con_param;
919}
920
921/**
922 * hif_get_callbacks_handle() - API to get callbacks Handle
923 * @scn: HIF Context
924 *
925 * Return: pointer to HIF Callbacks
926 */
927struct hif_callbacks *hif_get_callbacks_handle(struct hif_softc *scn)
928{
929 return &scn->callbacks;
930}
931
932/**
933 * hif_is_driver_unloading() - API to query upper layers if driver is unloading
934 * @scn: HIF Context
935 *
936 * Return: True/False
937 */
938bool hif_is_driver_unloading(struct hif_softc *scn)
939{
940 struct hif_callbacks *cbk = hif_get_callbacks_handle(scn);
941
942 if (cbk && cbk->is_driver_unloading)
943 return cbk->is_driver_unloading(cbk->context);
944
945 return false;
946}
947
948/**
949 * hif_is_load_or_unload_in_progress() - API to query upper layers if
950 * load/unload in progress
951 * @scn: HIF Context
952 *
953 * Return: True/False
954 */
955bool hif_is_load_or_unload_in_progress(struct hif_softc *scn)
956{
957 struct hif_callbacks *cbk = hif_get_callbacks_handle(scn);
958
959 if (cbk && cbk->is_load_unload_in_progress)
960 return cbk->is_load_unload_in_progress(cbk->context);
961
962 return false;
963}
964
965/**
966 * hif_is_recovery_in_progress() - API to query upper layers if recovery in
967 * progress
968 * @scn: HIF Context
969 *
970 * Return: True/False
971 */
972bool hif_is_recovery_in_progress(struct hif_softc *scn)
973{
974 struct hif_callbacks *cbk = hif_get_callbacks_handle(scn);
975
976 if (cbk && cbk->is_recovery_in_progress)
977 return cbk->is_recovery_in_progress(cbk->context);
978
979 return false;
980}