bmi.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. /*
  2. * Copyright (c) 2014-2016 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 "i_bmi.h"
  27. #include "cds_api.h"
  28. /* APIs visible to the driver */
  29. QDF_STATUS bmi_init(struct ol_context *ol_ctx)
  30. {
  31. struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
  32. struct hif_opaque_softc *scn = ol_ctx->scn;
  33. qdf_device_t qdf_dev = ol_ctx->qdf_dev;
  34. if (!scn) {
  35. BMI_ERR("Invalid scn Context");
  36. bmi_assert(0);
  37. return QDF_STATUS_NOT_INITIALIZED;
  38. }
  39. if (!qdf_dev->dev) {
  40. BMI_ERR("%s: Invalid Device Pointer", __func__);
  41. return QDF_STATUS_NOT_INITIALIZED;
  42. }
  43. info->bmi_done = false;
  44. if (!info->bmi_cmd_buff) {
  45. info->bmi_cmd_buff =
  46. qdf_mem_alloc_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ,
  47. &info->bmi_cmd_da);
  48. if (!info->bmi_cmd_buff) {
  49. BMI_ERR("No Memory for BMI Command");
  50. return QDF_STATUS_E_NOMEM;
  51. }
  52. }
  53. if (!info->bmi_rsp_buff) {
  54. info->bmi_rsp_buff =
  55. qdf_mem_alloc_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ,
  56. &info->bmi_rsp_da);
  57. if (!info->bmi_rsp_buff) {
  58. BMI_ERR("No Memory for BMI Response");
  59. goto end;
  60. }
  61. }
  62. return QDF_STATUS_SUCCESS;
  63. end:
  64. qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ,
  65. info->bmi_cmd_buff, info->bmi_cmd_da, 0);
  66. info->bmi_cmd_buff = NULL;
  67. return QDF_STATUS_E_NOMEM;
  68. }
  69. void bmi_cleanup(struct ol_context *ol_ctx)
  70. {
  71. struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
  72. qdf_device_t qdf_dev;
  73. if (!info || !ol_ctx) {
  74. BMI_WARN("%s: no bmi to cleanup", __func__);
  75. return;
  76. }
  77. qdf_dev = ol_ctx->qdf_dev;
  78. if (!qdf_dev || !qdf_dev->dev) {
  79. BMI_ERR("%s: Invalid Device Pointer", __func__);
  80. return;
  81. }
  82. if (info->bmi_cmd_buff) {
  83. qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
  84. MAX_BMI_CMDBUF_SZ,
  85. info->bmi_cmd_buff, info->bmi_cmd_da, 0);
  86. info->bmi_cmd_buff = NULL;
  87. info->bmi_cmd_da = 0;
  88. }
  89. if (info->bmi_rsp_buff) {
  90. qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
  91. MAX_BMI_CMDBUF_SZ,
  92. info->bmi_rsp_buff, info->bmi_rsp_da, 0);
  93. info->bmi_rsp_buff = NULL;
  94. info->bmi_rsp_da = 0;
  95. }
  96. }
  97. /**
  98. * bmi_done() - finish the bmi opperation
  99. * @ol_ctx: the bmi context
  100. *
  101. * does some sanity checking.
  102. * exchanges one last message with firmware.
  103. * frees some buffers.
  104. *
  105. * Return: QDF_STATUS_SUCCESS if bmi isn't needed.
  106. * QDF_STATUS_SUCCESS if bmi finishes.
  107. * otherwise returns failure.
  108. */
  109. QDF_STATUS bmi_done(struct ol_context *ol_ctx)
  110. {
  111. QDF_STATUS status = QDF_STATUS_SUCCESS;
  112. if (NO_BMI)
  113. return QDF_STATUS_SUCCESS;
  114. if (!ol_ctx) {
  115. BMI_ERR("%s: null context", __func__);
  116. return QDF_STATUS_E_NOMEM;
  117. }
  118. hif_claim_device(ol_ctx->scn);
  119. if (!hif_needs_bmi(ol_ctx->scn))
  120. return QDF_STATUS_SUCCESS;
  121. status = bmi_done_local(ol_ctx);
  122. if (status != QDF_STATUS_SUCCESS)
  123. BMI_ERR("BMI_DONE Failed status:%d", status);
  124. return status;
  125. }
  126. void bmi_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx)
  127. {
  128. ol_target_ready(scn, cfg_ctx);
  129. }
  130. static QDF_STATUS
  131. bmi_get_target_info_message_based(struct bmi_target_info *targ_info,
  132. struct ol_context *ol_ctx)
  133. {
  134. int status = 0;
  135. struct hif_opaque_softc *scn = ol_ctx->scn;
  136. struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
  137. uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
  138. uint8_t *bmi_rsp_buff = info->bmi_rsp_buff;
  139. uint32_t cid, length;
  140. qdf_dma_addr_t cmd = info->bmi_cmd_da;
  141. qdf_dma_addr_t rsp = info->bmi_rsp_da;
  142. if (!bmi_cmd_buff || !bmi_rsp_buff) {
  143. BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__);
  144. return QDF_STATUS_NOT_INITIALIZED;
  145. }
  146. cid = BMI_GET_TARGET_INFO;
  147. qdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid));
  148. length = sizeof(struct bmi_target_info);
  149. status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, sizeof(cid),
  150. (uint8_t *)bmi_rsp_buff, &length,
  151. BMI_EXCHANGE_TIMEOUT_MS);
  152. if (status) {
  153. BMI_ERR("Failed to target info: status:%d", status);
  154. return QDF_STATUS_E_FAILURE;
  155. }
  156. qdf_mem_copy(targ_info, bmi_rsp_buff, length);
  157. return QDF_STATUS_SUCCESS;
  158. }
  159. QDF_STATUS
  160. bmi_get_target_info(struct bmi_target_info *targ_info,
  161. struct ol_context *ol_ctx)
  162. {
  163. struct hif_opaque_softc *scn = ol_ctx->scn;
  164. struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
  165. QDF_STATUS status;
  166. if (info->bmi_done) {
  167. BMI_ERR("BMI Phase is Already Done");
  168. return QDF_STATUS_E_PERM;
  169. }
  170. switch (hif_get_bus_type(scn)) {
  171. case QDF_BUS_TYPE_PCI:
  172. case QDF_BUS_TYPE_SNOC:
  173. status = bmi_get_target_info_message_based(targ_info, ol_ctx);
  174. break;
  175. case QDF_BUS_TYPE_SDIO:
  176. status = hif_reg_based_get_target_info(scn, targ_info);
  177. break;
  178. default:
  179. status = QDF_STATUS_E_FAILURE;
  180. break;
  181. }
  182. return status;
  183. }
  184. QDF_STATUS bmi_download_firmware(struct ol_context *ol_ctx)
  185. {
  186. struct hif_opaque_softc *scn = ol_ctx->scn;
  187. if (NO_BMI || !hif_needs_bmi(scn))
  188. return QDF_STATUS_SUCCESS;
  189. if (!scn) {
  190. BMI_ERR("Invalid scn context");
  191. bmi_assert(0);
  192. return QDF_STATUS_NOT_INITIALIZED;
  193. }
  194. return bmi_firmware_download(ol_ctx);
  195. }
  196. QDF_STATUS bmi_read_soc_register(uint32_t address, uint32_t *param,
  197. struct ol_context *ol_ctx)
  198. {
  199. struct hif_opaque_softc *scn = ol_ctx->scn;
  200. uint32_t cid;
  201. int status;
  202. uint32_t offset, param_len;
  203. struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
  204. uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
  205. uint8_t *bmi_rsp_buff = info->bmi_rsp_buff;
  206. qdf_dma_addr_t cmd = info->bmi_cmd_da;
  207. qdf_dma_addr_t rsp = info->bmi_rsp_da;
  208. bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
  209. qdf_mem_set(bmi_cmd_buff, 0, sizeof(cid) + sizeof(address));
  210. qdf_mem_set(bmi_rsp_buff, 0, sizeof(cid) + sizeof(address));
  211. if (info->bmi_done) {
  212. BMI_DBG("Command disallowed");
  213. return QDF_STATUS_E_PERM;
  214. }
  215. BMI_DBG("BMI Read SOC Register:device: 0x%p, address: 0x%x",
  216. scn, address);
  217. cid = BMI_READ_SOC_REGISTER;
  218. offset = 0;
  219. qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
  220. offset += sizeof(cid);
  221. qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
  222. offset += sizeof(address);
  223. param_len = sizeof(*param);
  224. status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset,
  225. bmi_rsp_buff, &param_len, BMI_EXCHANGE_TIMEOUT_MS);
  226. if (status) {
  227. BMI_DBG("Unable to read from the device; status:%d", status);
  228. return QDF_STATUS_E_FAILURE;
  229. }
  230. qdf_mem_copy(param, bmi_rsp_buff, sizeof(*param));
  231. BMI_DBG("BMI Read SOC Register: Exit value: %d", *param);
  232. return QDF_STATUS_SUCCESS;
  233. }
  234. QDF_STATUS bmi_write_soc_register(uint32_t address, uint32_t param,
  235. struct ol_context *ol_ctx)
  236. {
  237. struct hif_opaque_softc *scn = ol_ctx->scn;
  238. uint32_t cid;
  239. int status;
  240. uint32_t offset;
  241. struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
  242. uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
  243. uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param);
  244. qdf_dma_addr_t cmd = info->bmi_cmd_da;
  245. qdf_dma_addr_t rsp = info->bmi_rsp_da;
  246. bmi_assert(BMI_COMMAND_FITS(size));
  247. qdf_mem_set(bmi_cmd_buff, 0, size);
  248. if (info->bmi_done) {
  249. BMI_DBG("Command disallowed");
  250. return QDF_STATUS_E_FAILURE;
  251. }
  252. BMI_DBG("SOC Register Write:device:0x%p, addr:0x%x, param:%d",
  253. scn, address, param);
  254. cid = BMI_WRITE_SOC_REGISTER;
  255. offset = 0;
  256. qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
  257. offset += sizeof(cid);
  258. qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
  259. offset += sizeof(address);
  260. qdf_mem_copy(&(bmi_cmd_buff[offset]), &param, sizeof(param));
  261. offset += sizeof(param);
  262. status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset,
  263. NULL, NULL, 0);
  264. if (status) {
  265. BMI_ERR("Unable to write to the device: status:%d", status);
  266. return QDF_STATUS_E_FAILURE;
  267. }
  268. BMI_DBG("BMI Read SOC Register: Exit");
  269. return QDF_STATUS_SUCCESS;
  270. }
  271. QDF_STATUS
  272. bmilz_data(uint8_t *buffer, uint32_t length, struct ol_context *ol_ctx)
  273. {
  274. uint32_t cid;
  275. int status;
  276. uint32_t offset;
  277. uint32_t remaining, txlen;
  278. const uint32_t header = sizeof(cid) + sizeof(length);
  279. struct hif_opaque_softc *scn = ol_ctx->scn;
  280. struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
  281. uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
  282. qdf_dma_addr_t cmd = info->bmi_cmd_da;
  283. qdf_dma_addr_t rsp = info->bmi_rsp_da;
  284. bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
  285. qdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header);
  286. if (info->bmi_done) {
  287. BMI_ERR("Command disallowed");
  288. return QDF_STATUS_E_PERM;
  289. }
  290. BMI_DBG("BMI Send LZ Data: device: 0x%p, length: %d",
  291. scn, length);
  292. cid = BMI_LZ_DATA;
  293. remaining = length;
  294. while (remaining) {
  295. txlen = (remaining < (BMI_DATASZ_MAX - header)) ?
  296. remaining : (BMI_DATASZ_MAX - header);
  297. offset = 0;
  298. qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
  299. offset += sizeof(cid);
  300. qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen));
  301. offset += sizeof(txlen);
  302. qdf_mem_copy(&(bmi_cmd_buff[offset]),
  303. &buffer[length - remaining], txlen);
  304. offset += txlen;
  305. status = hif_exchange_bmi_msg(scn, cmd, rsp,
  306. bmi_cmd_buff, offset,
  307. NULL, NULL, 0);
  308. if (status) {
  309. BMI_ERR("Failed to write to the device: status:%d",
  310. status);
  311. return QDF_STATUS_E_FAILURE;
  312. }
  313. remaining -= txlen;
  314. }
  315. BMI_DBG("BMI LZ Data: Exit");
  316. return QDF_STATUS_SUCCESS;
  317. }
  318. QDF_STATUS bmi_sign_stream_start(uint32_t address, uint8_t *buffer,
  319. uint32_t length, struct ol_context *ol_ctx)
  320. {
  321. uint32_t cid;
  322. int status;
  323. uint32_t offset;
  324. const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length);
  325. uint8_t aligned_buf[BMI_DATASZ_MAX + 4];
  326. uint8_t *src;
  327. struct hif_opaque_softc *scn = ol_ctx->scn;
  328. struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
  329. uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
  330. uint32_t remaining, txlen;
  331. qdf_dma_addr_t cmd = info->bmi_cmd_da;
  332. qdf_dma_addr_t rsp = info->bmi_rsp_da;
  333. bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
  334. qdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header);
  335. if (info->bmi_done) {
  336. BMI_ERR("Command disallowed");
  337. return QDF_STATUS_E_PERM;
  338. }
  339. BMI_ERR("Sign Stream start:device:0x%p, addr:0x%x, length:%d",
  340. scn, address, length);
  341. cid = BMI_SIGN_STREAM_START;
  342. remaining = length;
  343. while (remaining) {
  344. src = &buffer[length - remaining];
  345. if (remaining < (BMI_DATASZ_MAX - header)) {
  346. if (remaining & 0x3) {
  347. remaining = remaining + (4 - (remaining & 0x3));
  348. memcpy(aligned_buf, src, remaining);
  349. src = aligned_buf;
  350. }
  351. txlen = remaining;
  352. } else {
  353. txlen = (BMI_DATASZ_MAX - header);
  354. }
  355. offset = 0;
  356. qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
  357. offset += sizeof(cid);
  358. qdf_mem_copy(&(bmi_cmd_buff[offset]), &address,
  359. sizeof(address));
  360. offset += sizeof(offset);
  361. qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen));
  362. offset += sizeof(txlen);
  363. qdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen);
  364. offset += txlen;
  365. status = hif_exchange_bmi_msg(scn, cmd, rsp,
  366. bmi_cmd_buff, offset, NULL,
  367. NULL, BMI_EXCHANGE_TIMEOUT_MS);
  368. if (status) {
  369. BMI_ERR("Unable to write to the device: status:%d",
  370. status);
  371. return QDF_STATUS_E_FAILURE;
  372. }
  373. remaining -= txlen;
  374. }
  375. BMI_DBG("BMI SIGN Stream Start: Exit");
  376. return QDF_STATUS_SUCCESS;
  377. }
  378. QDF_STATUS
  379. bmilz_stream_start(uint32_t address, struct ol_context *ol_ctx)
  380. {
  381. uint32_t cid;
  382. int status;
  383. uint32_t offset;
  384. struct hif_opaque_softc *scn = ol_ctx->scn;
  385. struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
  386. uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
  387. qdf_dma_addr_t cmd = info->bmi_cmd_da;
  388. qdf_dma_addr_t rsp = info->bmi_rsp_da;
  389. bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
  390. qdf_mem_set(bmi_cmd_buff, 0, sizeof(cid) + sizeof(address));
  391. if (info->bmi_done) {
  392. BMI_DBG("Command disallowed");
  393. return QDF_STATUS_E_PERM;
  394. }
  395. BMI_DBG("BMI LZ Stream Start: (device: 0x%p, address: 0x%x)",
  396. scn, address);
  397. cid = BMI_LZ_STREAM_START;
  398. offset = 0;
  399. qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
  400. offset += sizeof(cid);
  401. qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
  402. offset += sizeof(address);
  403. status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset,
  404. NULL, NULL, 0);
  405. if (status) {
  406. BMI_ERR("Unable to Start LZ Stream to the device status:%d",
  407. status);
  408. return QDF_STATUS_E_FAILURE;
  409. }
  410. BMI_DBG("BMI LZ Stream: Exit");
  411. return QDF_STATUS_SUCCESS;
  412. }
  413. QDF_STATUS
  414. bmi_fast_download(uint32_t address, uint8_t *buffer,
  415. uint32_t length, struct ol_context *ol_ctx)
  416. {
  417. QDF_STATUS status = QDF_STATUS_E_FAILURE;
  418. uint32_t last_word = 0;
  419. uint32_t last_word_offset = length & ~0x3;
  420. uint32_t unaligned_bytes = length & 0x3;
  421. status = bmilz_stream_start(address, ol_ctx);
  422. if (status != QDF_STATUS_SUCCESS)
  423. goto end;
  424. /* copy the last word into a zero padded buffer */
  425. if (unaligned_bytes)
  426. qdf_mem_copy(&last_word, &buffer[last_word_offset],
  427. unaligned_bytes);
  428. status = bmilz_data(buffer, last_word_offset, ol_ctx);
  429. if (status != QDF_STATUS_SUCCESS)
  430. goto end;
  431. if (unaligned_bytes)
  432. status = bmilz_data((uint8_t *) &last_word, 4, ol_ctx);
  433. if (status != QDF_STATUS_SUCCESS)
  434. /*
  435. * Close compressed stream and open a new (fake) one.
  436. * This serves mainly to flush Target caches.
  437. */
  438. status = bmilz_stream_start(0x00, ol_ctx);
  439. end:
  440. return status;
  441. }
  442. /**
  443. * ol_cds_init() - API to initialize global CDS OL Context
  444. * @qdf_dev: QDF Device
  445. * @hif_ctx: HIF Context
  446. *
  447. * Return: Success/Failure
  448. */
  449. QDF_STATUS ol_cds_init(qdf_device_t qdf_dev, void *hif_ctx)
  450. {
  451. struct ol_context *ol_info;
  452. QDF_STATUS status = QDF_STATUS_SUCCESS;
  453. if (NO_BMI)
  454. return QDF_STATUS_SUCCESS; /* no BMI for Q6 bring up */
  455. status = cds_alloc_context(cds_get_global_context(), QDF_MODULE_ID_BMI,
  456. (void **)&ol_info, sizeof(*ol_info));
  457. if (status != QDF_STATUS_SUCCESS) {
  458. BMI_ERR("%s: CDS Allocation failed for ol_bmi context",
  459. __func__);
  460. return status;
  461. }
  462. ol_info->qdf_dev = qdf_dev;
  463. ol_info->scn = hif_ctx;
  464. ol_info->tgt_def.targetdef = hif_get_targetdef(hif_ctx);
  465. qdf_create_work(qdf_dev, &ol_info->ramdump_work,
  466. ramdump_work_handler, ol_info);
  467. qdf_create_work(qdf_dev, &ol_info->fw_indication_work,
  468. fw_indication_work_handler, ol_info);
  469. return status;
  470. }
  471. /**
  472. * ol_cds_free() - API to free the global CDS OL Context
  473. *
  474. * Return: void
  475. */
  476. void ol_cds_free(void)
  477. {
  478. struct ol_context *ol_info = cds_get_context(QDF_MODULE_ID_BMI);
  479. if (NO_BMI)
  480. return;
  481. cds_free_context(cds_get_global_context(), QDF_MODULE_ID_BMI, ol_info);
  482. }