hif_main.c 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304
  1. /*
  2. * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
  3. *
  4. * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  5. *
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for
  8. * any purpose with or without fee is hereby granted, provided that the
  9. * above copyright notice and this permission notice appear in all
  10. * copies.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  13. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  15. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  16. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  17. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  18. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  19. * PERFORMANCE OF THIS SOFTWARE.
  20. */
  21. /*
  22. * This file was originally distributed by Qualcomm Atheros, Inc.
  23. * under proprietary terms before Copyright ownership was assigned
  24. * to the Linux Foundation.
  25. */
  26. #include "targcfg.h"
  27. #include "qdf_lock.h"
  28. #include "qdf_status.h"
  29. #include "qdf_status.h"
  30. #include <qdf_atomic.h> /* qdf_atomic_read */
  31. #include <targaddrs.h>
  32. #include "hif_io32.h"
  33. #include <hif.h>
  34. #include "regtable.h"
  35. #define ATH_MODULE_NAME hif
  36. #include <a_debug.h>
  37. #include "hif_main.h"
  38. #include "hif_hw_version.h"
  39. #if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB)
  40. #include "ce_tasklet.h"
  41. #endif
  42. #include "qdf_trace.h"
  43. #include "qdf_status.h"
  44. #include "hif_debug.h"
  45. #include "mp_dev.h"
  46. #include "ce_api.h"
  47. #ifdef QCA_WIFI_QCA8074
  48. #include "hal_api.h"
  49. #endif
  50. #include "hif_napi.h"
  51. void hif_dump(struct hif_opaque_softc *hif_ctx, uint8_t cmd_id, bool start)
  52. {
  53. hif_trigger_dump(hif_ctx, cmd_id, start);
  54. }
  55. /**
  56. * hif_get_target_id(): hif_get_target_id
  57. *
  58. * Return the virtual memory base address to the caller
  59. *
  60. * @scn: hif_softc
  61. *
  62. * Return: A_target_id_t
  63. */
  64. A_target_id_t hif_get_target_id(struct hif_softc *scn)
  65. {
  66. return scn->mem;
  67. }
  68. /**
  69. * hif_get_targetdef(): hif_get_targetdef
  70. * @scn: scn
  71. *
  72. * Return: void *
  73. */
  74. void *hif_get_targetdef(struct hif_opaque_softc *hif_ctx)
  75. {
  76. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  77. return scn->targetdef;
  78. }
  79. /**
  80. * hif_vote_link_down(): unvote for link up
  81. *
  82. * Call hif_vote_link_down to release a previous request made using
  83. * hif_vote_link_up. A hif_vote_link_down call should only be made
  84. * after a corresponding hif_vote_link_up, otherwise you could be
  85. * negating a vote from another source. When no votes are present
  86. * hif will not guarantee the linkstate after hif_bus_suspend.
  87. *
  88. * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread
  89. * and initialization deinitialization sequencences.
  90. *
  91. * Return: n/a
  92. */
  93. void hif_vote_link_down(struct hif_opaque_softc *hif_ctx)
  94. {
  95. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  96. QDF_BUG(scn);
  97. scn->linkstate_vote--;
  98. if (scn->linkstate_vote == 0)
  99. hif_bus_prevent_linkdown(scn, false);
  100. }
  101. /**
  102. * hif_vote_link_up(): vote to prevent bus from suspending
  103. *
  104. * Makes hif guarantee that fw can message the host normally
  105. * durring suspend.
  106. *
  107. * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread
  108. * and initialization deinitialization sequencences.
  109. *
  110. * Return: n/a
  111. */
  112. void hif_vote_link_up(struct hif_opaque_softc *hif_ctx)
  113. {
  114. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  115. QDF_BUG(scn);
  116. scn->linkstate_vote++;
  117. if (scn->linkstate_vote == 1)
  118. hif_bus_prevent_linkdown(scn, true);
  119. }
  120. /**
  121. * hif_can_suspend_link(): query if hif is permitted to suspend the link
  122. *
  123. * Hif will ensure that the link won't be suspended if the upperlayers
  124. * don't want it to.
  125. *
  126. * SYNCHRONIZATION: MC thread is stopped before bus suspend thus
  127. * we don't need extra locking to ensure votes dont change while
  128. * we are in the process of suspending or resuming.
  129. *
  130. * Return: false if hif will guarantee link up durring suspend.
  131. */
  132. bool hif_can_suspend_link(struct hif_opaque_softc *hif_ctx)
  133. {
  134. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  135. QDF_BUG(scn);
  136. return scn->linkstate_vote == 0;
  137. }
  138. #ifndef CONFIG_WIN
  139. #define QCA9984_HOST_INTEREST_ADDRESS -1
  140. #define QCA9888_HOST_INTEREST_ADDRESS -1
  141. #define IPQ4019_HOST_INTEREST_ADDRESS -1
  142. #endif
  143. /**
  144. * hif_hia_item_address(): hif_hia_item_address
  145. * @target_type: target_type
  146. * @item_offset: item_offset
  147. *
  148. * Return: n/a
  149. */
  150. uint32_t hif_hia_item_address(uint32_t target_type, uint32_t item_offset)
  151. {
  152. switch (target_type) {
  153. case TARGET_TYPE_AR6002:
  154. return AR6002_HOST_INTEREST_ADDRESS + item_offset;
  155. case TARGET_TYPE_AR6003:
  156. return AR6003_HOST_INTEREST_ADDRESS + item_offset;
  157. case TARGET_TYPE_AR6004:
  158. return AR6004_HOST_INTEREST_ADDRESS + item_offset;
  159. case TARGET_TYPE_AR6006:
  160. return AR6006_HOST_INTEREST_ADDRESS + item_offset;
  161. case TARGET_TYPE_AR9888:
  162. return AR9888_HOST_INTEREST_ADDRESS + item_offset;
  163. case TARGET_TYPE_AR6320:
  164. case TARGET_TYPE_AR6320V2:
  165. return AR6320_HOST_INTEREST_ADDRESS + item_offset;
  166. case TARGET_TYPE_ADRASTEA:
  167. /* ADRASTEA doesn't have a host interest address */
  168. ASSERT(0);
  169. return 0;
  170. case TARGET_TYPE_AR900B:
  171. return AR900B_HOST_INTEREST_ADDRESS + item_offset;
  172. case TARGET_TYPE_QCA9984:
  173. return QCA9984_HOST_INTEREST_ADDRESS + item_offset;
  174. case TARGET_TYPE_QCA9888:
  175. return QCA9888_HOST_INTEREST_ADDRESS + item_offset;
  176. case TARGET_TYPE_IPQ4019:
  177. return IPQ4019_HOST_INTEREST_ADDRESS + item_offset;
  178. default:
  179. ASSERT(0);
  180. return 0;
  181. }
  182. }
  183. /**
  184. * hif_max_num_receives_reached() - check max receive is reached
  185. * @scn: HIF Context
  186. * @count: unsigned int.
  187. *
  188. * Output check status as bool
  189. *
  190. * Return: bool
  191. */
  192. bool hif_max_num_receives_reached(struct hif_softc *scn, unsigned int count)
  193. {
  194. if (QDF_IS_EPPING_ENABLED(hif_get_conparam(scn)))
  195. return count > 120;
  196. else
  197. return count > MAX_NUM_OF_RECEIVES;
  198. }
  199. /**
  200. * init_buffer_count() - initial buffer count
  201. * @maxSize: qdf_size_t
  202. *
  203. * routine to modify the initial buffer count to be allocated on an os
  204. * platform basis. Platform owner will need to modify this as needed
  205. *
  206. * Return: qdf_size_t
  207. */
  208. qdf_size_t init_buffer_count(qdf_size_t maxSize)
  209. {
  210. return maxSize;
  211. }
  212. /**
  213. * hif_save_htc_htt_config_endpoint() - save htt_tx_endpoint
  214. * @hif_ctx: hif context
  215. * @htc_htt_tx_endpoint: htt_tx_endpoint
  216. *
  217. * Return: void
  218. */
  219. void hif_save_htc_htt_config_endpoint(struct hif_opaque_softc *hif_ctx,
  220. int htc_htt_tx_endpoint)
  221. {
  222. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  223. if (!scn) {
  224. HIF_ERROR("%s: error: scn or scn->hif_sc is NULL!",
  225. __func__);
  226. return;
  227. }
  228. scn->htc_htt_tx_endpoint = htc_htt_tx_endpoint;
  229. }
  230. static const struct qwlan_hw qwlan_hw_list[] = {
  231. {
  232. .id = AR6320_REV1_VERSION,
  233. .subid = 0,
  234. .name = "QCA6174_REV1",
  235. },
  236. {
  237. .id = AR6320_REV1_1_VERSION,
  238. .subid = 0x1,
  239. .name = "QCA6174_REV1_1",
  240. },
  241. {
  242. .id = AR6320_REV1_3_VERSION,
  243. .subid = 0x2,
  244. .name = "QCA6174_REV1_3",
  245. },
  246. {
  247. .id = AR6320_REV2_1_VERSION,
  248. .subid = 0x4,
  249. .name = "QCA6174_REV2_1",
  250. },
  251. {
  252. .id = AR6320_REV2_1_VERSION,
  253. .subid = 0x5,
  254. .name = "QCA6174_REV2_2",
  255. },
  256. {
  257. .id = AR6320_REV3_VERSION,
  258. .subid = 0x6,
  259. .name = "QCA6174_REV2.3",
  260. },
  261. {
  262. .id = AR6320_REV3_VERSION,
  263. .subid = 0x8,
  264. .name = "QCA6174_REV3",
  265. },
  266. {
  267. .id = AR6320_REV3_VERSION,
  268. .subid = 0x9,
  269. .name = "QCA6174_REV3_1",
  270. },
  271. {
  272. .id = AR6320_REV3_2_VERSION,
  273. .subid = 0xA,
  274. .name = "AR6320_REV3_2_VERSION",
  275. },
  276. {
  277. .id = WCN3990_v1,
  278. .subid = 0x0,
  279. .name = "WCN3990_V1",
  280. },
  281. {
  282. .id = WCN3990_v2,
  283. .subid = 0x0,
  284. .name = "WCN3990_V2",
  285. },
  286. {
  287. .id = WCN3990_v2_1,
  288. .subid = 0x0,
  289. .name = "WCN3990_V2.1",
  290. },
  291. {
  292. .id = QCA9379_REV1_VERSION,
  293. .subid = 0xC,
  294. .name = "QCA9379_REV1",
  295. },
  296. {
  297. .id = QCA9379_REV1_VERSION,
  298. .subid = 0xD,
  299. .name = "QCA9379_REV1_1",
  300. }
  301. };
  302. /**
  303. * hif_get_hw_name(): get a human readable name for the hardware
  304. * @info: Target Info
  305. *
  306. * Return: human readable name for the underlying wifi hardware.
  307. */
  308. static const char *hif_get_hw_name(struct hif_target_info *info)
  309. {
  310. int i;
  311. if (info->hw_name)
  312. return info->hw_name;
  313. for (i = 0; i < ARRAY_SIZE(qwlan_hw_list); i++) {
  314. if (info->target_version == qwlan_hw_list[i].id &&
  315. info->target_revision == qwlan_hw_list[i].subid) {
  316. return qwlan_hw_list[i].name;
  317. }
  318. }
  319. info->hw_name = qdf_mem_malloc(64);
  320. if (!info->hw_name)
  321. return "Unknown Device (nomem)";
  322. i = qdf_snprint(info->hw_name, 64, "HW_VERSION=%x.",
  323. info->target_version);
  324. if (i < 0)
  325. return "Unknown Device (snprintf failure)";
  326. else
  327. return info->hw_name;
  328. }
  329. /**
  330. * hif_get_hw_info(): hif_get_hw_info
  331. * @scn: scn
  332. * @version: version
  333. * @revision: revision
  334. *
  335. * Return: n/a
  336. */
  337. void hif_get_hw_info(struct hif_opaque_softc *scn, u32 *version, u32 *revision,
  338. const char **target_name)
  339. {
  340. struct hif_target_info *info = hif_get_target_info_handle(scn);
  341. struct hif_softc *sc = HIF_GET_SOFTC(scn);
  342. if (sc->bus_type == QDF_BUS_TYPE_USB)
  343. hif_usb_get_hw_info(sc);
  344. *version = info->target_version;
  345. *revision = info->target_revision;
  346. *target_name = hif_get_hw_name(info);
  347. }
  348. /**
  349. * hif_get_dev_ba(): API to get device base address.
  350. * @scn: scn
  351. * @version: version
  352. * @revision: revision
  353. *
  354. * Return: n/a
  355. */
  356. void *hif_get_dev_ba(struct hif_opaque_softc *hif_handle)
  357. {
  358. struct hif_softc *scn = (struct hif_softc *)hif_handle;
  359. return scn->mem;
  360. }
  361. /**
  362. * hif_open(): hif_open
  363. * @qdf_ctx: QDF Context
  364. * @mode: Driver Mode
  365. * @bus_type: Bus Type
  366. * @cbk: CDS Callbacks
  367. *
  368. * API to open HIF Context
  369. *
  370. * Return: HIF Opaque Pointer
  371. */
  372. struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx, uint32_t mode,
  373. enum qdf_bus_type bus_type,
  374. struct hif_driver_state_callbacks *cbk)
  375. {
  376. struct hif_softc *scn;
  377. QDF_STATUS status = QDF_STATUS_SUCCESS;
  378. int bus_context_size = hif_bus_get_context_size(bus_type);
  379. if (bus_context_size == 0) {
  380. HIF_ERROR("%s: context size 0 not allowed", __func__);
  381. return NULL;
  382. }
  383. scn = (struct hif_softc *)qdf_mem_malloc(bus_context_size);
  384. if (!scn) {
  385. HIF_ERROR("%s: cannot alloc memory for HIF context of size:%d",
  386. __func__, bus_context_size);
  387. return GET_HIF_OPAQUE_HDL(scn);
  388. }
  389. scn->qdf_dev = qdf_ctx;
  390. scn->hif_con_param = mode;
  391. qdf_atomic_init(&scn->active_tasklet_cnt);
  392. qdf_atomic_init(&scn->active_grp_tasklet_cnt);
  393. qdf_atomic_init(&scn->link_suspended);
  394. qdf_atomic_init(&scn->tasklet_from_intr);
  395. qdf_mem_copy(&scn->callbacks, cbk, sizeof(struct hif_driver_state_callbacks));
  396. scn->bus_type = bus_type;
  397. status = hif_bus_open(scn, bus_type);
  398. if (status != QDF_STATUS_SUCCESS) {
  399. HIF_ERROR("%s: hif_bus_open error = %d, bus_type = %d",
  400. __func__, status, bus_type);
  401. qdf_mem_free(scn);
  402. scn = NULL;
  403. }
  404. return GET_HIF_OPAQUE_HDL(scn);
  405. }
  406. /**
  407. * hif_close(): hif_close
  408. * @hif_ctx: hif_ctx
  409. *
  410. * Return: n/a
  411. */
  412. void hif_close(struct hif_opaque_softc *hif_ctx)
  413. {
  414. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  415. if (scn == NULL) {
  416. HIF_ERROR("%s: hif_opaque_softc is NULL", __func__);
  417. return;
  418. }
  419. if (scn->athdiag_procfs_inited) {
  420. athdiag_procfs_remove();
  421. scn->athdiag_procfs_inited = false;
  422. }
  423. if (scn->target_info.hw_name) {
  424. char *hw_name = scn->target_info.hw_name;
  425. scn->target_info.hw_name = "ErrUnloading";
  426. qdf_mem_free(hw_name);
  427. }
  428. hif_bus_close(scn);
  429. qdf_mem_free(scn);
  430. }
  431. #ifdef QCA_WIFI_QCA8074
  432. static QDF_STATUS hif_hal_attach(struct hif_softc *scn)
  433. {
  434. if (ce_srng_based(scn)) {
  435. scn->hal_soc = hal_attach(scn, scn->qdf_dev);
  436. if (scn->hal_soc == NULL)
  437. return QDF_STATUS_E_FAILURE;
  438. }
  439. return QDF_STATUS_SUCCESS;
  440. }
  441. #else
  442. static QDF_STATUS hif_hal_attach(struct hif_softc *scn)
  443. {
  444. return QDF_STATUS_SUCCESS;
  445. }
  446. #endif
  447. /**
  448. * hif_enable(): hif_enable
  449. * @hif_ctx: hif_ctx
  450. * @dev: dev
  451. * @bdev: bus dev
  452. * @bid: bus ID
  453. * @bus_type: bus type
  454. * @type: enable type
  455. *
  456. * Return: QDF_STATUS
  457. */
  458. QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev,
  459. void *bdev, const hif_bus_id *bid,
  460. enum qdf_bus_type bus_type,
  461. enum hif_enable_type type)
  462. {
  463. QDF_STATUS status;
  464. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  465. if (scn == NULL) {
  466. HIF_ERROR("%s: hif_ctx = NULL", __func__);
  467. return QDF_STATUS_E_NULL_VALUE;
  468. }
  469. status = hif_enable_bus(scn, dev, bdev, bid, type);
  470. if (status != QDF_STATUS_SUCCESS) {
  471. HIF_ERROR("%s: hif_enable_bus error = %d",
  472. __func__, status);
  473. return status;
  474. }
  475. status = hif_hal_attach(scn);
  476. if (status != QDF_STATUS_SUCCESS) {
  477. HIF_ERROR("%s: hal attach failed", __func__);
  478. return status;
  479. }
  480. if (hif_bus_configure(scn)) {
  481. HIF_ERROR("%s: Target probe failed.", __func__);
  482. hif_disable_bus(scn);
  483. status = QDF_STATUS_E_FAILURE;
  484. return status;
  485. }
  486. /*
  487. * Flag to avoid potential unallocated memory access from MSI
  488. * interrupt handler which could get scheduled as soon as MSI
  489. * is enabled, i.e to take care of the race due to the order
  490. * in where MSI is enabled before the memory, that will be
  491. * in interrupt handlers, is allocated.
  492. */
  493. scn->hif_init_done = true;
  494. HIF_TRACE("%s: OK", __func__);
  495. return QDF_STATUS_SUCCESS;
  496. }
  497. void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type)
  498. {
  499. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  500. if (!scn)
  501. return;
  502. hif_nointrs(scn);
  503. if (scn->hif_init_done == false)
  504. hif_shutdown_device(hif_ctx);
  505. else
  506. hif_stop(hif_ctx);
  507. hif_disable_bus(scn);
  508. hif_wlan_disable(scn);
  509. scn->notice_send = false;
  510. HIF_INFO("%s: X", __func__);
  511. }
  512. void hif_display_stats(struct hif_opaque_softc *hif_ctx)
  513. {
  514. hif_display_bus_stats(hif_ctx);
  515. }
  516. void hif_clear_stats(struct hif_opaque_softc *hif_ctx)
  517. {
  518. hif_clear_bus_stats(hif_ctx);
  519. }
  520. /**
  521. * hif_crash_shutdown_dump_bus_register() - dump bus registers
  522. * @hif_ctx: hif_ctx
  523. *
  524. * Return: n/a
  525. */
  526. #if defined(TARGET_RAMDUMP_AFTER_KERNEL_PANIC) \
  527. && defined(DEBUG)
  528. static void hif_crash_shutdown_dump_bus_register(void *hif_ctx)
  529. {
  530. struct hif_opaque_softc *scn = hif_ctx;
  531. if (hif_check_soc_status(scn))
  532. return;
  533. if (hif_dump_registers(scn))
  534. HIF_ERROR("Failed to dump bus registers!");
  535. }
  536. /**
  537. * hif_crash_shutdown(): hif_crash_shutdown
  538. *
  539. * This function is called by the platform driver to dump CE registers
  540. *
  541. * @hif_ctx: hif_ctx
  542. *
  543. * Return: n/a
  544. */
  545. void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx)
  546. {
  547. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  548. if (!hif_ctx)
  549. return;
  550. if (scn->bus_type == QDF_BUS_TYPE_SNOC) {
  551. HIF_INFO_MED("%s: RAM dump disabled for bustype %d",
  552. __func__, scn->bus_type);
  553. return;
  554. }
  555. if (TARGET_STATUS_RESET == scn->target_status) {
  556. HIF_INFO_MED("%s: Target is already asserted, ignore!",
  557. __func__);
  558. return;
  559. }
  560. if (hif_is_load_or_unload_in_progress(scn)) {
  561. HIF_ERROR("%s: Load/unload is in progress, ignore!", __func__);
  562. return;
  563. }
  564. hif_crash_shutdown_dump_bus_register(hif_ctx);
  565. if (ol_copy_ramdump(hif_ctx))
  566. goto out;
  567. HIF_INFO_MED("%s: RAM dump collecting completed!", __func__);
  568. out:
  569. return;
  570. }
  571. #else
  572. void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx)
  573. {
  574. HIF_INFO_MED("%s: Collecting target RAM dump disabled",
  575. __func__);
  576. return;
  577. }
  578. #endif /* TARGET_RAMDUMP_AFTER_KERNEL_PANIC */
  579. #ifdef QCA_WIFI_3_0
  580. /**
  581. * hif_check_fw_reg(): hif_check_fw_reg
  582. * @scn: scn
  583. * @state:
  584. *
  585. * Return: int
  586. */
  587. int hif_check_fw_reg(struct hif_opaque_softc *scn)
  588. {
  589. return 0;
  590. }
  591. #endif
  592. #ifdef IPA_OFFLOAD
  593. /**
  594. * hif_read_phy_mem_base(): hif_read_phy_mem_base
  595. * @scn: scn
  596. * @phy_mem_base: physical mem base
  597. *
  598. * Return: n/a
  599. */
  600. void hif_read_phy_mem_base(struct hif_softc *scn, qdf_dma_addr_t *phy_mem_base)
  601. {
  602. *phy_mem_base = scn->mem_pa;
  603. }
  604. #endif /* IPA_OFFLOAD */
  605. /**
  606. * hif_get_device_type(): hif_get_device_type
  607. * @device_id: device_id
  608. * @revision_id: revision_id
  609. * @hif_type: returned hif_type
  610. * @target_type: returned target_type
  611. *
  612. * Return: int
  613. */
  614. int hif_get_device_type(uint32_t device_id,
  615. uint32_t revision_id,
  616. uint32_t *hif_type, uint32_t *target_type)
  617. {
  618. int ret = 0;
  619. switch (device_id) {
  620. case ADRASTEA_DEVICE_ID_P2_E12:
  621. *hif_type = HIF_TYPE_ADRASTEA;
  622. *target_type = TARGET_TYPE_ADRASTEA;
  623. break;
  624. case AR9888_DEVICE_ID:
  625. *hif_type = HIF_TYPE_AR9888;
  626. *target_type = TARGET_TYPE_AR9888;
  627. break;
  628. case AR6320_DEVICE_ID:
  629. switch (revision_id) {
  630. case AR6320_FW_1_1:
  631. case AR6320_FW_1_3:
  632. *hif_type = HIF_TYPE_AR6320;
  633. *target_type = TARGET_TYPE_AR6320;
  634. break;
  635. case AR6320_FW_2_0:
  636. case AR6320_FW_3_0:
  637. case AR6320_FW_3_2:
  638. *hif_type = HIF_TYPE_AR6320V2;
  639. *target_type = TARGET_TYPE_AR6320V2;
  640. break;
  641. default:
  642. HIF_ERROR("%s: error - dev_id = 0x%x, rev_id = 0x%x",
  643. __func__, device_id, revision_id);
  644. ret = -ENODEV;
  645. goto end;
  646. }
  647. break;
  648. case AR9887_DEVICE_ID:
  649. *hif_type = HIF_TYPE_AR9888;
  650. *target_type = TARGET_TYPE_AR9888;
  651. HIF_INFO(" *********** AR9887 **************");
  652. break;
  653. case QCA9984_DEVICE_ID:
  654. *hif_type = HIF_TYPE_QCA9984;
  655. *target_type = TARGET_TYPE_QCA9984;
  656. HIF_INFO(" *********** QCA9984 *************");
  657. break;
  658. case QCA9888_DEVICE_ID:
  659. *hif_type = HIF_TYPE_QCA9888;
  660. *target_type = TARGET_TYPE_QCA9888;
  661. HIF_INFO(" *********** QCA9888 *************");
  662. break;
  663. case AR900B_DEVICE_ID:
  664. *hif_type = HIF_TYPE_AR900B;
  665. *target_type = TARGET_TYPE_AR900B;
  666. HIF_INFO(" *********** AR900B *************");
  667. break;
  668. case IPQ4019_DEVICE_ID:
  669. *hif_type = HIF_TYPE_IPQ4019;
  670. *target_type = TARGET_TYPE_IPQ4019;
  671. HIF_INFO(" *********** IPQ4019 *************");
  672. break;
  673. case QCA8074_DEVICE_ID:
  674. case RUMIM2M_DEVICE_ID_NODE0:
  675. case RUMIM2M_DEVICE_ID_NODE1:
  676. case RUMIM2M_DEVICE_ID_NODE2:
  677. case RUMIM2M_DEVICE_ID_NODE3:
  678. *hif_type = HIF_TYPE_QCA8074;
  679. *target_type = TARGET_TYPE_QCA8074;
  680. HIF_INFO(" *********** QCA8074 *************\n");
  681. break;
  682. case QCA6290_EMULATION_DEVICE_ID:
  683. *hif_type = HIF_TYPE_QCA6290;
  684. *target_type = TARGET_TYPE_QCA6290;
  685. HIF_INFO(" *********** QCA6290EMU *************\n");
  686. break;
  687. default:
  688. HIF_ERROR("%s: Unsupported device ID!", __func__);
  689. ret = -ENODEV;
  690. break;
  691. }
  692. end:
  693. return ret;
  694. }
  695. /**
  696. * hif_needs_bmi() - return true if the soc needs bmi through the driver
  697. * @hif_ctx: hif context
  698. *
  699. * Return: true if the soc needs driver bmi otherwise false
  700. */
  701. bool hif_needs_bmi(struct hif_opaque_softc *hif_ctx)
  702. {
  703. struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx);
  704. return (hif_sc->bus_type != QDF_BUS_TYPE_SNOC) &&
  705. !ce_srng_based(hif_sc);
  706. }
  707. /**
  708. * hif_get_bus_type() - return the bus type
  709. *
  710. * Return: enum qdf_bus_type
  711. */
  712. enum qdf_bus_type hif_get_bus_type(struct hif_opaque_softc *hif_hdl)
  713. {
  714. struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl);
  715. return scn->bus_type;
  716. }
  717. /**
  718. * Target info and ini parameters are global to the driver
  719. * Hence these structures are exposed to all the modules in
  720. * the driver and they don't need to maintains multiple copies
  721. * of the same info, instead get the handle from hif and
  722. * modify them in hif
  723. */
  724. /**
  725. * hif_get_ini_handle() - API to get hif_config_param handle
  726. * @hif_ctx: HIF Context
  727. *
  728. * Return: pointer to hif_config_info
  729. */
  730. struct hif_config_info *hif_get_ini_handle(struct hif_opaque_softc *hif_ctx)
  731. {
  732. struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx);
  733. return &sc->hif_config;
  734. }
  735. /**
  736. * hif_get_target_info_handle() - API to get hif_target_info handle
  737. * @hif_ctx: HIF context
  738. *
  739. * Return: Pointer to hif_target_info
  740. */
  741. struct hif_target_info *hif_get_target_info_handle(
  742. struct hif_opaque_softc *hif_ctx)
  743. {
  744. struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx);
  745. return &sc->target_info;
  746. }
  747. #if defined(FEATURE_LRO)
  748. /**
  749. * hif_lro_flush_cb_register - API to register for LRO Flush Callback
  750. * @scn: HIF Context
  751. * @handler: Function pointer to be called by HIF
  752. * @data: Private data to be used by the module registering to HIF
  753. *
  754. * Return: void
  755. */
  756. void hif_lro_flush_cb_register(struct hif_opaque_softc *scn,
  757. void (lro_flush_handler)(void *),
  758. void *(lro_init_handler)(void))
  759. {
  760. if (hif_napi_enabled(scn, -1))
  761. hif_napi_lro_flush_cb_register(scn, lro_flush_handler,
  762. lro_init_handler);
  763. else
  764. ce_lro_flush_cb_register(scn, lro_flush_handler,
  765. lro_init_handler);
  766. }
  767. /**
  768. * hif_get_lro_info - Returns LRO instance for instance ID
  769. * @ctx_id: LRO instance ID
  770. * @hif_hdl: HIF Context
  771. *
  772. * Return: Pointer to LRO instance.
  773. */
  774. void *hif_get_lro_info(int ctx_id, struct hif_opaque_softc *hif_hdl)
  775. {
  776. void *data;
  777. if (hif_napi_enabled(hif_hdl, -1))
  778. data = hif_napi_get_lro_info(hif_hdl, ctx_id);
  779. else
  780. data = hif_ce_get_lro_ctx(hif_hdl, ctx_id);
  781. return data;
  782. }
  783. /**
  784. * hif_get_rx_ctx_id - Returns LRO instance ID based on underlying LRO instance
  785. * @ctx_id: LRO context ID
  786. * @hif_hdl: HIF Context
  787. *
  788. * Return: LRO instance ID
  789. */
  790. int hif_get_rx_ctx_id(int ctx_id, struct hif_opaque_softc *hif_hdl)
  791. {
  792. if (hif_napi_enabled(hif_hdl, -1))
  793. return NAPI_PIPE2ID(ctx_id);
  794. else
  795. return ctx_id;
  796. }
  797. /**
  798. * hif_lro_flush_cb_deregister - API to deregister for LRO Flush Callbacks
  799. * @hif_hdl: HIF Context
  800. * @lro_deinit_cb: LRO deinit callback
  801. *
  802. * Return: void
  803. */
  804. void hif_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl,
  805. void (lro_deinit_cb)(void *))
  806. {
  807. if (hif_napi_enabled(hif_hdl, -1))
  808. hif_napi_lro_flush_cb_deregister(hif_hdl, lro_deinit_cb);
  809. else
  810. ce_lro_flush_cb_deregister(hif_hdl, lro_deinit_cb);
  811. }
  812. #else /* !defined(FEATURE_LRO) */
  813. int hif_get_rx_ctx_id(int ctx_id, struct hif_opaque_softc *hif_hdl)
  814. {
  815. return 0;
  816. }
  817. #endif
  818. /**
  819. * hif_get_target_status - API to get target status
  820. * @hif_ctx: HIF Context
  821. *
  822. * Return: enum hif_target_status
  823. */
  824. enum hif_target_status hif_get_target_status(struct hif_opaque_softc *hif_ctx)
  825. {
  826. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  827. return scn->target_status;
  828. }
  829. /**
  830. * hif_set_target_status() - API to set target status
  831. * @hif_ctx: HIF Context
  832. * @status: Target Status
  833. *
  834. * Return: void
  835. */
  836. void hif_set_target_status(struct hif_opaque_softc *hif_ctx, enum
  837. hif_target_status status)
  838. {
  839. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  840. scn->target_status = status;
  841. }
  842. /**
  843. * hif_init_ini_config() - API to initialize HIF configuration parameters
  844. * @hif_ctx: HIF Context
  845. * @cfg: HIF Configuration
  846. *
  847. * Return: void
  848. */
  849. void hif_init_ini_config(struct hif_opaque_softc *hif_ctx,
  850. struct hif_config_info *cfg)
  851. {
  852. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  853. qdf_mem_copy(&scn->hif_config, cfg, sizeof(struct hif_config_info));
  854. }
  855. /**
  856. * hif_get_conparam() - API to get driver mode in HIF
  857. * @scn: HIF Context
  858. *
  859. * Return: driver mode of operation
  860. */
  861. uint32_t hif_get_conparam(struct hif_softc *scn)
  862. {
  863. if (!scn)
  864. return 0;
  865. return scn->hif_con_param;
  866. }
  867. /**
  868. * hif_get_callbacks_handle() - API to get callbacks Handle
  869. * @scn: HIF Context
  870. *
  871. * Return: pointer to HIF Callbacks
  872. */
  873. struct hif_driver_state_callbacks *hif_get_callbacks_handle(struct hif_softc *scn)
  874. {
  875. return &scn->callbacks;
  876. }
  877. /**
  878. * hif_is_driver_unloading() - API to query upper layers if driver is unloading
  879. * @scn: HIF Context
  880. *
  881. * Return: True/False
  882. */
  883. bool hif_is_driver_unloading(struct hif_softc *scn)
  884. {
  885. struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn);
  886. if (cbk && cbk->is_driver_unloading)
  887. return cbk->is_driver_unloading(cbk->context);
  888. return false;
  889. }
  890. /**
  891. * hif_is_load_or_unload_in_progress() - API to query upper layers if
  892. * load/unload in progress
  893. * @scn: HIF Context
  894. *
  895. * Return: True/False
  896. */
  897. bool hif_is_load_or_unload_in_progress(struct hif_softc *scn)
  898. {
  899. struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn);
  900. if (cbk && cbk->is_load_unload_in_progress)
  901. return cbk->is_load_unload_in_progress(cbk->context);
  902. return false;
  903. }
  904. /**
  905. * hif_update_pipe_callback() - API to register pipe specific callbacks
  906. * @osc: Opaque softc
  907. * @pipeid: pipe id
  908. * @callbacks: callbacks to register
  909. *
  910. * Return: void
  911. */
  912. void hif_update_pipe_callback(struct hif_opaque_softc *osc,
  913. u_int8_t pipeid,
  914. struct hif_msg_callbacks *callbacks)
  915. {
  916. struct hif_softc *scn = HIF_GET_SOFTC(osc);
  917. struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
  918. struct HIF_CE_pipe_info *pipe_info;
  919. QDF_BUG(pipeid < CE_COUNT_MAX);
  920. HIF_INFO_LO("+%s pipeid %d\n", __func__, pipeid);
  921. pipe_info = &hif_state->pipe_info[pipeid];
  922. qdf_mem_copy(&pipe_info->pipe_callbacks,
  923. callbacks, sizeof(pipe_info->pipe_callbacks));
  924. HIF_INFO_LO("-%s\n", __func__);
  925. }
  926. /**
  927. * hif_is_recovery_in_progress() - API to query upper layers if recovery in
  928. * progress
  929. * @scn: HIF Context
  930. *
  931. * Return: True/False
  932. */
  933. bool hif_is_recovery_in_progress(struct hif_softc *scn)
  934. {
  935. struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn);
  936. if (cbk && cbk->is_recovery_in_progress)
  937. return cbk->is_recovery_in_progress(cbk->context);
  938. return false;
  939. }
  940. #if defined(HIF_PCI) || defined(SNOC) || defined(HIF_AHB)
  941. /**
  942. * hif_batch_send() - API to access hif specific function
  943. * ce_batch_send.
  944. * @osc: HIF Context
  945. * @msdu : list of msdus to be sent
  946. * @transfer_id : transfer id
  947. * @len : donwloaded length
  948. *
  949. * Return: list of msds not sent
  950. */
  951. qdf_nbuf_t hif_batch_send(struct hif_opaque_softc *osc, qdf_nbuf_t msdu,
  952. uint32_t transfer_id, u_int32_t len, uint32_t sendhead)
  953. {
  954. void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE);
  955. return ce_batch_send((struct CE_handle *)ce_tx_hdl, msdu, transfer_id,
  956. len, sendhead);
  957. }
  958. /**
  959. * hif_update_tx_ring() - API to access hif specific function
  960. * ce_update_tx_ring.
  961. * @osc: HIF Context
  962. * @num_htt_cmpls : number of htt compl received.
  963. *
  964. * Return: void
  965. */
  966. void hif_update_tx_ring(struct hif_opaque_softc *osc, u_int32_t num_htt_cmpls)
  967. {
  968. void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE);
  969. ce_update_tx_ring(ce_tx_hdl, num_htt_cmpls);
  970. }
  971. /**
  972. * hif_send_single() - API to access hif specific function
  973. * ce_send_single.
  974. * @osc: HIF Context
  975. * @msdu : msdu to be sent
  976. * @transfer_id: transfer id
  977. * @len : downloaded length
  978. *
  979. * Return: msdu sent status
  980. */
  981. int hif_send_single(struct hif_opaque_softc *osc, qdf_nbuf_t msdu, uint32_t
  982. transfer_id, u_int32_t len)
  983. {
  984. void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE);
  985. return ce_send_single((struct CE_handle *)ce_tx_hdl, msdu, transfer_id,
  986. len);
  987. }
  988. /**
  989. * hif_send_fast() - API to access hif specific function
  990. * ce_send_fast.
  991. * @osc: HIF Context
  992. * @msdu : array of msdus to be sent
  993. * @num_msdus : number of msdus in an array
  994. * @transfer_id: transfer id
  995. * @download_len: download length
  996. *
  997. * Return: No. of packets that could be sent
  998. */
  999. int hif_send_fast(struct hif_opaque_softc *osc, qdf_nbuf_t nbuf,
  1000. uint32_t transfer_id, uint32_t download_len)
  1001. {
  1002. void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE);
  1003. return ce_send_fast((struct CE_handle *)ce_tx_hdl, nbuf,
  1004. transfer_id, download_len);
  1005. }
  1006. #endif
  1007. /**
  1008. * hif_reg_write() - API to access hif specific function
  1009. * hif_write32_mb.
  1010. * @hif_ctx : HIF Context
  1011. * @offset : offset on which value has to be written
  1012. * @value : value to be written
  1013. *
  1014. * Return: None
  1015. */
  1016. void hif_reg_write(struct hif_opaque_softc *hif_ctx, uint32_t offset,
  1017. uint32_t value)
  1018. {
  1019. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  1020. hif_write32_mb(scn->mem + offset, value);
  1021. }
  1022. /**
  1023. * hif_reg_read() - API to access hif specific function
  1024. * hif_read32_mb.
  1025. * @hif_ctx : HIF Context
  1026. * @offset : offset from which value has to be read
  1027. *
  1028. * Return: Read value
  1029. */
  1030. uint32_t hif_reg_read(struct hif_opaque_softc *hif_ctx, uint32_t offset)
  1031. {
  1032. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  1033. return hif_read32_mb(scn->mem + offset);
  1034. }
  1035. #if defined(HIF_USB)
  1036. /**
  1037. * hif_ramdump_handler(): generic ramdump handler
  1038. * @scn: struct hif_opaque_softc
  1039. *
  1040. * Return: None
  1041. */
  1042. void hif_ramdump_handler(struct hif_opaque_softc *scn)
  1043. {
  1044. if (hif_get_bus_type == QDF_BUS_TYPE_USB)
  1045. hif_usb_ramdump_handler();
  1046. }
  1047. #endif
  1048. /**
  1049. * hif_register_ext_group_int_handler() - API to register external group
  1050. * interrupt handler.
  1051. * @hif_ctx : HIF Context
  1052. * @numirq: number of irq's in the group
  1053. * @irq: array of irq values
  1054. * @ext_intr_handler: callback interrupt handler function
  1055. * @context: context to passed in callback
  1056. *
  1057. * Return: status
  1058. */
  1059. uint32_t hif_register_ext_group_int_handler(struct hif_opaque_softc *hif_ctx,
  1060. uint32_t numirq, uint32_t irq[], ext_intr_handler handler,
  1061. void *context)
  1062. {
  1063. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  1064. struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
  1065. struct hif_ext_group_entry *hif_ext_group;
  1066. if (scn->ext_grp_irq_configured) {
  1067. HIF_ERROR("%s Called after ext grp irq configured\n", __func__);
  1068. return QDF_STATUS_E_FAILURE;
  1069. }
  1070. if (hif_state->hif_num_extgroup >= HIF_MAX_GROUP) {
  1071. HIF_ERROR("%s Max groups reached\n", __func__);
  1072. return QDF_STATUS_E_FAILURE;
  1073. }
  1074. if (numirq >= HIF_MAX_GRP_IRQ) {
  1075. HIF_ERROR("%s invalid numirq\n", __func__);
  1076. return QDF_STATUS_E_FAILURE;
  1077. }
  1078. hif_ext_group = &hif_state->hif_ext_group[hif_state->hif_num_extgroup];
  1079. hif_ext_group->numirq = numirq;
  1080. qdf_mem_copy(&hif_ext_group->irq[0], irq, numirq * sizeof(irq[0]));
  1081. hif_ext_group->context = context;
  1082. hif_ext_group->handler = handler;
  1083. hif_ext_group->configured = true;
  1084. hif_ext_group->grp_id = hif_state->hif_num_extgroup;
  1085. hif_ext_group->hif_state = hif_state;
  1086. hif_state->hif_num_extgroup++;
  1087. return QDF_STATUS_SUCCESS;
  1088. }
  1089. /**
  1090. * hif_configure_ext_group_interrupts() - API to configure external group
  1091. * interrpts
  1092. * @hif_ctx : HIF Context
  1093. *
  1094. * Return: status
  1095. */
  1096. uint32_t hif_configure_ext_group_interrupts(struct hif_opaque_softc *hif_ctx)
  1097. {
  1098. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  1099. if (scn->ext_grp_irq_configured) {
  1100. HIF_ERROR("%s Called after ext grp irq configured\n", __func__);
  1101. return QDF_STATUS_E_FAILURE;
  1102. }
  1103. hif_grp_irq_configure(scn);
  1104. scn->ext_grp_irq_configured = true;
  1105. return QDF_STATUS_SUCCESS;
  1106. }
  1107. /**
  1108. * hif_ext_grp_tasklet() - grp tasklet
  1109. * data: context
  1110. *
  1111. * return: void
  1112. */
  1113. void hif_ext_grp_tasklet(unsigned long data)
  1114. {
  1115. struct hif_ext_group_entry *hif_ext_group =
  1116. (struct hif_ext_group_entry *)data;
  1117. struct HIF_CE_state *hif_state = hif_ext_group->hif_state;
  1118. struct hif_softc *scn = HIF_GET_SOFTC(hif_state);
  1119. if (hif_ext_group->grp_id < HIF_MAX_GROUP) {
  1120. hif_ext_group->handler(hif_ext_group->context, HIF_MAX_BUDGET);
  1121. hif_grp_irq_enable(scn, hif_ext_group->grp_id);
  1122. } else {
  1123. HIF_ERROR("%s: ERROR - invalid grp_id = %d",
  1124. __func__, hif_ext_group->grp_id);
  1125. }
  1126. qdf_atomic_dec(&scn->active_grp_tasklet_cnt);
  1127. }
  1128. /**
  1129. * hif_grp_tasklet_kill() - grp tasklet kill
  1130. * scn: hif_softc
  1131. *
  1132. * return: void
  1133. */
  1134. void hif_grp_tasklet_kill(struct hif_softc *scn)
  1135. {
  1136. int i;
  1137. struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
  1138. for (i = 0; i < HIF_MAX_GROUP; i++)
  1139. if (hif_state->hif_ext_group[i].inited) {
  1140. tasklet_kill(&hif_state->hif_ext_group[i].intr_tq);
  1141. hif_state->hif_ext_group[i].inited = false;
  1142. }
  1143. qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0);
  1144. }