ipa_nat.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /* Copyright (c) 2012-2016, 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/device.h>
  13. #include <linux/fs.h>
  14. #include <linux/init.h>
  15. #include <linux/kernel.h>
  16. #include <linux/mm.h>
  17. #include <linux/uaccess.h>
  18. #include "ipa_i.h"
  19. #define IPA_NAT_PHYS_MEM_OFFSET 0
  20. #define IPA_NAT_PHYS_MEM_SIZE IPA_RAM_NAT_SIZE
  21. #define IPA_NAT_SYSTEM_MEMORY 0
  22. #define IPA_NAT_SHARED_MEMORY 1
  23. enum nat_table_type {
  24. IPA_NAT_BASE_TBL = 0,
  25. IPA_NAT_EXPN_TBL = 1,
  26. IPA_NAT_INDX_TBL = 2,
  27. IPA_NAT_INDEX_EXPN_TBL = 3,
  28. };
  29. #define NAT_TABLE_ENTRY_SIZE_BYTE 32
  30. #define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4
  31. static int ipa_nat_vma_fault_remap(
  32. struct vm_area_struct *vma, struct vm_fault *vmf)
  33. {
  34. IPADBG("\n");
  35. vmf->page = NULL;
  36. return VM_FAULT_SIGBUS;
  37. }
  38. /* VMA related file operations functions */
  39. static struct vm_operations_struct ipa_nat_remap_vm_ops = {
  40. .fault = ipa_nat_vma_fault_remap,
  41. };
  42. static int ipa_nat_open(struct inode *inode, struct file *filp)
  43. {
  44. struct ipa_nat_mem *nat_ctx;
  45. IPADBG("\n");
  46. nat_ctx = container_of(inode->i_cdev, struct ipa_nat_mem, cdev);
  47. filp->private_data = nat_ctx;
  48. IPADBG("return\n");
  49. return 0;
  50. }
  51. static int ipa_nat_mmap(struct file *filp, struct vm_area_struct *vma)
  52. {
  53. unsigned long vsize = vma->vm_end - vma->vm_start;
  54. struct ipa_nat_mem *nat_ctx = (struct ipa_nat_mem *)filp->private_data;
  55. unsigned long phys_addr;
  56. int result;
  57. mutex_lock(&nat_ctx->lock);
  58. vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  59. if (nat_ctx->is_sys_mem) {
  60. IPADBG("Mapping system memory\n");
  61. if (nat_ctx->is_mapped) {
  62. IPAERR("mapping already exists, only 1 supported\n");
  63. result = -EINVAL;
  64. goto bail;
  65. }
  66. IPADBG("map sz=0x%x\n", nat_ctx->size);
  67. result =
  68. dma_mmap_coherent(
  69. NULL, vma,
  70. nat_ctx->vaddr, nat_ctx->dma_handle,
  71. nat_ctx->size);
  72. if (result) {
  73. IPAERR("unable to map memory. Err:%d\n", result);
  74. goto bail;
  75. }
  76. ipa_ctx->nat_mem.nat_base_address = nat_ctx->vaddr;
  77. } else {
  78. IPADBG("Mapping shared(local) memory\n");
  79. IPADBG("map sz=0x%lx\n", vsize);
  80. phys_addr = ipa_ctx->ipa_wrapper_base + IPA_REG_BASE_OFST +
  81. IPA_SRAM_DIRECT_ACCESS_n_OFST(IPA_NAT_PHYS_MEM_OFFSET);
  82. if (remap_pfn_range(
  83. vma, vma->vm_start,
  84. phys_addr >> PAGE_SHIFT, vsize, vma->vm_page_prot)) {
  85. IPAERR("remap failed\n");
  86. result = -EAGAIN;
  87. goto bail;
  88. }
  89. ipa_ctx->nat_mem.nat_base_address = (void *)vma->vm_start;
  90. }
  91. nat_ctx->is_mapped = true;
  92. vma->vm_ops = &ipa_nat_remap_vm_ops;
  93. IPADBG("return\n");
  94. result = 0;
  95. bail:
  96. mutex_unlock(&nat_ctx->lock);
  97. return result;
  98. }
  99. static const struct file_operations ipa_nat_fops = {
  100. .owner = THIS_MODULE,
  101. .open = ipa_nat_open,
  102. .mmap = ipa_nat_mmap
  103. };
  104. /**
  105. * allocate_nat_device() - Allocates memory for the NAT device
  106. * @mem: [in/out] memory parameters
  107. *
  108. * Called by NAT client driver to allocate memory for the NAT entries. Based on
  109. * the request size either shared or system memory will be used.
  110. *
  111. * Returns: 0 on success, negative on failure
  112. */
  113. int allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem)
  114. {
  115. struct ipa_nat_mem *nat_ctx = &(ipa_ctx->nat_mem);
  116. int gfp_flags = GFP_KERNEL | __GFP_ZERO;
  117. int result;
  118. IPADBG("passed memory size %d\n", mem->size);
  119. mutex_lock(&nat_ctx->lock);
  120. if (mem->size <= 0 || !strlen(mem->dev_name)
  121. || nat_ctx->is_dev_init == true) {
  122. IPADBG("Invalid Parameters or device is already init\n");
  123. result = -EPERM;
  124. goto bail;
  125. }
  126. if (mem->size > IPA_NAT_PHYS_MEM_SIZE) {
  127. IPADBG("Allocating system memory\n");
  128. nat_ctx->is_sys_mem = true;
  129. nat_ctx->vaddr =
  130. dma_alloc_coherent(NULL, mem->size, &nat_ctx->dma_handle,
  131. gfp_flags);
  132. if (nat_ctx->vaddr == NULL) {
  133. IPAERR("memory alloc failed\n");
  134. result = -ENOMEM;
  135. goto bail;
  136. }
  137. nat_ctx->size = mem->size;
  138. } else {
  139. IPADBG("using shared(local) memory\n");
  140. nat_ctx->is_sys_mem = false;
  141. }
  142. nat_ctx->class = class_create(THIS_MODULE, mem->dev_name);
  143. if (IS_ERR(nat_ctx->class)) {
  144. IPAERR("unable to create the class\n");
  145. result = -ENODEV;
  146. goto vaddr_alloc_fail;
  147. }
  148. result = alloc_chrdev_region(&nat_ctx->dev_num,
  149. 0,
  150. 1,
  151. mem->dev_name);
  152. if (result) {
  153. IPAERR("alloc_chrdev_region err.\n");
  154. result = -ENODEV;
  155. goto alloc_chrdev_region_fail;
  156. }
  157. nat_ctx->dev =
  158. device_create(nat_ctx->class, NULL, nat_ctx->dev_num, nat_ctx,
  159. "%s", mem->dev_name);
  160. if (IS_ERR(nat_ctx->dev)) {
  161. IPAERR("device_create err:%ld\n", PTR_ERR(nat_ctx->dev));
  162. result = -ENODEV;
  163. goto device_create_fail;
  164. }
  165. cdev_init(&nat_ctx->cdev, &ipa_nat_fops);
  166. nat_ctx->cdev.owner = THIS_MODULE;
  167. nat_ctx->cdev.ops = &ipa_nat_fops;
  168. result = cdev_add(&nat_ctx->cdev, nat_ctx->dev_num, 1);
  169. if (result) {
  170. IPAERR("cdev_add err=%d\n", -result);
  171. goto cdev_add_fail;
  172. }
  173. nat_ctx->is_dev_init = true;
  174. IPADBG("IPA NAT driver init successfully\n");
  175. result = 0;
  176. goto bail;
  177. cdev_add_fail:
  178. device_destroy(nat_ctx->class, nat_ctx->dev_num);
  179. device_create_fail:
  180. unregister_chrdev_region(nat_ctx->dev_num, 1);
  181. alloc_chrdev_region_fail:
  182. class_destroy(nat_ctx->class);
  183. vaddr_alloc_fail:
  184. if (nat_ctx->vaddr) {
  185. IPADBG("Releasing system memory\n");
  186. dma_free_coherent(
  187. NULL, nat_ctx->size,
  188. nat_ctx->vaddr, nat_ctx->dma_handle);
  189. nat_ctx->vaddr = NULL;
  190. nat_ctx->dma_handle = 0;
  191. nat_ctx->size = 0;
  192. }
  193. bail:
  194. mutex_unlock(&nat_ctx->lock);
  195. return result;
  196. }
  197. /* IOCTL function handlers */
  198. /**
  199. * ipa_nat_init_cmd() - Post IP_V4_NAT_INIT command to IPA HW
  200. * @init: [in] initialization command attributes
  201. *
  202. * Called by NAT client driver to post IP_V4_NAT_INIT command to IPA HW
  203. *
  204. * Returns: 0 on success, negative on failure
  205. */
  206. int ipa_nat_init_cmd(struct ipa_ioc_v4_nat_init *init)
  207. {
  208. struct ipa_desc desc = { 0 };
  209. struct ipa_ip_v4_nat_init *cmd;
  210. u16 size = sizeof(struct ipa_ip_v4_nat_init);
  211. int result;
  212. IPADBG("\n");
  213. if (init->tbl_index < 0 || init->table_entries <= 0) {
  214. IPADBG("Table index or entries is zero\n");
  215. result = -EPERM;
  216. goto bail;
  217. }
  218. cmd = kmalloc(size, GFP_KERNEL);
  219. if (!cmd) {
  220. IPAERR("Failed to alloc immediate command object\n");
  221. result = -ENOMEM;
  222. goto bail;
  223. }
  224. if (ipa_ctx->nat_mem.vaddr) {
  225. IPADBG("using system memory for nat table\n");
  226. cmd->ipv4_rules_addr_type = IPA_NAT_SYSTEM_MEMORY;
  227. cmd->ipv4_expansion_rules_addr_type = IPA_NAT_SYSTEM_MEMORY;
  228. cmd->index_table_addr_type = IPA_NAT_SYSTEM_MEMORY;
  229. cmd->index_table_expansion_addr_type = IPA_NAT_SYSTEM_MEMORY;
  230. cmd->ipv4_rules_addr =
  231. ipa_ctx->nat_mem.dma_handle + init->ipv4_rules_offset;
  232. IPADBG("ipv4_rules_offset:0x%x\n", init->ipv4_rules_offset);
  233. cmd->ipv4_expansion_rules_addr =
  234. ipa_ctx->nat_mem.dma_handle + init->expn_rules_offset;
  235. IPADBG("expn_rules_offset:0x%x\n", init->expn_rules_offset);
  236. cmd->index_table_addr =
  237. ipa_ctx->nat_mem.dma_handle + init->index_offset;
  238. IPADBG("index_offset:0x%x\n", init->index_offset);
  239. cmd->index_table_expansion_addr =
  240. ipa_ctx->nat_mem.dma_handle + init->index_expn_offset;
  241. IPADBG("index_expn_offset:0x%x\n", init->index_expn_offset);
  242. } else {
  243. IPADBG("using shared(local) memory for nat table\n");
  244. cmd->ipv4_rules_addr_type = IPA_NAT_SHARED_MEMORY;
  245. cmd->ipv4_expansion_rules_addr_type = IPA_NAT_SHARED_MEMORY;
  246. cmd->index_table_addr_type = IPA_NAT_SHARED_MEMORY;
  247. cmd->index_table_expansion_addr_type = IPA_NAT_SHARED_MEMORY;
  248. cmd->ipv4_rules_addr =
  249. init->ipv4_rules_offset + IPA_RAM_NAT_OFST;
  250. cmd->ipv4_expansion_rules_addr =
  251. init->expn_rules_offset + IPA_RAM_NAT_OFST;
  252. cmd->index_table_addr = init->index_offset + IPA_RAM_NAT_OFST;
  253. cmd->index_table_expansion_addr =
  254. init->index_expn_offset + IPA_RAM_NAT_OFST;
  255. }
  256. cmd->table_index = init->tbl_index;
  257. IPADBG("Table index:0x%x\n", cmd->table_index);
  258. cmd->size_base_tables = init->table_entries;
  259. IPADBG("Base Table size:0x%x\n", cmd->size_base_tables);
  260. cmd->size_expansion_tables = init->expn_table_entries;
  261. IPADBG("Expansion Table size:0x%x\n", cmd->size_expansion_tables);
  262. cmd->public_ip_addr = init->ip_addr;
  263. IPADBG("Public ip address:0x%x\n", cmd->public_ip_addr);
  264. desc.opcode = IPA_IP_V4_NAT_INIT;
  265. desc.type = IPA_IMM_CMD_DESC;
  266. desc.callback = NULL;
  267. desc.user1 = NULL;
  268. desc.user2 = NULL;
  269. desc.pyld = (void *)cmd;
  270. desc.len = size;
  271. IPADBG("posting v4 init command\n");
  272. if (ipa_send_cmd(1, &desc)) {
  273. IPAERR("Fail to send immediate command\n");
  274. result = -EPERM;
  275. goto free_cmd;
  276. }
  277. ipa_ctx->nat_mem.public_ip_addr = init->ip_addr;
  278. IPADBG("Table ip address:0x%x", ipa_ctx->nat_mem.public_ip_addr);
  279. ipa_ctx->nat_mem.ipv4_rules_addr =
  280. (char *)ipa_ctx->nat_mem.nat_base_address + init->ipv4_rules_offset;
  281. IPADBG("ipv4_rules_addr: 0x%p\n",
  282. ipa_ctx->nat_mem.ipv4_rules_addr);
  283. ipa_ctx->nat_mem.ipv4_expansion_rules_addr =
  284. (char *)ipa_ctx->nat_mem.nat_base_address + init->expn_rules_offset;
  285. IPADBG("ipv4_expansion_rules_addr: 0x%p\n",
  286. ipa_ctx->nat_mem.ipv4_expansion_rules_addr);
  287. ipa_ctx->nat_mem.index_table_addr =
  288. (char *)ipa_ctx->nat_mem.nat_base_address + init->index_offset;
  289. IPADBG("index_table_addr: 0x%p\n",
  290. ipa_ctx->nat_mem.index_table_addr);
  291. ipa_ctx->nat_mem.index_table_expansion_addr =
  292. (char *)ipa_ctx->nat_mem.nat_base_address + init->index_expn_offset;
  293. IPADBG("index_table_expansion_addr: 0x%p\n",
  294. ipa_ctx->nat_mem.index_table_expansion_addr);
  295. IPADBG("size_base_tables: %d\n", init->table_entries);
  296. ipa_ctx->nat_mem.size_base_tables = init->table_entries;
  297. IPADBG("size_expansion_tables: %d\n", init->expn_table_entries);
  298. ipa_ctx->nat_mem.size_expansion_tables = init->expn_table_entries;
  299. IPADBG("return\n");
  300. result = 0;
  301. free_cmd:
  302. kfree(cmd);
  303. bail:
  304. return result;
  305. }
  306. /**
  307. * ipa_nat_dma_cmd() - Post NAT_DMA command to IPA HW
  308. * @dma: [in] initialization command attributes
  309. *
  310. * Called by NAT client driver to post NAT_DMA command to IPA HW
  311. *
  312. * Returns: 0 on success, negative on failure
  313. */
  314. int ipa_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)
  315. {
  316. struct ipa_nat_dma *cmd = NULL;
  317. struct ipa_desc *desc = NULL;
  318. u16 size = 0, cnt = 0;
  319. int ret = 0;
  320. IPADBG("\n");
  321. if (dma->entries <= 0) {
  322. IPADBG("Invalid number of commands\n");
  323. ret = -EPERM;
  324. goto bail;
  325. }
  326. for (cnt = 0; cnt < dma->entries; cnt++) {
  327. if (dma->dma[cnt].table_index >= 1) {
  328. IPAERR("Invalid table index %d\n",
  329. dma->dma[cnt].table_index);
  330. ret = -EPERM;
  331. goto bail;
  332. }
  333. switch (dma->dma[cnt].base_addr) {
  334. case IPA_NAT_BASE_TBL:
  335. if (dma->dma[cnt].offset >=
  336. (ipa_ctx->nat_mem.size_base_tables + 1) *
  337. NAT_TABLE_ENTRY_SIZE_BYTE) {
  338. IPAERR("Invalid offset %d\n",
  339. dma->dma[cnt].offset);
  340. ret = -EPERM;
  341. goto bail;
  342. }
  343. break;
  344. case IPA_NAT_EXPN_TBL:
  345. if (dma->dma[cnt].offset >=
  346. ipa_ctx->nat_mem.size_expansion_tables *
  347. NAT_TABLE_ENTRY_SIZE_BYTE) {
  348. IPAERR("Invalid offset %d\n",
  349. dma->dma[cnt].offset);
  350. ret = -EPERM;
  351. goto bail;
  352. }
  353. break;
  354. case IPA_NAT_INDX_TBL:
  355. if (dma->dma[cnt].offset >=
  356. (ipa_ctx->nat_mem.size_base_tables + 1) *
  357. NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
  358. IPAERR("Invalid offset %d\n",
  359. dma->dma[cnt].offset);
  360. ret = -EPERM;
  361. goto bail;
  362. }
  363. break;
  364. case IPA_NAT_INDEX_EXPN_TBL:
  365. if (dma->dma[cnt].offset >=
  366. ipa_ctx->nat_mem.size_expansion_tables *
  367. NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
  368. IPAERR("Invalid offset %d\n",
  369. dma->dma[cnt].offset);
  370. ret = -EPERM;
  371. goto bail;
  372. }
  373. break;
  374. default:
  375. IPAERR("Invalid base_addr %d\n",
  376. dma->dma[cnt].base_addr);
  377. ret = -EPERM;
  378. goto bail;
  379. }
  380. }
  381. size = sizeof(struct ipa_desc) * dma->entries;
  382. desc = kmalloc(size, GFP_KERNEL);
  383. if (desc == NULL) {
  384. IPAERR("Failed to alloc memory\n");
  385. ret = -ENOMEM;
  386. goto bail;
  387. }
  388. size = sizeof(struct ipa_nat_dma) * dma->entries;
  389. cmd = kmalloc(size, GFP_KERNEL);
  390. if (cmd == NULL) {
  391. IPAERR("Failed to alloc memory\n");
  392. ret = -ENOMEM;
  393. goto bail;
  394. }
  395. for (cnt = 0; cnt < dma->entries; cnt++) {
  396. cmd[cnt].table_index = dma->dma[cnt].table_index;
  397. cmd[cnt].base_addr = dma->dma[cnt].base_addr;
  398. cmd[cnt].offset = dma->dma[cnt].offset;
  399. cmd[cnt].data = dma->dma[cnt].data;
  400. desc[cnt].type = IPA_IMM_CMD_DESC;
  401. desc[cnt].opcode = IPA_NAT_DMA;
  402. desc[cnt].callback = NULL;
  403. desc[cnt].user1 = NULL;
  404. desc[cnt].user2 = NULL;
  405. desc[cnt].len = sizeof(struct ipa_nat_dma);
  406. desc[cnt].pyld = (void *)&cmd[cnt];
  407. ret = ipa_send_cmd(1, &desc[cnt]);
  408. if (ret == -EPERM)
  409. IPAERR("Fail to send immediate command %d\n", cnt);
  410. }
  411. bail:
  412. kfree(cmd);
  413. kfree(desc);
  414. return ret;
  415. }
  416. /**
  417. * ipa_nat_free_mem_and_device() - free the NAT memory and remove the device
  418. * @nat_ctx: [in] the IPA NAT memory to free
  419. *
  420. * Called by NAT client driver to free the NAT memory and remove the device
  421. */
  422. void ipa_nat_free_mem_and_device(struct ipa_nat_mem *nat_ctx)
  423. {
  424. IPADBG("\n");
  425. mutex_lock(&nat_ctx->lock);
  426. if (nat_ctx->is_sys_mem) {
  427. IPADBG("freeing the dma memory\n");
  428. dma_free_coherent(
  429. NULL, nat_ctx->size,
  430. nat_ctx->vaddr, nat_ctx->dma_handle);
  431. nat_ctx->size = 0;
  432. nat_ctx->vaddr = NULL;
  433. }
  434. nat_ctx->is_mapped = false;
  435. nat_ctx->is_sys_mem = false;
  436. cdev_del(&nat_ctx->cdev);
  437. device_destroy(nat_ctx->class, nat_ctx->dev_num);
  438. unregister_chrdev_region(nat_ctx->dev_num, 1);
  439. class_destroy(nat_ctx->class);
  440. nat_ctx->is_dev_init = false;
  441. mutex_unlock(&nat_ctx->lock);
  442. IPADBG("return\n");
  443. return;
  444. }
  445. /**
  446. * ipa_nat_del_cmd() - Delete a NAT table
  447. * @del: [in] delete table table table parameters
  448. *
  449. * Called by NAT client driver to delete the nat table
  450. *
  451. * Returns: 0 on success, negative on failure
  452. */
  453. int ipa_nat_del_cmd(struct ipa_ioc_v4_nat_del *del)
  454. {
  455. struct ipa_desc desc = { 0 };
  456. struct ipa_ip_v4_nat_init *cmd;
  457. u16 size = sizeof(struct ipa_ip_v4_nat_init);
  458. u8 mem_type = IPA_NAT_SHARED_MEMORY;
  459. u32 base_addr = IPA_NAT_PHYS_MEM_OFFSET;
  460. int result;
  461. IPADBG("\n");
  462. if (del->table_index < 0 || del->public_ip_addr == 0) {
  463. IPADBG("Bad Parameter\n");
  464. result = -EPERM;
  465. goto bail;
  466. }
  467. cmd = kmalloc(size, GFP_KERNEL);
  468. if (cmd == NULL) {
  469. IPAERR("Failed to alloc immediate command object\n");
  470. result = -ENOMEM;
  471. goto bail;
  472. }
  473. cmd->table_index = del->table_index;
  474. cmd->ipv4_rules_addr = base_addr;
  475. cmd->ipv4_rules_addr_type = mem_type;
  476. cmd->ipv4_expansion_rules_addr = base_addr;
  477. cmd->ipv4_expansion_rules_addr_type = mem_type;
  478. cmd->index_table_addr = base_addr;
  479. cmd->index_table_addr_type = mem_type;
  480. cmd->index_table_expansion_addr = base_addr;
  481. cmd->index_table_expansion_addr_type = mem_type;
  482. cmd->size_base_tables = 0;
  483. cmd->size_expansion_tables = 0;
  484. cmd->public_ip_addr = del->public_ip_addr;
  485. desc.opcode = IPA_IP_V4_NAT_INIT;
  486. desc.type = IPA_IMM_CMD_DESC;
  487. desc.callback = NULL;
  488. desc.user1 = NULL;
  489. desc.user2 = NULL;
  490. desc.pyld = (void *)cmd;
  491. desc.len = size;
  492. if (ipa_send_cmd(1, &desc)) {
  493. IPAERR("Fail to send immediate command\n");
  494. result = -EPERM;
  495. goto free_mem;
  496. }
  497. ipa_nat_free_mem_and_device(&ipa_ctx->nat_mem);
  498. IPADBG("return\n");
  499. result = 0;
  500. free_mem:
  501. kfree(cmd);
  502. bail:
  503. return result;
  504. }