|
@@ -15,6 +15,8 @@
|
|
#include <linux/workqueue.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/genalloc.h>
|
|
#include <linux/genalloc.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/debugfs.h>
|
|
|
|
+#include <linux/dma-iommu.h>
|
|
|
|
+
|
|
#include <soc/qcom/secure_buffer.h>
|
|
#include <soc/qcom/secure_buffer.h>
|
|
|
|
|
|
#include <media/cam_req_mgr.h>
|
|
#include <media/cam_req_mgr.h>
|
|
@@ -137,6 +139,10 @@ struct cam_context_bank_info {
|
|
bool is_mul_client;
|
|
bool is_mul_client;
|
|
int device_count;
|
|
int device_count;
|
|
int num_shared_hdl;
|
|
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 {
|
|
struct cam_iommu_cb_set {
|
|
@@ -1440,11 +1446,13 @@ end:
|
|
EXPORT_SYMBOL(cam_smmu_dealloc_qdss);
|
|
EXPORT_SYMBOL(cam_smmu_dealloc_qdss);
|
|
|
|
|
|
int cam_smmu_get_io_region_info(int32_t smmu_hdl,
|
|
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;
|
|
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");
|
|
CAM_ERR(CAM_SMMU, "Error: Input args are invalid");
|
|
return -EINVAL;
|
|
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);
|
|
mutex_lock(&iommu_cb_set.cb_info[idx].lock);
|
|
*iova = iommu_cb_set.cb_info[idx].io_info.iova_start;
|
|
*iova = iommu_cb_set.cb_info[idx].io_info.iova_start;
|
|
*len = iommu_cb_set.cb_info[idx].io_info.iova_len;
|
|
*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,
|
|
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);
|
|
mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -3339,6 +3352,11 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb,
|
|
rc = -ENODEV;
|
|
rc = -ENODEV;
|
|
goto end;
|
|
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;
|
|
cb->state = CAM_SMMU_ATTACH;
|
|
} else {
|
|
} else {
|
|
CAM_ERR(CAM_SMMU, "Context bank does not have IO region");
|
|
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;
|
|
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,
|
|
static int cam_smmu_get_memory_regions_info(struct device_node *of_node,
|
|
struct cam_context_bank_info *cb)
|
|
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_support = 1;
|
|
cb->io_info.iova_start = region_start;
|
|
cb->io_info.iova_start = region_start;
|
|
cb->io_info.iova_len = region_len;
|
|
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;
|
|
break;
|
|
case CAM_SMMU_REGION_SECHEAP:
|
|
case CAM_SMMU_REGION_SECHEAP:
|
|
cb->secheap_support = 1;
|
|
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_len -> %X", region_len);
|
|
CAM_DBG(CAM_SMMU, "region_id -> %X", region_id);
|
|
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);
|
|
of_node_put(mem_map_node);
|
|
|
|
|
|
if (!num_regions) {
|
|
if (!num_regions) {
|