Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad07f8a0 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa4: add multi PDN support"

parents e8656108 05fccd08
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -556,6 +556,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
	struct ipa_ioc_nat_alloc_mem nat_mem;
	struct ipa_ioc_v4_nat_init nat_init;
	struct ipa_ioc_v4_nat_del nat_del;
	struct ipa_ioc_nat_pdn_entry mdfy_pdn;
	struct ipa_ioc_rm_dependency rm_depend;
	size_t sz;
	int pre_entry;
@@ -654,6 +655,18 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		}
		break;

	case IPA_IOC_NAT_MODIFY_PDN:
		if (copy_from_user((u8 *)&mdfy_pdn, (const void __user *)arg,
			sizeof(struct ipa_ioc_nat_pdn_entry))) {
			retval = -EFAULT;
			break;
		}
		if (ipa4_nat_mdfy_pdn(&mdfy_pdn)) {
			retval = -EFAULT;
			break;
		}
		break;

	case IPA_IOC_ADD_HDR:
		if (copy_from_user(header, (u8 *)arg,
					sizeof(struct ipa_ioc_add_hdr))) {
+22 −0
Original line number Diff line number Diff line
@@ -906,6 +906,10 @@ static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count,
			pr_err("hashable:%u rule_id:%u max_prio:%u prio:%u ",
				entry->rule.hashable, entry->rule_id,
				entry->rule.max_prio, entry->prio);
			if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
				pr_err("pdn index %d, set metadata %d ",
					entry->rule.pdn_idx,
					entry->rule.set_metadata);
			if (eq)
				ipa3_attrib_dump_eq(
					&entry->rule.eq_attrib);
@@ -968,6 +972,10 @@ static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf,
				bitmap, rules[rl].rule.retain_hdr);
			pr_err("rule_id:%u prio:%u ",
				rules[rl].id, rules[rl].priority);
			if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
				pr_err("pdn: %u, set_metadata: %u ",
					rules[rl].rule.pdn_idx,
					rules[rl].rule.set_metadata);
			ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
		}

@@ -992,6 +1000,10 @@ static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf,
				bitmap, rules[rl].rule.retain_hdr);
			pr_err("rule_id:%u  prio:%u ",
				rules[rl].id, rules[rl].priority);
			if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
				pr_err("pdn: %u, set_metadata: %u ",
					rules[rl].rule.pdn_idx,
					rules[rl].rule.set_metadata);
			ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
		}
		pr_err("\n");
@@ -1502,6 +1514,7 @@ static ssize_t ipa3_read_nat4(struct file *file,
	u32 value, i, j, rule_id;
	u16 enable, tbl_entry, flag;
	u32 no_entrys = 0;
	struct ipa_pdn_entry *pdn_table = ipa3_ctx->nat_mem.pdn_mem.base;

	mutex_lock(&ipa3_ctx->nat_mem.lock);
	value = ipa3_ctx->nat_mem.public_ip_addr;
@@ -1512,6 +1525,15 @@ static ssize_t ipa3_read_nat4(struct file *file,
				((value & 0x0000FF00) >> 8),
				((value & 0x000000FF)));

	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
		for (i = 0; i < IPA_MAX_PDN_NUM; i++) {
			pr_err(
				"PDN %d: ip 0x%X, src_metadata 0x%X, dst_metadata 0x%X\n",
				i, pdn_table[i].public_ip,
				pdn_table[i].src_metadata,
				pdn_table[i].dst_metadata);
		}

	pr_err("Table Size:%d\n",
				ipa3_ctx->nat_mem.size_base_tables);

+17 −0
Original line number Diff line number Diff line
@@ -755,6 +755,23 @@ static int __ipa_validate_flt_rule(const struct ipa_flt_rule *rule,
		}
	}

	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
		if (rule->pdn_idx) {
			if (rule->action == IPA_PASS_TO_EXCEPTION ||
				rule->action == IPA_PASS_TO_ROUTING) {
				IPAERR(
					"PDN index should be 0 when action is not pass to NAT\n");
				goto error;
			} else {
				if (rule->pdn_idx >= IPA_MAX_PDN_NUM) {
					IPAERR("PDN index %d is too large\n",
						rule->pdn_idx);
					goto error;
				}
			}
		}
	}

	if (rule->rule_id) {
		if (!(rule->rule_id & ipahal_get_rule_id_hi_bit())) {
			IPAERR("invalid rule_id provided 0x%x\n"
+17 −0
Original line number Diff line number Diff line
@@ -738,6 +738,19 @@ struct ipa3_rx_pkt_wrapper {
	struct ipa3_sys_context *sys;
};

/**
* struct ipa_pdn_entry - IPA PDN config table entry
* @public_ip: the PDN's public ip
* @src_metadata: the PDN's metadata to be replaced for source NAT
* @dst_metadata: the PDN's metadata to be replaced for destination NAT
* @resrvd: reserved field
*/
struct ipa_pdn_entry {
	u32 public_ip;
	u32 src_metadata;
	u32 dst_metadata;
	u32 resrvd;
};
/**
 * struct ipa3_nat_mem - IPA NAT memory description
 * @class: pointer to the struct class
@@ -759,6 +772,7 @@ struct ipa3_rx_pkt_wrapper {
 * @size_base_tables: base table size
 * @size_expansion_tables: expansion table size
 * @public_ip_addr: ip address of nat table
 * @pdn_mem: pdn config table SW cache memory structure
 */
struct ipa3_nat_mem {
	struct class *class;
@@ -784,6 +798,7 @@ struct ipa3_nat_mem {
	void *tmp_vaddr;
	dma_addr_t tmp_dma_handle;
	bool is_tmp_mem;
	struct ipa_mem_buffer pdn_mem;
};

/**
@@ -1580,6 +1595,8 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma);

int ipa3_nat_del_cmd(struct ipa_ioc_v4_nat_del *del);

int ipa4_nat_mdfy_pdn(struct ipa_ioc_nat_pdn_entry *mdfy_pdn);

/*
 * Messaging
 */
+253 −37
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ enum nat_table_type {
#define NAT_TABLE_ENTRY_SIZE_BYTE 32
#define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4


static int ipa3_nat_vma_fault_remap(
	 struct vm_area_struct *vma, struct vm_fault *vmf)
{
@@ -247,7 +246,7 @@ int ipa3_create_nat_device(void)
int ipa3_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem)
{
	struct ipa3_nat_mem *nat_ctx = &(ipa3_ctx->nat_mem);
	int gfp_flags = GFP_KERNEL | __GFP_ZERO;
	gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO;
	int result;

	IPADBG("passed memory size %zu\n", mem->size);
@@ -295,11 +294,44 @@ int ipa3_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem)
		IPADBG("using shared(local) memory\n");
		nat_ctx->is_sys_mem = false;
	}
	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
		struct ipa_pdn_entry *pdn_entries;
		struct ipa_mem_buffer *pdn_mem = &ipa3_ctx->nat_mem.pdn_mem;

		pdn_mem->size = sizeof(struct ipa_pdn_entry) * IPA_MAX_PDN_NUM;
		if (IPA_MEM_PART(pdn_config_size) < pdn_mem->size) {
			IPAERR(
				"number of PDN entries exceeds SRAM available space\n");
			result = -ENOMEM;
			goto fail_alloc_pdn;
		}

		pdn_mem->base = dma_alloc_coherent(ipa3_ctx->pdev,
			pdn_mem->size,
			&pdn_mem->phys_base,
			gfp_flags);
		if (!pdn_mem->base) {
			IPAERR("fail to allocate PDN memory\n");
			result = -ENOMEM;
			goto fail_alloc_pdn;
		}
		pdn_entries = pdn_mem->base;
		memset(pdn_entries, 0, pdn_mem->size);
		IPADBG("IPA NAT dev allocated PDN memory successfully\n");
	}

	nat_ctx->is_dev_init = true;
	IPADBG("IPA NAT dev init successfully\n");
	result = 0;
	mutex_unlock(&nat_ctx->lock);

	return 0;

fail_alloc_pdn:
	if (nat_ctx->vaddr) {
		dma_free_coherent(ipa3_ctx->pdev, mem->size, nat_ctx->vaddr,
			nat_ctx->dma_handle);
		nat_ctx->vaddr = NULL;
	}
bail:
	mutex_unlock(&nat_ctx->lock);

@@ -320,11 +352,13 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init)
#define TBL_ENTRY_SIZE 32
#define INDX_TBL_ENTRY_SIZE 4

	struct ipahal_imm_cmd_pyld *nop_cmd_pyld = NULL;
	struct ipa3_desc desc[2];
	struct ipa3_desc desc[3];
	struct ipahal_imm_cmd_ip_v4_nat_init cmd;
	struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
	int result;
	int num_cmd = 0;
	int i = 0;
	struct ipahal_imm_cmd_pyld *cmd_pyld[3];
	struct ipahal_imm_cmd_dma_shared_mem mem_cmd = { 0 };
	int result = 0;
	u32 offset = 0;
	size_t tmp;

@@ -412,21 +446,22 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init)

	memset(&desc, 0, sizeof(desc));
	/* NO-OP IC for ensuring that IPA pipeline is empty */
	nop_cmd_pyld =
	cmd_pyld[num_cmd] =
		ipahal_construct_nop_imm_cmd(false, IPAHAL_HPS_CLEAR, false);
	if (!nop_cmd_pyld) {
	if (!cmd_pyld[num_cmd]) {
		IPAERR("failed to construct NOP imm cmd\n");
		result = -ENOMEM;
		goto bail;
	}

	desc[0].opcode = nop_cmd_pyld->opcode;
	desc[0].type = IPA_IMM_CMD_DESC;
	desc[0].callback = NULL;
	desc[0].user1 = NULL;
	desc[0].user2 = 0;
	desc[0].pyld = nop_cmd_pyld->data;
	desc[0].len = nop_cmd_pyld->len;
	desc[num_cmd].opcode = cmd_pyld[num_cmd]->opcode;
	desc[num_cmd].type = IPA_IMM_CMD_DESC;
	desc[num_cmd].callback = NULL;
	desc[num_cmd].user1 = NULL;
	desc[num_cmd].user2 = 0;
	desc[num_cmd].pyld = cmd_pyld[num_cmd]->data;
	desc[num_cmd].len = cmd_pyld[num_cmd]->len;
	num_cmd++;

	if (ipa3_ctx->nat_mem.vaddr) {
		IPADBG("using system memory for nat table\n");
@@ -453,7 +488,7 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init)
			IPAERR("index_expn_offset: 0x%x\n",
				init->index_expn_offset);
			result = -EPERM;
			goto free_nop;
			goto destroy_imm_cmd;
		}
		cmd.ipv4_rules_addr =
			ipa3_ctx->nat_mem.dma_handle + init->ipv4_rules_offset;
@@ -495,25 +530,75 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init)
	IPADBG("Base Table size:0x%x\n", cmd.size_base_tables);
	cmd.size_expansion_tables = init->expn_table_entries;
	IPADBG("Expansion Table size:0x%x\n", cmd.size_expansion_tables);
	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
		/*
		 * public ip field changed to store the PDN config base
		 * address in IPAv4
		 */
		cmd.public_ip_addr = IPA_MEM_PART(pdn_config_ofst);
		IPADBG("pdn config base:0x%x\n", cmd.public_ip_addr);
	} else {
		cmd.public_ip_addr = init->ip_addr;
		IPADBG("Public ip address:0x%x\n", cmd.public_ip_addr);
	cmd_pyld = ipahal_construct_imm_cmd(
	}
	cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
		IPA_IMM_CMD_IP_V4_NAT_INIT, &cmd, false);
	if (!cmd_pyld) {
	if (!cmd_pyld[num_cmd]) {
		IPAERR("Fail to construct ip_v4_nat_init imm cmd\n");
		result = -EPERM;
		goto free_nop;
		goto destroy_imm_cmd;
	}

	desc[num_cmd].opcode = cmd_pyld[num_cmd]->opcode;
	desc[num_cmd].type = IPA_IMM_CMD_DESC;
	desc[num_cmd].callback = NULL;
	desc[num_cmd].user1 = NULL;
	desc[num_cmd].user2 = 0;
	desc[num_cmd].pyld = cmd_pyld[num_cmd]->data;
	desc[num_cmd].len = cmd_pyld[num_cmd]->len;
	num_cmd++;

	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
		struct ipa_pdn_entry *pdn_entries;

		/* store ip in pdn entries cache array */
		pdn_entries = ipa3_ctx->nat_mem.pdn_mem.base;
		pdn_entries[0].public_ip = init->ip_addr;
		pdn_entries[0].dst_metadata = 0;
		pdn_entries[0].src_metadata = 0;
		pdn_entries[0].resrvd = 0;

		IPADBG("Public ip address:0x%x\n", init->ip_addr);

		/* Copy the PDN config table to SRAM */
		mem_cmd.is_read = false;
		mem_cmd.skip_pipeline_clear = false;
		mem_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
		mem_cmd.size = sizeof(struct ipa_pdn_entry) * IPA_MAX_PDN_NUM;
		mem_cmd.system_addr = ipa3_ctx->nat_mem.pdn_mem.phys_base;
		mem_cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
			IPA_MEM_PART(pdn_config_ofst);
		cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
			IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
		if (!cmd_pyld[num_cmd]) {
			IPAERR(
			"fail construct dma_shared_mem cmd: for pdn table");
			result = -ENOMEM;
			goto destroy_imm_cmd;
		}
		desc[num_cmd].opcode = cmd_pyld[num_cmd]->opcode;
		desc[num_cmd].type = IPA_IMM_CMD_DESC;
		desc[num_cmd].callback = NULL;
		desc[num_cmd].user1 = NULL;
		desc[num_cmd].user2 = 0;
		desc[num_cmd].pyld = cmd_pyld[num_cmd]->data;
		desc[num_cmd].len = cmd_pyld[num_cmd]->len;
		num_cmd++;
		IPADBG("added PDN table copy cmd\n");
	}

	desc[1].opcode = cmd_pyld->opcode;
	desc[1].type = IPA_IMM_CMD_DESC;
	desc[1].callback = NULL;
	desc[1].user1 = NULL;
	desc[1].user2 = 0;
	desc[1].pyld = cmd_pyld->data;
	desc[1].len = cmd_pyld->len;
	IPADBG("posting v4 init command\n");
	if (ipa3_send_cmd(2, desc)) {
	if (ipa3_send_cmd(num_cmd, desc)) {
		IPAERR("Fail to send immediate command\n");
		result = -EPERM;
		goto destroy_imm_cmd;
@@ -550,15 +635,96 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init)
	ipa3_ctx->nat_mem.size_expansion_tables = init->expn_table_entries;

	IPADBG("return\n");
	result = 0;
destroy_imm_cmd:
	ipahal_destroy_imm_cmd(cmd_pyld);
free_nop:
	ipahal_destroy_imm_cmd(nop_cmd_pyld);
	for (i = 0; i < num_cmd; i++)
		ipahal_destroy_imm_cmd(cmd_pyld[i]);
bail:
	return result;
}

/**
* ipa4_nat_mdfy_pdn() - Modify a PDN entry in PDN config table in IPA SRAM
* @mdfy_pdn:	[in] PDN info to be written to SRAM
*
* Called by NAT client driver to modify an entry in the PDN config table
*
* Returns:	0 on success, negative on failure
*/
int ipa4_nat_mdfy_pdn(struct ipa_ioc_nat_pdn_entry *mdfy_pdn)
{
	struct ipahal_imm_cmd_dma_shared_mem mem_cmd = { 0 };
	struct ipa3_desc desc;
	struct ipahal_imm_cmd_pyld *cmd_pyld;
	int result = 0;
	struct ipa3_nat_mem *nat_ctx = &(ipa3_ctx->nat_mem);
	struct ipa_pdn_entry *pdn_entries = nat_ctx->pdn_mem.base;

	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
		IPAERR("IPA HW does not support multi PDN\n");
		return -EPERM;
	}
	if (!nat_ctx->is_dev_init) {
		IPAERR("attempt to modify a PDN entry before dev init\n");
		return -EPERM;
	}

	if (mdfy_pdn->pdn_index > (IPA_MAX_PDN_NUM - 1)) {
		IPAERR("pdn index out of range %d\n", mdfy_pdn->pdn_index);
		return -EPERM;
	}

	mutex_lock(&nat_ctx->lock);

	/* store ip in pdn entries cache array */
	pdn_entries[mdfy_pdn->pdn_index].public_ip =
		mdfy_pdn->public_ip;
	pdn_entries[mdfy_pdn->pdn_index].dst_metadata =
		mdfy_pdn->dst_metadata;
	pdn_entries[mdfy_pdn->pdn_index].src_metadata =
		mdfy_pdn->src_metadata;

	IPADBG("Modify PDN in index %d: ", mdfy_pdn->pdn_index);
	IPADBG("Public ip address:0x%x, ", mdfy_pdn->public_ip);
	IPADBG("dst metadata:0x%x, ", mdfy_pdn->dst_metadata);
	IPADBG("src metadata:0x%x\n", mdfy_pdn->src_metadata);

	memset(&desc, 0, sizeof(desc));

	/* Copy the PDN config table to SRAM */
	mem_cmd.is_read = false;
	mem_cmd.skip_pipeline_clear = false;
	mem_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
	mem_cmd.size = sizeof(struct ipa_pdn_entry) * IPA_MAX_PDN_NUM;
	mem_cmd.system_addr = nat_ctx->pdn_mem.phys_base;
	mem_cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
		IPA_MEM_PART(pdn_config_ofst);
	cmd_pyld = ipahal_construct_imm_cmd(
		IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
	if (!cmd_pyld) {
		IPAERR(
			"fail construct dma_shared_mem cmd: for pdn table");
		result = -ENOMEM;
		goto bail;
	}
	desc.opcode = cmd_pyld->opcode;
	desc.type = IPA_IMM_CMD_DESC;
	desc.callback = NULL;
	desc.user1 = NULL;
	desc.user2 = 0;
	desc.pyld = cmd_pyld->data;
	desc.len = cmd_pyld->len;

	IPADBG("sending PDN table copy cmd");
	if (ipa3_send_cmd(1, &desc)) {
		IPAERR("Fail to send immediate command\n");
		result = -EPERM;
	}

	ipahal_destroy_imm_cmd(cmd_pyld);
bail:
	mutex_unlock(&nat_ctx->lock);
	return result;
}
/**
 * ipa3_nat_dma_cmd() - Post NAT_DMA command to IPA HW
 * @dma:	[in] initialization command attributes
@@ -573,6 +739,7 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)

	struct ipahal_imm_cmd_pyld *nop_cmd_pyld = NULL;
	struct ipahal_imm_cmd_nat_dma cmd;
	enum ipahal_imm_cmd_name cmd_name = IPA_IMM_CMD_NAT_DMA;
	struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
	struct ipa3_desc *desc = NULL;
	u16 size = 0, cnt = 0;
@@ -675,13 +842,16 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)
	desc[0].pyld = nop_cmd_pyld->data;
	desc[0].len = nop_cmd_pyld->len;

	/* NAT_DMA was renamed to TABLE_DMA starting from IPAv4 */
	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
		cmd_name = IPA_IMM_CMD_TABLE_DMA;

	for (cnt = 0; cnt < dma->entries; cnt++) {
		cmd.table_index = dma->dma[cnt].table_index;
		cmd.base_addr = dma->dma[cnt].base_addr;
		cmd.offset = dma->dma[cnt].offset;
		cmd.data = dma->dma[cnt].data;
		cmd_pyld = ipahal_construct_imm_cmd(
			IPA_IMM_CMD_NAT_DMA, &cmd, false);
		cmd_pyld = ipahal_construct_imm_cmd(cmd_name, &cmd, false);
		if (!cmd_pyld) {
			IPAERR("Fail to construct nat_dma imm cmd\n");
			continue;
@@ -718,6 +888,10 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)
 */
void ipa3_nat_free_mem_and_device(struct ipa3_nat_mem *nat_ctx)
{
	struct ipahal_imm_cmd_dma_shared_mem mem_cmd = { 0 };
	struct ipa3_desc desc;
	struct ipahal_imm_cmd_pyld *cmd_pyld;

	IPADBG("\n");
	mutex_lock(&nat_ctx->lock);

@@ -729,6 +903,47 @@ void ipa3_nat_free_mem_and_device(struct ipa3_nat_mem *nat_ctx)
		nat_ctx->size = 0;
		nat_ctx->vaddr = NULL;
	}

	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
		struct ipa_pdn_entry *pdn_entries =
			nat_ctx->pdn_mem.base;

		/* zero the PDN table and copy the PDN config table to SRAM */
		IPADBG("zeroing the PDN config table\n");
		memset(pdn_entries, 0, sizeof(struct ipa_pdn_entry) *
			IPA_MAX_PDN_NUM);
		mem_cmd.is_read = false;
		mem_cmd.skip_pipeline_clear = false;
		mem_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
		mem_cmd.size = sizeof(struct ipa_pdn_entry) * IPA_MAX_PDN_NUM;
		mem_cmd.system_addr = nat_ctx->pdn_mem.phys_base;
		mem_cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
			IPA_MEM_PART(pdn_config_ofst);
		cmd_pyld = ipahal_construct_imm_cmd(
			IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
		if (!cmd_pyld) {
			IPAERR(
				"fail construct dma_shared_mem cmd: for pdn table");
			goto lbl_free_pdn;
		}
		memset(&desc, 0, sizeof(desc));
		desc.opcode = cmd_pyld->opcode;
		desc.pyld = cmd_pyld->data;
		desc.len = cmd_pyld->len;
		desc.type = IPA_IMM_CMD_DESC;

		IPADBG("sending PDN table copy cmd\n");
		if (ipa3_send_cmd(1, &desc))
			IPAERR("Fail to send immediate command\n");

		ipahal_destroy_imm_cmd(cmd_pyld);
lbl_free_pdn:
		IPADBG("freeing the PDN memory\n");
		dma_free_coherent(ipa3_ctx->pdev,
			nat_ctx->pdn_mem.size,
			nat_ctx->pdn_mem.base,
			nat_ctx->pdn_mem.phys_base);
	}
	nat_ctx->is_mapped = false;
	nat_ctx->is_sys_mem = false;
	nat_ctx->is_dev_init = false;
@@ -762,7 +977,8 @@ int ipa3_nat_del_cmd(struct ipa_ioc_v4_nat_del *del)
		base_addr = ipa3_ctx->nat_mem.tmp_dma_handle;
	}

	if (del->public_ip_addr == 0) {
	if ((ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) &&
		(del->public_ip_addr == 0)) {
		IPADBG("Bad Parameter\n");
		result = -EPERM;
		goto bail;
Loading