ipa_bridge.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/delay.h>
  13. #include <linux/ratelimit.h>
  14. #include <mach/msm_smem.h>
  15. #include "ipa_i.h"
  16. /*
  17. * EP0 (teth)
  18. * A2_BAM(1)->(12)DMA_BAM->DMA_BAM(13)->(6)IPA_BAM->IPA_BAM(10)->USB_BAM(0)
  19. * A2_BAM(0)<-(15)DMA_BAM<-DMA_BAM(14)<-(7)IPA_BAM<-IPA_BAM(11)<-USB_BAM(1)
  20. *
  21. * EP2 (emb)
  22. * A2_BAM(5)->(16)DMA_BAM->DMA_BAM(17)->(8)IPA_BAM->
  23. * A2_BAM(4)<-(19)DMA_BAM<-DMA_BAM(18)<-(9)IPA_BAM<-
  24. */
  25. #define A2_TETHERED_PIPE_UL 0
  26. #define DMA_A2_TETHERED_PIPE_UL 15
  27. #define DMA_IPA_TETHERED_PIPE_UL 14
  28. #define A2_TETHERED_PIPE_DL 1
  29. #define DMA_A2_TETHERED_PIPE_DL 12
  30. #define DMA_IPA_TETHERED_PIPE_DL 13
  31. #define A2_EMBEDDED_PIPE_UL 4
  32. #define DMA_A2_EMBEDDED_PIPE_UL 19
  33. #define DMA_IPA_EMBEDDED_PIPE_UL 18
  34. #define A2_EMBEDDED_PIPE_DL 5
  35. #define DMA_A2_EMBEDDED_PIPE_DL 16
  36. #define DMA_IPA_EMBEDDED_PIPE_DL 17
  37. #define IPA_SMEM_PIPE_MEM_SZ 32768
  38. #define IPA_UL_DATA_FIFO_SZ 0xc00
  39. #define IPA_UL_DESC_FIFO_SZ 0x530
  40. #define IPA_DL_DATA_FIFO_SZ 0x2400
  41. #define IPA_DL_DESC_FIFO_SZ 0x8a0
  42. #define IPA_DL_EMB_DATA_FIFO_SZ 0x1800
  43. #define IPA_DL_EMB_DESC_FIFO_SZ 0x4e8
  44. #define IPA_SMEM_UL_DATA_FIFO_OFST 0
  45. #define IPA_SMEM_UL_DESC_FIFO_OFST 0xc00
  46. #define IPA_SMEM_DL_DATA_FIFO_OFST 0x1130
  47. #define IPA_SMEM_DL_DESC_FIFO_OFST 0x3530
  48. #define IPA_SMEM_UL_EMB_DATA_FIFO_OFST 0x3dd0
  49. #define IPA_SMEM_UL_EMB_DESC_FIFO_OFST 0x49d0
  50. #define IPA_OCIMEM_DL_A2_DATA_FIFO_OFST 0
  51. #define IPA_OCIMEM_DL_A2_DESC_FIFO_OFST (IPA_OCIMEM_DL_A2_DATA_FIFO_OFST + \
  52. IPA_DL_EMB_DATA_FIFO_SZ)
  53. #define IPA_OCIMEM_DL_IPA_DATA_FIFO_OFST (IPA_OCIMEM_DL_A2_DESC_FIFO_OFST + \
  54. IPA_DL_EMB_DESC_FIFO_SZ)
  55. #define IPA_OCIMEM_DL_IPA_DESC_FIFO_OFST (IPA_OCIMEM_DL_IPA_DATA_FIFO_OFST + \
  56. IPA_DL_EMB_DATA_FIFO_SZ)
  57. enum ipa_pipe_type {
  58. IPA_DL_FROM_A2,
  59. IPA_DL_TO_IPA,
  60. IPA_UL_FROM_IPA,
  61. IPA_UL_TO_A2,
  62. IPA_PIPE_TYPE_MAX
  63. };
  64. struct ipa_bridge_pipe_context {
  65. struct sps_pipe *pipe;
  66. bool ipa_facing;
  67. bool valid;
  68. };
  69. struct ipa_bridge_context {
  70. struct ipa_bridge_pipe_context pipe[IPA_PIPE_TYPE_MAX];
  71. enum ipa_bridge_type type;
  72. };
  73. static struct ipa_bridge_context bridge[IPA_BRIDGE_TYPE_MAX];
  74. static void ipa_get_dma_pipe_num(enum ipa_bridge_dir dir,
  75. enum ipa_bridge_type type, int *a2, int *ipa)
  76. {
  77. if (type == IPA_BRIDGE_TYPE_TETHERED) {
  78. if (dir == IPA_BRIDGE_DIR_UL) {
  79. *a2 = DMA_A2_TETHERED_PIPE_UL;
  80. *ipa = DMA_IPA_TETHERED_PIPE_UL;
  81. } else {
  82. *a2 = DMA_A2_TETHERED_PIPE_DL;
  83. *ipa = DMA_IPA_TETHERED_PIPE_DL;
  84. }
  85. } else {
  86. if (dir == IPA_BRIDGE_DIR_UL) {
  87. *a2 = DMA_A2_EMBEDDED_PIPE_UL;
  88. *ipa = DMA_IPA_EMBEDDED_PIPE_UL;
  89. } else {
  90. *a2 = DMA_A2_EMBEDDED_PIPE_DL;
  91. *ipa = DMA_IPA_EMBEDDED_PIPE_DL;
  92. }
  93. }
  94. }
  95. static int ipa_get_desc_fifo_sz(enum ipa_bridge_dir dir,
  96. enum ipa_bridge_type type)
  97. {
  98. int sz;
  99. if (type == IPA_BRIDGE_TYPE_TETHERED) {
  100. if (dir == IPA_BRIDGE_DIR_UL)
  101. sz = IPA_UL_DESC_FIFO_SZ;
  102. else
  103. sz = IPA_DL_DESC_FIFO_SZ;
  104. } else {
  105. if (dir == IPA_BRIDGE_DIR_UL)
  106. sz = IPA_UL_DESC_FIFO_SZ;
  107. else
  108. sz = IPA_DL_EMB_DESC_FIFO_SZ;
  109. }
  110. return sz;
  111. }
  112. static int ipa_get_data_fifo_sz(enum ipa_bridge_dir dir,
  113. enum ipa_bridge_type type)
  114. {
  115. int sz;
  116. if (type == IPA_BRIDGE_TYPE_TETHERED) {
  117. if (dir == IPA_BRIDGE_DIR_UL)
  118. sz = IPA_UL_DATA_FIFO_SZ;
  119. else
  120. sz = IPA_DL_DATA_FIFO_SZ;
  121. } else {
  122. if (dir == IPA_BRIDGE_DIR_UL)
  123. sz = IPA_UL_DATA_FIFO_SZ;
  124. else
  125. sz = IPA_DL_EMB_DATA_FIFO_SZ;
  126. }
  127. return sz;
  128. }
  129. static int ipa_get_a2_pipe_num(enum ipa_bridge_dir dir,
  130. enum ipa_bridge_type type)
  131. {
  132. int ep;
  133. if (type == IPA_BRIDGE_TYPE_TETHERED) {
  134. if (dir == IPA_BRIDGE_DIR_UL)
  135. ep = A2_TETHERED_PIPE_UL;
  136. else
  137. ep = A2_TETHERED_PIPE_DL;
  138. } else {
  139. if (dir == IPA_BRIDGE_DIR_UL)
  140. ep = A2_EMBEDDED_PIPE_UL;
  141. else
  142. ep = A2_EMBEDDED_PIPE_DL;
  143. }
  144. return ep;
  145. }
  146. int ipa_setup_ipa_dma_fifos(enum ipa_bridge_dir dir,
  147. enum ipa_bridge_type type,
  148. struct sps_mem_buffer *desc,
  149. struct sps_mem_buffer *data)
  150. {
  151. int ret;
  152. ret = sps_setup_bam2bam_fifo(data,
  153. IPA_OCIMEM_DL_IPA_DATA_FIFO_OFST,
  154. ipa_get_data_fifo_sz(dir, type), 1);
  155. if (ret) {
  156. IPAERR("DAFIFO setup fail %d dir %d type %d\n",
  157. ret, dir, type);
  158. return ret;
  159. }
  160. ret = sps_setup_bam2bam_fifo(desc,
  161. IPA_OCIMEM_DL_IPA_DESC_FIFO_OFST,
  162. ipa_get_desc_fifo_sz(dir, type), 1);
  163. if (ret) {
  164. IPAERR("DEFIFO setup fail %d dir %d type %d\n",
  165. ret, dir, type);
  166. return ret;
  167. }
  168. IPADBG("dir=%d type=%d Dpa=%x Dsz=%u Dva=%p dpa=%x dsz=%u dva=%p\n",
  169. dir, type, data->phys_base, data->size, data->base,
  170. desc->phys_base, desc->size, desc->base);
  171. return 0;
  172. }
  173. int ipa_setup_a2_dma_fifos(enum ipa_bridge_dir dir,
  174. enum ipa_bridge_type type,
  175. struct sps_mem_buffer *desc,
  176. struct sps_mem_buffer *data)
  177. {
  178. int ret;
  179. if (type == IPA_BRIDGE_TYPE_TETHERED) {
  180. if (dir == IPA_BRIDGE_DIR_UL) {
  181. desc->base = ipa_ctx->smem_pipe_mem +
  182. IPA_SMEM_UL_DESC_FIFO_OFST;
  183. desc->phys_base = smem_virt_to_phys(desc->base);
  184. desc->size = ipa_get_desc_fifo_sz(dir, type);
  185. data->base = ipa_ctx->smem_pipe_mem +
  186. IPA_SMEM_UL_DATA_FIFO_OFST;
  187. data->phys_base = smem_virt_to_phys(data->base);
  188. data->size = ipa_get_data_fifo_sz(dir, type);
  189. } else {
  190. desc->base = ipa_ctx->smem_pipe_mem +
  191. IPA_SMEM_DL_DESC_FIFO_OFST;
  192. desc->phys_base = smem_virt_to_phys(desc->base);
  193. desc->size = ipa_get_desc_fifo_sz(dir, type);
  194. data->base = ipa_ctx->smem_pipe_mem +
  195. IPA_SMEM_DL_DATA_FIFO_OFST;
  196. data->phys_base = smem_virt_to_phys(data->base);
  197. data->size = ipa_get_data_fifo_sz(dir, type);
  198. }
  199. } else {
  200. if (dir == IPA_BRIDGE_DIR_UL) {
  201. desc->base = ipa_ctx->smem_pipe_mem +
  202. IPA_SMEM_UL_EMB_DESC_FIFO_OFST;
  203. desc->phys_base = smem_virt_to_phys(desc->base);
  204. desc->size = ipa_get_desc_fifo_sz(dir, type);
  205. data->base = ipa_ctx->smem_pipe_mem +
  206. IPA_SMEM_UL_EMB_DATA_FIFO_OFST;
  207. data->phys_base = smem_virt_to_phys(data->base);
  208. data->size = ipa_get_data_fifo_sz(dir, type);
  209. } else {
  210. ret = sps_setup_bam2bam_fifo(data,
  211. IPA_OCIMEM_DL_A2_DATA_FIFO_OFST,
  212. ipa_get_data_fifo_sz(dir, type), 1);
  213. if (ret) {
  214. IPAERR("DAFIFO setup fail %d dir %d type %d\n",
  215. ret, dir, type);
  216. return ret;
  217. }
  218. ret = sps_setup_bam2bam_fifo(desc,
  219. IPA_OCIMEM_DL_A2_DESC_FIFO_OFST,
  220. ipa_get_desc_fifo_sz(dir, type), 1);
  221. if (ret) {
  222. IPAERR("DEFIFO setup fail %d dir %d type %d\n",
  223. ret, dir, type);
  224. return ret;
  225. }
  226. }
  227. }
  228. IPADBG("dir=%d type=%d Dpa=%x Dsz=%u Dva=%p dpa=%x dsz=%u dva=%p\n",
  229. dir, type, data->phys_base, data->size, data->base,
  230. desc->phys_base, desc->size, desc->base);
  231. return 0;
  232. }
  233. static int setup_dma_bam_bridge(enum ipa_bridge_dir dir,
  234. enum ipa_bridge_type type,
  235. struct ipa_sys_connect_params *props,
  236. u32 *clnt_hdl)
  237. {
  238. struct ipa_connect_params ipa_in_params;
  239. struct ipa_sps_params sps_out_params;
  240. int dma_a2_pipe;
  241. int dma_ipa_pipe;
  242. struct sps_pipe *pipe;
  243. struct sps_pipe *pipe_a2;
  244. struct sps_connect _connection;
  245. struct sps_connect *connection = &_connection;
  246. struct a2_mux_pipe_connection pipe_conn = {0};
  247. enum a2_mux_pipe_direction pipe_dir;
  248. u32 dma_hdl = sps_dma_get_bam_handle();
  249. u32 a2_hdl;
  250. u32 pa;
  251. int ret;
  252. memset(&ipa_in_params, 0, sizeof(ipa_in_params));
  253. memset(&sps_out_params, 0, sizeof(sps_out_params));
  254. pipe_dir = (dir == IPA_BRIDGE_DIR_UL) ? IPA_TO_A2 : A2_TO_IPA;
  255. ret = ipa_get_a2_mux_pipe_info(pipe_dir, &pipe_conn);
  256. if (ret) {
  257. IPAERR("ipa_get_a2_mux_pipe_info failed dir=%d type=%d\n",
  258. dir, type);
  259. goto fail_get_a2_prop;
  260. }
  261. pa = (dir == IPA_BRIDGE_DIR_UL) ? pipe_conn.dst_phy_addr :
  262. pipe_conn.src_phy_addr;
  263. ret = sps_phy2h(pa, &a2_hdl);
  264. if (ret) {
  265. IPAERR("sps_phy2h failed (A2 BAM) %d dir=%d type=%d\n",
  266. ret, dir, type);
  267. goto fail_get_a2_prop;
  268. }
  269. ipa_get_dma_pipe_num(dir, type, &dma_a2_pipe, &dma_ipa_pipe);
  270. ipa_in_params.ipa_ep_cfg = props->ipa_ep_cfg;
  271. ipa_in_params.client = props->client;
  272. ipa_in_params.client_bam_hdl = dma_hdl;
  273. ipa_in_params.client_ep_idx = dma_ipa_pipe;
  274. ipa_in_params.priv = props->priv;
  275. ipa_in_params.notify = props->notify;
  276. ipa_in_params.desc_fifo_sz = ipa_get_desc_fifo_sz(dir, type);
  277. ipa_in_params.data_fifo_sz = ipa_get_data_fifo_sz(dir, type);
  278. if (type == IPA_BRIDGE_TYPE_EMBEDDED && dir == IPA_BRIDGE_DIR_DL) {
  279. if (ipa_setup_ipa_dma_fifos(dir, type, &ipa_in_params.desc,
  280. &ipa_in_params.data)) {
  281. IPAERR("fail to setup IPA-DMA FIFOs dir=%d type=%d\n",
  282. dir, type);
  283. goto fail_get_a2_prop;
  284. }
  285. }
  286. if (ipa_connect(&ipa_in_params, &sps_out_params, clnt_hdl)) {
  287. IPAERR("ipa connect failed dir=%d type=%d\n", dir, type);
  288. goto fail_get_a2_prop;
  289. }
  290. pipe = sps_alloc_endpoint();
  291. if (pipe == NULL) {
  292. IPAERR("sps_alloc_endpoint failed dir=%d type=%d\n", dir, type);
  293. ret = -ENOMEM;
  294. goto fail_sps_alloc;
  295. }
  296. memset(&_connection, 0, sizeof(_connection));
  297. ret = sps_get_config(pipe, connection);
  298. if (ret) {
  299. IPAERR("sps_get_config failed %d dir=%d type=%d\n", ret, dir,
  300. type);
  301. goto fail_sps_get_config;
  302. }
  303. if (dir == IPA_BRIDGE_DIR_DL) {
  304. connection->mode = SPS_MODE_SRC;
  305. connection->source = dma_hdl;
  306. connection->destination = sps_out_params.ipa_bam_hdl;
  307. connection->src_pipe_index = dma_ipa_pipe;
  308. connection->dest_pipe_index = sps_out_params.ipa_ep_idx;
  309. } else {
  310. connection->mode = SPS_MODE_DEST;
  311. connection->source = sps_out_params.ipa_bam_hdl;
  312. connection->destination = dma_hdl;
  313. connection->src_pipe_index = sps_out_params.ipa_ep_idx;
  314. connection->dest_pipe_index = dma_ipa_pipe;
  315. }
  316. connection->event_thresh = IPA_EVENT_THRESHOLD;
  317. connection->data = sps_out_params.data;
  318. connection->desc = sps_out_params.desc;
  319. connection->options = SPS_O_AUTO_ENABLE;
  320. ret = sps_connect(pipe, connection);
  321. if (ret) {
  322. IPAERR("sps_connect failed %d dir=%d type=%d\n", ret, dir,
  323. type);
  324. goto fail_sps_get_config;
  325. }
  326. if (dir == IPA_BRIDGE_DIR_DL) {
  327. bridge[type].pipe[IPA_DL_TO_IPA].pipe = pipe;
  328. bridge[type].pipe[IPA_DL_TO_IPA].ipa_facing = true;
  329. bridge[type].pipe[IPA_DL_TO_IPA].valid = true;
  330. } else {
  331. bridge[type].pipe[IPA_UL_FROM_IPA].pipe = pipe;
  332. bridge[type].pipe[IPA_UL_FROM_IPA].ipa_facing = true;
  333. bridge[type].pipe[IPA_UL_FROM_IPA].valid = true;
  334. }
  335. IPADBG("dir=%d type=%d (ipa) src(0x%x:%u)->dst(0x%x:%u)\n", dir, type,
  336. connection->source, connection->src_pipe_index,
  337. connection->destination, connection->dest_pipe_index);
  338. pipe_a2 = sps_alloc_endpoint();
  339. if (pipe_a2 == NULL) {
  340. IPAERR("sps_alloc_endpoint failed2 dir=%d type=%d\n", dir,
  341. type);
  342. ret = -ENOMEM;
  343. goto fail_sps_alloc_a2;
  344. }
  345. memset(&_connection, 0, sizeof(_connection));
  346. ret = sps_get_config(pipe_a2, connection);
  347. if (ret) {
  348. IPAERR("sps_get_config failed2 %d dir=%d type=%d\n", ret, dir,
  349. type);
  350. goto fail_sps_get_config_a2;
  351. }
  352. if (dir == IPA_BRIDGE_DIR_DL) {
  353. connection->mode = SPS_MODE_DEST;
  354. connection->source = a2_hdl;
  355. connection->destination = dma_hdl;
  356. connection->src_pipe_index = ipa_get_a2_pipe_num(dir, type);
  357. connection->dest_pipe_index = dma_a2_pipe;
  358. } else {
  359. connection->mode = SPS_MODE_SRC;
  360. connection->source = dma_hdl;
  361. connection->destination = a2_hdl;
  362. connection->src_pipe_index = dma_a2_pipe;
  363. connection->dest_pipe_index = ipa_get_a2_pipe_num(dir, type);
  364. }
  365. connection->event_thresh = IPA_EVENT_THRESHOLD;
  366. if (ipa_setup_a2_dma_fifos(dir, type, &connection->desc,
  367. &connection->data)) {
  368. IPAERR("fail to setup A2-DMA FIFOs dir=%d type=%d\n",
  369. dir, type);
  370. goto fail_sps_get_config_a2;
  371. }
  372. connection->options = SPS_O_AUTO_ENABLE;
  373. ret = sps_connect(pipe_a2, connection);
  374. if (ret) {
  375. IPAERR("sps_connect failed2 %d dir=%d type=%d\n", ret, dir,
  376. type);
  377. goto fail_sps_get_config_a2;
  378. }
  379. if (dir == IPA_BRIDGE_DIR_DL) {
  380. bridge[type].pipe[IPA_DL_FROM_A2].pipe = pipe_a2;
  381. bridge[type].pipe[IPA_DL_FROM_A2].valid = true;
  382. } else {
  383. bridge[type].pipe[IPA_UL_TO_A2].pipe = pipe_a2;
  384. bridge[type].pipe[IPA_UL_TO_A2].valid = true;
  385. }
  386. IPADBG("dir=%d type=%d (a2) src(0x%x:%u)->dst(0x%x:%u)\n", dir, type,
  387. connection->source, connection->src_pipe_index,
  388. connection->destination, connection->dest_pipe_index);
  389. return 0;
  390. fail_sps_get_config_a2:
  391. sps_free_endpoint(pipe_a2);
  392. fail_sps_alloc_a2:
  393. sps_disconnect(pipe);
  394. fail_sps_get_config:
  395. sps_free_endpoint(pipe);
  396. fail_sps_alloc:
  397. ipa_disconnect(*clnt_hdl);
  398. fail_get_a2_prop:
  399. return ret;
  400. }
  401. /**
  402. * ipa_bridge_init()
  403. *
  404. * Return codes: 0: success, -ENOMEM: failure
  405. */
  406. int ipa_bridge_init(void)
  407. {
  408. int i;
  409. ipa_ctx->smem_pipe_mem = smem_alloc2(SMEM_BAM_PIPE_MEMORY,
  410. IPA_SMEM_PIPE_MEM_SZ);
  411. if (!ipa_ctx->smem_pipe_mem) {
  412. IPAERR("smem alloc failed\n");
  413. return -ENOMEM;
  414. }
  415. IPADBG("smem_pipe_mem = %p\n", ipa_ctx->smem_pipe_mem);
  416. for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++)
  417. bridge[i].type = i;
  418. return 0;
  419. }
  420. /**
  421. * ipa_bridge_setup() - setup SW bridge leg
  422. * @dir: downlink or uplink (from air interface perspective)
  423. * @type: tethered or embedded bridge
  424. * @props: bridge leg properties (EP config, callbacks, etc)
  425. * @clnt_hdl: [out] handle of IPA EP belonging to bridge leg
  426. *
  427. * NOTE: IT IS CALLER'S RESPONSIBILITY TO ENSURE BAMs ARE
  428. * OPERATIONAL AS LONG AS BRIDGE REMAINS UP
  429. *
  430. * Return codes:
  431. * 0: success
  432. * various negative error codes on errors
  433. */
  434. int ipa_bridge_setup(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
  435. struct ipa_sys_connect_params *props, u32 *clnt_hdl)
  436. {
  437. int ret;
  438. if (props == NULL || clnt_hdl == NULL ||
  439. type >= IPA_BRIDGE_TYPE_MAX || dir >= IPA_BRIDGE_DIR_MAX ||
  440. props->client >= IPA_CLIENT_MAX) {
  441. IPAERR("Bad param props=%p clnt_hdl=%p type=%d dir=%d\n",
  442. props, clnt_hdl, type, dir);
  443. return -EINVAL;
  444. }
  445. ipa_inc_client_enable_clks();
  446. if (setup_dma_bam_bridge(dir, type, props, clnt_hdl)) {
  447. IPAERR("fail to setup SYS pipe to IPA dir=%d type=%d\n",
  448. dir, type);
  449. ret = -EINVAL;
  450. goto bail_ipa;
  451. }
  452. return 0;
  453. bail_ipa:
  454. ipa_dec_client_disable_clks();
  455. return ret;
  456. }
  457. EXPORT_SYMBOL(ipa_bridge_setup);
  458. /**
  459. * ipa_bridge_teardown() - teardown SW bridge leg
  460. * @dir: downlink or uplink (from air interface perspective)
  461. * @type: tethered or embedded bridge
  462. * @clnt_hdl: handle of IPA EP
  463. *
  464. * Return codes:
  465. * 0: success
  466. * various negative error codes on errors
  467. */
  468. int ipa_bridge_teardown(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
  469. u32 clnt_hdl)
  470. {
  471. struct ipa_bridge_pipe_context *sys;
  472. int lo;
  473. int hi;
  474. if (dir >= IPA_BRIDGE_DIR_MAX || type >= IPA_BRIDGE_TYPE_MAX ||
  475. clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
  476. IPAERR("Bad param dir=%d type=%d\n", dir, type);
  477. return -EINVAL;
  478. }
  479. if (dir == IPA_BRIDGE_DIR_UL) {
  480. lo = IPA_UL_FROM_IPA;
  481. hi = IPA_UL_TO_A2;
  482. } else {
  483. lo = IPA_DL_FROM_A2;
  484. hi = IPA_DL_TO_IPA;
  485. }
  486. for (; lo <= hi; lo++) {
  487. sys = &bridge[type].pipe[lo];
  488. if (sys->valid) {
  489. if (sys->ipa_facing)
  490. ipa_disconnect(clnt_hdl);
  491. sps_disconnect(sys->pipe);
  492. sps_free_endpoint(sys->pipe);
  493. sys->valid = false;
  494. }
  495. }
  496. memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
  497. ipa_dec_client_disable_clks();
  498. return 0;
  499. }
  500. EXPORT_SYMBOL(ipa_bridge_teardown);
  501. bool ipa_emb_ul_pipes_empty(void)
  502. {
  503. struct sps_pipe *emb_ipa_ul =
  504. ipa_ctx->sys[IPA_A5_LAN_WAN_OUT].ep->ep_hdl;
  505. struct sps_pipe *emb_ipa_to_dma =
  506. bridge[IPA_BRIDGE_TYPE_EMBEDDED].pipe[IPA_UL_FROM_IPA].pipe;
  507. struct sps_pipe *emb_dma_to_a2 =
  508. bridge[IPA_BRIDGE_TYPE_EMBEDDED].pipe[IPA_UL_TO_A2].pipe;
  509. u32 emb_ipa_ul_empty;
  510. u32 emb_ipa_to_dma_empty;
  511. u32 emb_dma_to_a2_empty;
  512. if (sps_is_pipe_empty(emb_ipa_ul, &emb_ipa_ul_empty)) {
  513. IPAERR("emb_ip_ul pipe empty check fail\n");
  514. return false;
  515. }
  516. if (sps_is_pipe_empty(emb_ipa_to_dma, &emb_ipa_to_dma_empty)) {
  517. IPAERR("emb_ipa_to_dma pipe empty check fail\n");
  518. return false;
  519. }
  520. if (sps_is_pipe_empty(emb_dma_to_a2, &emb_dma_to_a2_empty)) {
  521. IPAERR("emb_dma_to_a2 pipe empty check fail\n");
  522. return false;
  523. }
  524. return emb_ipa_ul_empty && emb_ipa_to_dma_empty && emb_dma_to_a2_empty;
  525. }
  526. EXPORT_SYMBOL(ipa_emb_ul_pipes_empty);