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: Pavan Kumar Chilamkurthi <pchilamk@codeaurora.org>
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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 */
|
||||
|
||||
|
@@ -669,6 +669,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;
|
||||
}
|
||||
|
||||
@@ -859,6 +868,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);
|
||||
|
||||
|
@@ -2858,18 +2858,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;
|
||||
}
|
||||
@@ -3162,12 +3165,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,
|
||||
@@ -3637,9 +3666,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);
|
||||
|
@@ -15,6 +15,8 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/dma-iommu.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 {
|
||||
@@ -1440,11 +1446,13 @@ end:
|
||||
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;
|
||||
}
|
||||
@@ -1466,10 +1474,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;
|
||||
@@ -3339,6 +3352,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");
|
||||
@@ -3405,6 +3423,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)
|
||||
{
|
||||
@@ -3503,6 +3567,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;
|
||||
@@ -3527,6 +3601,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) {
|
||||
|
@@ -62,10 +62,14 @@ typedef void (*cam_smmu_client_page_fault_handler)(struct iommu_domain *domain,
|
||||
*
|
||||
* @param iova_start : Start address of region
|
||||
* @param iova_len : length of region
|
||||
* @param discard_iova_start : iova addr start from where should not be used
|
||||
* @param discard_iova_len : length of discard iova region
|
||||
*/
|
||||
struct cam_smmu_region_info {
|
||||
dma_addr_t iova_start;
|
||||
size_t iova_len;
|
||||
dma_addr_t discard_iova_start;
|
||||
size_t discard_iova_len;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -387,11 +391,14 @@ int cam_smmu_dealloc_qdss(int32_t smmu_hdl);
|
||||
* @param smmu_hdl: SMMU handle identifying the context bank
|
||||
* @param iova: IOVA address of allocated I/O region
|
||||
* @param len: Length of allocated I/O memory
|
||||
* @param discard_iova_start: Start address of io space to discard
|
||||
* @param discard_iova_len: Length of io space to discard
|
||||
*
|
||||
* @return Status of operation. Negative in case of error. Zero otherwise.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief : API to register SMMU hw to platform framework.
|
||||
|
Reference in New Issue
Block a user