if_ipci.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. /*
  2. * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. */
  15. #include <linux/slab.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/if_arp.h>
  18. #ifdef CONFIG_PCI_MSM
  19. #include <linux/msm_pcie.h>
  20. #endif
  21. #include "hif_io32.h"
  22. #include "if_ipci.h"
  23. #include "hif.h"
  24. #include "target_type.h"
  25. #include "hif_main.h"
  26. #include "ce_main.h"
  27. #include "ce_api.h"
  28. #include "ce_internal.h"
  29. #include "ce_reg.h"
  30. #include "ce_bmi.h"
  31. #include "regtable.h"
  32. #include "hif_hw_version.h"
  33. #include <linux/debugfs.h>
  34. #include <linux/seq_file.h>
  35. #include "qdf_status.h"
  36. #include "qdf_atomic.h"
  37. #include "pld_common.h"
  38. #include "mp_dev.h"
  39. #include "hif_debug.h"
  40. #include "ce_tasklet.h"
  41. #include "targaddrs.h"
  42. #include "hif_exec.h"
  43. #include "ipci_api.h"
  44. void hif_ipci_enable_power_management(struct hif_softc *hif_sc,
  45. bool is_packet_log_enabled)
  46. {
  47. }
  48. void hif_ipci_disable_power_management(struct hif_softc *hif_ctx)
  49. {
  50. }
  51. void hif_ipci_display_stats(struct hif_softc *hif_ctx)
  52. {
  53. hif_display_ce_stats(hif_ctx);
  54. }
  55. void hif_ipci_clear_stats(struct hif_softc *hif_ctx)
  56. {
  57. struct hif_ipci_softc *ipci_ctx = HIF_GET_IPCI_SOFTC(hif_ctx);
  58. if (!ipci_ctx) {
  59. HIF_ERROR("%s, hif_ctx null", __func__);
  60. return;
  61. }
  62. hif_clear_ce_stats(&ipci_ctx->ce_sc);
  63. }
  64. QDF_STATUS hif_ipci_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
  65. {
  66. struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(hif_ctx);
  67. hif_ctx->bus_type = bus_type;
  68. qdf_spinlock_create(&sc->irq_lock);
  69. return hif_ce_open(hif_ctx);
  70. }
  71. /**
  72. * hif_ce_msi_map_ce_to_irq() - map CE to IRQ
  73. * @scn: hif context
  74. * @ce_id: CE Id
  75. *
  76. * Return: IRQ number
  77. */
  78. static int hif_ce_msi_map_ce_to_irq(struct hif_softc *scn, int ce_id)
  79. {
  80. struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
  81. return ipci_scn->ce_msi_irq_num[ce_id];
  82. }
  83. int hif_ipci_bus_configure(struct hif_softc *hif_sc)
  84. {
  85. int status = 0;
  86. struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc);
  87. uint8_t wake_ce_id;
  88. hif_ce_prepare_config(hif_sc);
  89. /* initialize sleep state adjust variables */
  90. hif_state->sleep_timer_init = true;
  91. hif_state->keep_awake_count = 0;
  92. hif_state->fake_sleep = false;
  93. hif_state->sleep_ticks = 0;
  94. status = hif_wlan_enable(hif_sc);
  95. if (status) {
  96. HIF_ERROR("%s: hif_wlan_enable error = %d",
  97. __func__, status);
  98. goto timer_free;
  99. }
  100. A_TARGET_ACCESS_LIKELY(hif_sc);
  101. status = hif_config_ce(hif_sc);
  102. if (status)
  103. goto disable_wlan;
  104. status = hif_get_wake_ce_id(hif_sc, &wake_ce_id);
  105. if (status)
  106. goto unconfig_ce;
  107. status = hif_configure_irq(hif_sc);
  108. if (status < 0)
  109. goto unconfig_ce;
  110. hif_sc->wake_irq = hif_ce_msi_map_ce_to_irq(hif_sc, wake_ce_id);
  111. HIF_INFO("expecting wake from ce %d, irq %d",
  112. wake_ce_id, hif_sc->wake_irq);
  113. A_TARGET_ACCESS_UNLIKELY(hif_sc);
  114. return status;
  115. unconfig_ce:
  116. hif_unconfig_ce(hif_sc);
  117. disable_wlan:
  118. A_TARGET_ACCESS_UNLIKELY(hif_sc);
  119. hif_wlan_disable(hif_sc);
  120. timer_free:
  121. qdf_timer_stop(&hif_state->sleep_timer);
  122. qdf_timer_free(&hif_state->sleep_timer);
  123. hif_state->sleep_timer_init = false;
  124. HIF_ERROR("%s: failed, status = %d", __func__, status);
  125. return status;
  126. }
  127. void hif_ipci_close(struct hif_softc *hif_sc)
  128. {
  129. hif_ce_close(hif_sc);
  130. }
  131. /**
  132. * hif_ce_srng_msi_free_irq(): free CE msi IRQ
  133. * @scn: struct hif_softc
  134. *
  135. * Return: ErrorNo
  136. */
  137. static int hif_ce_srng_msi_free_irq(struct hif_softc *scn)
  138. {
  139. int ret;
  140. int ce_id, irq;
  141. uint32_t msi_data_start;
  142. uint32_t msi_data_count;
  143. uint32_t msi_irq_start;
  144. struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
  145. ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
  146. &msi_data_count, &msi_data_start,
  147. &msi_irq_start);
  148. if (ret)
  149. return ret;
  150. /* needs to match the ce_id -> irq data mapping
  151. * used in the srng parameter configuration
  152. */
  153. for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
  154. unsigned int msi_data;
  155. if (!ce_sc->tasklets[ce_id].inited)
  156. continue;
  157. msi_data = (ce_id % msi_data_count) + msi_irq_start;
  158. irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
  159. hif_debug("%s: (ce_id %d, msi_data %d, irq %d)", __func__,
  160. ce_id, msi_data, irq);
  161. pfrm_free_irq(scn->qdf_dev->dev, irq, &ce_sc->tasklets[ce_id]);
  162. }
  163. return ret;
  164. }
  165. /**
  166. * hif_ipci_deconfigure_grp_irq(): deconfigure HW block IRQ
  167. * @scn: struct hif_softc
  168. *
  169. * Return: none
  170. */
  171. static void hif_ipci_deconfigure_grp_irq(struct hif_softc *scn)
  172. {
  173. int i, j, irq;
  174. struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
  175. struct hif_exec_context *hif_ext_group;
  176. for (i = 0; i < hif_state->hif_num_extgroup; i++) {
  177. hif_ext_group = hif_state->hif_ext_group[i];
  178. if (hif_ext_group->irq_requested) {
  179. hif_ext_group->irq_requested = false;
  180. for (j = 0; j < hif_ext_group->numirq; j++) {
  181. irq = hif_ext_group->os_irq[j];
  182. pfrm_free_irq(scn->qdf_dev->dev,
  183. irq, hif_ext_group);
  184. }
  185. hif_ext_group->numirq = 0;
  186. }
  187. }
  188. }
  189. void hif_ipci_nointrs(struct hif_softc *scn)
  190. {
  191. int ret;
  192. struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
  193. ce_unregister_irq(hif_state, CE_ALL_BITMAP);
  194. if (scn->request_irq_done == false)
  195. return;
  196. hif_ipci_deconfigure_grp_irq(scn);
  197. ret = hif_ce_srng_msi_free_irq(scn);
  198. scn->request_irq_done = false;
  199. }
  200. void hif_ipci_disable_bus(struct hif_softc *scn)
  201. {
  202. struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(scn);
  203. void __iomem *mem;
  204. /* Attach did not succeed, all resources have been
  205. * freed in error handler
  206. */
  207. if (!sc)
  208. return;
  209. mem = (void __iomem *)sc->mem;
  210. if (mem) {
  211. hif_dump_pipe_debug_count(scn);
  212. if (scn->athdiag_procfs_inited) {
  213. athdiag_procfs_remove();
  214. scn->athdiag_procfs_inited = false;
  215. }
  216. scn->mem = NULL;
  217. }
  218. HIF_INFO("%s: X", __func__);
  219. }
  220. #if defined(CONFIG_PCI_MSM)
  221. void hif_ipci_prevent_linkdown(struct hif_softc *scn, bool flag)
  222. {
  223. int errno;
  224. HIF_INFO("wlan: %s pcie power collapse", flag ? "disable" : "enable");
  225. errno = pld_wlan_pm_control(scn->qdf_dev->dev, flag);
  226. if (errno)
  227. HIF_ERROR("%s: Failed pld_wlan_pm_control; errno %d",
  228. __func__, errno);
  229. }
  230. #else
  231. void hif_ipci_prevent_linkdown(struct hif_softc *scn, bool flag)
  232. {
  233. HIF_INFO("wlan: %s pcie power collapse", (flag ? "disable" : "enable"));
  234. }
  235. #endif
  236. int hif_ipci_bus_suspend(struct hif_softc *scn)
  237. {
  238. hif_apps_irqs_disable(GET_HIF_OPAQUE_HDL(scn));
  239. if (hif_drain_tasklets(scn)) {
  240. hif_apps_irqs_enable(GET_HIF_OPAQUE_HDL(scn));
  241. return -EBUSY;
  242. }
  243. return 0;
  244. }
  245. int hif_ipci_bus_resume(struct hif_softc *scn)
  246. {
  247. hif_apps_irqs_enable(GET_HIF_OPAQUE_HDL(scn));
  248. return 0;
  249. }
  250. int hif_ipci_bus_suspend_noirq(struct hif_softc *scn)
  251. {
  252. if (hif_can_suspend_link(GET_HIF_OPAQUE_HDL(scn)))
  253. qdf_atomic_set(&scn->link_suspended, 1);
  254. return 0;
  255. }
  256. int hif_ipci_bus_resume_noirq(struct hif_softc *scn)
  257. {
  258. if (hif_can_suspend_link(GET_HIF_OPAQUE_HDL(scn)))
  259. qdf_atomic_set(&scn->link_suspended, 0);
  260. return 0;
  261. }
  262. void hif_ipci_disable_isr(struct hif_softc *scn)
  263. {
  264. struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(scn);
  265. hif_exec_kill(&scn->osc);
  266. hif_nointrs(scn);
  267. /* Cancel the pending tasklet */
  268. ce_tasklet_kill(scn);
  269. tasklet_kill(&sc->intr_tq);
  270. qdf_atomic_set(&scn->active_tasklet_cnt, 0);
  271. qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0);
  272. }
  273. int hif_ipci_dump_registers(struct hif_softc *hif_ctx)
  274. {
  275. int status;
  276. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  277. status = hif_dump_ce_registers(scn);
  278. if (status)
  279. HIF_ERROR("%s: Dump CE Registers Failed", __func__);
  280. return 0;
  281. }
  282. /**
  283. * hif_ce_interrupt_handler() - interrupt handler for copy engine
  284. * @irq: irq number
  285. * @context: tasklet context
  286. *
  287. * Return: irqreturn_t
  288. */
  289. static irqreturn_t hif_ce_interrupt_handler(int irq, void *context)
  290. {
  291. struct ce_tasklet_entry *tasklet_entry = context;
  292. return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry);
  293. }
  294. extern const char *ce_name[];
  295. /* hif_ce_srng_msi_irq_disable() - disable the irq for msi
  296. * @hif_sc: hif context
  297. * @ce_id: which ce to disable copy complete interrupts for
  298. *
  299. * @Return: none
  300. */
  301. static void hif_ce_srng_msi_irq_disable(struct hif_softc *hif_sc, int ce_id)
  302. {
  303. pfrm_disable_irq_nosync(hif_sc->qdf_dev->dev,
  304. hif_ce_msi_map_ce_to_irq(hif_sc, ce_id));
  305. }
  306. /* hif_ce_srng_msi_irq_enable() - enable the irq for msi
  307. * @hif_sc: hif context
  308. * @ce_id: which ce to enable copy complete interrupts for
  309. *
  310. * @Return: none
  311. */
  312. static void hif_ce_srng_msi_irq_enable(struct hif_softc *hif_sc, int ce_id)
  313. {
  314. pfrm_enable_irq(hif_sc->qdf_dev->dev,
  315. hif_ce_msi_map_ce_to_irq(hif_sc, ce_id));
  316. }
  317. /* hif_ce_msi_configure_irq() - configure the irq
  318. * @scn: hif context
  319. *
  320. * @Return: none
  321. */
  322. static int hif_ce_msi_configure_irq(struct hif_softc *scn)
  323. {
  324. int ret;
  325. int ce_id, irq;
  326. uint32_t msi_data_start;
  327. uint32_t msi_data_count;
  328. uint32_t msi_irq_start;
  329. struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
  330. struct hif_ipci_softc *ipci_sc = HIF_GET_IPCI_SOFTC(scn);
  331. uint8_t wake_ce_id;
  332. ret = hif_get_wake_ce_id(scn, &wake_ce_id);
  333. if (ret)
  334. return ret;
  335. /* do ce irq assignments */
  336. ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
  337. &msi_data_count, &msi_data_start,
  338. &msi_irq_start);
  339. if (ret)
  340. return ret;
  341. scn->bus_ops.hif_irq_disable = &hif_ce_srng_msi_irq_disable;
  342. scn->bus_ops.hif_irq_enable = &hif_ce_srng_msi_irq_enable;
  343. scn->bus_ops.hif_map_ce_to_irq = &hif_ce_msi_map_ce_to_irq;
  344. /* needs to match the ce_id -> irq data mapping
  345. * used in the srng parameter configuration
  346. */
  347. for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
  348. unsigned long irqflags = IRQF_SHARED;
  349. unsigned int msi_data = (ce_id % msi_data_count) +
  350. msi_irq_start;
  351. irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
  352. HIF_DBG("%s: (ce_id %d, msi_data %d, irq %d tasklet %pK)",
  353. __func__, ce_id, msi_data, irq,
  354. &ce_sc->tasklets[ce_id]);
  355. /* implies the ce is also initialized */
  356. if (!ce_sc->tasklets[ce_id].inited)
  357. continue;
  358. if (ce_id == wake_ce_id)
  359. irqflags |= IRQF_NO_SUSPEND;
  360. ipci_sc->ce_msi_irq_num[ce_id] = irq;
  361. ret = pfrm_request_irq(scn->qdf_dev->dev,
  362. irq, hif_ce_interrupt_handler,
  363. irqflags,
  364. ce_name[ce_id],
  365. &ce_sc->tasklets[ce_id]);
  366. if (ret)
  367. goto free_irq;
  368. }
  369. return ret;
  370. free_irq:
  371. /* the request_irq for the last ce_id failed so skip it. */
  372. while (ce_id > 0 && ce_id < scn->ce_count) {
  373. unsigned int msi_data;
  374. ce_id--;
  375. msi_data = (ce_id % msi_data_count) + msi_irq_start;
  376. irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
  377. pfrm_free_irq(scn->qdf_dev->dev, irq, &ce_sc->tasklets[ce_id]);
  378. }
  379. return ret;
  380. }
  381. /**
  382. * hif_exec_grp_irq_disable() - disable the irq for group
  383. * @hif_ext_group: hif exec context
  384. *
  385. * Return: none
  386. */
  387. static void hif_exec_grp_irq_disable(struct hif_exec_context *hif_ext_group)
  388. {
  389. int i;
  390. struct hif_softc *scn = HIF_GET_SOFTC(hif_ext_group->hif);
  391. for (i = 0; i < hif_ext_group->numirq; i++)
  392. pfrm_disable_irq_nosync(scn->qdf_dev->dev,
  393. hif_ext_group->os_irq[i]);
  394. }
  395. /**
  396. * hif_exec_grp_irq_enable() - enable the irq for group
  397. * @hif_ext_group: hif exec context
  398. *
  399. * Return: none
  400. */
  401. static void hif_exec_grp_irq_enable(struct hif_exec_context *hif_ext_group)
  402. {
  403. int i;
  404. struct hif_softc *scn = HIF_GET_SOFTC(hif_ext_group->hif);
  405. for (i = 0; i < hif_ext_group->numirq; i++)
  406. pfrm_enable_irq(scn->qdf_dev->dev, hif_ext_group->os_irq[i]);
  407. }
  408. const char *hif_ipci_get_irq_name(int irq_no)
  409. {
  410. return "pci-dummy";
  411. }
  412. int hif_ipci_configure_grp_irq(struct hif_softc *scn,
  413. struct hif_exec_context *hif_ext_group)
  414. {
  415. int ret = 0;
  416. int irq = 0;
  417. int j;
  418. hif_ext_group->irq_enable = &hif_exec_grp_irq_enable;
  419. hif_ext_group->irq_disable = &hif_exec_grp_irq_disable;
  420. hif_ext_group->irq_name = &hif_ipci_get_irq_name;
  421. hif_ext_group->work_complete = &hif_dummy_grp_done;
  422. for (j = 0; j < hif_ext_group->numirq; j++) {
  423. irq = hif_ext_group->irq[j];
  424. hif_info("request_irq = %d for grp %d",
  425. irq, hif_ext_group->grp_id);
  426. ret = pfrm_request_irq(scn->qdf_dev->dev, irq,
  427. hif_ext_group_interrupt_handler,
  428. IRQF_SHARED | IRQF_NO_SUSPEND,
  429. "wlan_EXT_GRP",
  430. hif_ext_group);
  431. if (ret) {
  432. HIF_ERROR("%s: request_irq failed ret = %d",
  433. __func__, ret);
  434. return -EFAULT;
  435. }
  436. hif_ext_group->os_irq[j] = irq;
  437. }
  438. hif_ext_group->irq_requested = true;
  439. return 0;
  440. }
  441. int hif_configure_irq(struct hif_softc *scn)
  442. {
  443. int ret = 0;
  444. HIF_TRACE("%s: E", __func__);
  445. if (hif_is_polled_mode_enabled(GET_HIF_OPAQUE_HDL(scn))) {
  446. scn->request_irq_done = false;
  447. return 0;
  448. }
  449. ret = hif_ce_msi_configure_irq(scn);
  450. if (ret == 0)
  451. goto end;
  452. if (ret < 0) {
  453. HIF_ERROR("%s: hif_ipci_configure_irq error = %d",
  454. __func__, ret);
  455. return ret;
  456. }
  457. end:
  458. scn->request_irq_done = true;
  459. return 0;
  460. }
  461. /**
  462. * hif_ipci_get_soc_info_pld() - get soc info for ipcie bus from pld target
  463. * @sc: ipci context
  464. * @dev: device structure
  465. *
  466. * Return: none
  467. */
  468. static void hif_ipci_get_soc_info_pld(struct hif_ipci_softc *sc,
  469. struct device *dev)
  470. {
  471. struct pld_soc_info info;
  472. pld_get_soc_info(dev, &info);
  473. sc->mem = info.v_addr;
  474. sc->ce_sc.ol_sc.mem = info.v_addr;
  475. sc->ce_sc.ol_sc.mem_pa = info.p_addr;
  476. }
  477. /**
  478. * hif_ipci_get_soc_info_nopld() - get soc info for ipcie bus for non pld target
  479. * @sc: ipci context
  480. * @dev: device structure
  481. *
  482. * Return: none
  483. */
  484. static void hif_ipci_get_soc_info_nopld(struct hif_ipci_softc *sc,
  485. struct device *dev)
  486. {}
  487. /**
  488. * hif_is_pld_based_target() - verify if the target is pld based
  489. * @sc: ipci context
  490. * @device_id: device id
  491. *
  492. * Return: none
  493. */
  494. static bool hif_is_pld_based_target(struct hif_ipci_softc *sc,
  495. int device_id)
  496. {
  497. if (!pld_have_platform_driver_support(sc->dev))
  498. return false;
  499. switch (device_id) {
  500. #ifdef QCA_WIFI_QCA6750
  501. case QCA6750_DEVICE_ID:
  502. #endif
  503. return true;
  504. }
  505. return false;
  506. }
  507. /**
  508. * hif_ipci_init_deinit_ops_attach() - attach ops for ipci
  509. * @sc: ipci context
  510. * @device_id: device id
  511. *
  512. * Return: none
  513. */
  514. static void hif_ipci_init_deinit_ops_attach(struct hif_ipci_softc *sc,
  515. int device_id)
  516. {
  517. if (hif_is_pld_based_target(sc, device_id))
  518. sc->hif_ipci_get_soc_info = hif_ipci_get_soc_info_pld;
  519. else
  520. sc->hif_ipci_get_soc_info = hif_ipci_get_soc_info_nopld;
  521. }
  522. QDF_STATUS hif_ipci_enable_bus(struct hif_softc *ol_sc,
  523. struct device *dev, void *bdev,
  524. const struct hif_bus_id *bid,
  525. enum hif_enable_type type)
  526. {
  527. int ret = 0;
  528. uint32_t hif_type, target_type;
  529. struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(ol_sc);
  530. struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(ol_sc);
  531. uint16_t revision_id = 0;
  532. struct hif_target_info *tgt_info;
  533. int device_id = QCA6750_DEVICE_ID;
  534. if (!ol_sc) {
  535. HIF_ERROR("%s: hif_ctx is NULL", __func__);
  536. return QDF_STATUS_E_NOMEM;
  537. }
  538. ret = qdf_set_dma_coherent_mask(dev,
  539. DMA_COHERENT_MASK_DEFAULT);
  540. if (ret) {
  541. HIF_ERROR("%s: failed to set dma mask error = %d",
  542. __func__, ret);
  543. return ret;
  544. }
  545. sc->dev = dev;
  546. tgt_info = hif_get_target_info_handle(hif_hdl);
  547. hif_ipci_init_deinit_ops_attach(sc, device_id);
  548. sc->hif_ipci_get_soc_info(sc, dev);
  549. HIF_TRACE("%s: hif_enable_pci done", __func__);
  550. ret = hif_get_device_type(device_id, revision_id,
  551. &hif_type, &target_type);
  552. if (ret < 0) {
  553. HIF_ERROR("%s: invalid device id/revision_id", __func__);
  554. return QDF_STATUS_E_ABORTED;
  555. }
  556. HIF_TRACE("%s: hif_type = 0x%x, target_type = 0x%x",
  557. __func__, hif_type, target_type);
  558. hif_register_tbl_attach(ol_sc, hif_type);
  559. hif_target_register_tbl_attach(ol_sc, target_type);
  560. sc->use_register_windowing = false;
  561. tgt_info->target_type = target_type;
  562. if (!ol_sc->mem_pa) {
  563. HIF_ERROR("%s: ERROR - BAR0 uninitialized", __func__);
  564. ret = -EIO;
  565. return QDF_STATUS_E_ABORTED;
  566. }
  567. return 0;
  568. }
  569. bool hif_ipci_needs_bmi(struct hif_softc *scn)
  570. {
  571. return !ce_srng_based(scn);
  572. }
  573. #ifdef FORCE_WAKE
  574. int hif_force_wake_request(struct hif_opaque_softc *hif_handle)
  575. {
  576. uint32_t timeout = 0;
  577. struct hif_softc *scn = (struct hif_softc *)hif_handle;
  578. struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
  579. if (pld_force_wake_request(scn->qdf_dev->dev)) {
  580. hif_err("force wake request send failed");
  581. return -EINVAL;
  582. }
  583. HIF_STATS_INC(ipci_scn, mhi_force_wake_request_vote, 1);
  584. while (!pld_is_device_awake(scn->qdf_dev->dev) &&
  585. timeout <= FORCE_WAKE_DELAY_TIMEOUT_MS) {
  586. qdf_mdelay(FORCE_WAKE_DELAY_MS);
  587. timeout += FORCE_WAKE_DELAY_MS;
  588. }
  589. if (pld_is_device_awake(scn->qdf_dev->dev) <= 0) {
  590. hif_err("Unable to wake up mhi");
  591. HIF_STATS_INC(ipci_scn, mhi_force_wake_failure, 1);
  592. return -EINVAL;
  593. }
  594. HIF_STATS_INC(ipci_scn, mhi_force_wake_success, 1);
  595. HIF_STATS_INC(ipci_scn, soc_force_wake_success, 1);
  596. return 0;
  597. }
  598. int hif_force_wake_release(struct hif_opaque_softc *hif_handle)
  599. {
  600. int ret;
  601. struct hif_softc *scn = (struct hif_softc *)hif_handle;
  602. struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
  603. ret = pld_force_wake_release(scn->qdf_dev->dev);
  604. if (ret) {
  605. hif_err("force wake release failure");
  606. HIF_STATS_INC(ipci_scn, mhi_force_wake_release_failure, 1);
  607. return ret;
  608. }
  609. HIF_STATS_INC(ipci_scn, mhi_force_wake_release_success, 1);
  610. HIF_STATS_INC(ipci_scn, soc_force_wake_release_success, 1);
  611. return 0;
  612. }
  613. void hif_print_ipci_stats(struct hif_ipci_softc *ipci_handle)
  614. {
  615. hif_debug("mhi_force_wake_request_vote: %d",
  616. ipci_handle->stats.mhi_force_wake_request_vote);
  617. hif_debug("mhi_force_wake_failure: %d",
  618. ipci_handle->stats.mhi_force_wake_failure);
  619. hif_debug("mhi_force_wake_success: %d",
  620. ipci_handle->stats.mhi_force_wake_success);
  621. hif_debug("soc_force_wake_register_write_success: %d",
  622. ipci_handle->stats.soc_force_wake_register_write_success);
  623. hif_debug("soc_force_wake_failure: %d",
  624. ipci_handle->stats.soc_force_wake_failure);
  625. hif_debug("soc_force_wake_success: %d",
  626. ipci_handle->stats.soc_force_wake_success);
  627. hif_debug("mhi_force_wake_release_failure: %d",
  628. ipci_handle->stats.mhi_force_wake_release_failure);
  629. hif_debug("mhi_force_wake_release_success: %d",
  630. ipci_handle->stats.mhi_force_wake_release_success);
  631. hif_debug("oc_force_wake_release_success: %d",
  632. ipci_handle->stats.soc_force_wake_release_success);
  633. }
  634. #endif /* FORCE_WAKE */