blob: 53c4778556973185c44b4adae89e8a319e9488a9 [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
Houston Hoffman108da402016-03-14 21:11:24 -0700559 if (hif_bus_configure(scn)) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800560 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 }
Houston Hoffman108da402016-03-14 21:11:24 -0700565
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800566 /*
567 * Flag to avoid potential unallocated memory access from MSI
568 * interrupt handler which could get scheduled as soon as MSI
569 * is enabled, i.e to take care of the race due to the order
570 * in where MSI is enabled before the memory, that will be
571 * in interrupt handlers, is allocated.
572 */
573
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800574 scn->hif_init_done = true;
575
576 HIF_TRACE("%s: X OK", __func__);
577
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530578 return QDF_STATUS_SUCCESS;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800579}
580
581/**
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800582 * hif_wlan_disable(): call the platform driver to disable wlan
Komal Seelambd7c51d2016-02-24 10:27:30 +0530583 * @scn: HIF Context
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800584 *
585 * This function passes the con_mode to platform driver to disable
586 * wlan.
587 *
588 * Return: void
589 */
Komal Seelambd7c51d2016-02-24 10:27:30 +0530590void hif_wlan_disable(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800591{
592 enum icnss_driver_mode mode;
Komal Seelambd7c51d2016-02-24 10:27:30 +0530593 uint32_t con_mode = hif_get_conparam(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800594
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530595 if (QDF_GLOBAL_FTM_MODE == con_mode)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800596 mode = ICNSS_FTM;
Komal Seelambd7c51d2016-02-24 10:27:30 +0530597 else if (WLAN_IS_EPPING_ENABLED(con_mode))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800598 mode = ICNSS_EPPING;
Peng Xu7b962532015-10-02 17:17:03 -0700599 else
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800600 mode = ICNSS_MISSION;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800601
602 icnss_wlan_disable(mode);
603}
604
Komal Seelam5584a7c2016-02-24 19:22:48 +0530605void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800606{
Komal Seelam644263d2016-02-22 20:45:49 +0530607 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800608
609 if (!scn)
610 return;
611
612 hif_nointrs(scn);
613 if (scn->hif_init_done == false)
Komal Seelam644263d2016-02-22 20:45:49 +0530614 hif_shut_down_device(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800615 else
Komal Seelam644263d2016-02-22 20:45:49 +0530616 hif_stop(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800617
618 if (ADRASTEA_BU)
Komal Seelamf8600682016-02-02 18:17:13 +0530619 hif_vote_link_down(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800620
Vishwajith Upendra3f78aa62016-02-09 17:53:02 +0530621 hif_disable_bus(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800622
Komal Seelambd7c51d2016-02-24 10:27:30 +0530623 hif_wlan_disable(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800624
625 scn->notice_send = false;
626
627 HIF_INFO("%s: X", __func__);
628}
629
630
631/**
Govind Singh2443fb32016-01-13 17:44:48 +0530632 * hif_crash_shutdown_dump_bus_register() - dump bus registers
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800633 * @hif_ctx: hif_ctx
634 *
635 * Return: n/a
636 */
637#if defined(TARGET_RAMDUMP_AFTER_KERNEL_PANIC) \
638&& defined(HIF_PCI) && defined(DEBUG)
639
Govind Singh2443fb32016-01-13 17:44:48 +0530640static void hif_crash_shutdown_dump_bus_register(void *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800641{
Komal Seelam5584a7c2016-02-24 19:22:48 +0530642 struct hif_opaque_softc *scn = hif_ctx;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800643
Govind Singh2443fb32016-01-13 17:44:48 +0530644 if (hif_check_soc_status(scn))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800645 return;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800646
Govind Singh2443fb32016-01-13 17:44:48 +0530647 if (hif_dump_registers(scn))
648 HIF_ERROR("Failed to dump bus registers!");
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800649}
650
651/**
652 * hif_crash_shutdown(): hif_crash_shutdown
653 *
654 * This function is called by the platform driver to dump CE registers
655 *
656 * @hif_ctx: hif_ctx
657 *
658 * Return: n/a
659 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530660void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800661{
Komal Seelam644263d2016-02-22 20:45:49 +0530662 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Komal Seelam02cf2f82016-02-22 20:44:25 +0530663 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800664
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800665 if (!hif_state)
666 return;
667
668
669 if (OL_TRGET_STATUS_RESET == scn->target_status) {
670 HIF_INFO_MED("%s: Target is already asserted, ignore!",
671 __func__);
672 return;
673 }
674
Komal Seelambd7c51d2016-02-24 10:27:30 +0530675 if (hif_is_load_or_unload_in_progress(scn)) {
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800676 HIF_ERROR("%s: Load/unload is in progress, ignore!", __func__);
677 return;
678 }
679
Govind Singh2443fb32016-01-13 17:44:48 +0530680 hif_crash_shutdown_dump_bus_register(hif_ctx);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800681
Komal Seelam644263d2016-02-22 20:45:49 +0530682 if (ol_copy_ramdump(hif_ctx))
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800683 goto out;
684
685 HIF_INFO_MED("%s: RAM dump collecting completed!", __func__);
686
687out:
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800688 return;
689}
690#else
Komal Seelam5584a7c2016-02-24 19:22:48 +0530691void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800692{
693 HIF_INFO_MED("%s: Collecting target RAM dump disabled",
694 __func__);
695 return;
696}
697#endif /* TARGET_RAMDUMP_AFTER_KERNEL_PANIC */
698
699#ifdef QCA_WIFI_3_0
700/**
701 * hif_check_fw_reg(): hif_check_fw_reg
702 * @scn: scn
703 * @state:
704 *
705 * Return: int
706 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530707int hif_check_fw_reg(struct hif_opaque_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800708{
709 return 0;
710}
711#endif
712
713#ifdef IPA_OFFLOAD
714/**
715 * hif_read_phy_mem_base(): hif_read_phy_mem_base
716 * @scn: scn
717 * @phy_mem_base: physical mem base
718 *
719 * Return: n/a
720 */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530721void hif_read_phy_mem_base(struct hif_softc *scn, qdf_dma_addr_t *phy_mem_base)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800722{
723 *phy_mem_base = scn->mem_pa;
724}
725#endif /* IPA_OFFLOAD */
726
727/**
728 * hif_get_device_type(): hif_get_device_type
729 * @device_id: device_id
730 * @revision_id: revision_id
731 * @hif_type: returned hif_type
732 * @target_type: returned target_type
733 *
734 * Return: int
735 */
736int hif_get_device_type(uint32_t device_id,
737 uint32_t revision_id,
738 uint32_t *hif_type, uint32_t *target_type)
739{
740 int ret = 0;
741
742 switch (device_id) {
743#ifdef QCA_WIFI_3_0_ADRASTEA
744 case ADRASTEA_DEVICE_ID:
745 case ADRASTEA_DEVICE_ID_P2_E12:
746
747 *hif_type = HIF_TYPE_ADRASTEA;
748 *target_type = TARGET_TYPE_ADRASTEA;
749 break;
750#else
751 case QCA6180_DEVICE_ID:
752 *hif_type = HIF_TYPE_QCA6180;
753 *target_type = TARGET_TYPE_QCA6180;
754 break;
755#endif
756
757 case AR9888_DEVICE_ID:
758 *hif_type = HIF_TYPE_AR9888;
759 *target_type = TARGET_TYPE_AR9888;
760 break;
761
762 case AR6320_DEVICE_ID:
763 switch (revision_id) {
764 case AR6320_FW_1_1:
765 case AR6320_FW_1_3:
766 *hif_type = HIF_TYPE_AR6320;
767 *target_type = TARGET_TYPE_AR6320;
768 break;
769
770 case AR6320_FW_2_0:
771 case AR6320_FW_3_0:
772 case AR6320_FW_3_2:
773 *hif_type = HIF_TYPE_AR6320V2;
774 *target_type = TARGET_TYPE_AR6320V2;
775 break;
776
777 default:
778 HIF_ERROR("%s: error - dev_id = 0x%x, rev_id = 0x%x",
779 __func__, device_id, revision_id);
780 ret = -ENODEV;
781 goto end;
782 }
783 break;
784
785 default:
786 HIF_ERROR("%s: Unsupported device ID!", __func__);
787 ret = -ENODEV;
788 break;
789 }
790end:
791 return ret;
792}
Komal Seelam91553ce2016-01-27 18:57:10 +0530793
794/**
795 * Target info and ini parameters are global to the driver
796 * Hence these structures are exposed to all the modules in
797 * the driver and they don't need to maintains multiple copies
798 * of the same info, instead get the handle from hif and
799 * modify them in hif
800 */
801
802/**
803 * hif_get_ini_handle() - API to get hif_config_param handle
Komal Seelam644263d2016-02-22 20:45:49 +0530804 * @hif_ctx: HIF Context
Komal Seelam91553ce2016-01-27 18:57:10 +0530805 *
806 * Return: pointer to hif_config_info
807 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530808struct hif_config_info *hif_get_ini_handle(struct hif_opaque_softc *hif_ctx)
Komal Seelam91553ce2016-01-27 18:57:10 +0530809{
Komal Seelam644263d2016-02-22 20:45:49 +0530810 struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx);
811
812 return &sc->hif_config;
Komal Seelam91553ce2016-01-27 18:57:10 +0530813}
814
815/**
816 * hif_get_target_info_handle() - API to get hif_target_info handle
Komal Seelam644263d2016-02-22 20:45:49 +0530817 * @hif_ctx: HIF context
Komal Seelam91553ce2016-01-27 18:57:10 +0530818 *
819 * Return: Pointer to hif_target_info
820 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530821struct hif_target_info *hif_get_target_info_handle(
822 struct hif_opaque_softc *hif_ctx)
Komal Seelam91553ce2016-01-27 18:57:10 +0530823{
Komal Seelam644263d2016-02-22 20:45:49 +0530824 struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx);
825
826 return &sc->target_info;
827
Komal Seelam91553ce2016-01-27 18:57:10 +0530828}
Komal Seelamc92a0cf2016-02-22 20:43:52 +0530829
830#if defined(FEATURE_LRO)
831/**
832 * hif_lro_flush_cb_register - API to register for LRO Flush Callback
833 * @scn: HIF Context
834 * @handler: Function pointer to be called by HIF
835 * @data: Private data to be used by the module registering to HIF
836 *
837 * Return: void
838 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530839void hif_lro_flush_cb_register(struct hif_opaque_softc *scn,
840 void (handler)(void *), void *data)
Komal Seelamc92a0cf2016-02-22 20:43:52 +0530841{
842 ce_lro_flush_cb_register(scn, handler, data);
843}
844
845/**
846 * hif_lro_flush_cb_deregister - API to deregister for LRO Flush Callbacks
847 * @scn: HIF Context
848 *
849 * Return: void
850 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530851void hif_lro_flush_cb_deregister(struct hif_opaque_softc *scn)
Komal Seelamc92a0cf2016-02-22 20:43:52 +0530852{
853 ce_lro_flush_cb_deregister(scn);
854}
855#endif
Komal Seelam644263d2016-02-22 20:45:49 +0530856
857/**
858 * hif_get_target_status - API to get target status
859 * @hif_ctx: HIF Context
860 *
861 * Return: enum ol_target_status
862 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530863ol_target_status hif_get_target_status(struct hif_opaque_softc *hif_ctx)
Komal Seelam644263d2016-02-22 20:45:49 +0530864{
865 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
866
867 return scn->target_status;
868}
869
870/**
Komal Seelama5911d32016-02-24 19:21:59 +0530871 * hif_set_target_status() - API to set target status
Komal Seelam644263d2016-02-22 20:45:49 +0530872 * @hif_ctx: HIF Context
873 * @status: Target Status
874 *
875 * Return: void
876 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530877void hif_set_target_status(struct hif_opaque_softc *hif_ctx,
878 ol_target_status status)
Komal Seelam644263d2016-02-22 20:45:49 +0530879{
880 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
881
882 scn->target_status = status;
883}
Komal Seelama5911d32016-02-24 19:21:59 +0530884
885/**
886 * hif_init_ini_config() - API to initialize HIF configuration parameters
887 * @hif_ctx: HIF Context
888 * @cfg: HIF Configuration
889 *
890 * Return: void
891 */
Komal Seelam5584a7c2016-02-24 19:22:48 +0530892void hif_init_ini_config(struct hif_opaque_softc *hif_ctx,
893 struct hif_config_info *cfg)
Komal Seelama5911d32016-02-24 19:21:59 +0530894{
895 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
896
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530897 qdf_mem_copy(&scn->hif_config, cfg, sizeof(struct hif_config_info));
Komal Seelama5911d32016-02-24 19:21:59 +0530898}
Komal Seelambd7c51d2016-02-24 10:27:30 +0530899
900/**
901 * hif_get_conparam() - API to get driver mode in HIF
902 * @scn: HIF Context
903 *
904 * Return: driver mode of operation
905 */
906uint32_t hif_get_conparam(struct hif_softc *scn)
907{
908 if (!scn)
909 return 0;
910
911 return scn->hif_con_param;
912}
913
914/**
915 * hif_get_callbacks_handle() - API to get callbacks Handle
916 * @scn: HIF Context
917 *
918 * Return: pointer to HIF Callbacks
919 */
920struct hif_callbacks *hif_get_callbacks_handle(struct hif_softc *scn)
921{
922 return &scn->callbacks;
923}
924
925/**
926 * hif_is_driver_unloading() - API to query upper layers if driver is unloading
927 * @scn: HIF Context
928 *
929 * Return: True/False
930 */
931bool hif_is_driver_unloading(struct hif_softc *scn)
932{
933 struct hif_callbacks *cbk = hif_get_callbacks_handle(scn);
934
935 if (cbk && cbk->is_driver_unloading)
936 return cbk->is_driver_unloading(cbk->context);
937
938 return false;
939}
940
941/**
942 * hif_is_load_or_unload_in_progress() - API to query upper layers if
943 * load/unload in progress
944 * @scn: HIF Context
945 *
946 * Return: True/False
947 */
948bool hif_is_load_or_unload_in_progress(struct hif_softc *scn)
949{
950 struct hif_callbacks *cbk = hif_get_callbacks_handle(scn);
951
952 if (cbk && cbk->is_load_unload_in_progress)
953 return cbk->is_load_unload_in_progress(cbk->context);
954
955 return false;
956}
957
958/**
959 * hif_is_recovery_in_progress() - API to query upper layers if recovery in
960 * progress
961 * @scn: HIF Context
962 *
963 * Return: True/False
964 */
965bool hif_is_recovery_in_progress(struct hif_softc *scn)
966{
967 struct hif_callbacks *cbk = hif_get_callbacks_handle(scn);
968
969 if (cbk && cbk->is_recovery_in_progress)
970 return cbk->is_recovery_in_progress(cbk->context);
971
972 return false;
973}