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

Commit 5bf7277a authored by Ashok Vuyyuru's avatar Ashok Vuyyuru
Browse files

msm: ipa3: Changes to enable stage 1 SMMU for WDI2.0 GSI offload



Because of SMMU address alignment issue, enable stage 1 for WDI
pipes was failing. Adding changes to fix the alignment issue to
support wdi2.0 stage 1 SMMU.

Change-Id: Iddbac686c1fb82f4b811c2446392abe9f9160aa0
Signed-off-by: default avatarAshok Vuyyuru <avuyyuru@codeaurora.org>
parent 642059a3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6685,6 +6685,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)

	smmu_info.present[IPA_SMMU_CB_AP] = true;
	ipa3_ctx->pdev = dev;
	cb->next_addr = cb->va_end;

	return 0;
}
+126 −11
Original line number Diff line number Diff line
@@ -497,6 +497,35 @@ int ipa3_wdi_init(void)
	return 0;
}

static int ipa_create_ap_smmu_mapping_pa(phys_addr_t pa, size_t len,
		bool device, unsigned long *iova)
{
	struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
	unsigned long va = roundup(cb->next_addr, PAGE_SIZE);
	int prot = IOMMU_READ | IOMMU_WRITE;
	size_t true_len = roundup(len + pa - rounddown(pa, PAGE_SIZE),
			PAGE_SIZE);
	int ret;

	if (!cb->valid) {
		IPAERR("No SMMU CB setup\n");
		return -EINVAL;
	}

	ret = ipa3_iommu_map(cb->mapping->domain, va, rounddown(pa, PAGE_SIZE),
			true_len,
			device ? (prot | IOMMU_MMIO) : prot);
	if (ret) {
		IPAERR("iommu map failed for pa=%pa len=%zu\n", &pa, true_len);
		return -EINVAL;
	}

	ipa3_ctx->wdi_map_cnt++;
	cb->next_addr = va + true_len;
	*iova = va + pa - rounddown(pa, PAGE_SIZE);
	return 0;
}

static int ipa_create_uc_smmu_mapping_pa(phys_addr_t pa, size_t len,
		bool device, unsigned long *iova)
{
@@ -526,6 +555,56 @@ static int ipa_create_uc_smmu_mapping_pa(phys_addr_t pa, size_t len,
	return 0;
}

static int ipa_create_ap_smmu_mapping_sgt(struct sg_table *sgt,
		unsigned long *iova)
{
	struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
	unsigned long va = roundup(cb->next_addr, PAGE_SIZE);
	int prot = IOMMU_READ | IOMMU_WRITE;
	int ret, i;
	struct scatterlist *sg;
	unsigned long start_iova = va;
	phys_addr_t phys;
	size_t len;
	int count = 0;

	if (!cb->valid) {
		IPAERR("No SMMU CB setup\n");
		return -EINVAL;
	}
	if (!sgt) {
		IPAERR("Bad parameters, scatter / gather list is NULL\n");
		return -EINVAL;
	}

	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
		/* directly get sg_tbl PA from wlan-driver */
		phys = sg->dma_address;
		len = PAGE_ALIGN(sg->offset + sg->length);

		ret = ipa3_iommu_map(cb->mapping->domain, va, phys, len, prot);
		if (ret) {
			IPAERR("iommu map failed for pa=%pa len=%zu\n",
					&phys, len);
			goto bad_mapping;
		}
		va += len;
		ipa3_ctx->wdi_map_cnt++;
		count++;
	}
	cb->next_addr = va;
	*iova = start_iova;

	return 0;

bad_mapping:
	for_each_sg(sgt->sgl, sg, count, i)
		iommu_unmap(cb->mapping->domain, sg_dma_address(sg),
				sg_dma_len(sg));
	return -EINVAL;
}


static int ipa_create_uc_smmu_mapping_sgt(struct sg_table *sgt,
		unsigned long *iova)
{
@@ -576,6 +655,39 @@ static int ipa_create_uc_smmu_mapping_sgt(struct sg_table *sgt,
	return -EINVAL;
}

static void ipa_release_ap_smmu_mappings(enum ipa_client_type client)
{
	struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
	int i, j, start, end;

	if (IPA_CLIENT_IS_CONS(client)) {
		start = IPA_WDI_TX_RING_RES;
		end = IPA_WDI_CE_DB_RES;
	} else {
		start = IPA_WDI_RX_RING_RES;
		if (ipa3_ctx->ipa_wdi2)
			end = IPA_WDI_RX_COMP_RING_WP_RES;
		else
			end = IPA_WDI_RX_RING_RP_RES;
	}

	for (i = start; i <= end; i++) {
		if (wdi_res[i].valid) {
			for (j = 0; j < wdi_res[i].nents; j++) {
				iommu_unmap(cb->mapping->domain,
					wdi_res[i].res[j].iova,
					wdi_res[i].res[j].size);
				ipa3_ctx->wdi_map_cnt--;
			}
			kfree(wdi_res[i].res);
			wdi_res[i].valid = false;
		}
	}

	if (ipa3_ctx->wdi_map_cnt == 0)
		cb->next_addr = cb->va_end;
}

static void ipa_release_uc_smmu_mappings(enum ipa_client_type client)
{
	struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_UC);
@@ -751,9 +863,11 @@ int ipa_create_gsi_smmu_mapping(int res_idx, bool wlan_smmu_en,

	/* no SMMU on WLAN but SMMU on IPA */
	if (!wlan_smmu_en && !ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]) {
		if (ipa3_smmu_map_peer_buff(*iova, pa, len,
						sgt, IPA_SMMU_CB_WLAN)) {
			IPAERR("Fail to create mapping res %d\n", res_idx);
		if (ipa_create_ap_smmu_mapping_pa(pa, len,
				(res_idx == IPA_WDI_CE_DB_RES) ? true : false,
					iova)) {
			IPAERR("Fail to create mapping res %d\n",
					res_idx);
			return -EFAULT;
		}
		ipa_save_uc_smmu_mapping_pa(res_idx, pa, *iova, len);
@@ -765,8 +879,10 @@ int ipa_create_gsi_smmu_mapping(int res_idx, bool wlan_smmu_en,
		case IPA_WDI_RX_RING_RP_RES:
		case IPA_WDI_RX_COMP_RING_WP_RES:
		case IPA_WDI_CE_DB_RES:
			if (ipa3_smmu_map_peer_buff(*iova, pa, len, sgt,
							IPA_SMMU_CB_WLAN)) {
		case IPA_WDI_TX_DB_RES:
			if (ipa_create_ap_smmu_mapping_pa(pa, len,
				(res_idx == IPA_WDI_CE_DB_RES) ? true : false,
						iova)) {
				IPAERR("Fail to create mapping res %d\n",
						res_idx);
				return -EFAULT;
@@ -777,8 +893,7 @@ int ipa_create_gsi_smmu_mapping(int res_idx, bool wlan_smmu_en,
		case IPA_WDI_RX_COMP_RING_RES:
		case IPA_WDI_TX_RING_RES:
		case IPA_WDI_CE_RING_RES:
			if (ipa3_smmu_map_peer_reg(pa, true,
							IPA_SMMU_CB_WLAN)) {
			if (ipa_create_ap_smmu_mapping_sgt(sgt, iova)) {
				IPAERR("Fail to create mapping res %d\n",
						res_idx);
				return -EFAULT;
@@ -1304,7 +1419,7 @@ int ipa3_connect_gsi_wdi_pipe(struct ipa_wdi_in_params *in,
ipa_cfg_ep_fail:
	memset(&ipa3_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa3_ep_context));
gsi_timeout:
	ipa_release_uc_smmu_mappings(in->sys.client);
	ipa_release_ap_smmu_mappings(in->sys.client);
	IPA_ACTIVE_CLIENTS_DEC_EP(in->sys.client);
fail:
	return result;
@@ -1864,7 +1979,7 @@ int ipa3_disconnect_gsi_wdi_pipe(u32 clnt_hdl)
				result);
		goto fail_dealloc_channel;
	}
	ipa_release_uc_smmu_mappings(clnt_hdl);
	ipa_release_ap_smmu_mappings(clnt_hdl);

	/* for AP+STA stats update */
	if (ipa3_ctx->uc_wdi_ctx.stats_notify)