|
@@ -1,6 +1,6 @@
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
/*
|
|
|
- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
|
|
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
|
|
*/
|
|
|
|
|
|
#include <linux/module.h>
|
|
@@ -22,6 +22,11 @@
|
|
|
static struct cam_mem_table tbl;
|
|
|
static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED);
|
|
|
|
|
|
+#if IS_REACHABLE(CONFIG_DMABUF_HEAPS)
|
|
|
+static void cam_mem_mgr_put_dma_heaps(void);
|
|
|
+static int cam_mem_mgr_get_dma_heaps(void);
|
|
|
+#endif
|
|
|
+
|
|
|
static void cam_mem_mgr_print_tbl(void)
|
|
|
{
|
|
|
int i;
|
|
@@ -163,6 +168,7 @@ int cam_mem_mgr_init(void)
|
|
|
{
|
|
|
int i;
|
|
|
int bitmap_size;
|
|
|
+ int rc = 0;
|
|
|
|
|
|
memset(tbl.bufq, 0, sizeof(tbl.bufq));
|
|
|
|
|
@@ -171,10 +177,19 @@ int cam_mem_mgr_init(void)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+#if IS_REACHABLE(CONFIG_DMABUF_HEAPS)
|
|
|
+ rc = cam_mem_mgr_get_dma_heaps();
|
|
|
+ if (rc) {
|
|
|
+ CAM_ERR(CAM_MEM, "Failed in getting dma heaps rc=%d", rc);
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+#endif
|
|
|
bitmap_size = BITS_TO_LONGS(CAM_MEM_BUFQ_MAX) * sizeof(long);
|
|
|
tbl.bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
|
|
- if (!tbl.bitmap)
|
|
|
- return -ENOMEM;
|
|
|
+ if (!tbl.bitmap) {
|
|
|
+ rc = -ENOMEM;
|
|
|
+ goto put_heaps;
|
|
|
+ }
|
|
|
|
|
|
tbl.bits = bitmap_size * BITS_PER_BYTE;
|
|
|
bitmap_zero(tbl.bitmap, tbl.bits);
|
|
@@ -192,6 +207,11 @@ int cam_mem_mgr_init(void)
|
|
|
cam_mem_mgr_create_debug_fs();
|
|
|
|
|
|
return 0;
|
|
|
+put_heaps:
|
|
|
+#if IS_REACHABLE(CONFIG_DMABUF_HEAPS)
|
|
|
+ cam_mem_mgr_put_dma_heaps();
|
|
|
+#endif
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
static int32_t cam_mem_get_slot(void)
|
|
@@ -365,6 +385,10 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd)
|
|
|
goto end;
|
|
|
}
|
|
|
|
|
|
+#if IS_REACHABLE(CONFIG_DMABUF_HEAPS)
|
|
|
+ CAM_DBG(CAM_MEM, "Calling dmap buf APIs for cache operations");
|
|
|
+ cache_dir = DMA_BIDIRECTIONAL;
|
|
|
+#else
|
|
|
if (dmabuf_flag & ION_FLAG_CACHED) {
|
|
|
switch (cmd->mem_cache_ops) {
|
|
|
case CAM_MEM_CLEAN_CACHE:
|
|
@@ -386,7 +410,7 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd)
|
|
|
CAM_DBG(CAM_MEM, "BUF is not cached");
|
|
|
goto end;
|
|
|
}
|
|
|
-
|
|
|
+#endif
|
|
|
rc = dma_buf_begin_cpu_access(tbl.bufq[idx].dma_buf,
|
|
|
(cmd->mem_cache_ops == CAM_MEM_CLEAN_INV_CACHE) ?
|
|
|
DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
|
|
@@ -408,6 +432,192 @@ end:
|
|
|
}
|
|
|
EXPORT_SYMBOL(cam_mem_mgr_cache_ops);
|
|
|
|
|
|
+#if IS_REACHABLE(CONFIG_DMABUF_HEAPS)
|
|
|
+static void cam_mem_mgr_put_dma_heaps(void)
|
|
|
+{
|
|
|
+ CAM_DBG(CAM_MEM, "Releasing DMA Buf heaps usage");
|
|
|
+}
|
|
|
+
|
|
|
+static int cam_mem_mgr_get_dma_heaps(void)
|
|
|
+{
|
|
|
+ int rc = 0;
|
|
|
+
|
|
|
+ tbl.system_heap = NULL;
|
|
|
+ tbl.system_uncached_heap = NULL;
|
|
|
+ tbl.camera_heap = NULL;
|
|
|
+ tbl.camera_uncached_heap = NULL;
|
|
|
+ tbl.secure_display_heap = NULL;
|
|
|
+
|
|
|
+ tbl.system_heap = dma_heap_find("qcom,system");
|
|
|
+ if (IS_ERR_OR_NULL(tbl.system_heap)) {
|
|
|
+ rc = PTR_ERR(tbl.system_heap);
|
|
|
+ CAM_ERR(CAM_MEM, "qcom system heap not found, rc=%d", rc);
|
|
|
+ tbl.system_heap = NULL;
|
|
|
+ goto put_heaps;
|
|
|
+ }
|
|
|
+
|
|
|
+ tbl.system_uncached_heap = dma_heap_find("qcom,system-uncached");
|
|
|
+ if (IS_ERR_OR_NULL(tbl.system_uncached_heap)) {
|
|
|
+ if (tbl.force_cache_allocs) {
|
|
|
+ /* optional, we anyway do not use uncached */
|
|
|
+ CAM_DBG(CAM_MEM,
|
|
|
+ "qcom system-uncached heap not found, err=%d",
|
|
|
+ PTR_ERR(tbl.system_uncached_heap));
|
|
|
+ tbl.system_uncached_heap = NULL;
|
|
|
+ } else {
|
|
|
+ /* fatal, must need uncached heaps */
|
|
|
+ rc = PTR_ERR(tbl.system_uncached_heap);
|
|
|
+ CAM_ERR(CAM_MEM,
|
|
|
+ "qcom system-uncached heap not found, rc=%d",
|
|
|
+ rc);
|
|
|
+ tbl.system_uncached_heap = NULL;
|
|
|
+ goto put_heaps;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ tbl.secure_display_heap = dma_heap_find("qcom,secure-display");
|
|
|
+ if (IS_ERR_OR_NULL(tbl.secure_display_heap)) {
|
|
|
+ rc = PTR_ERR(tbl.secure_display_heap);
|
|
|
+ CAM_ERR(CAM_MEM, "qcom,secure-display heap not found, rc=%d",
|
|
|
+ rc);
|
|
|
+ tbl.secure_display_heap = NULL;
|
|
|
+ goto put_heaps;
|
|
|
+ }
|
|
|
+
|
|
|
+ tbl.camera_heap = dma_heap_find("qcom,camera");
|
|
|
+ if (IS_ERR_OR_NULL(tbl.camera_heap)) {
|
|
|
+ /* optional heap, not a fatal error */
|
|
|
+ CAM_DBG(CAM_MEM, "qcom camera heap not found, err=%d",
|
|
|
+ PTR_ERR(tbl.camera_heap));
|
|
|
+ tbl.camera_heap = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ tbl.camera_uncached_heap = dma_heap_find("qcom,camera-uncached");
|
|
|
+ if (IS_ERR_OR_NULL(tbl.camera_uncached_heap)) {
|
|
|
+ /* optional heap, not a fatal error */
|
|
|
+ CAM_DBG(CAM_MEM, "qcom camera heap not found, err=%d",
|
|
|
+ PTR_ERR(tbl.camera_uncached_heap));
|
|
|
+ tbl.camera_uncached_heap = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ CAM_INFO(CAM_MEM,
|
|
|
+ "Heaps : system=%pK, system_uncached=%pK, camera=%pK, camera-uncached=%pK, secure_display=%pK",
|
|
|
+ tbl.system_heap, tbl.system_uncached_heap,
|
|
|
+ tbl.camera_heap, tbl.camera_uncached_heap,
|
|
|
+ tbl.secure_display_heap);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+put_heaps:
|
|
|
+ cam_mem_mgr_put_dma_heaps();
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static int cam_mem_util_get_dma_buf(size_t len,
|
|
|
+ unsigned int cam_flags,
|
|
|
+ struct dma_buf **buf)
|
|
|
+{
|
|
|
+ int rc = 0;
|
|
|
+ struct dma_heap *heap;
|
|
|
+ struct dma_heap *try_heap = NULL;
|
|
|
+ struct timespec64 ts1, ts2;
|
|
|
+ long microsec = 0;
|
|
|
+ bool use_cached_heap = false;
|
|
|
+
|
|
|
+ if (!buf) {
|
|
|
+ CAM_ERR(CAM_MEM, "Invalid params");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tbl.alloc_profile_enable)
|
|
|
+ CAM_GET_TIMESTAMP(ts1);
|
|
|
+
|
|
|
+ if ((cam_flags & CAM_MEM_FLAG_CACHE) ||
|
|
|
+ (tbl.force_cache_allocs &&
|
|
|
+ (!(cam_flags & CAM_MEM_FLAG_PROTECTED_MODE)))) {
|
|
|
+ CAM_DBG(CAM_MEM,
|
|
|
+ "Using CACHED heap, cam_flags=0x%x, force_cache_allocs=%d",
|
|
|
+ cam_flags, tbl.force_cache_allocs);
|
|
|
+ use_cached_heap = true;
|
|
|
+ } else if (cam_flags & CAM_MEM_FLAG_PROTECTED_MODE) {
|
|
|
+ use_cached_heap = true;
|
|
|
+ CAM_DBG(CAM_MEM,
|
|
|
+ "Using CACHED heap for secure, cam_flags=0x%x, force_cache_allocs=%d",
|
|
|
+ cam_flags, tbl.force_cache_allocs);
|
|
|
+ } else {
|
|
|
+ use_cached_heap = false;
|
|
|
+ CAM_ERR(CAM_MEM,
|
|
|
+ "Using UNCACHED heap not supported, cam_flags=0x%x, force_cache_allocs=%d",
|
|
|
+ cam_flags, tbl.force_cache_allocs);
|
|
|
+ /*
|
|
|
+ * Need a better handling based on whether dma-buf-heaps support
|
|
|
+ * uncached heaps or not. For now, assume not supported.
|
|
|
+ */
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((cam_flags & CAM_MEM_FLAG_PROTECTED_MODE) &&
|
|
|
+ (cam_flags & CAM_MEM_FLAG_CDSP_OUTPUT)) {
|
|
|
+ heap = tbl.secure_display_heap;
|
|
|
+ CAM_ERR(CAM_MEM, "Secure CDSP not supported yet");
|
|
|
+ return -EBADR;
|
|
|
+ } else if (cam_flags & CAM_MEM_FLAG_PROTECTED_MODE) {
|
|
|
+ heap = tbl.secure_display_heap;
|
|
|
+ CAM_ERR(CAM_MEM, "Secure mode not supported yet");
|
|
|
+ return -EBADR;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (use_cached_heap) {
|
|
|
+ try_heap = tbl.camera_heap;
|
|
|
+ heap = tbl.system_heap;
|
|
|
+ } else {
|
|
|
+ try_heap = tbl.camera_uncached_heap;
|
|
|
+ heap = tbl.system_uncached_heap;
|
|
|
+ }
|
|
|
+
|
|
|
+ CAM_DBG(CAM_MEM, "Using heaps : try=%pK, heap=%pK", try_heap, heap);
|
|
|
+
|
|
|
+ *buf = NULL;
|
|
|
+
|
|
|
+ if (!try_heap && !heap) {
|
|
|
+ CAM_ERR(CAM_MEM,
|
|
|
+ "No heap available for allocation, cant allocate");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (try_heap) {
|
|
|
+ *buf = dma_heap_buffer_alloc(try_heap, len, O_RDWR, 0);
|
|
|
+ if (IS_ERR_OR_NULL(*buf)) {
|
|
|
+ CAM_WARN(CAM_MEM,
|
|
|
+ "Failed in allocating from try heap, heap=%pK, len=%zu, err=%d",
|
|
|
+ try_heap, len, PTR_ERR(*buf));
|
|
|
+ *buf = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (*buf == NULL) {
|
|
|
+ *buf = dma_heap_buffer_alloc(heap, len, O_RDWR, 0);
|
|
|
+ if (IS_ERR_OR_NULL(*buf)) {
|
|
|
+ rc = PTR_ERR(*buf);
|
|
|
+ CAM_ERR(CAM_MEM,
|
|
|
+ "Failed in allocating from heap, heap=%pK, len=%zu, err=%d",
|
|
|
+ heap, len, rc);
|
|
|
+ *buf = NULL;
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ CAM_DBG(CAM_MEM, "Allocate success, len=%zu, *buf=%pK", len, *buf);
|
|
|
+
|
|
|
+ if (tbl.alloc_profile_enable) {
|
|
|
+ CAM_GET_TIMESTAMP(ts2);
|
|
|
+ CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts1, ts2, microsec);
|
|
|
+ trace_cam_log_event("IONAllocProfile", "size and time in micro",
|
|
|
+ len, microsec);
|
|
|
+ }
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+#else
|
|
|
static int cam_mem_util_get_dma_buf(size_t len,
|
|
|
unsigned int cam_flags,
|
|
|
struct dma_buf **buf)
|
|
@@ -460,8 +670,9 @@ static int cam_mem_util_get_dma_buf(size_t len,
|
|
|
|
|
|
return rc;
|
|
|
}
|
|
|
+#endif
|
|
|
|
|
|
-static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd,
|
|
|
+static int cam_mem_util_buffer_alloc(struct cam_mem_mgr_alloc_cmd *cmd,
|
|
|
struct dma_buf **dmabuf,
|
|
|
int *fd)
|
|
|
{
|
|
@@ -485,6 +696,9 @@ static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd,
|
|
|
goto put_buf;
|
|
|
}
|
|
|
|
|
|
+ CAM_DBG(CAM_MEM, "Alloc success : len=%zu, *dmabuf=%pK, fd=%d",
|
|
|
+ cmd->len, *dmabuf, *fd);
|
|
|
+
|
|
|
/*
|
|
|
* increment the ref count so that ref count becomes 2 here
|
|
|
* when we close fd, refcount becomes 1 and when we do
|
|
@@ -655,7 +869,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
- rc = cam_mem_util_ion_alloc(cmd,
|
|
|
+ rc = cam_mem_util_buffer_alloc(cmd,
|
|
|
&dmabuf,
|
|
|
&fd);
|
|
|
if (rc) {
|