blob: db8b6ad36ac736feaec52c3b59d525b9417ee2d5 [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"
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +053033#include "qdf_lock.h"
34#include "qdf_status.h"
35#include "qdf_status.h"
36#include <qdf_atomic.h> /* qdf_atomic_read */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080037#include <targaddrs.h>
38#include <bmi_msg.h>
39#include "hif_io32.h"
40#include <hif.h>
41#include <htc_services.h>
42#include "regtable.h"
43#define ATH_MODULE_NAME hif
44#include <a_debug.h>
45#include "hif_main.h"
46#include "hif_hw_version.h"
47#include "ce_api.h"
48#include "ce_tasklet.h"
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +053049#include "qdf_trace.h"
50#include "qdf_status.h"
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080051#ifdef CONFIG_CNSS
52#include <net/cnss.h>
53#endif
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080054#include "epping_main.h"
55#include "hif_debug.h"
56#include "mp_dev.h"
57#ifdef HIF_PCI
58#include "icnss_stub.h"
59#else
60#include <soc/qcom/icnss.h>
61#endif
62
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080063#define AGC_DUMP 1
64#define CHANINFO_DUMP 2
65#define BB_WATCHDOG_DUMP 3
66#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
67#define PCIE_ACCESS_DUMP 4
68#endif
69
Komal Seelam5584a7c2016-02-24 19:22:48 +053070void hif_dump(struct hif_opaque_softc *hif_ctx, uint8_t cmd_id, bool start)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080071{
Komal Seelam644263d2016-02-22 20:45:49 +053072 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080073 switch (cmd_id) {
74 case AGC_DUMP:
75 if (start)
76 priv_start_agc(scn);
77 else
78 priv_dump_agc(scn);
79 break;
80
81 case CHANINFO_DUMP:
82 if (start)
83 priv_start_cap_chaninfo(scn);
84 else
85 priv_dump_chaninfo(scn);
86 break;
87
88 case BB_WATCHDOG_DUMP:
89 priv_dump_bbwatchdog(scn);
90 break;
91
92#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
93 case PCIE_ACCESS_DUMP:
94 hif_target_dump_access_log();
95 break;
96#endif
97 default:
98 HIF_ERROR("%s: Invalid htc dump command", __func__);
99 break;
100 }
101}
102
103/**
104 * hif_shut_down_device() - hif_shut_down_device
105 *
106 * SThis fucntion shuts down the device
107 *
Komal Seelam5584a7c2016-02-24 19:22:48 +0530108 * @scn: hif_opaque_softc
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800109 *
110 * Return: void
111 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530112void hif_shut_down_device(struct hif_opaque_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800113{
Komal Seelam02cf2f82016-02-22 20:44:25 +0530114 hif_stop(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800115}
116
117
118
119/**
120 * hif_cancel_deferred_target_sleep() - cancel deferred target sleep
121 *
122 * This function cancels the defered target sleep
123 *
Komal Seelam5584a7c2016-02-24 19:22:48 +0530124 * @scn: hif_opaque_softc
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800125 *
126 * Return: void
127 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530128void hif_cancel_deferred_target_sleep(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800129{
Komal Seelam644263d2016-02-22 20:45:49 +0530130 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
131
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800132 hif_pci_cancel_deferred_target_sleep(scn);
133}
134
135/**
136 * hif_get_target_id(): hif_get_target_id
137 *
138 * Return the virtual memory base address to the caller
139 *
Komal Seelam644263d2016-02-22 20:45:49 +0530140 * @scn: hif_softc
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800141 *
142 * Return: A_target_id_t
143 */
Komal Seelam644263d2016-02-22 20:45:49 +0530144A_target_id_t hif_get_target_id(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800145{
146 return scn->mem;
147}
148
149/**
150 * hif_set_target_sleep(): hif_set_target_sleep
151 * @scn: scn
152 * @sleep_ok: sleep_ok
153 * @wait_for_it: wait
154 *
155 * Return: void
156 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530157void hif_set_target_sleep(struct hif_opaque_softc *hif_ctx,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800158 bool sleep_ok, bool wait_for_it)
159{
Komal Seelam644263d2016-02-22 20:45:49 +0530160 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800161 hif_target_sleep_state_adjust(scn,
162 sleep_ok, wait_for_it);
163}
164
165/**
166 * hif_target_forced_awake(): hif_target_forced_awake
167 * @scn: scn
168 *
169 * Return: bool
170 */
Komal Seelam644263d2016-02-22 20:45:49 +0530171bool hif_target_forced_awake(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800172{
173 A_target_id_t addr = scn->mem;
174 bool awake;
175 bool forced_awake;
176
177 awake = hif_targ_is_awake(scn, addr);
178
179 forced_awake =
180 !!(hif_read32_mb
181 (addr + PCIE_LOCAL_BASE_ADDRESS +
182 PCIE_SOC_WAKE_ADDRESS) & PCIE_SOC_WAKE_V_MASK);
183
184 return awake && forced_awake;
185}
186
Houston Hoffman0dad5092015-09-28 16:25:51 -0700187
188static inline void hif_fw_event_handler(struct HIF_CE_state *hif_state)
189{
190 struct hif_msg_callbacks *msg_callbacks =
191 &hif_state->msg_callbacks_current;
192
193 if (!msg_callbacks->fwEventHandler)
194 return;
195
196 msg_callbacks->fwEventHandler(msg_callbacks->Context,
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530197 QDF_STATUS_E_FAILURE);
Houston Hoffman0dad5092015-09-28 16:25:51 -0700198}
199
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800200/**
201 * hif_fw_interrupt_handler(): FW interrupt handler
202 *
203 * This function is the FW interrupt handlder
204 *
205 * @irq: irq number
206 * @arg: the user pointer
207 *
208 * Return: bool
209 */
210#ifndef QCA_WIFI_3_0
211irqreturn_t hif_fw_interrupt_handler(int irq, void *arg)
212{
Komal Seelam644263d2016-02-22 20:45:49 +0530213 struct hif_softc *scn = arg;
Komal Seelam02cf2f82016-02-22 20:44:25 +0530214 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800215 uint32_t fw_indicator_address, fw_indicator;
216
217 A_TARGET_ACCESS_BEGIN_RET(scn);
218
219 fw_indicator_address = hif_state->fw_indicator_address;
220 /* For sudden unplug this will return ~0 */
221 fw_indicator = A_TARGET_READ(scn, fw_indicator_address);
222
223 if ((fw_indicator != ~0) && (fw_indicator & FW_IND_EVENT_PENDING)) {
224 /* ACK: clear Target-side pending event */
225 A_TARGET_WRITE(scn, fw_indicator_address,
226 fw_indicator & ~FW_IND_EVENT_PENDING);
227 A_TARGET_ACCESS_END_RET(scn);
228
229 if (hif_state->started) {
Houston Hoffman0dad5092015-09-28 16:25:51 -0700230 hif_fw_event_handler(hif_state);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800231 } else {
232 /*
233 * Probable Target failure before we're prepared
234 * to handle it. Generally unexpected.
235 */
236 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
237 ("%s: Early firmware event indicated\n",
238 __func__));
239 }
240 } else {
241 A_TARGET_ACCESS_END_RET(scn);
242 }
243
244 return ATH_ISR_SCHED;
245}
246#else
247irqreturn_t hif_fw_interrupt_handler(int irq, void *arg)
248{
249 return ATH_ISR_SCHED;
250}
251#endif /* #ifdef QCA_WIFI_3_0 */
252
253/**
254 * hif_get_targetdef(): hif_get_targetdef
255 * @scn: scn
256 *
257 * Return: void *
258 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530259void *hif_get_targetdef(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800260{
Komal Seelam644263d2016-02-22 20:45:49 +0530261 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
262
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800263 return scn->targetdef;
264}
265
266/**
267 * hif_vote_link_down(): unvote for link up
268 *
269 * Call hif_vote_link_down to release a previous request made using
270 * hif_vote_link_up. A hif_vote_link_down call should only be made
271 * after a corresponding hif_vote_link_up, otherwise you could be
272 * negating a vote from another source. When no votes are present
273 * hif will not guarantee the linkstate after hif_bus_suspend.
274 *
275 * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread
276 * and initialization deinitialization sequencences.
277 *
278 * Return: n/a
279 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530280void hif_vote_link_down(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800281{
Komal Seelam644263d2016-02-22 20:45:49 +0530282 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530283 QDF_BUG(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800284
285 scn->linkstate_vote--;
286 if (scn->linkstate_vote == 0)
Houston Hoffmancceec342015-11-11 11:37:20 -0800287 hif_bus_prevent_linkdown(scn, false);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800288}
289
290/**
291 * hif_vote_link_up(): vote to prevent bus from suspending
292 *
293 * Makes hif guarantee that fw can message the host normally
294 * durring suspend.
295 *
296 * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread
297 * and initialization deinitialization sequencences.
298 *
299 * Return: n/a
300 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530301void hif_vote_link_up(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800302{
Komal Seelam644263d2016-02-22 20:45:49 +0530303 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530304 QDF_BUG(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800305
306 scn->linkstate_vote++;
307 if (scn->linkstate_vote == 1)
Houston Hoffmancceec342015-11-11 11:37:20 -0800308 hif_bus_prevent_linkdown(scn, true);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800309}
310
311/**
312 * hif_can_suspend_link(): query if hif is permitted to suspend the link
313 *
314 * Hif will ensure that the link won't be suspended if the upperlayers
315 * don't want it to.
316 *
317 * SYNCHRONIZATION: MC thread is stopped before bus suspend thus
318 * we don't need extra locking to ensure votes dont change while
319 * we are in the process of suspending or resuming.
320 *
321 * Return: false if hif will guarantee link up durring suspend.
322 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530323bool hif_can_suspend_link(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800324{
Komal Seelam644263d2016-02-22 20:45:49 +0530325 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530326 QDF_BUG(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800327
328 return scn->linkstate_vote == 0;
329}
330
331/**
332 * hif_hia_item_address(): hif_hia_item_address
333 * @target_type: target_type
334 * @item_offset: item_offset
335 *
336 * Return: n/a
337 */
338uint32_t hif_hia_item_address(uint32_t target_type, uint32_t item_offset)
339{
340 switch (target_type) {
341 case TARGET_TYPE_AR6002:
342 return AR6002_HOST_INTEREST_ADDRESS + item_offset;
343 case TARGET_TYPE_AR6003:
344 return AR6003_HOST_INTEREST_ADDRESS + item_offset;
345 case TARGET_TYPE_AR6004:
346 return AR6004_HOST_INTEREST_ADDRESS + item_offset;
347 case TARGET_TYPE_AR6006:
348 return AR6006_HOST_INTEREST_ADDRESS + item_offset;
349 case TARGET_TYPE_AR9888:
350 return AR9888_HOST_INTEREST_ADDRESS + item_offset;
351 case TARGET_TYPE_AR6320:
352 case TARGET_TYPE_AR6320V2:
353 return AR6320_HOST_INTEREST_ADDRESS + item_offset;
354 case TARGET_TYPE_QCA6180:
355 return QCA6180_HOST_INTEREST_ADDRESS + item_offset;
356 case TARGET_TYPE_ADRASTEA:
357 /* ADRASTEA doesn't have a host interest address */
358 ASSERT(0);
359 return 0;
360 default:
361 ASSERT(0);
362 return 0;
363 }
364}
365
366/**
367 * hif_max_num_receives_reached() - check max receive is reached
Komal Seelambd7c51d2016-02-24 10:27:30 +0530368 * @scn: HIF Context
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800369 * @count: unsigned int.
370 *
371 * Output check status as bool
372 *
373 * Return: bool
374 */
Komal Seelambd7c51d2016-02-24 10:27:30 +0530375bool hif_max_num_receives_reached(struct hif_softc *scn, unsigned int count)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800376{
Komal Seelambd7c51d2016-02-24 10:27:30 +0530377 if (WLAN_IS_EPPING_ENABLED(hif_get_conparam(scn)))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800378 return count > 120;
379 else
380 return count > MAX_NUM_OF_RECEIVES;
381}
382
383/**
384 * init_buffer_count() - initial buffer count
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530385 * @maxSize: qdf_size_t
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800386 *
387 * routine to modify the initial buffer count to be allocated on an os
388 * platform basis. Platform owner will need to modify this as needed
389 *
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530390 * Return: qdf_size_t
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800391 */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530392qdf_size_t init_buffer_count(qdf_size_t maxSize)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800393{
394 return maxSize;
395}
396
397/**
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800398 * hif_save_htc_htt_config_endpoint():
399 * hif_save_htc_htt_config_endpoint
400 * @htc_endpoint: htc_endpoint
401 *
402 * Return: void
403 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530404void hif_save_htc_htt_config_endpoint(struct hif_opaque_softc *hif_ctx,
405 int htc_endpoint)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800406{
Komal Seelam644263d2016-02-22 20:45:49 +0530407 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800408
409 if (!scn) {
410 HIF_ERROR("%s: error: scn or scn->hif_sc is NULL!",
411 __func__);
412 return;
413 }
414
415 scn->htc_endpoint = htc_endpoint;
416}
417
418/**
419 * hif_get_hw_name(): get a human readable name for the hardware
Komal Seelam91553ce2016-01-27 18:57:10 +0530420 * @info: Target Info
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800421 *
Komal Seelam91553ce2016-01-27 18:57:10 +0530422 * Return: human readable name for the underlying wifi hardware.
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800423 */
Komal Seelam91553ce2016-01-27 18:57:10 +0530424static const char *hif_get_hw_name(struct hif_target_info *info)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800425{
426 int i;
Komal Seelam91553ce2016-01-27 18:57:10 +0530427
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800428 for (i = 0; i < ARRAY_SIZE(qwlan_hw_list); i++) {
Komal Seelam91553ce2016-01-27 18:57:10 +0530429 if (info->target_version == qwlan_hw_list[i].id &&
430 info->target_revision == qwlan_hw_list[i].subid) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800431 return qwlan_hw_list[i].name;
432 }
433 }
434
435 return "Unknown Device";
436}
437
438/**
439 * hif_get_hw_info(): hif_get_hw_info
440 * @scn: scn
441 * @version: version
442 * @revision: revision
443 *
444 * Return: n/a
445 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530446void hif_get_hw_info(struct hif_opaque_softc *scn, u32 *version, u32 *revision,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800447 const char **target_name)
448{
Komal Seelam91553ce2016-01-27 18:57:10 +0530449 struct hif_target_info *info = hif_get_target_info_handle(scn);
450 *version = info->target_version;
451 *revision = info->target_revision;
452 *target_name = hif_get_hw_name(info);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800453}
454
455/**
456 * hif_open(): hif_open
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530457 * @qdf_ctx: QDF Context
Komal Seelambd7c51d2016-02-24 10:27:30 +0530458 * @mode: Driver Mode
459 * @bus_type: Bus Type
460 * @cbk: CDS Callbacks
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800461 *
Komal Seelambd7c51d2016-02-24 10:27:30 +0530462 * API to open HIF Context
463 *
464 * Return: HIF Opaque Pointer
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800465 */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530466struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx, uint32_t mode,
467 enum qdf_bus_type bus_type,
Komal Seelambd7c51d2016-02-24 10:27:30 +0530468 struct hif_callbacks *cbk)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800469{
Komal Seelam644263d2016-02-22 20:45:49 +0530470 struct hif_softc *scn;
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530471 QDF_STATUS status = QDF_STATUS_SUCCESS;
Komal Seelam43301de2016-02-02 18:20:48 +0530472 int bus_context_size = hif_bus_get_context_size();
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800473
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530474 scn = (struct hif_softc *)qdf_mem_malloc(bus_context_size);
Komal Seelambd7c51d2016-02-24 10:27:30 +0530475 if (!scn) {
476 HIF_ERROR("%s: cannot alloc memory for HIF context of size:%d",
477 __func__, bus_context_size);
478 return GET_HIF_OPAQUE_HDL(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800479 }
480
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530481 qdf_mem_zero(scn, bus_context_size);
Komal Seelambd7c51d2016-02-24 10:27:30 +0530482
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530483 scn->qdf_dev = qdf_ctx;
Komal Seelambd7c51d2016-02-24 10:27:30 +0530484 scn->hif_con_param = mode;
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530485 qdf_atomic_init(&scn->active_tasklet_cnt);
486 qdf_atomic_init(&scn->link_suspended);
487 qdf_atomic_init(&scn->tasklet_from_intr);
488 qdf_mem_copy(&scn->callbacks, cbk, sizeof(struct hif_callbacks));
Houston Hoffman3cfe6862016-01-08 10:33:55 -0800489
490 status = hif_bus_open(scn, bus_type);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530491 if (status != QDF_STATUS_SUCCESS) {
Houston Hoffman3cfe6862016-01-08 10:33:55 -0800492 HIF_ERROR("%s: hif_bus_open error = %d, bus_type = %d",
493 __func__, status, bus_type);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530494 qdf_mem_free(scn);
Komal Seelambd7c51d2016-02-24 10:27:30 +0530495 scn = NULL;
Houston Hoffman3cfe6862016-01-08 10:33:55 -0800496 }
497
Komal Seelambd7c51d2016-02-24 10:27:30 +0530498 return GET_HIF_OPAQUE_HDL(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800499}
500
501/**
502 * hif_close(): hif_close
503 * @hif_ctx: hif_ctx
504 *
505 * Return: n/a
506 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530507void hif_close(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800508{
Komal Seelam644263d2016-02-22 20:45:49 +0530509 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800510
511 if (scn == NULL) {
Komal Seelam5584a7c2016-02-24 19:22:48 +0530512 HIF_ERROR("%s: hif_opaque_softc is NULL", __func__);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800513 return;
514 }
515
516 if (scn->athdiag_procfs_inited) {
517 athdiag_procfs_remove();
518 scn->athdiag_procfs_inited = false;
519 }
520
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800521 hif_bus_close(scn);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530522 qdf_mem_free(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800523}
524
525/**
526 * hif_enable(): hif_enable
527 * @hif_ctx: hif_ctx
528 * @dev: dev
529 * @bdev: bus dev
530 * @bid: bus ID
531 * @bus_type: bus type
532 * @type: enable type
533 *
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530534 * Return: QDF_STATUS
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800535 */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530536QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800537 void *bdev, const hif_bus_id *bid,
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530538 enum qdf_bus_type bus_type,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800539 enum hif_enable_type type)
540{
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530541 QDF_STATUS status;
Komal Seelam644263d2016-02-22 20:45:49 +0530542 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800543
544 if (scn == NULL) {
545 HIF_ERROR("%s: hif_ctx = NULL", __func__);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530546 return QDF_STATUS_E_NULL_VALUE;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800547 }
548
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800549 status = hif_enable_bus(scn, dev, bdev, bid, type);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530550 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800551 HIF_ERROR("%s: hif_enable_bus error = %d",
552 __func__, status);
553 return status;
554 }
555
556 if (ADRASTEA_BU)
Komal Seelamf8600682016-02-02 18:17:13 +0530557 hif_vote_link_up(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800558
559 if (hif_config_ce(scn)) {
560 HIF_ERROR("%s: Target probe failed.", __func__);
Vishwajith Upendra3f78aa62016-02-09 17:53:02 +0530561 hif_disable_bus(scn);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530562 status = QDF_STATUS_E_FAILURE;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800563 return status;
564 }
565 /*
566 * Flag to avoid potential unallocated memory access from MSI
567 * interrupt handler which could get scheduled as soon as MSI
568 * is enabled, i.e to take care of the race due to the order
569 * in where MSI is enabled before the memory, that will be
570 * in interrupt handlers, is allocated.
571 */
572
573#ifdef HIF_PCI
Komal Seelam644263d2016-02-22 20:45:49 +0530574 status = hif_configure_irq(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800575 if (status < 0) {
576 HIF_ERROR("%s: ERROR - configure_IRQ_and_CE failed, status = %d",
577 __func__, status);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530578 return QDF_STATUS_E_FAILURE;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800579 }
580#endif
581
582 scn->hif_init_done = true;
583
584 HIF_TRACE("%s: X OK", __func__);
585
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530586 return QDF_STATUS_SUCCESS;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800587}
588
589/**
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800590 * hif_wlan_disable(): call the platform driver to disable wlan
Komal Seelambd7c51d2016-02-24 10:27:30 +0530591 * @scn: HIF Context
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800592 *
593 * This function passes the con_mode to platform driver to disable
594 * wlan.
595 *
596 * Return: void
597 */
Komal Seelambd7c51d2016-02-24 10:27:30 +0530598void hif_wlan_disable(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800599{
600 enum icnss_driver_mode mode;
Komal Seelambd7c51d2016-02-24 10:27:30 +0530601 uint32_t con_mode = hif_get_conparam(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800602
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530603 if (QDF_GLOBAL_FTM_MODE == con_mode)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800604 mode = ICNSS_FTM;
Komal Seelambd7c51d2016-02-24 10:27:30 +0530605 else if (WLAN_IS_EPPING_ENABLED(con_mode))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800606 mode = ICNSS_EPPING;
Peng Xu7b962532015-10-02 17:17:03 -0700607 else
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800608 mode = ICNSS_MISSION;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800609
610 icnss_wlan_disable(mode);
611}
612
Komal Seelam5584a7c2016-02-24 19:22:48 +0530613void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800614{
Komal Seelam644263d2016-02-22 20:45:49 +0530615 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800616
617 if (!scn)
618 return;
619
620 hif_nointrs(scn);
621 if (scn->hif_init_done == false)
Komal Seelam644263d2016-02-22 20:45:49 +0530622 hif_shut_down_device(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800623 else
Komal Seelam644263d2016-02-22 20:45:49 +0530624 hif_stop(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800625
626 if (ADRASTEA_BU)
Komal Seelamf8600682016-02-02 18:17:13 +0530627 hif_vote_link_down(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800628
Vishwajith Upendra3f78aa62016-02-09 17:53:02 +0530629 hif_disable_bus(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800630
Komal Seelambd7c51d2016-02-24 10:27:30 +0530631 hif_wlan_disable(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800632
633 scn->notice_send = false;
634
635 HIF_INFO("%s: X", __func__);
636}
637
638
639/**
Govind Singh2443fb32016-01-13 17:44:48 +0530640 * hif_crash_shutdown_dump_bus_register() - dump bus registers
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800641 * @hif_ctx: hif_ctx
642 *
643 * Return: n/a
644 */
645#if defined(TARGET_RAMDUMP_AFTER_KERNEL_PANIC) \
646&& defined(HIF_PCI) && defined(DEBUG)
647
Govind Singh2443fb32016-01-13 17:44:48 +0530648static void hif_crash_shutdown_dump_bus_register(void *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800649{
Komal Seelam5584a7c2016-02-24 19:22:48 +0530650 struct hif_opaque_softc *scn = hif_ctx;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800651
Govind Singh2443fb32016-01-13 17:44:48 +0530652 if (hif_check_soc_status(scn))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800653 return;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800654
Govind Singh2443fb32016-01-13 17:44:48 +0530655 if (hif_dump_registers(scn))
656 HIF_ERROR("Failed to dump bus registers!");
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800657}
658
659/**
660 * hif_crash_shutdown(): hif_crash_shutdown
661 *
662 * This function is called by the platform driver to dump CE registers
663 *
664 * @hif_ctx: hif_ctx
665 *
666 * Return: n/a
667 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530668void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800669{
Komal Seelam644263d2016-02-22 20:45:49 +0530670 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Komal Seelam02cf2f82016-02-22 20:44:25 +0530671 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800672
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800673 if (!hif_state)
674 return;
675
676
677 if (OL_TRGET_STATUS_RESET == scn->target_status) {
678 HIF_INFO_MED("%s: Target is already asserted, ignore!",
679 __func__);
680 return;
681 }
682
Komal Seelambd7c51d2016-02-24 10:27:30 +0530683 if (hif_is_load_or_unload_in_progress(scn)) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800684 HIF_ERROR("%s: Load/unload is in progress, ignore!", __func__);
685 return;
686 }
687
Govind Singh2443fb32016-01-13 17:44:48 +0530688 hif_crash_shutdown_dump_bus_register(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800689
Komal Seelam644263d2016-02-22 20:45:49 +0530690 if (ol_copy_ramdump(hif_ctx))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800691 goto out;
692
693 HIF_INFO_MED("%s: RAM dump collecting completed!", __func__);
694
695out:
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800696 return;
697}
698#else
Komal Seelam5584a7c2016-02-24 19:22:48 +0530699void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800700{
701 HIF_INFO_MED("%s: Collecting target RAM dump disabled",
702 __func__);
703 return;
704}
705#endif /* TARGET_RAMDUMP_AFTER_KERNEL_PANIC */
706
707#ifdef QCA_WIFI_3_0
708/**
709 * hif_check_fw_reg(): hif_check_fw_reg
710 * @scn: scn
711 * @state:
712 *
713 * Return: int
714 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530715int hif_check_fw_reg(struct hif_opaque_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800716{
717 return 0;
718}
719#endif
720
721#ifdef IPA_OFFLOAD
722/**
723 * hif_read_phy_mem_base(): hif_read_phy_mem_base
724 * @scn: scn
725 * @phy_mem_base: physical mem base
726 *
727 * Return: n/a
728 */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530729void hif_read_phy_mem_base(struct hif_softc *scn, qdf_dma_addr_t *phy_mem_base)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800730{
731 *phy_mem_base = scn->mem_pa;
732}
733#endif /* IPA_OFFLOAD */
734
735/**
736 * hif_get_device_type(): hif_get_device_type
737 * @device_id: device_id
738 * @revision_id: revision_id
739 * @hif_type: returned hif_type
740 * @target_type: returned target_type
741 *
742 * Return: int
743 */
744int hif_get_device_type(uint32_t device_id,
745 uint32_t revision_id,
746 uint32_t *hif_type, uint32_t *target_type)
747{
748 int ret = 0;
749
750 switch (device_id) {
751#ifdef QCA_WIFI_3_0_ADRASTEA
752 case ADRASTEA_DEVICE_ID:
753 case ADRASTEA_DEVICE_ID_P2_E12:
754
755 *hif_type = HIF_TYPE_ADRASTEA;
756 *target_type = TARGET_TYPE_ADRASTEA;
757 break;
758#else
759 case QCA6180_DEVICE_ID:
760 *hif_type = HIF_TYPE_QCA6180;
761 *target_type = TARGET_TYPE_QCA6180;
762 break;
763#endif
764
765 case AR9888_DEVICE_ID:
766 *hif_type = HIF_TYPE_AR9888;
767 *target_type = TARGET_TYPE_AR9888;
768 break;
769
770 case AR6320_DEVICE_ID:
771 switch (revision_id) {
772 case AR6320_FW_1_1:
773 case AR6320_FW_1_3:
774 *hif_type = HIF_TYPE_AR6320;
775 *target_type = TARGET_TYPE_AR6320;
776 break;
777
778 case AR6320_FW_2_0:
779 case AR6320_FW_3_0:
780 case AR6320_FW_3_2:
781 *hif_type = HIF_TYPE_AR6320V2;
782 *target_type = TARGET_TYPE_AR6320V2;
783 break;
784
785 default:
786 HIF_ERROR("%s: error - dev_id = 0x%x, rev_id = 0x%x",
787 __func__, device_id, revision_id);
788 ret = -ENODEV;
789 goto end;
790 }
791 break;
792
793 default:
794 HIF_ERROR("%s: Unsupported device ID!", __func__);
795 ret = -ENODEV;
796 break;
797 }
798end:
799 return ret;
800}
Komal Seelam91553ce2016-01-27 18:57:10 +0530801
802/**
803 * Target info and ini parameters are global to the driver
804 * Hence these structures are exposed to all the modules in
805 * the driver and they don't need to maintains multiple copies
806 * of the same info, instead get the handle from hif and
807 * modify them in hif
808 */
809
810/**
811 * hif_get_ini_handle() - API to get hif_config_param handle
Komal Seelam644263d2016-02-22 20:45:49 +0530812 * @hif_ctx: HIF Context
Komal Seelam91553ce2016-01-27 18:57:10 +0530813 *
814 * Return: pointer to hif_config_info
815 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530816struct hif_config_info *hif_get_ini_handle(struct hif_opaque_softc *hif_ctx)
Komal Seelam91553ce2016-01-27 18:57:10 +0530817{
Komal Seelam644263d2016-02-22 20:45:49 +0530818 struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx);
819
820 return &sc->hif_config;
Komal Seelam91553ce2016-01-27 18:57:10 +0530821}
822
823/**
824 * hif_get_target_info_handle() - API to get hif_target_info handle
Komal Seelam644263d2016-02-22 20:45:49 +0530825 * @hif_ctx: HIF context
Komal Seelam91553ce2016-01-27 18:57:10 +0530826 *
827 * Return: Pointer to hif_target_info
828 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530829struct hif_target_info *hif_get_target_info_handle(
830 struct hif_opaque_softc *hif_ctx)
Komal Seelam91553ce2016-01-27 18:57:10 +0530831{
Komal Seelam644263d2016-02-22 20:45:49 +0530832 struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx);
833
834 return &sc->target_info;
835
Komal Seelam91553ce2016-01-27 18:57:10 +0530836}
Komal Seelamc92a0cf2016-02-22 20:43:52 +0530837
838#if defined(FEATURE_LRO)
839/**
840 * hif_lro_flush_cb_register - API to register for LRO Flush Callback
841 * @scn: HIF Context
842 * @handler: Function pointer to be called by HIF
843 * @data: Private data to be used by the module registering to HIF
844 *
845 * Return: void
846 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530847void hif_lro_flush_cb_register(struct hif_opaque_softc *scn,
848 void (handler)(void *), void *data)
Komal Seelamc92a0cf2016-02-22 20:43:52 +0530849{
850 ce_lro_flush_cb_register(scn, handler, data);
851}
852
853/**
854 * hif_lro_flush_cb_deregister - API to deregister for LRO Flush Callbacks
855 * @scn: HIF Context
856 *
857 * Return: void
858 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530859void hif_lro_flush_cb_deregister(struct hif_opaque_softc *scn)
Komal Seelamc92a0cf2016-02-22 20:43:52 +0530860{
861 ce_lro_flush_cb_deregister(scn);
862}
863#endif
Komal Seelam644263d2016-02-22 20:45:49 +0530864
865/**
866 * hif_get_target_status - API to get target status
867 * @hif_ctx: HIF Context
868 *
869 * Return: enum ol_target_status
870 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530871ol_target_status hif_get_target_status(struct hif_opaque_softc *hif_ctx)
Komal Seelam644263d2016-02-22 20:45:49 +0530872{
873 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
874
875 return scn->target_status;
876}
877
878/**
Komal Seelama5911d32016-02-24 19:21:59 +0530879 * hif_set_target_status() - API to set target status
Komal Seelam644263d2016-02-22 20:45:49 +0530880 * @hif_ctx: HIF Context
881 * @status: Target Status
882 *
883 * Return: void
884 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530885void hif_set_target_status(struct hif_opaque_softc *hif_ctx,
886 ol_target_status status)
Komal Seelam644263d2016-02-22 20:45:49 +0530887{
888 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
889
890 scn->target_status = status;
891}
Komal Seelama5911d32016-02-24 19:21:59 +0530892
893/**
894 * hif_init_ini_config() - API to initialize HIF configuration parameters
895 * @hif_ctx: HIF Context
896 * @cfg: HIF Configuration
897 *
898 * Return: void
899 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530900void hif_init_ini_config(struct hif_opaque_softc *hif_ctx,
901 struct hif_config_info *cfg)
Komal Seelama5911d32016-02-24 19:21:59 +0530902{
903 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
904
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530905 qdf_mem_copy(&scn->hif_config, cfg, sizeof(struct hif_config_info));
Komal Seelama5911d32016-02-24 19:21:59 +0530906}
Komal Seelambd7c51d2016-02-24 10:27:30 +0530907
908/**
909 * hif_get_conparam() - API to get driver mode in HIF
910 * @scn: HIF Context
911 *
912 * Return: driver mode of operation
913 */
914uint32_t hif_get_conparam(struct hif_softc *scn)
915{
916 if (!scn)
917 return 0;
918
919 return scn->hif_con_param;
920}
921
922/**
923 * hif_get_callbacks_handle() - API to get callbacks Handle
924 * @scn: HIF Context
925 *
926 * Return: pointer to HIF Callbacks
927 */
928struct hif_callbacks *hif_get_callbacks_handle(struct hif_softc *scn)
929{
930 return &scn->callbacks;
931}
932
933/**
934 * hif_is_driver_unloading() - API to query upper layers if driver is unloading
935 * @scn: HIF Context
936 *
937 * Return: True/False
938 */
939bool hif_is_driver_unloading(struct hif_softc *scn)
940{
941 struct hif_callbacks *cbk = hif_get_callbacks_handle(scn);
942
943 if (cbk && cbk->is_driver_unloading)
944 return cbk->is_driver_unloading(cbk->context);
945
946 return false;
947}
948
949/**
950 * hif_is_load_or_unload_in_progress() - API to query upper layers if
951 * load/unload in progress
952 * @scn: HIF Context
953 *
954 * Return: True/False
955 */
956bool hif_is_load_or_unload_in_progress(struct hif_softc *scn)
957{
958 struct hif_callbacks *cbk = hif_get_callbacks_handle(scn);
959
960 if (cbk && cbk->is_load_unload_in_progress)
961 return cbk->is_load_unload_in_progress(cbk->context);
962
963 return false;
964}
965
966/**
967 * hif_is_recovery_in_progress() - API to query upper layers if recovery in
968 * progress
969 * @scn: HIF Context
970 *
971 * Return: True/False
972 */
973bool hif_is_recovery_in_progress(struct hif_softc *scn)
974{
975 struct hif_callbacks *cbk = hif_get_callbacks_handle(scn);
976
977 if (cbk && cbk->is_recovery_in_progress)
978 return cbk->is_recovery_in_progress(cbk->context);
979
980 return false;
981}