ipa_wdi3.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/ipa_wdi3.h>
  6. #include <linux/msm_ipa.h>
  7. #include <linux/string.h>
  8. #include "../ipa_common_i.h"
  9. #include "../ipa_v3/ipa_pm.h"
  10. #include "../ipa_v3/ipa_i.h"
  11. #define OFFLOAD_DRV_NAME "ipa_wdi"
  12. #define IPA_WDI_DBG(fmt, args...) \
  13. do { \
  14. pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \
  15. __func__, __LINE__, ## args); \
  16. IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
  17. OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
  18. IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
  19. OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
  20. } while (0)
  21. #define IPA_WDI_DBG_LOW(fmt, args...) \
  22. do { \
  23. pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \
  24. __func__, __LINE__, ## args); \
  25. IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
  26. OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
  27. } while (0)
  28. #define IPA_WDI_ERR(fmt, args...) \
  29. do { \
  30. pr_err(OFFLOAD_DRV_NAME " %s:%d " fmt, \
  31. __func__, __LINE__, ## args); \
  32. IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \
  33. OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
  34. IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \
  35. OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
  36. } while (0)
  37. struct ipa_wdi_intf_info {
  38. char netdev_name[IPA_RESOURCE_NAME_MAX];
  39. u8 hdr_len;
  40. u32 partial_hdr_hdl[IPA_IP_MAX];
  41. struct list_head link;
  42. };
  43. struct ipa_wdi_context {
  44. struct list_head head_intf_list;
  45. struct completion wdi_completion;
  46. struct mutex lock;
  47. enum ipa_wdi_version wdi_version;
  48. u8 is_smmu_enabled;
  49. u32 tx_pipe_hdl;
  50. u32 rx_pipe_hdl;
  51. u8 num_sys_pipe_needed;
  52. u32 sys_pipe_hdl[IPA_WDI_MAX_SUPPORTED_SYS_PIPE];
  53. u32 ipa_pm_hdl;
  54. #ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
  55. ipa_wdi_meter_notifier_cb wdi_notify;
  56. #endif
  57. };
  58. static struct ipa_wdi_context *ipa_wdi_ctx;
  59. int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
  60. struct ipa_wdi_init_out_params *out)
  61. {
  62. struct ipa_wdi_uc_ready_params uc_ready_params;
  63. struct ipa_smmu_in_params smmu_in;
  64. struct ipa_smmu_out_params smmu_out;
  65. if (ipa_wdi_ctx) {
  66. IPA_WDI_ERR("ipa_wdi_ctx was initialized before\n");
  67. return -EFAULT;
  68. }
  69. if (in->wdi_version > IPA_WDI_3 || in->wdi_version < IPA_WDI_1) {
  70. IPA_WDI_ERR("wrong wdi version: %d\n", in->wdi_version);
  71. return -EFAULT;
  72. }
  73. ipa_wdi_ctx = kzalloc(sizeof(*ipa_wdi_ctx), GFP_KERNEL);
  74. if (ipa_wdi_ctx == NULL) {
  75. IPA_WDI_ERR("fail to alloc wdi ctx\n");
  76. return -ENOMEM;
  77. }
  78. mutex_init(&ipa_wdi_ctx->lock);
  79. init_completion(&ipa_wdi_ctx->wdi_completion);
  80. INIT_LIST_HEAD(&ipa_wdi_ctx->head_intf_list);
  81. ipa_wdi_ctx->wdi_version = in->wdi_version;
  82. uc_ready_params.notify = in->notify;
  83. uc_ready_params.priv = in->priv;
  84. #ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
  85. ipa_wdi_ctx->wdi_notify = in->wdi_notify;
  86. #endif
  87. if (ipa_uc_reg_rdyCB(&uc_ready_params) != 0) {
  88. mutex_destroy(&ipa_wdi_ctx->lock);
  89. kfree(ipa_wdi_ctx);
  90. ipa_wdi_ctx = NULL;
  91. return -EFAULT;
  92. }
  93. out->is_uC_ready = uc_ready_params.is_uC_ready;
  94. smmu_in.smmu_client = IPA_SMMU_WLAN_CLIENT;
  95. if (ipa_get_smmu_params(&smmu_in, &smmu_out))
  96. out->is_smmu_enabled = false;
  97. else
  98. out->is_smmu_enabled = smmu_out.smmu_enable;
  99. ipa_wdi_ctx->is_smmu_enabled = out->is_smmu_enabled;
  100. if (ipa3_ctx->ipa_wdi3_over_gsi)
  101. out->is_over_gsi = true;
  102. else
  103. out->is_over_gsi = false;
  104. return 0;
  105. }
  106. EXPORT_SYMBOL(ipa_wdi_init);
  107. int ipa_wdi_cleanup(void)
  108. {
  109. struct ipa_wdi_intf_info *entry;
  110. struct ipa_wdi_intf_info *next;
  111. /* clear interface list */
  112. list_for_each_entry_safe(entry, next,
  113. &ipa_wdi_ctx->head_intf_list, link) {
  114. list_del(&entry->link);
  115. kfree(entry);
  116. }
  117. mutex_destroy(&ipa_wdi_ctx->lock);
  118. kfree(ipa_wdi_ctx);
  119. ipa_wdi_ctx = NULL;
  120. return 0;
  121. }
  122. EXPORT_SYMBOL(ipa_wdi_cleanup);
  123. static int ipa_wdi_commit_partial_hdr(
  124. struct ipa_ioc_add_hdr *hdr,
  125. const char *netdev_name,
  126. struct ipa_wdi_hdr_info *hdr_info)
  127. {
  128. int i;
  129. if (!hdr || !hdr_info || !netdev_name) {
  130. IPA_WDI_ERR("Invalid input\n");
  131. return -EINVAL;
  132. }
  133. hdr->commit = 1;
  134. hdr->num_hdrs = 2;
  135. snprintf(hdr->hdr[0].name, sizeof(hdr->hdr[0].name),
  136. "%s_ipv4", netdev_name);
  137. snprintf(hdr->hdr[1].name, sizeof(hdr->hdr[1].name),
  138. "%s_ipv6", netdev_name);
  139. for (i = IPA_IP_v4; i < IPA_IP_MAX; i++) {
  140. hdr->hdr[i].hdr_len = hdr_info[i].hdr_len;
  141. memcpy(hdr->hdr[i].hdr, hdr_info[i].hdr, hdr->hdr[i].hdr_len);
  142. hdr->hdr[i].type = hdr_info[i].hdr_type;
  143. hdr->hdr[i].is_partial = 1;
  144. hdr->hdr[i].is_eth2_ofst_valid = 1;
  145. hdr->hdr[i].eth2_ofst = hdr_info[i].dst_mac_addr_offset;
  146. }
  147. if (ipa_add_hdr(hdr)) {
  148. IPA_WDI_ERR("fail to add partial headers\n");
  149. return -EFAULT;
  150. }
  151. return 0;
  152. }
  153. int ipa_wdi_reg_intf(struct ipa_wdi_reg_intf_in_params *in)
  154. {
  155. struct ipa_ioc_add_hdr *hdr;
  156. struct ipa_wdi_intf_info *new_intf;
  157. struct ipa_wdi_intf_info *entry;
  158. struct ipa_tx_intf tx;
  159. struct ipa_rx_intf rx;
  160. struct ipa_ioc_tx_intf_prop tx_prop[2];
  161. struct ipa_ioc_rx_intf_prop rx_prop[2];
  162. u32 len;
  163. int ret = 0;
  164. if (in == NULL) {
  165. IPA_WDI_ERR("invalid params in=%pK\n", in);
  166. return -EINVAL;
  167. }
  168. if (!ipa_wdi_ctx) {
  169. IPA_WDI_ERR("wdi ctx is not initialized\n");
  170. return -EPERM;
  171. }
  172. IPA_WDI_DBG("register interface for netdev %s\n",
  173. in->netdev_name);
  174. mutex_lock(&ipa_wdi_ctx->lock);
  175. list_for_each_entry(entry, &ipa_wdi_ctx->head_intf_list, link)
  176. if (strcmp(entry->netdev_name, in->netdev_name) == 0) {
  177. IPA_WDI_DBG("intf was added before.\n");
  178. mutex_unlock(&ipa_wdi_ctx->lock);
  179. return 0;
  180. }
  181. IPA_WDI_DBG("intf was not added before, proceed.\n");
  182. new_intf = kzalloc(sizeof(*new_intf), GFP_KERNEL);
  183. if (new_intf == NULL) {
  184. IPA_WDI_ERR("fail to alloc new intf\n");
  185. mutex_unlock(&ipa_wdi_ctx->lock);
  186. return -ENOMEM;
  187. }
  188. INIT_LIST_HEAD(&new_intf->link);
  189. strlcpy(new_intf->netdev_name, in->netdev_name,
  190. sizeof(new_intf->netdev_name));
  191. new_intf->hdr_len = in->hdr_info[0].hdr_len;
  192. /* add partial header */
  193. len = sizeof(struct ipa_ioc_add_hdr) + 2 * sizeof(struct ipa_hdr_add);
  194. hdr = kzalloc(len, GFP_KERNEL);
  195. if (hdr == NULL) {
  196. IPA_WDI_ERR("fail to alloc %d bytes\n", len);
  197. ret = -EFAULT;
  198. goto fail_alloc_hdr;
  199. }
  200. if (ipa_wdi_commit_partial_hdr(hdr, in->netdev_name, in->hdr_info)) {
  201. IPA_WDI_ERR("fail to commit partial headers\n");
  202. ret = -EFAULT;
  203. goto fail_commit_hdr;
  204. }
  205. new_intf->partial_hdr_hdl[IPA_IP_v4] = hdr->hdr[IPA_IP_v4].hdr_hdl;
  206. new_intf->partial_hdr_hdl[IPA_IP_v6] = hdr->hdr[IPA_IP_v6].hdr_hdl;
  207. IPA_WDI_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
  208. hdr->hdr[IPA_IP_v4].hdr_hdl, hdr->hdr[IPA_IP_v6].hdr_hdl);
  209. /* populate tx prop */
  210. tx.num_props = 2;
  211. tx.prop = tx_prop;
  212. memset(tx_prop, 0, sizeof(tx_prop));
  213. tx_prop[0].ip = IPA_IP_v4;
  214. if (!ipa3_ctx->ipa_wdi3_over_gsi)
  215. tx_prop[0].dst_pipe = IPA_CLIENT_WLAN1_CONS;
  216. else
  217. tx_prop[0].dst_pipe = IPA_CLIENT_WLAN2_CONS;
  218. tx_prop[0].alt_dst_pipe = in->alt_dst_pipe;
  219. tx_prop[0].hdr_l2_type = in->hdr_info[0].hdr_type;
  220. strlcpy(tx_prop[0].hdr_name, hdr->hdr[IPA_IP_v4].name,
  221. sizeof(tx_prop[0].hdr_name));
  222. tx_prop[1].ip = IPA_IP_v6;
  223. if (!ipa3_ctx->ipa_wdi3_over_gsi)
  224. tx_prop[1].dst_pipe = IPA_CLIENT_WLAN1_CONS;
  225. else
  226. tx_prop[1].dst_pipe = IPA_CLIENT_WLAN2_CONS;
  227. tx_prop[1].alt_dst_pipe = in->alt_dst_pipe;
  228. tx_prop[1].hdr_l2_type = in->hdr_info[1].hdr_type;
  229. strlcpy(tx_prop[1].hdr_name, hdr->hdr[IPA_IP_v6].name,
  230. sizeof(tx_prop[1].hdr_name));
  231. /* populate rx prop */
  232. rx.num_props = 2;
  233. rx.prop = rx_prop;
  234. memset(rx_prop, 0, sizeof(rx_prop));
  235. rx_prop[0].ip = IPA_IP_v4;
  236. if (!ipa3_ctx->ipa_wdi3_over_gsi)
  237. rx_prop[0].src_pipe = IPA_CLIENT_WLAN1_PROD;
  238. else
  239. rx_prop[0].src_pipe = IPA_CLIENT_WLAN2_PROD;
  240. rx_prop[0].hdr_l2_type = in->hdr_info[0].hdr_type;
  241. if (in->is_meta_data_valid) {
  242. rx_prop[0].attrib.attrib_mask |= IPA_FLT_META_DATA;
  243. rx_prop[0].attrib.meta_data = in->meta_data;
  244. rx_prop[0].attrib.meta_data_mask = in->meta_data_mask;
  245. }
  246. rx_prop[1].ip = IPA_IP_v6;
  247. if (!ipa3_ctx->ipa_wdi3_over_gsi)
  248. rx_prop[1].src_pipe = IPA_CLIENT_WLAN1_PROD;
  249. else
  250. rx_prop[1].src_pipe = IPA_CLIENT_WLAN2_PROD;
  251. rx_prop[1].hdr_l2_type = in->hdr_info[1].hdr_type;
  252. if (in->is_meta_data_valid) {
  253. rx_prop[1].attrib.attrib_mask |= IPA_FLT_META_DATA;
  254. rx_prop[1].attrib.meta_data = in->meta_data;
  255. rx_prop[1].attrib.meta_data_mask = in->meta_data_mask;
  256. }
  257. if (ipa_register_intf(in->netdev_name, &tx, &rx)) {
  258. IPA_WDI_ERR("fail to add interface prop\n");
  259. ret = -EFAULT;
  260. goto fail_commit_hdr;
  261. }
  262. list_add(&new_intf->link, &ipa_wdi_ctx->head_intf_list);
  263. init_completion(&ipa_wdi_ctx->wdi_completion);
  264. kfree(hdr);
  265. mutex_unlock(&ipa_wdi_ctx->lock);
  266. return 0;
  267. fail_commit_hdr:
  268. kfree(hdr);
  269. fail_alloc_hdr:
  270. kfree(new_intf);
  271. mutex_unlock(&ipa_wdi_ctx->lock);
  272. return ret;
  273. }
  274. EXPORT_SYMBOL(ipa_wdi_reg_intf);
  275. int ipa_wdi_dereg_intf(const char *netdev_name)
  276. {
  277. int len, ret = 0;
  278. struct ipa_ioc_del_hdr *hdr = NULL;
  279. struct ipa_wdi_intf_info *entry;
  280. struct ipa_wdi_intf_info *next;
  281. if (!netdev_name) {
  282. IPA_WDI_ERR("no netdev name.\n");
  283. return -EINVAL;
  284. }
  285. if (!ipa_wdi_ctx) {
  286. IPA_WDI_ERR("wdi ctx is not initialized.\n");
  287. return -EPERM;
  288. }
  289. mutex_lock(&ipa_wdi_ctx->lock);
  290. list_for_each_entry_safe(entry, next, &ipa_wdi_ctx->head_intf_list,
  291. link)
  292. if (strcmp(entry->netdev_name, netdev_name) == 0) {
  293. len = sizeof(struct ipa_ioc_del_hdr) +
  294. 2 * sizeof(struct ipa_hdr_del);
  295. hdr = kzalloc(len, GFP_KERNEL);
  296. if (hdr == NULL) {
  297. IPA_WDI_ERR("fail to alloc %d bytes\n", len);
  298. mutex_unlock(&ipa_wdi_ctx->lock);
  299. return -ENOMEM;
  300. }
  301. hdr->commit = 1;
  302. hdr->num_hdls = 2;
  303. hdr->hdl[0].hdl = entry->partial_hdr_hdl[0];
  304. hdr->hdl[1].hdl = entry->partial_hdr_hdl[1];
  305. IPA_WDI_DBG("IPv4 hdr hdl: %d IPv6 hdr hdl: %d\n",
  306. hdr->hdl[0].hdl, hdr->hdl[1].hdl);
  307. if (ipa_del_hdr(hdr)) {
  308. IPA_WDI_ERR("fail to delete partial header\n");
  309. ret = -EFAULT;
  310. goto fail;
  311. }
  312. if (ipa_deregister_intf(entry->netdev_name)) {
  313. IPA_WDI_ERR("fail to del interface props\n");
  314. ret = -EFAULT;
  315. goto fail;
  316. }
  317. list_del(&entry->link);
  318. kfree(entry);
  319. break;
  320. }
  321. fail:
  322. kfree(hdr);
  323. mutex_unlock(&ipa_wdi_ctx->lock);
  324. return ret;
  325. }
  326. EXPORT_SYMBOL(ipa_wdi_dereg_intf);
  327. static void ipa_wdi_pm_cb(void *p, enum ipa_pm_cb_event event)
  328. {
  329. IPA_WDI_DBG("received pm event %d\n", event);
  330. }
  331. int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
  332. struct ipa_wdi_conn_out_params *out)
  333. {
  334. int i, j, ret = 0;
  335. struct ipa_pm_register_params pm_params;
  336. struct ipa_wdi_in_params in_tx;
  337. struct ipa_wdi_in_params in_rx;
  338. struct ipa_wdi_out_params out_tx;
  339. struct ipa_wdi_out_params out_rx;
  340. if (!(in && out)) {
  341. IPA_WDI_ERR("empty parameters. in=%pK out=%pK\n", in, out);
  342. return -EINVAL;
  343. }
  344. if (!ipa_wdi_ctx) {
  345. IPA_WDI_ERR("wdi ctx is not initialized\n");
  346. return -EPERM;
  347. }
  348. if (in->num_sys_pipe_needed > IPA_WDI_MAX_SUPPORTED_SYS_PIPE) {
  349. IPA_WDI_ERR("ipa can only support up to %d sys pipe\n",
  350. IPA_WDI_MAX_SUPPORTED_SYS_PIPE);
  351. return -EINVAL;
  352. }
  353. ipa_wdi_ctx->num_sys_pipe_needed = in->num_sys_pipe_needed;
  354. IPA_WDI_DBG("number of sys pipe %d\n", in->num_sys_pipe_needed);
  355. /* setup sys pipe when needed */
  356. for (i = 0; i < ipa_wdi_ctx->num_sys_pipe_needed; i++) {
  357. ret = ipa_setup_sys_pipe(&in->sys_in[i],
  358. &ipa_wdi_ctx->sys_pipe_hdl[i]);
  359. if (ret) {
  360. IPA_WDI_ERR("fail to setup sys pipe %d\n", i);
  361. ret = -EFAULT;
  362. goto fail_setup_sys_pipe;
  363. }
  364. }
  365. memset(&pm_params, 0, sizeof(pm_params));
  366. pm_params.name = "wdi";
  367. pm_params.callback = ipa_wdi_pm_cb;
  368. pm_params.user_data = NULL;
  369. pm_params.group = IPA_PM_GROUP_DEFAULT;
  370. if (ipa_pm_register(&pm_params, &ipa_wdi_ctx->ipa_pm_hdl)) {
  371. IPA_WDI_ERR("fail to register ipa pm\n");
  372. ret = -EFAULT;
  373. goto fail_setup_sys_pipe;
  374. }
  375. if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
  376. if (ipa_conn_wdi_pipes(in, out, ipa_wdi_ctx->wdi_notify)) {
  377. IPA_WDI_ERR("fail to setup wdi pipes\n");
  378. ret = -EFAULT;
  379. goto fail_connect_pipe;
  380. }
  381. } else {
  382. memset(&in_tx, 0, sizeof(in_tx));
  383. memset(&in_rx, 0, sizeof(in_rx));
  384. memset(&out_tx, 0, sizeof(out_tx));
  385. memset(&out_rx, 0, sizeof(out_rx));
  386. #ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
  387. in_rx.wdi_notify = ipa_wdi_ctx->wdi_notify;
  388. #endif
  389. if (in->is_smmu_enabled == false) {
  390. /* firsr setup rx pipe */
  391. in_rx.sys.ipa_ep_cfg = in->u_rx.rx.ipa_ep_cfg;
  392. in_rx.sys.client = in->u_rx.rx.client;
  393. in_rx.sys.notify = in->notify;
  394. in_rx.sys.priv = in->priv;
  395. in_rx.smmu_enabled = in->is_smmu_enabled;
  396. in_rx.u.ul.rdy_ring_base_pa =
  397. in->u_rx.rx.transfer_ring_base_pa;
  398. in_rx.u.ul.rdy_ring_size =
  399. in->u_rx.rx.transfer_ring_size;
  400. in_rx.u.ul.rdy_ring_rp_pa =
  401. in->u_rx.rx.transfer_ring_doorbell_pa;
  402. in_rx.u.ul.rdy_comp_ring_base_pa =
  403. in->u_rx.rx.event_ring_base_pa;
  404. in_rx.u.ul.rdy_comp_ring_wp_pa =
  405. in->u_rx.rx.event_ring_doorbell_pa;
  406. in_rx.u.ul.rdy_comp_ring_size =
  407. in->u_rx.rx.event_ring_size;
  408. if (ipa_connect_wdi_pipe(&in_rx, &out_rx)) {
  409. IPA_WDI_ERR("fail to setup rx pipe\n");
  410. ret = -EFAULT;
  411. goto fail_connect_pipe;
  412. }
  413. ipa_wdi_ctx->rx_pipe_hdl = out_rx.clnt_hdl;
  414. out->rx_uc_db_pa = out_rx.uc_door_bell_pa;
  415. IPA_WDI_DBG("rx uc db pa: 0x%pad\n", &out->rx_uc_db_pa);
  416. /* then setup tx pipe */
  417. in_tx.sys.ipa_ep_cfg = in->u_tx.tx.ipa_ep_cfg;
  418. in_tx.sys.client = in->u_tx.tx.client;
  419. in_tx.smmu_enabled = in->is_smmu_enabled;
  420. in_tx.u.dl.comp_ring_base_pa =
  421. in->u_tx.tx.transfer_ring_base_pa;
  422. in_tx.u.dl.comp_ring_size =
  423. in->u_tx.tx.transfer_ring_size;
  424. in_tx.u.dl.ce_ring_base_pa =
  425. in->u_tx.tx.event_ring_base_pa;
  426. in_tx.u.dl.ce_door_bell_pa =
  427. in->u_tx.tx.event_ring_doorbell_pa;
  428. in_tx.u.dl.ce_ring_size =
  429. in->u_tx.tx.event_ring_size;
  430. in_tx.u.dl.num_tx_buffers =
  431. in->u_tx.tx.num_pkt_buffers;
  432. if (ipa_connect_wdi_pipe(&in_tx, &out_tx)) {
  433. IPA_WDI_ERR("fail to setup tx pipe\n");
  434. ret = -EFAULT;
  435. goto fail;
  436. }
  437. ipa_wdi_ctx->tx_pipe_hdl = out_tx.clnt_hdl;
  438. out->tx_uc_db_pa = out_tx.uc_door_bell_pa;
  439. IPA_WDI_DBG("tx uc db pa: 0x%pad\n", &out->tx_uc_db_pa);
  440. } else { /* smmu is enabled */
  441. /* firsr setup rx pipe */
  442. in_rx.sys.ipa_ep_cfg = in->u_rx.rx_smmu.ipa_ep_cfg;
  443. in_rx.sys.client = in->u_rx.rx_smmu.client;
  444. in_rx.sys.notify = in->notify;
  445. in_rx.sys.priv = in->priv;
  446. in_rx.smmu_enabled = in->is_smmu_enabled;
  447. in_rx.u.ul_smmu.rdy_ring =
  448. in->u_rx.rx_smmu.transfer_ring_base;
  449. in_rx.u.ul_smmu.rdy_ring_size =
  450. in->u_rx.rx_smmu.transfer_ring_size;
  451. in_rx.u.ul_smmu.rdy_ring_rp_pa =
  452. in->u_rx.rx_smmu.transfer_ring_doorbell_pa;
  453. in_rx.u.ul_smmu.rdy_comp_ring =
  454. in->u_rx.rx_smmu.event_ring_base;
  455. in_rx.u.ul_smmu.rdy_comp_ring_wp_pa =
  456. in->u_rx.rx_smmu.event_ring_doorbell_pa;
  457. in_rx.u.ul_smmu.rdy_comp_ring_size =
  458. in->u_rx.rx_smmu.event_ring_size;
  459. if (ipa_connect_wdi_pipe(&in_rx, &out_rx)) {
  460. IPA_WDI_ERR("fail to setup rx pipe\n");
  461. ret = -EFAULT;
  462. goto fail_connect_pipe;
  463. }
  464. ipa_wdi_ctx->rx_pipe_hdl = out_rx.clnt_hdl;
  465. out->rx_uc_db_pa = out_rx.uc_door_bell_pa;
  466. IPA_WDI_DBG("rx uc db pa: 0x%pad\n", &out->rx_uc_db_pa);
  467. /* then setup tx pipe */
  468. in_tx.sys.ipa_ep_cfg = in->u_tx.tx_smmu.ipa_ep_cfg;
  469. in_tx.sys.client = in->u_tx.tx_smmu.client;
  470. in_tx.smmu_enabled = in->is_smmu_enabled;
  471. in_tx.u.dl_smmu.comp_ring =
  472. in->u_tx.tx_smmu.transfer_ring_base;
  473. in_tx.u.dl_smmu.comp_ring_size =
  474. in->u_tx.tx_smmu.transfer_ring_size;
  475. in_tx.u.dl_smmu.ce_ring =
  476. in->u_tx.tx_smmu.event_ring_base;
  477. in_tx.u.dl_smmu.ce_door_bell_pa =
  478. in->u_tx.tx_smmu.event_ring_doorbell_pa;
  479. in_tx.u.dl_smmu.ce_ring_size =
  480. in->u_tx.tx_smmu.event_ring_size;
  481. in_tx.u.dl_smmu.num_tx_buffers =
  482. in->u_tx.tx_smmu.num_pkt_buffers;
  483. if (ipa_connect_wdi_pipe(&in_tx, &out_tx)) {
  484. IPA_WDI_ERR("fail to setup tx pipe\n");
  485. ret = -EFAULT;
  486. goto fail;
  487. }
  488. ipa_wdi_ctx->tx_pipe_hdl = out_tx.clnt_hdl;
  489. out->tx_uc_db_pa = out_tx.uc_door_bell_pa;
  490. IPA_WDI_DBG("tx uc db pa: 0x%pad\n", &out->tx_uc_db_pa);
  491. }
  492. }
  493. return 0;
  494. fail:
  495. ipa_disconnect_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl);
  496. fail_connect_pipe:
  497. ipa_pm_deregister(ipa_wdi_ctx->ipa_pm_hdl);
  498. fail_setup_sys_pipe:
  499. for (j = 0; j < i; j++)
  500. ipa_teardown_sys_pipe(ipa_wdi_ctx->sys_pipe_hdl[j]);
  501. return ret;
  502. }
  503. EXPORT_SYMBOL(ipa_wdi_conn_pipes);
  504. int ipa_wdi_disconn_pipes(void)
  505. {
  506. int i, ipa_ep_idx_rx, ipa_ep_idx_tx;
  507. if (!ipa_wdi_ctx) {
  508. IPA_WDI_ERR("wdi ctx is not initialized\n");
  509. return -EPERM;
  510. }
  511. /* tear down sys pipe if needed */
  512. for (i = 0; i < ipa_wdi_ctx->num_sys_pipe_needed; i++) {
  513. if (ipa_teardown_sys_pipe(ipa_wdi_ctx->sys_pipe_hdl[i])) {
  514. IPA_WDI_ERR("fail to tear down sys pipe %d\n", i);
  515. return -EFAULT;
  516. }
  517. }
  518. if (!ipa3_ctx->ipa_wdi3_over_gsi) {
  519. ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
  520. ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
  521. } else {
  522. ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN2_PROD);
  523. ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN2_CONS);
  524. }
  525. if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
  526. if (ipa_disconn_wdi_pipes(ipa_ep_idx_rx, ipa_ep_idx_tx)) {
  527. IPA_WDI_ERR("fail to tear down wdi pipes\n");
  528. return -EFAULT;
  529. }
  530. } else {
  531. if (ipa_disconnect_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
  532. IPA_WDI_ERR("fail to tear down wdi tx pipes\n");
  533. return -EFAULT;
  534. }
  535. if (ipa_disconnect_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
  536. IPA_WDI_ERR("fail to tear down wdi rx pipes\n");
  537. return -EFAULT;
  538. }
  539. }
  540. if (ipa_pm_deregister(ipa_wdi_ctx->ipa_pm_hdl)) {
  541. IPA_WDI_ERR("fail to deregister ipa pm\n");
  542. return -EFAULT;
  543. }
  544. return 0;
  545. }
  546. EXPORT_SYMBOL(ipa_wdi_disconn_pipes);
  547. int ipa_wdi_enable_pipes(void)
  548. {
  549. int ret;
  550. int ipa_ep_idx_tx, ipa_ep_idx_rx;
  551. if (!ipa_wdi_ctx) {
  552. IPA_WDI_ERR("wdi ctx is not initialized.\n");
  553. return -EPERM;
  554. }
  555. if (!ipa3_ctx->ipa_wdi3_over_gsi) {
  556. ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
  557. ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
  558. } else {
  559. ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN2_PROD);
  560. ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN2_CONS);
  561. }
  562. if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
  563. if (ipa_enable_wdi_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
  564. IPA_WDI_ERR("fail to enable wdi pipes\n");
  565. return -EFAULT;
  566. }
  567. } else {
  568. if (ipa_enable_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
  569. IPA_WDI_ERR("fail to enable wdi tx pipe\n");
  570. return -EFAULT;
  571. }
  572. if (ipa_resume_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
  573. IPA_WDI_ERR("fail to resume wdi tx pipe\n");
  574. return -EFAULT;
  575. }
  576. if (ipa_enable_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
  577. IPA_WDI_ERR("fail to enable wdi rx pipe\n");
  578. return -EFAULT;
  579. }
  580. if (ipa_resume_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
  581. IPA_WDI_ERR("fail to resume wdi rx pipe\n");
  582. return -EFAULT;
  583. }
  584. }
  585. ret = ipa_pm_activate_sync(ipa_wdi_ctx->ipa_pm_hdl);
  586. if (ret) {
  587. IPA_WDI_ERR("fail to activate ipa pm\n");
  588. return -EFAULT;
  589. }
  590. return 0;
  591. }
  592. EXPORT_SYMBOL(ipa_wdi_enable_pipes);
  593. int ipa_wdi_disable_pipes(void)
  594. {
  595. int ret;
  596. int ipa_ep_idx_tx, ipa_ep_idx_rx;
  597. if (!ipa_wdi_ctx) {
  598. IPA_WDI_ERR("wdi ctx is not initialized.\n");
  599. return -EPERM;
  600. }
  601. if (!ipa3_ctx->ipa_wdi3_over_gsi) {
  602. ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
  603. ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN1_CONS);
  604. } else {
  605. ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_WLAN2_PROD);
  606. ipa_ep_idx_tx = ipa_get_ep_mapping(IPA_CLIENT_WLAN2_CONS);
  607. }
  608. if (ipa_wdi_ctx->wdi_version == IPA_WDI_3) {
  609. if (ipa_disable_wdi_pipes(ipa_ep_idx_tx, ipa_ep_idx_rx)) {
  610. IPA_WDI_ERR("fail to disable wdi pipes\n");
  611. return -EFAULT;
  612. }
  613. } else {
  614. if (ipa_suspend_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
  615. IPA_WDI_ERR("fail to suspend wdi tx pipe\n");
  616. return -EFAULT;
  617. }
  618. if (ipa_disable_wdi_pipe(ipa_wdi_ctx->tx_pipe_hdl)) {
  619. IPA_WDI_ERR("fail to disable wdi tx pipe\n");
  620. return -EFAULT;
  621. }
  622. if (ipa_suspend_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
  623. IPA_WDI_ERR("fail to suspend wdi rx pipe\n");
  624. return -EFAULT;
  625. }
  626. if (ipa_disable_wdi_pipe(ipa_wdi_ctx->rx_pipe_hdl)) {
  627. IPA_WDI_ERR("fail to disable wdi rx pipe\n");
  628. return -EFAULT;
  629. }
  630. }
  631. ret = ipa_pm_deactivate_sync(ipa_wdi_ctx->ipa_pm_hdl);
  632. if (ret) {
  633. IPA_WDI_ERR("fail to deactivate ipa pm\n");
  634. return -EFAULT;
  635. }
  636. return 0;
  637. }
  638. EXPORT_SYMBOL(ipa_wdi_disable_pipes);
  639. int ipa_wdi_set_perf_profile(struct ipa_wdi_perf_profile *profile)
  640. {
  641. if (profile == NULL) {
  642. IPA_WDI_ERR("Invalid input\n");
  643. return -EINVAL;
  644. }
  645. if (ipa_pm_set_throughput(ipa_wdi_ctx->ipa_pm_hdl,
  646. profile->max_supported_bw_mbps)) {
  647. IPA_WDI_ERR("fail to set pm throughput\n");
  648. return -EFAULT;
  649. }
  650. return 0;
  651. }
  652. EXPORT_SYMBOL(ipa_wdi_set_perf_profile);
  653. int ipa_wdi_create_smmu_mapping(u32 num_buffers,
  654. struct ipa_wdi_buffer_info *info)
  655. {
  656. return ipa_create_wdi_mapping(num_buffers, info);
  657. }
  658. EXPORT_SYMBOL(ipa_wdi_create_smmu_mapping);
  659. int ipa_wdi_release_smmu_mapping(u32 num_buffers,
  660. struct ipa_wdi_buffer_info *info)
  661. {
  662. return ipa_release_wdi_mapping(num_buffers, info);
  663. }
  664. EXPORT_SYMBOL(ipa_wdi_release_smmu_mapping);
  665. int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats)
  666. {
  667. return ipa_get_wdi_stats(stats);
  668. }
  669. EXPORT_SYMBOL(ipa_wdi_get_stats);
  670. int ipa_wdi_bw_monitor(struct ipa_wdi_bw_info *info)
  671. {
  672. return ipa_uc_bw_monitor(info);
  673. }
  674. EXPORT_SYMBOL(ipa_wdi_bw_monitor);
  675. int ipa_wdi_sw_stats(struct ipa_wdi_tx_info *info)
  676. {
  677. return ipa_set_wlan_tx_info(info);
  678. }
  679. EXPORT_SYMBOL(ipa_wdi_sw_stats);