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

Commit 93f940cb authored by Seemanta Dutta's avatar Seemanta Dutta
Browse files

msm: cam: smmu: Add separate region for secondary heap for ICP



Currently, secondary heap for ICP firmware is allocated within
the shared region. This means that the properties of the secondary
heap (system cache enabled/disabled) is coupled with that of the
shared region. ICP firmware would like to be able to control the
secondary heap properties independent of the shared region. Hence,
create a separate region for secondary heap region and let ICP host
driver reserve this region during initialization. This will let the
ICP firmware to set the properties of the secondary heap independent
of the shared memory region.

Change-Id: I2e2bc4c2a79c3dfb83e6b9bd8460a47c25f240c2
Signed-off-by: default avatarSeemanta Dutta <seemanta@codeaurora.org>
parent c7f3276e
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -296,11 +296,20 @@
					status = "ok";
				};

				iova-mem-region-secondary-heap {
					/* Secondary heap region is 1MB long */
					iova-region-name = "secheap";
					iova-region-start = <0xd800000>;
					iova-region-len = <0x100000>;
					iova-region-id = <0x4>;
					status = "ok";
				};

				iova-mem-region-io {
					/* IO region is approximately 3.3 GB */
					iova-region-name = "io";
					iova-region-start = <0xd800000>;
					iova-region-len = <0xd2800000>;
					iova-region-start = <0xd900000>;
					iova-region-len = <0xd2700000>;
					iova-region-id = <0x3>;
					status = "ok";
				};
+11 −2
Original line number Diff line number Diff line
@@ -210,11 +210,20 @@
					status = "ok";
				};

				iova-mem-region-secondary-heap {
					/* Secondary heap region is 1MB long */
					iova-region-name = "secheap";
					iova-region-start = <0xd800000>;
					iova-region-len = <0x100000>;
					iova-region-id = <0x4>;
					status = "ok";
				};

				iova-mem-region-io {
					/* IO region is approximately 3.3 GB */
					iova-region-name = "io";
					iova-region-start = <0xd800000>;
					iova-region-len = <0xd2800000>;
					iova-region-start = <0xd900000>;
					iova-region-len = <0xd2700000>;
					iova-region-id = <0x3>;
					status = "ok";
				};
+43 −3
Original line number Diff line number Diff line
@@ -1183,12 +1183,52 @@ int32_t cam_icp_hw_mgr_cb(uint32_t irq_status, void *data)

static void cam_icp_free_hfi_mem(void)
{
	int rc;
	cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl);
	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl);
	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q);
	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q);
	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q);
	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sec_heap);
	rc = cam_mem_mgr_free_memory_region(&icp_hw_mgr.hfi_mem.sec_heap);
	if (rc)
		CAM_ERR(CAM_ICP, "failed to unreserve sec heap");
}

static int cam_icp_alloc_secheap_mem(struct cam_mem_mgr_memory_desc *secheap)
{
	int rc;
	struct cam_mem_mgr_request_desc alloc;
	struct cam_mem_mgr_memory_desc out;
	struct cam_smmu_region_info secheap_info;

	memset(&alloc, 0, sizeof(alloc));
	memset(&out, 0, sizeof(out));

	rc = cam_smmu_get_region_info(icp_hw_mgr.iommu_hdl,
		CAM_SMMU_REGION_SECHEAP,
		&secheap_info);
	if (rc) {
		CAM_ERR(CAM_ICP, "Unable to get secheap memory info");
		return rc;
	}

	alloc.size = secheap_info.iova_len;
	alloc.align = 0;
	alloc.flags = 0;
	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
	rc = cam_mem_mgr_reserve_memory_region(&alloc,
		CAM_SMMU_REGION_SECHEAP,
		&out);
	if (rc) {
		CAM_ERR(CAM_ICP, "Unable to reserve secheap memory");
		return rc;
	}

	*secheap = out;
	CAM_DBG(CAM_ICP, "kva: %llX, iova: %x, hdl: %x, len: %lld",
		out.kva, out.iova, out.mem_handle, out.len);

	return rc;
}

static int cam_icp_alloc_shared_mem(struct cam_mem_mgr_memory_desc *qtbl)
@@ -1280,9 +1320,9 @@ static int cam_icp_allocate_hfi_mem(void)
		goto dbg_q_alloc_failed;
	}

	rc = cam_icp_alloc_shared_mem(&icp_hw_mgr.hfi_mem.sec_heap);
	rc = cam_icp_alloc_secheap_mem(&icp_hw_mgr.hfi_mem.sec_heap);
	if (rc) {
		CAM_ERR(CAM_ICP, "Unable to allocate sec heap q memory");
		CAM_ERR(CAM_ICP, "Unable to allocate sec heap memory");
		goto sec_heap_alloc_failed;
	}

+161 −0
Original line number Diff line number Diff line
@@ -986,3 +986,164 @@ int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp)
	return rc;
}
EXPORT_SYMBOL(cam_mem_mgr_release_mem);

int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp,
	enum cam_smmu_region_id region,
	struct cam_mem_mgr_memory_desc *out)
{
	struct ion_handle *hdl;
	int ion_fd;
	int rc = 0;
	uint32_t heap_id;
	dma_addr_t iova = 0;
	size_t request_len = 0;
	int32_t idx;
	uint32_t mem_handle;
	int32_t smmu_hdl = 0;
	int32_t num_hdl = 0;

	if (!inp || !out) {
		CAM_ERR(CAM_CRM, "Invalid param(s)");
		return -EINVAL;
	}

	if (!inp->smmu_hdl) {
		CAM_ERR(CAM_CRM, "Invalid SMMU handle");
		return -EINVAL;
	}

	if (region != CAM_SMMU_REGION_SECHEAP) {
		CAM_ERR(CAM_CRM, "Only secondary heap supported");
		return -EINVAL;
	}

	heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
	rc = cam_mem_util_get_ion_buffer(inp->size,
		inp->align,
		heap_id,
		0,
		&hdl,
		&ion_fd);

	if (rc) {
		CAM_ERR(CAM_CRM, "ION alloc failed for sec heap buffer");
		goto ion_fail;
	} else {
		CAM_DBG(CAM_CRM, "Got ION fd = %d, hdl = %pK", ion_fd, hdl);
	}

	rc = cam_smmu_reserve_sec_heap(inp->smmu_hdl,
		ion_fd,
		&iova,
		&request_len);
	if (rc) {
		CAM_ERR(CAM_CRM, "Reserving secondary heap failed");
		goto smmu_fail;
	}

	smmu_hdl = inp->smmu_hdl;
	num_hdl = 1;

	idx = cam_mem_get_slot();
	if (idx < 0) {
		rc = -ENOMEM;
		goto slot_fail;
	}

	mutex_lock(&tbl.bufq[idx].q_lock);
	mem_handle = GET_MEM_HANDLE(idx, ion_fd);
	tbl.bufq[idx].fd = ion_fd;
	tbl.bufq[idx].flags = inp->flags;
	tbl.bufq[idx].buf_handle = mem_handle;
	tbl.bufq[idx].kmdvaddr = 0;

	tbl.bufq[idx].vaddr = iova;

	tbl.bufq[idx].i_hdl = hdl;
	tbl.bufq[idx].len = request_len;
	tbl.bufq[idx].num_hdl = num_hdl;
	memcpy(tbl.bufq[idx].hdls, &smmu_hdl,
		sizeof(int32_t));
	tbl.bufq[idx].is_imported = false;
	mutex_unlock(&tbl.bufq[idx].q_lock);

	out->kva = 0;
	out->iova = (uint32_t)iova;
	out->smmu_hdl = smmu_hdl;
	out->mem_handle = mem_handle;
	out->len = request_len;
	out->region = region;

	return rc;

slot_fail:
	cam_smmu_release_sec_heap(smmu_hdl);
smmu_fail:
	ion_free(tbl.client, hdl);
ion_fail:
	return rc;
}
EXPORT_SYMBOL(cam_mem_mgr_reserve_memory_region);

int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp)
{
	int32_t idx;
	int rc;
	int32_t smmu_hdl;

	if (!inp) {
		CAM_ERR(CAM_CRM, "Invalid argument");
		return -EINVAL;
	}

	if (inp->region != CAM_SMMU_REGION_SECHEAP) {
		CAM_ERR(CAM_CRM, "Only secondary heap supported");
		return -EINVAL;
	}

	idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle);
	if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
		CAM_ERR(CAM_CRM, "Incorrect index extracted from mem handle");
		return -EINVAL;
	}

	if (!tbl.bufq[idx].active) {
		CAM_ERR(CAM_CRM, "Released buffer state should be active");
		return -EINVAL;
	}

	if (tbl.bufq[idx].buf_handle != inp->mem_handle) {
		CAM_ERR(CAM_CRM,
			"Released buf handle not matching within table");
		return -EINVAL;
	}

	if (tbl.bufq[idx].num_hdl != 1) {
		CAM_ERR(CAM_CRM,
			"Sec heap region should have only one smmu hdl");
		return -ENODEV;
	}

	memcpy(&smmu_hdl, tbl.bufq[idx].hdls,
		sizeof(int32_t));
	if (inp->smmu_hdl != smmu_hdl) {
		CAM_ERR(CAM_CRM,
			"Passed SMMU handle doesn't match with internal hdl");
		return -ENODEV;
	}

	rc = cam_smmu_release_sec_heap(inp->smmu_hdl);
	if (rc) {
		CAM_ERR(CAM_CRM,
			"Sec heap region release failed");
		return -ENODEV;
	}

	CAM_DBG(CAM_CRM, "Releasing hdl = %X", inp->mem_handle);
	rc = cam_mem_util_unmap(idx);
	if (rc)
		CAM_ERR(CAM_CRM, "unmapping secondary heap failed");

	return rc;
}
EXPORT_SYMBOL(cam_mem_mgr_free_memory_region);
+22 −0
Original line number Diff line number Diff line
@@ -100,4 +100,26 @@ static inline bool cam_mem_is_secure_buf(int32_t buf_handle)
	return CAM_MEM_MGR_IS_SECURE_HDL(buf_handle);
}

/**
 * @brief: Reserves a memory region
 *
 * @inp:  Information specifying requested region properties
 * @region : Region which is to be reserved
 * @out   : Information about reserved region
 *
 * @return Status of operation. Negative in case of error. Zero otherwise.
 */
int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp,
		enum cam_smmu_region_id region,
		struct cam_mem_mgr_memory_desc *out);

/**
 * @brief: Frees a memory region
 *
 * @inp   : Information about region which is to be freed
 *
 * @return Status of operation. Negative in case of error. Zero otherwise.
 */
int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp);

#endif /* _CAM_MEM_MGR_API_H_ */
Loading