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

Commit 7ff13b27 authored by Pavan Kumar Chilamkurthi's avatar Pavan Kumar Chilamkurthi
Browse files

msm: camera: smmu: Add support for non-contiguous mermory region



Add support to discard a memory region inside the full dma map
virtual address space region.

CRs-Fixed: 2580128
Change-Id: I76cc778f2437a01a4efabec836ce92c47d983d61
Signed-off-by: default avatarPavan Kumar Chilamkurthi <pchilamk@codeaurora.org>
parent 44516500
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ struct hfi_mem {
 * @sec_heap: secondary heap hfi memory for firmware
 * @qdss: qdss mapped memory for fw
 * @io_mem: io memory info
 * @io_mem2: 2nd io memory info
 * @icp_base: icp base address
 */
struct hfi_mem_info {
@@ -44,6 +45,7 @@ struct hfi_mem_info {
	struct hfi_mem shmem;
	struct hfi_mem qdss;
	struct hfi_mem io_mem;
	struct hfi_mem io_mem2;
	void __iomem *icp_base;
};

+2 −0
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@
#define HFI_REG_QDSS_IOVA_SIZE                  0x70
#define HFI_REG_IO_REGION_IOVA                  0x74
#define HFI_REG_IO_REGION_SIZE                  0x78
#define HFI_REG_IO2_REGION_IOVA                 0x7C
#define HFI_REG_IO2_REGION_SIZE                 0x80

/* end of ICP CSR registers */

+17 −0
Original line number Diff line number Diff line
@@ -671,6 +671,15 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem,
	cam_io_w_mb((uint32_t)hfi_mem->io_mem.len,
		icp_base + HFI_REG_IO_REGION_SIZE);

	cam_io_w_mb((uint32_t)hfi_mem->io_mem2.iova,
		icp_base + HFI_REG_IO2_REGION_IOVA);
	cam_io_w_mb((uint32_t)hfi_mem->io_mem2.len,
		icp_base + HFI_REG_IO2_REGION_SIZE);

	CAM_INFO(CAM_HFI, "Resume IO1 : [0x%x 0x%x] IO2 [0x%x 0x%x]",
		hfi_mem->io_mem.iova, hfi_mem->io_mem.len,
		hfi_mem->io_mem2.iova, hfi_mem->io_mem2.len);

	return rc;
}

@@ -862,6 +871,14 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
		icp_base + HFI_REG_IO_REGION_IOVA);
	cam_io_w_mb((uint32_t)hfi_mem->io_mem.len,
		icp_base + HFI_REG_IO_REGION_SIZE);
	cam_io_w_mb((uint32_t)hfi_mem->io_mem2.iova,
		icp_base + HFI_REG_IO2_REGION_IOVA);
	cam_io_w_mb((uint32_t)hfi_mem->io_mem2.len,
		icp_base + HFI_REG_IO2_REGION_SIZE);

	CAM_INFO(CAM_HFI, "Init IO1 : [0x%x 0x%x] IO2 [0x%x 0x%x]",
		hfi_mem->io_mem.iova, hfi_mem->io_mem.len,
		hfi_mem->io_mem2.iova, hfi_mem->io_mem2.len);

	hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION);

+63 −11
Original line number Diff line number Diff line
@@ -2710,18 +2710,21 @@ static int cam_icp_allocate_qdss_mem(void)
static int cam_icp_get_io_mem_info(void)
{
	int rc;
	size_t len;
	dma_addr_t iova;
	size_t len, discard_iova_len;
	dma_addr_t iova, discard_iova_start;

	rc = cam_smmu_get_io_region_info(icp_hw_mgr.iommu_hdl,
		&iova, &len);
		&iova, &len, &discard_iova_start, &discard_iova_len);
	if (rc)
		return rc;

	icp_hw_mgr.hfi_mem.io_mem.iova_len = len;
	icp_hw_mgr.hfi_mem.io_mem.iova_start = iova;
	icp_hw_mgr.hfi_mem.io_mem.discard_iova_start = discard_iova_start;
	icp_hw_mgr.hfi_mem.io_mem.discard_iova_len = discard_iova_len;

	CAM_DBG(CAM_ICP, "iova: %llx, len: %zu", iova, len);
	CAM_DBG(CAM_ICP, "iova: %llx, len: %zu discard iova %llx len %llx",
		iova, len, discard_iova_start, discard_iova_len);

	return rc;
}
@@ -3014,12 +3017,38 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr)
	hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova;
	hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len;

	if (icp_hw_mgr.hfi_mem.io_mem.discard_iova_start &&
		icp_hw_mgr.hfi_mem.io_mem.discard_iova_len) {
		/* IO Region 1 */
		hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start;
		hfi_mem.io_mem.len =
			icp_hw_mgr.hfi_mem.io_mem.discard_iova_start -
			icp_hw_mgr.hfi_mem.io_mem.iova_start;

		/* IO Region 2 */
		hfi_mem.io_mem2.iova =
			icp_hw_mgr.hfi_mem.io_mem.discard_iova_start +
			icp_hw_mgr.hfi_mem.io_mem.discard_iova_len;
		hfi_mem.io_mem2.len =
			icp_hw_mgr.hfi_mem.io_mem.iova_start +
			icp_hw_mgr.hfi_mem.io_mem.iova_len   -
			hfi_mem.io_mem2.iova;
	} else {
		/* IO Region 1 */
		hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start;
		hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len;

	CAM_DBG(CAM_ICP, "IO region IOVA = %X length = %lld",
		/* IO Region 2 */
		hfi_mem.io_mem2.iova = 0x0;
		hfi_mem.io_mem2.len = 0x0;
	}

	CAM_DBG(CAM_ICP,
		"IO region1 IOVA = %X length = %lld, IO region2 IOVA = %X length = %lld",
		hfi_mem.io_mem.iova,
			hfi_mem.io_mem.len);
		hfi_mem.io_mem.len,
		hfi_mem.io_mem2.iova,
		hfi_mem.io_mem2.len);

	return cam_hfi_resume(&hfi_mem,
		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base,
@@ -3401,9 +3430,32 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr)
	hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova;
	hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len;

	if (icp_hw_mgr.hfi_mem.io_mem.discard_iova_start &&
		icp_hw_mgr.hfi_mem.io_mem.discard_iova_len) {
		/* IO Region 1 */
		hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start;
		hfi_mem.io_mem.len =
			icp_hw_mgr.hfi_mem.io_mem.discard_iova_start -
			icp_hw_mgr.hfi_mem.io_mem.iova_start;

		/* IO Region 2 */
		hfi_mem.io_mem2.iova =
			icp_hw_mgr.hfi_mem.io_mem.discard_iova_start +
			icp_hw_mgr.hfi_mem.io_mem.discard_iova_len;
		hfi_mem.io_mem2.len =
			icp_hw_mgr.hfi_mem.io_mem.iova_start +
			icp_hw_mgr.hfi_mem.io_mem.iova_len   -
			hfi_mem.io_mem2.iova;
	} else {
		/* IO Region 1 */
		hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start;
		hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len;

		/* IO Region 2 */
		hfi_mem.io_mem2.iova = 0x0;
		hfi_mem.io_mem2.len = 0x0;
	}

	return cam_hfi_init(0, &hfi_mem,
		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base,
		hw_mgr->a5_jtag_debug);
+132 −4
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
#include <linux/workqueue.h>
#include <linux/genalloc.h>
#include <linux/debugfs.h>
#include <linux/dma-iommu.h>

#include <soc/qcom/scm.h>
#include <soc/qcom/secure_buffer.h>
#include <media/cam_req_mgr.h>
@@ -137,6 +139,10 @@ struct cam_context_bank_info {
	bool is_mul_client;
	int device_count;
	int num_shared_hdl;

	/* discard iova - non-zero values are valid */
	dma_addr_t discard_iova_start;
	size_t discard_iova_len;
};

struct cam_iommu_cb_set {
@@ -1450,11 +1456,13 @@ int cam_smmu_dealloc_qdss(int32_t smmu_hdl)
EXPORT_SYMBOL(cam_smmu_dealloc_qdss);

int cam_smmu_get_io_region_info(int32_t smmu_hdl,
	dma_addr_t *iova, size_t *len)
	dma_addr_t *iova, size_t *len,
	dma_addr_t *discard_iova_start, size_t *discard_iova_len)
{
	int32_t idx;

	if (!iova || !len || (smmu_hdl == HANDLE_INIT)) {
	if (!iova || !len || !discard_iova_start || !discard_iova_len ||
		(smmu_hdl == HANDLE_INIT)) {
		CAM_ERR(CAM_SMMU, "Error: Input args are invalid");
		return -EINVAL;
	}
@@ -1476,10 +1484,15 @@ int cam_smmu_get_io_region_info(int32_t smmu_hdl,
	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
	*iova = iommu_cb_set.cb_info[idx].io_info.iova_start;
	*len = iommu_cb_set.cb_info[idx].io_info.iova_len;
	*discard_iova_start =
		iommu_cb_set.cb_info[idx].io_info.discard_iova_start;
	*discard_iova_len =
		iommu_cb_set.cb_info[idx].io_info.discard_iova_len;

	CAM_DBG(CAM_SMMU,
		"I/O area for hdl = %x start addr = %pK len = %zu",
		smmu_hdl, *iova, *len);
		"I/O area for hdl = %x Region:[%pK %zu] Discard:[%pK %zu]",
		smmu_hdl, *iova, *len,
		*discard_iova_start, *discard_iova_len);
	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);

	return 0;
@@ -3324,6 +3337,11 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb,
			rc = -ENODEV;
			goto end;
		}

		if (cb->discard_iova_start)
			iommu_dma_reserve_iova(dev, cb->discard_iova_start,
				cb->discard_iova_len);

		cb->state = CAM_SMMU_ATTACH;
	} else {
		CAM_ERR(CAM_SMMU, "Context bank does not have IO region");
@@ -3390,6 +3408,52 @@ static int cam_alloc_smmu_context_banks(struct device *dev)
	return 0;
}

static int cam_smmu_get_discard_memory_regions(struct device_node *of_node,
	dma_addr_t *discard_iova_start, size_t *discard_iova_len)
{
	uint32_t discard_iova[2] = { 0 };
	int num_values = 0;
	int rc = 0;

	if (!discard_iova_start || !discard_iova_len)
		return -EINVAL;

	*discard_iova_start = 0;
	*discard_iova_len = 0;

	num_values = of_property_count_u32_elems(of_node,
		"iova-region-discard");
	if (num_values <= 0) {
		CAM_DBG(CAM_UTIL, "No discard region specified");
		return 0;
	} else if (num_values != 2) {
		CAM_ERR(CAM_UTIL, "Invalid discard region specified %d",
			num_values);
		return -EINVAL;
	}

	rc = of_property_read_u32_array(of_node,
		"iova-region-discard",
		discard_iova, num_values);
	if (rc) {
		CAM_ERR(CAM_UTIL, "Can not read discard region %d", num_values);
		return rc;
	} else if (!discard_iova[0] || !discard_iova[1]) {
		CAM_ERR(CAM_UTIL,
			"Incorrect Discard region specified [0x%x 0x%x]",
			discard_iova[0], discard_iova[1]);
		return -EINVAL;
	}

	CAM_DBG(CAM_UTIL, "Discard region [0x%x 0x%x]",
		discard_iova[0], discard_iova[0] + discard_iova[1]);

	*discard_iova_start = discard_iova[0];
	*discard_iova_len = discard_iova[1];

	return 0;
}

static int cam_smmu_get_memory_regions_info(struct device_node *of_node,
	struct cam_context_bank_info *cb)
{
@@ -3488,6 +3552,16 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node,
			cb->io_support = 1;
			cb->io_info.iova_start = region_start;
			cb->io_info.iova_len = region_len;
			rc = cam_smmu_get_discard_memory_regions(child_node,
				&cb->io_info.discard_iova_start,
				&cb->io_info.discard_iova_len);
			if (rc) {
				CAM_ERR(CAM_SMMU,
					"Invalid Discard region specified in IO region, rc=%d",
					rc);
				of_node_put(mem_map_node);
				return -EINVAL;
			}
			break;
		case CAM_SMMU_REGION_SECHEAP:
			cb->secheap_support = 1;
@@ -3512,6 +3586,60 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node,
		CAM_DBG(CAM_SMMU, "region_len -> %X", region_len);
		CAM_DBG(CAM_SMMU, "region_id -> %X", region_id);
	}

	if (cb->io_support) {
		rc = cam_smmu_get_discard_memory_regions(of_node,
			&cb->discard_iova_start,
			&cb->discard_iova_len);
		if (rc) {
			CAM_ERR(CAM_SMMU,
				"Invalid Discard region specified in CB, rc=%d",
				rc);
			of_node_put(mem_map_node);
			return -EINVAL;
		}

		/* Make sure Discard region is properly specified */
		if ((cb->discard_iova_start !=
			cb->io_info.discard_iova_start) ||
			(cb->discard_iova_len !=
			cb->io_info.discard_iova_len)) {
			CAM_ERR(CAM_SMMU,
				"Mismatch Discard region specified, [0x%x 0x%x] [0x%x 0x%x]",
				cb->discard_iova_start,
				cb->discard_iova_len,
				cb->io_info.discard_iova_start,
				cb->io_info.discard_iova_len);
			of_node_put(mem_map_node);
			return -EINVAL;
		} else if (cb->discard_iova_start && cb->discard_iova_len) {
			if ((cb->discard_iova_start <=
			cb->io_info.iova_start) ||
			(cb->discard_iova_start >=
			cb->io_info.iova_start + cb->io_info.iova_len) ||
			(cb->discard_iova_start + cb->discard_iova_len >=
			cb->io_info.iova_start + cb->io_info.iova_len)) {
				CAM_ERR(CAM_SMMU,
				"[%s] : Incorrect Discard region specified [0x%x 0x%x] in [0x%x 0x%x]",
				cb->name,
				cb->discard_iova_start,
				cb->discard_iova_start + cb->discard_iova_len,
				cb->io_info.iova_start,
				cb->io_info.iova_start + cb->io_info.iova_len);
				of_node_put(mem_map_node);
				return -EINVAL;
			}

			CAM_INFO(CAM_SMMU,
				"[%s] : Discard region specified [0x%x 0x%x] in [0x%x 0x%x]",
				cb->name,
				cb->discard_iova_start,
				cb->discard_iova_start + cb->discard_iova_len,
				cb->io_info.iova_start,
				cb->io_info.iova_start + cb->io_info.iova_len);
		}
	}

	of_node_put(mem_map_node);

	if (!num_regions) {
Loading