if_snoc.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  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. /**
  27. * DOC: if_snoc.c
  28. *
  29. * c file for snoc specif implementations.
  30. */
  31. #include "hif.h"
  32. #include "hif_main.h"
  33. #include "hif_debug.h"
  34. #include "hif_io32.h"
  35. #include "ce_main.h"
  36. #include "ce_tasklet.h"
  37. #include "snoc_api.h"
  38. #include <soc/qcom/icnss.h>
  39. #include "pld_common.h"
  40. #include "qdf_util.h"
  41. #ifdef IPA_OFFLOAD
  42. #include <uapi/linux/msm_ipa.h>
  43. #endif
  44. /**
  45. * hif_disable_isr(): disable isr
  46. *
  47. * This function disables isr and kills tasklets
  48. *
  49. * @hif_ctx: struct hif_softc
  50. *
  51. * Return: void
  52. */
  53. void hif_snoc_disable_isr(struct hif_softc *scn)
  54. {
  55. hif_nointrs(scn);
  56. ce_tasklet_kill(scn);
  57. hif_grp_tasklet_kill(scn);
  58. qdf_atomic_set(&scn->active_tasklet_cnt, 0);
  59. qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0);
  60. }
  61. /**
  62. * hif_dump_registers(): dump bus debug registers
  63. * @hif_ctx: struct hif_opaque_softc
  64. *
  65. * This function dumps hif bus debug registers
  66. *
  67. * Return: 0 for success or error code
  68. */
  69. int hif_snoc_dump_registers(struct hif_softc *hif_ctx)
  70. {
  71. int status;
  72. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  73. status = hif_dump_ce_registers(scn);
  74. if (status)
  75. HIF_ERROR("%s: Dump CE Registers Failed", __func__);
  76. return 0;
  77. }
  78. void hif_snoc_display_stats(struct hif_softc *hif_ctx)
  79. {
  80. struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
  81. if (hif_state == NULL) {
  82. HIF_ERROR("%s, hif_ctx null", __func__);
  83. return;
  84. }
  85. hif_display_ce_stats(hif_state);
  86. }
  87. void hif_snoc_clear_stats(struct hif_softc *hif_ctx)
  88. {
  89. struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
  90. if (hif_state == NULL) {
  91. HIF_ERROR("%s, hif_ctx null", __func__);
  92. return;
  93. }
  94. hif_clear_ce_stats(hif_state);
  95. }
  96. /**
  97. * hif_snoc_close(): hif_bus_close
  98. *
  99. * Return: n/a
  100. */
  101. void hif_snoc_close(struct hif_softc *scn)
  102. {
  103. hif_ce_close(scn);
  104. }
  105. /**
  106. * hif_bus_open(): hif_bus_open
  107. * @hif_ctx: hif context
  108. * @bus_type: bus type
  109. *
  110. * Return: n/a
  111. */
  112. QDF_STATUS hif_snoc_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
  113. {
  114. return hif_ce_open(hif_ctx);
  115. }
  116. /**
  117. * hif_snoc_get_soc_info() - populates scn with hw info
  118. *
  119. * fills in the virtual and physical base address as well as
  120. * soc version info.
  121. *
  122. * return 0 or QDF_STATUS_E_FAILURE
  123. */
  124. static QDF_STATUS hif_snoc_get_soc_info(struct hif_softc *scn)
  125. {
  126. int ret;
  127. struct pld_soc_info soc_info;
  128. qdf_mem_zero(&soc_info, sizeof(soc_info));
  129. ret = pld_get_soc_info(scn->qdf_dev->dev, &soc_info);
  130. if (ret < 0) {
  131. HIF_ERROR("%s: pld_get_soc_info error = %d", __func__, ret);
  132. return QDF_STATUS_E_FAILURE;
  133. }
  134. scn->mem = soc_info.v_addr;
  135. scn->mem_pa = soc_info.p_addr;
  136. scn->target_info.soc_version = soc_info.soc_id;
  137. scn->target_info.target_version = soc_info.soc_id;
  138. scn->target_info.target_revision = 0;
  139. return QDF_STATUS_SUCCESS;
  140. }
  141. /**
  142. * hif_bus_configure() - configure the snoc bus
  143. * @scn: pointer to the hif context.
  144. *
  145. * return: 0 for success. nonzero for failure.
  146. */
  147. int hif_snoc_bus_configure(struct hif_softc *scn)
  148. {
  149. int ret;
  150. ret = hif_snoc_get_soc_info(scn);
  151. if (ret)
  152. return ret;
  153. hif_ce_prepare_config(scn);
  154. ret = hif_wlan_enable(scn);
  155. if (ret) {
  156. HIF_ERROR("%s: hif_wlan_enable error = %d",
  157. __func__, ret);
  158. return ret;
  159. }
  160. ret = hif_config_ce(scn);
  161. if (ret)
  162. hif_wlan_disable(scn);
  163. return ret;
  164. }
  165. /**
  166. * hif_snoc_get_target_type(): Get the target type
  167. *
  168. * This function is used to query the target type.
  169. *
  170. * @ol_sc: hif_softc struct pointer
  171. * @dev: device pointer
  172. * @bdev: bus dev pointer
  173. * @bid: bus id pointer
  174. * @hif_type: HIF type such as HIF_TYPE_QCA6180
  175. * @target_type: target type such as TARGET_TYPE_QCA6180
  176. *
  177. * Return: 0 for success
  178. */
  179. static inline int hif_snoc_get_target_type(struct hif_softc *ol_sc,
  180. struct device *dev, void *bdev, const struct hif_bus_id *bid,
  181. uint32_t *hif_type, uint32_t *target_type)
  182. {
  183. /* TODO: need to use HW version. Hard code for now */
  184. #ifdef QCA_WIFI_3_0_ADRASTEA
  185. *hif_type = HIF_TYPE_ADRASTEA;
  186. *target_type = TARGET_TYPE_ADRASTEA;
  187. #else
  188. *hif_type = 0;
  189. *target_type = 0;
  190. #endif
  191. return 0;
  192. }
  193. #ifdef IPA_OFFLOAD
  194. static int hif_set_dma_coherent_mask(struct device *dev)
  195. {
  196. uint8_t addr_bits;
  197. if (hif_get_ipa_hw_type() < IPA_HW_v3_0)
  198. addr_bits = DMA_COHERENT_MASK_BELOW_IPA_VER_3;
  199. else
  200. addr_bits = DMA_COHERENT_MASK_IPA_VER_3_AND_ABOVE;
  201. return qdf_set_dma_coherent_mask(dev, addr_bits);
  202. }
  203. #else
  204. static int hif_set_dma_coherent_mask(struct device *dev)
  205. {
  206. return qdf_set_dma_coherent_mask(dev, 37);
  207. }
  208. #endif
  209. /**
  210. * hif_enable_bus(): hif_enable_bus
  211. * @dev: dev
  212. * @bdev: bus dev
  213. * @bid: bus id
  214. * @type: bus type
  215. *
  216. * Return: QDF_STATUS
  217. */
  218. QDF_STATUS hif_snoc_enable_bus(struct hif_softc *ol_sc,
  219. struct device *dev, void *bdev,
  220. const struct hif_bus_id *bid,
  221. enum hif_enable_type type)
  222. {
  223. int ret;
  224. int hif_type;
  225. int target_type;
  226. if (!ol_sc) {
  227. HIF_ERROR("%s: hif_ctx is NULL", __func__);
  228. return QDF_STATUS_E_NOMEM;
  229. }
  230. ret = hif_set_dma_coherent_mask(dev);
  231. if (ret) {
  232. HIF_ERROR("%s: failed to set dma mask error = %d",
  233. __func__, ret);
  234. return ret;
  235. }
  236. ret = qdf_device_init_wakeup(ol_sc->qdf_dev, true);
  237. if (ret == -EEXIST)
  238. HIF_WARN("%s: device_init_wakeup already done",
  239. __func__);
  240. else if (ret) {
  241. HIF_ERROR("%s: device_init_wakeup: err= %d",
  242. __func__, ret);
  243. return ret;
  244. }
  245. ret = hif_snoc_get_target_type(ol_sc, dev, bdev, bid,
  246. &hif_type, &target_type);
  247. if (ret < 0) {
  248. HIF_ERROR("%s: invalid device id/revision_id", __func__);
  249. return QDF_STATUS_E_FAILURE;
  250. }
  251. ol_sc->target_info.target_type = target_type;
  252. hif_register_tbl_attach(ol_sc, hif_type);
  253. hif_target_register_tbl_attach(ol_sc, target_type);
  254. /* the bus should remain on durring suspend for snoc */
  255. hif_vote_link_up(GET_HIF_OPAQUE_HDL(ol_sc));
  256. HIF_TRACE("%s: X - hif_type = 0x%x, target_type = 0x%x",
  257. __func__, hif_type, target_type);
  258. return QDF_STATUS_SUCCESS;
  259. }
  260. /**
  261. * hif_disable_bus(): hif_disable_bus
  262. *
  263. * This function disables the bus
  264. *
  265. * @bdev: bus dev
  266. *
  267. * Return: none
  268. */
  269. void hif_snoc_disable_bus(struct hif_softc *scn)
  270. {
  271. int ret;
  272. hif_vote_link_down(GET_HIF_OPAQUE_HDL(scn));
  273. ret = qdf_device_init_wakeup(scn->qdf_dev, false);
  274. if (ret)
  275. HIF_ERROR("%s: device_init_wakeup: err %d", __func__, ret);
  276. }
  277. /**
  278. * hif_nointrs(): disable IRQ
  279. *
  280. * This function stops interrupt(s)
  281. *
  282. * @scn: struct hif_softc
  283. *
  284. * Return: none
  285. */
  286. void hif_snoc_nointrs(struct hif_softc *scn)
  287. {
  288. struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
  289. ce_unregister_irq(hif_state, CE_ALL_BITMAP);
  290. }
  291. /**
  292. * ce_irq_enable() - enable copy engine IRQ
  293. * @scn: struct hif_softc
  294. * @ce_id: ce_id
  295. *
  296. * Return: N/A
  297. */
  298. void hif_snoc_irq_enable(struct hif_softc *scn,
  299. int ce_id)
  300. {
  301. ce_enable_irq_in_individual_register(scn, ce_id);
  302. }
  303. /**
  304. * ce_irq_disable() - disable copy engine IRQ
  305. * @scn: struct hif_softc
  306. * @ce_id: ce_id
  307. *
  308. * Return: N/A
  309. */
  310. void hif_snoc_irq_disable(struct hif_softc *scn, int ce_id)
  311. {
  312. ce_disable_irq_in_individual_register(scn, ce_id);
  313. }
  314. /*
  315. * hif_snoc_setup_wakeup_sources() - enable/disable irq wake on correct irqs
  316. * @hif_softc: hif context
  317. *
  318. * Firmware will send a wakeup request to the HTC_CTRL_RSVD_SVC when waking up
  319. * the host driver. Ensure that the copy complete interrupt from this copy
  320. * engine can wake up the apps processor.
  321. *
  322. * Return: 0 for success
  323. */
  324. static
  325. QDF_STATUS hif_snoc_setup_wakeup_sources(struct hif_softc *scn, bool enable)
  326. {
  327. struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn);
  328. uint8_t ul_pipe, dl_pipe;
  329. int ul_is_polled, dl_is_polled;
  330. int irq_to_wake_on;
  331. QDF_STATUS status;
  332. int ret;
  333. status = hif_map_service_to_pipe(hif_hdl, HTC_CTRL_RSVD_SVC,
  334. &ul_pipe, &dl_pipe,
  335. &ul_is_polled, &dl_is_polled);
  336. if (status) {
  337. HIF_ERROR("%s: pipe_mapping failure", __func__);
  338. return status;
  339. }
  340. irq_to_wake_on = icnss_get_irq(dl_pipe);
  341. if (irq_to_wake_on < 0) {
  342. HIF_ERROR("%s: failed to map ce to irq", __func__);
  343. return QDF_STATUS_E_RESOURCES;
  344. }
  345. if (enable)
  346. ret = enable_irq_wake(irq_to_wake_on);
  347. else
  348. ret = disable_irq_wake(irq_to_wake_on);
  349. if (ret) {
  350. HIF_ERROR("%s: Fail to setup wake IRQ!", __func__);
  351. return QDF_STATUS_E_RESOURCES;
  352. }
  353. HIF_INFO("%s: expecting wake from ce %d, irq %d enable %d",
  354. __func__, dl_pipe, irq_to_wake_on, enable);
  355. return QDF_STATUS_SUCCESS;
  356. }
  357. /**
  358. * hif_snoc_bus_suspend() - prepare to suspend the bus
  359. * @scn: hif context
  360. *
  361. * Setup wakeup interrupt configuration.
  362. * Disable CE interrupts (wakeup interrupt will still wake apps)
  363. * Drain tasklets. - make sure that we don't suspend while processing
  364. * the wakeup message.
  365. *
  366. * Return: 0 on success.
  367. */
  368. int hif_snoc_bus_suspend(struct hif_softc *scn)
  369. {
  370. if (hif_snoc_setup_wakeup_sources(scn, true) != QDF_STATUS_SUCCESS)
  371. return -EFAULT;
  372. return 0;
  373. }
  374. /**
  375. * hif_snoc_bus_resume() - snoc bus resume function
  376. * @scn: hif context
  377. *
  378. * Clear wakeup interrupt configuration.
  379. * Reenable ce interrupts
  380. *
  381. * Return: 0 on success
  382. */
  383. int hif_snoc_bus_resume(struct hif_softc *scn)
  384. {
  385. if (hif_snoc_setup_wakeup_sources(scn, false) != QDF_STATUS_SUCCESS)
  386. QDF_BUG(0);
  387. return 0;
  388. }
  389. /**
  390. * hif_snoc_bus_suspend_noirq() - ensure there are no pending transactions
  391. * @scn: hif context
  392. *
  393. * Ensure that if we recieved the wakeup message before the irq
  394. * was disabled that the message is pocessed before suspending.
  395. *
  396. * Return: -EBUSY if we fail to flush the tasklets.
  397. */
  398. int hif_snoc_bus_suspend_noirq(struct hif_softc *scn)
  399. {
  400. if (hif_drain_tasklets(scn) != 0)
  401. return -EBUSY;
  402. return 0;
  403. }
  404. int hif_snoc_map_ce_to_irq(struct hif_softc *scn, int ce_id)
  405. {
  406. return icnss_get_irq(ce_id);
  407. }