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

Commit 680eca4c authored by Skylar Chang's avatar Skylar Chang
Browse files

msm: ipa: add support for DOMAIN_ATTR_S1_BYPASS



In order to set SMMU to S1 bypass configuration
IPA driver needs to set DOMAIN_ATTR_S1_BYPASS before
attaching to SMMU. The actual SMMU setting is controlled
via device tree.

CRs-Fixed: 998074
Change-Id: I3e63d9e6c511dd692b299543881e7266799108af
Acked-by: default avatarAdy Abraham <adya@qti.qualcomm.com>
Signed-off-by: default avatarSkylar Chang <chiaweic@codeaurora.org>
parent ec82f6fd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ Optional:
- qcom,wan-rx-ring-size: size of WAN rx ring, default is 32
- qcom,arm-smmu: SMMU is present and ARM SMMU driver is used
- qcom,msm-smmu: SMMU is present and QSMMU driver is used
- qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
- ipa_smmu_ap: AP general purpose SMMU device
	compatible "qcom,ipa-smmu-ap-cb"
- ipa_smmu_wlan: WDI SMMU device
+85 −27
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ struct platform_device *ipa_pdev;
static bool smmu_present;
static bool arm_smmu;
static bool smmu_disable_htw;
static bool smmu_s1_bypass;

static char *active_clients_table_buf;

@@ -3570,6 +3571,10 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
	ipa_ctx->pdev = ipa_dev;
	ipa_ctx->uc_pdev = ipa_dev;
	ipa_ctx->smmu_present = smmu_present;
	if (!ipa_ctx->smmu_present)
		ipa_ctx->smmu_s1_bypass = true;
	else
		ipa_ctx->smmu_s1_bypass = smmu_s1_bypass;
	ipa_ctx->ipa_wrapper_base = resource_p->ipa_mem_base;
	ipa_ctx->ipa_hw_type = resource_p->ipa_hw_type;
	ipa_ctx->ipa_hw_mode = resource_p->ipa_hw_mode;
@@ -3707,7 +3712,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
		bam_props.options |= SPS_BAM_OPT_IRQ_WAKEUP;
	if (ipa_ctx->ipa_bam_remote_mode == true)
		bam_props.manage |= SPS_BAM_MGR_DEVICE_REMOTE;
	if (ipa_ctx->smmu_present)
	if (!ipa_ctx->smmu_s1_bypass)
		bam_props.options |= SPS_BAM_SMMU_EN;
	bam_props.options |= SPS_BAM_CACHED_WP;
	bam_props.ee = resource_p->ee;
@@ -4238,6 +4243,7 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev)
	struct ipa_smmu_cb_ctx *cb = &smmu_cb[IPA_SMMU_CB_WLAN];
	int disable_htw = 1;
	int atomic_ctx = 1;
	int bypass = 1;
	int ret;

	IPADBG("sub pdev=%p\n", dev);
@@ -4260,19 +4266,34 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev)
		}
	}

	if (smmu_s1_bypass) {
		if (iommu_domain_set_attr(cb->iommu,
			DOMAIN_ATTR_S1_BYPASS,
			&bypass)) {
			IPAERR("couldn't set bypass\n");
			cb->valid = false;
			return -EIO;
		}
		IPADBG("SMMU S1 BYPASS\n");
	} else {
		if (iommu_domain_set_attr(cb->iommu,
			DOMAIN_ATTR_ATOMIC,
			&atomic_ctx)) {
		IPAERR("couldn't disable coherent HTW\n");
			IPAERR("couldn't set domain as atomic\n");
			cb->valid = false;
			return -EIO;
		}
		IPADBG("SMMU atomic set\n");
	}

	ret = iommu_attach_device(cb->iommu, dev);
	if (ret) {
		IPAERR("could not attach device ret=%d\n", ret);
		cb->valid = false;
		return ret;
	}

	if (!smmu_s1_bypass) {
		IPAERR("map IPA region to WLAN_CB IOMMU\n");
		ret = iommu_map(cb->iommu, 0x680000, 0x680000,
			0x64000,
@@ -4282,6 +4303,7 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev)
				ret);
			return ret;
		}
	}

	cb->valid = true;

@@ -4293,6 +4315,7 @@ static int ipa_smmu_uc_cb_probe(struct device *dev)
	struct ipa_smmu_cb_ctx *cb = &smmu_cb[IPA_SMMU_CB_UC];
	int disable_htw = 1;
	int ret;
	int bypass = 1;

	IPADBG("sub pdev=%p\n", dev);

@@ -4320,10 +4343,25 @@ static int ipa_smmu_uc_cb_probe(struct device *dev)
		}
	}

	IPADBG("UC CB PROBE sub pdev=%p set attribute\n", dev);
	if (smmu_s1_bypass) {
		if (iommu_domain_set_attr(cb->mapping->domain,
			DOMAIN_ATTR_S1_BYPASS,
			&bypass)) {
			IPAERR("couldn't set bypass\n");
			arm_iommu_release_mapping(cb->mapping);
			cb->valid = false;
			return -EIO;
		}
		IPADBG("SMMU S1 BYPASS\n");
	}

	IPADBG("UC CB PROBE sub pdev=%p attaching IOMMU device\n", dev);
	ret = arm_iommu_attach_device(cb->dev, cb->mapping);
	if (ret) {
		IPAERR("could not attach device ret=%d\n", ret);
		arm_iommu_release_mapping(cb->mapping);
		cb->valid = false;
		return ret;
	}

@@ -4331,6 +4369,7 @@ static int ipa_smmu_uc_cb_probe(struct device *dev)
	cb->next_addr = IPA_SMMU_UC_VA_END;
	ipa_ctx->uc_pdev = dev;

	IPADBG("UC CB PROBE pdev=%p attached\n", dev);
	return 0;
}

@@ -4340,6 +4379,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)
	int result;
	int disable_htw = 1;
	int atomic_ctx = 1;
	int bypass = 1;

	IPADBG("sub pdev=%p\n", dev);

@@ -4358,15 +4398,6 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)
		return -EPROBE_DEFER;
	}

	IPAERR("map IPA region to AP_CB IOMMU\n");
	result = iommu_map(cb->mapping->domain, 0x680000, 0x680000,
		0x64000,
			IOMMU_READ | IOMMU_WRITE | IOMMU_DEVICE);
	if (result) {
		IPAERR("map IPA region to AP_CB IOMMU failed ret=%d\n",
			result);
		return result;
	}

	if (smmu_disable_htw) {
		if (iommu_domain_set_attr(cb->mapping->domain,
@@ -4378,13 +4409,37 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)
		}
	}

	if (smmu_s1_bypass) {
		if (iommu_domain_set_attr(cb->mapping->domain,
			DOMAIN_ATTR_S1_BYPASS,
			&bypass)) {
			IPAERR("couldn't set bypass\n");
			arm_iommu_release_mapping(cb->mapping);
			cb->valid = false;
			return -EIO;
		}
		IPADBG("SMMU S1 BYPASS\n");
	} else {
		if (iommu_domain_set_attr(cb->mapping->domain,
			DOMAIN_ATTR_ATOMIC,
			&atomic_ctx)) {
			IPAERR("couldn't set domain as atomic\n");
		arm_iommu_detach_device(cb->dev);
			arm_iommu_release_mapping(cb->mapping);
			cb->valid = false;
			return -EIO;
		}
		IPADBG("SMMU atomic set\n");

		IPADBG("map IPA region to AP_CB IOMMU\n");
		result = iommu_map(cb->mapping->domain, 0x680000, 0x680000,
			0x64000,
			IOMMU_READ | IOMMU_WRITE | IOMMU_DEVICE);
		if (result) {
			IPAERR("map IPA region to AP_CB IOMMU failed ret=%d\n",
				result);
			return result;
		}
	}

	result = arm_iommu_attach_device(cb->dev, cb->mapping);
	if (result) {
@@ -4444,6 +4499,9 @@ int ipa_plat_drv_probe(struct platform_device *pdev_p,
	}

	if (of_property_read_bool(pdev_p->dev.of_node, "qcom,arm-smmu")) {
		if (of_property_read_bool(pdev_p->dev.of_node,
		    "qcom,smmu-s1-bypass"))
			smmu_s1_bypass = true;
		arm_smmu = true;
		result = of_platform_populate(pdev_p->dev.of_node,
				pdrv_match, NULL, &pdev_p->dev);
+9 −9
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ static int ipa2_smmu_map_peer_bam(unsigned long dev)
	u32 size;
	struct iommu_domain *smmu_domain;

	if (ipa_ctx->smmu_present) {
	if (!ipa_ctx->smmu_s1_bypass) {
		if (ipa_ctx->peer_bam_map_cnt == 0) {
			if (sps_get_bam_addr(dev, &base, &size)) {
				IPAERR("Fail to get addr\n");
@@ -218,7 +218,7 @@ static int ipa_connect_allocate_fifo(const struct ipa_connect_params *in,
			dma_alloc_coherent(ipa_ctx->pdev, mem_buff_ptr->size,
			&dma_addr, GFP_KERNEL);
	}
	if (!ipa_ctx->smmu_present) {
	if (ipa_ctx->smmu_s1_bypass) {
		mem_buff_ptr->phys_base = dma_addr;
	} else {
		mem_buff_ptr->iova = dma_addr;
@@ -334,7 +334,7 @@ int ipa2_connect(const struct ipa_connect_params *in,
		goto ipa_cfg_ep_fail;
	}

	if (ipa_ctx->smmu_present &&
	if (!ipa_ctx->smmu_s1_bypass &&
			(in->desc.base == NULL ||
			 in->data.base == NULL)) {
		IPAERR(" allocate FIFOs data_fifo=0x%p desc_fifo=0x%p.\n",
@@ -376,7 +376,7 @@ int ipa2_connect(const struct ipa_connect_params *in,
	IPADBG("Data FIFO pa=%pa, size=%d\n", &ep->connect.data.phys_base,
	       ep->connect.data.size);

	if (ipa_ctx->smmu_present) {
	if (!ipa_ctx->smmu_s1_bypass) {
		ep->connect.data.iova = ep->connect.data.phys_base;
		base = ep->connect.data.iova;
		smmu_domain = ipa2_get_smmu_domain();
@@ -439,7 +439,7 @@ int ipa2_connect(const struct ipa_connect_params *in,
	return 0;

sps_connect_fail:
	if (ipa_ctx->smmu_present) {
	if (!ipa_ctx->smmu_s1_bypass) {
		base = ep->connect.desc.iova;
		smmu_domain = ipa2_get_smmu_domain();
		if (smmu_domain != NULL) {
@@ -450,7 +450,7 @@ sps_connect_fail:
		}
	}
iommu_map_desc_fail:
	if (ipa_ctx->smmu_present) {
	if (!ipa_ctx->smmu_s1_bypass) {
		base = ep->connect.data.iova;
		smmu_domain = ipa2_get_smmu_domain();
		if (smmu_domain != NULL) {
@@ -496,7 +496,7 @@ static int ipa2_smmu_unmap_peer_bam(unsigned long dev)
	size_t len;
	struct iommu_domain *smmu_domain;

	if (ipa_ctx->smmu_present) {
	if (!ipa_ctx->smmu_s1_bypass) {
		WARN_ON(dev != ipa_ctx->peer_bam_dev);
		ipa_ctx->peer_bam_map_cnt--;
		if (ipa_ctx->peer_bam_map_cnt == 0) {
@@ -616,7 +616,7 @@ int ipa2_disconnect(u32 clnt_hdl)
					  ep->connect.data.size);
	}

	if (ipa_ctx->smmu_present) {
	if (!ipa_ctx->smmu_s1_bypass) {
		base = ep->connect.desc.iova;
		smmu_domain = ipa2_get_smmu_domain();
		if (smmu_domain != NULL) {
@@ -627,7 +627,7 @@ int ipa2_disconnect(u32 clnt_hdl)
		}
	}

	if (ipa_ctx->smmu_present) {
	if (!ipa_ctx->smmu_s1_bypass) {
		base = ep->connect.data.iova;
		smmu_domain = ipa2_get_smmu_domain();
		if (smmu_domain != NULL) {
+1 −1
Original line number Diff line number Diff line
@@ -1286,7 +1286,7 @@ int ipa2_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl)
	ep->connect.desc.size = sys_in->desc_fifo_sz;
	ep->connect.desc.base = dma_alloc_coherent(ipa_ctx->pdev,
			ep->connect.desc.size, &dma_addr, GFP_KERNEL);
	if (!ipa_ctx->smmu_present) {
	if (ipa_ctx->smmu_s1_bypass) {
		ep->connect.desc.phys_base = dma_addr;
	} else {
		ep->connect.desc.iova = dma_addr;
+1 −0
Original line number Diff line number Diff line
@@ -1299,6 +1299,7 @@ struct ipa_context {
	u32 wan_rx_ring_size;
	bool skip_uc_pipe_reset;
	bool smmu_present;
	bool smmu_s1_bypass;
	unsigned long peer_bam_iova;
	phys_addr_t peer_bam_pa;
	u32 peer_bam_map_size;
Loading