Browse Source

msm: camera: memmgr: Add presil memory API implementation

Add code for dmabuf, fd conversion and copying all buffers
using presil framework APIs.

CRs-Fixed: 2932495
Change-Id: Icfb6dc1a3326ea8214a71fd39871a8583a6e902c
Signed-off-by: Suraj Dongre <[email protected]>
Signed-off-by: Mukund Madhusudan Atre <[email protected]>
Suraj Dongre 4 years ago
parent
commit
37de6613a8
2 changed files with 308 additions and 18 deletions
  1. 280 2
      drivers/cam_req_mgr/cam_mem_mgr.c
  2. 28 16
      drivers/cam_req_mgr/cam_mem_mgr.h

+ 280 - 2
drivers/cam_req_mgr/cam_mem_mgr.c

@@ -22,6 +22,7 @@
 #include "cam_debug_util.h"
 #include "cam_trace.h"
 #include "cam_common_util.h"
+#include "cam_presil_hw_access.h"
 
 #define CAM_MEM_SHARED_BUFFER_PAD_4K (4 * 1024)
 
@@ -33,6 +34,19 @@ static void cam_mem_mgr_put_dma_heaps(void);
 static int cam_mem_mgr_get_dma_heaps(void);
 #endif
 
+#ifdef CONFIG_CAM_PRESIL
+static inline void cam_mem_mgr_reset_presil_params(int idx)
+{
+        tbl.bufq[idx].presil_params.fd_for_umd_daemon = -1;
+        tbl.bufq[idx].presil_params.refcount = 0;
+}
+#else
+static inline void cam_mem_mgr_reset_presil_params(int idx)
+{
+        return;
+}
+#endif
+
 static unsigned long cam_mem_mgr_mini_dump_cb(void *dst, unsigned long len)
 {
 	struct cam_mem_table_mini_dump      *md;
@@ -220,6 +234,7 @@ int cam_mem_mgr_init(void)
 	for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) {
 		tbl.bufq[i].fd = -1;
 		tbl.bufq[i].buf_handle = -1;
+		cam_mem_mgr_reset_presil_params(i);
 	}
 	mutex_init(&tbl.m_lock);
 
@@ -1020,6 +1035,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd)
 	tbl.bufq[idx].dma_buf = dmabuf;
 	tbl.bufq[idx].len = len;
 	tbl.bufq[idx].num_hdl = cmd->num_hdl;
+	cam_mem_mgr_reset_presil_params(idx);
 	memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls,
 		sizeof(int32_t) * cmd->num_hdl);
 	tbl.bufq[idx].is_imported = false;
@@ -1297,6 +1313,7 @@ static int cam_mem_mgr_cleanup_table(void)
 		tbl.bufq[i].dma_buf = NULL;
 		tbl.bufq[i].active = false;
 		tbl.bufq[i].is_internal = false;
+		cam_mem_mgr_reset_presil_params(i);
 		mutex_unlock(&tbl.bufq[i].q_lock);
 		mutex_destroy(&tbl.bufq[i].q_lock);
 	}
@@ -1408,6 +1425,7 @@ static int cam_mem_util_unmap(int32_t idx,
 	tbl.bufq[idx].is_internal = false;
 	tbl.bufq[idx].len = 0;
 	tbl.bufq[idx].num_hdl = 0;
+	cam_mem_mgr_reset_presil_params(idx);
 	memset(&tbl.bufq[idx].timestamp, 0, sizeof(struct timespec64));
 	mutex_unlock(&tbl.bufq[idx].q_lock);
 	mutex_destroy(&tbl.bufq[idx].q_lock);
@@ -1821,8 +1839,268 @@ int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp)
 }
 EXPORT_SYMBOL(cam_mem_mgr_free_memory_region);
 
-#ifndef CONFIG_CAM_PRESIL
+#ifdef CONFIG_CAM_PRESIL
+struct dma_buf *cam_mem_mgr_get_dma_buf(int fd)
+{
+	struct dma_buf *dmabuf = NULL;
+
+	dmabuf = dma_buf_get(fd);
+	if (IS_ERR_OR_NULL((void *)(dmabuf))) {
+		CAM_ERR(CAM_MEM, "Failed to import dma_buf for fd");
+		return NULL;
+	}
+
+	CAM_INFO(CAM_PRESIL, "Received DMA Buf* %pK", dmabuf);
+
+	return dmabuf;
+}
+
+int cam_presil_put_dmabuf_from_fd(uint64_t input_dmabuf)
+{
+	struct dma_buf *dmabuf = (struct dma_buf *)(uint64_t)input_dmabuf;
+	int idx = 0;
+
+	CAM_INFO(CAM_PRESIL, "Received dma_buf :%pK", dmabuf);
+
+	if (!dmabuf) {
+		CAM_ERR(CAM_PRESIL, "NULL to import dma_buf fd");
+		return -EINVAL;
+	}
+
+	for (idx = 0; idx < CAM_MEM_BUFQ_MAX; idx++) {
+		if ((tbl.bufq[idx].dma_buf != NULL) && (tbl.bufq[idx].dma_buf == dmabuf)) {
+			if (tbl.bufq[idx].presil_params.refcount)
+				tbl.bufq[idx].presil_params.refcount--;
+			else
+				CAM_ERR(CAM_PRESIL, "Unbalanced dmabuf put: %pK", dmabuf);
+
+			if (!tbl.bufq[idx].presil_params.refcount) {
+				dma_buf_put(dmabuf);
+				cam_mem_mgr_reset_presil_params(idx);
+				CAM_DBG(CAM_PRESIL, "Done dma_buf_put for %pK", dmabuf);
+			}
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(cam_presil_put_dmabuf_from_fd);
+
+int cam_presil_get_fd_from_dmabuf(uint64_t input_dmabuf)
+{
+	int fd_for_dmabuf = -1;
+	struct dma_buf *dmabuf = (struct dma_buf *)(uint64_t)input_dmabuf;
+	int idx = 0;
+
+	CAM_DBG(CAM_PRESIL, "Received dma_buf :%pK", dmabuf);
+
+	if (!dmabuf) {
+		CAM_ERR(CAM_PRESIL, "NULL to import dma_buf fd");
+		return -EINVAL;
+	}
+
+	for (idx = 0; idx < CAM_MEM_BUFQ_MAX; idx++) {
+		if ((tbl.bufq[idx].dma_buf != NULL) && (tbl.bufq[idx].dma_buf == dmabuf)) {
+			CAM_DBG(CAM_PRESIL,
+				"Found entry for request from Presil UMD Daemon at %d, dmabuf %pK fd_for_umd_daemon %d refcount: %d",
+				idx, tbl.bufq[idx].dma_buf,
+				tbl.bufq[idx].presil_params.fd_for_umd_daemon,
+				tbl.bufq[idx].presil_params.refcount);
+
+			if (tbl.bufq[idx].presil_params.fd_for_umd_daemon < 0) {
+				fd_for_dmabuf = dma_buf_fd(dmabuf, O_CLOEXEC);
+				if (fd_for_dmabuf < 0) {
+					CAM_ERR(CAM_PRESIL, "get fd fail, fd_for_dmabuf=%d",
+						fd_for_dmabuf);
+					return -EINVAL;
+				}
+
+				tbl.bufq[idx].presil_params.fd_for_umd_daemon = fd_for_dmabuf;
+				CAM_INFO(CAM_PRESIL,
+					"Received generated idx %d fd_for_dmabuf Buf* %lld", idx,
+					fd_for_dmabuf);
+			} else {
+				fd_for_dmabuf = tbl.bufq[idx].presil_params.fd_for_umd_daemon;
+				CAM_INFO(CAM_PRESIL,
+					"Received existing at idx %d fd_for_dmabuf Buf* %lld", idx,
+					fd_for_dmabuf);
+			}
+
+			tbl.bufq[idx].presil_params.refcount++;
+		} else {
+			CAM_DBG(CAM_MEM,
+				"Not found dmabuf at idx=%d, dma_buf %pK handle 0x%0x active %d ",
+				idx, tbl.bufq[idx].dma_buf, tbl.bufq[idx].buf_handle,
+				tbl.bufq[idx].active);
+		}
+	}
+
+	return (int)fd_for_dmabuf;
+}
+EXPORT_SYMBOL(cam_presil_get_fd_from_dmabuf);
+
+int cam_mem_mgr_send_buffer_to_presil(int32_t iommu_hdl, int32_t buf_handle)
+{
+	int rc = 0;
+
+	/* Sending Presil IO Buf to PC side ( as iova start address indicates) */
+	uint64_t io_buf_addr;
+	size_t io_buf_size;
+	int i, fd = -1, idx = 0;
+	uint8_t *iova_ptr = NULL;
+	uint64_t dmabuf = 0;
+	bool is_mapped_in_cb = false;
+
+
+	CAM_DBG(CAM_PRESIL, "buf handle 0x%0x", buf_handle);
+
+	idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle);
+	for (i = 0; i < tbl.bufq[idx].num_hdl; i++) {
+		if (tbl.bufq[idx].hdls[i] == iommu_hdl)
+			is_mapped_in_cb = true;
+	}
+
+	if (!is_mapped_in_cb)
+		return 0;
+
+	if ((tbl.bufq[idx].buf_handle != 0) && (tbl.bufq[idx].active) &&
+		(tbl.bufq[idx].buf_handle == buf_handle)) {
+		CAM_DBG(CAM_PRESIL,
+			"Found dmabuf in bufq idx %d, FD %d handle 0x%0x dmabuf %pK",
+			idx, tbl.bufq[idx].fd, tbl.bufq[idx].buf_handle, tbl.bufq[idx].dma_buf);
+		dmabuf = (uint64_t)tbl.bufq[idx].dma_buf;
+		fd = tbl.bufq[idx].fd;
+	} else {
+		CAM_ERR(CAM_PRESIL,
+			"Could not find dmabuf Invalid Mem idx=%d, FD %d handle 0x%0x active %d",
+			idx, tbl.bufq[idx].fd, tbl.bufq[idx].buf_handle, tbl.bufq[idx].active);
+		return -EINVAL;
+	}
+
+	rc = cam_mem_get_io_buf(buf_handle, iommu_hdl, &io_buf_addr, &io_buf_size, NULL);
+	if (rc || NULL == (void *)io_buf_addr) {
+		CAM_DBG(CAM_PRESIL, "Invalid ioaddr : 0x%x, fd = %d,  dmabuf = %pK",
+			io_buf_addr, fd, dmabuf);
+		return -EINVAL;
+	}
+
+	iova_ptr = (uint8_t *)io_buf_addr;
+	CAM_INFO(CAM_PRESIL, "Sending buffer with ioaddr : 0x%x, fd = %d, dmabuf = %pK",
+		io_buf_addr, fd, dmabuf);
+
+	rc = cam_presil_send_buffer(dmabuf, 0, 0, (uint32_t)io_buf_size, (uint64_t)iova_ptr);
+
+	return rc;
+}
+
+int cam_mem_mgr_send_all_buffers_to_presil(int32_t iommu_hdl)
+{
+	int idx = 0;
+	int rc = 0;
+	int32_t fd_already_sent[128];
+	int fd_already_sent_count = 0;
+	int fd_already_index = 0;
+	int fd_already_sent_found = 0;
+
 
+	memset(&fd_already_sent, 0x0, sizeof(fd_already_sent));
+
+	for (idx = 0; idx < CAM_MEM_BUFQ_MAX; idx++) {
+		if ((tbl.bufq[idx].buf_handle != 0) && (tbl.bufq[idx].active)) {
+			CAM_DBG(CAM_PRESIL, "Sending %d, FD %d handle 0x%0x", idx, tbl.bufq[idx].fd,
+				tbl.bufq[idx].buf_handle);
+			fd_already_sent_found = 0;
+
+			for (fd_already_index = 0; fd_already_index < fd_already_sent_count;
+				fd_already_index++) {
+
+				if (fd_already_sent[fd_already_index] == tbl.bufq[idx].fd) {
+					fd_already_sent_found = 1;
+					CAM_DBG(CAM_PRESIL,
+						"fd_already_sent %d, FD %d handle 0x%0x flags=0x%0x",
+						idx, tbl.bufq[idx].fd, tbl.bufq[idx].buf_handle,
+						tbl.bufq[idx].flags);
+				}
+			}
+
+			if (fd_already_sent_found)
+				continue;
+
+			CAM_DBG(CAM_PRESIL, "Sending %d, FD %d handle 0x%0x flags=0x%0x", idx,
+				tbl.bufq[idx].fd, tbl.bufq[idx].buf_handle, tbl.bufq[idx].flags);
+
+			rc = cam_mem_mgr_send_buffer_to_presil(iommu_hdl, tbl.bufq[idx].buf_handle);
+			fd_already_sent[fd_already_sent_count++] = tbl.bufq[idx].fd;
+
+		} else {
+			CAM_DBG(CAM_PRESIL, "Invalid Mem idx=%d, FD %d handle 0x%0x active %d",
+				idx, tbl.bufq[idx].fd, tbl.bufq[idx].buf_handle,
+				tbl.bufq[idx].active);
+		}
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(cam_mem_mgr_send_all_buffers_to_presil);
+
+int cam_mem_mgr_retrieve_buffer_from_presil(int32_t buf_handle, uint32_t buf_size,
+	uint32_t offset, int32_t iommu_hdl)
+{
+	int rc = 0;
+
+	/* Receive output buffer from Presil IO Buf to PC side (as iova start address indicates) */
+	uint64_t io_buf_addr;
+	size_t io_buf_size;
+	uint64_t dmabuf = 0;
+	int fd = 0;
+	uint8_t *iova_ptr = NULL;
+	int idx = 0;
+
+
+	CAM_DBG(CAM_PRESIL, "buf handle 0x%0x ", buf_handle);
+	rc = cam_mem_get_io_buf(buf_handle, iommu_hdl, &io_buf_addr, &io_buf_size, NULL);
+	if (rc) {
+		CAM_ERR(CAM_PRESIL, "Unable to get IOVA for buffer buf_hdl: 0x%0x iommu_hdl: 0x%0x",
+			buf_handle, iommu_hdl);
+		return -EINVAL;
+	}
+
+	iova_ptr = (uint8_t *)io_buf_addr;
+	iova_ptr += offset;   // correct target address to start writing buffer to.
+
+	if (!buf_size) {
+		buf_size = io_buf_size;
+		CAM_DBG(CAM_PRESIL, "Updated buf_size from Zero to 0x%0x", buf_size);
+	}
+
+	fd = GET_FD_FROM_HANDLE(buf_handle);
+
+	idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle);
+	if ((tbl.bufq[idx].buf_handle != 0) && (tbl.bufq[idx].active) &&
+		(tbl.bufq[idx].buf_handle == buf_handle)) {
+		CAM_DBG(CAM_PRESIL, "Found dmabuf in bufq idx %d, FD %d handle 0x%0x dmabuf %pK",
+			idx, tbl.bufq[idx].fd, tbl.bufq[idx].buf_handle, tbl.bufq[idx].dma_buf);
+		dmabuf = (uint64_t)tbl.bufq[idx].dma_buf;
+	} else {
+		CAM_ERR(CAM_PRESIL,
+			"Could not find dmabuf Invalid Mem idx=%d, FD %d handle 0x%0x active %d ",
+			idx, tbl.bufq[idx].fd, tbl.bufq[idx].buf_handle, tbl.bufq[idx].active);
+	}
+
+	CAM_DBG(CAM_PRESIL,
+		"Retrieving buffer with ioaddr : 0x%x, offset = %d, size = %d, fd = %d, dmabuf = %pK",
+		io_buf_addr, offset, buf_size, fd, dmabuf);
+
+	rc = cam_presil_retrieve_buffer(dmabuf, 0, 0, (uint32_t)buf_size, (uint64_t)io_buf_addr);
+
+	CAM_INFO(CAM_PRESIL,
+		"Retrieved buffer with ioaddr : 0x%x, offset = %d, size = %d, fd = %d, dmabuf = %pK",
+		io_buf_addr, 0, buf_size, fd, dmabuf);
+
+	return rc;
+}
+
+#else /* ifdef CONFIG_CAM_PRESIL */
 struct dma_buf * cam_mem_mgr_get_dma_buf(int fd)
 {
 	return NULL;
@@ -1845,4 +2123,4 @@ int cam_mem_mgr_retrieve_buffer_from_presil(int32_t buf_handle,
 {
 	return 0;
 }
-#endif
+#endif /* ifdef CONFIG_CAM_PRESIL */

+ 28 - 16
drivers/cam_req_mgr/cam_mem_mgr.h

@@ -26,25 +26,33 @@ enum cam_smmu_mapping_client {
 	CAM_SMMU_MAPPING_KERNEL,
 };
 
+#ifdef CONFIG_CAM_PRESIL
+struct cam_presil_dmabuf_params {
+	int32_t fd_for_umd_daemon;
+	uint32_t refcount;
+};
+#endif
+
 /**
  * struct cam_mem_buf_queue
  *
- * @dma_buf:     pointer to the allocated dma_buf in the table
- * @q_lock:      mutex lock for buffer
- * @hdls:        list of mapped handles
- * @num_hdl:     number of handles
- * @fd:          file descriptor of buffer
- * @i_ino:       inode number of this dmabuf. Uniquely identifies a buffer
- * @buf_handle:  unique handle for buffer
- * @align:       alignment for allocation
- * @len:         size of buffer
- * @flags:       attributes of buffer
- * @vaddr:       IOVA of buffer
- * @kmdvaddr:    Kernel virtual address
- * @active:      state of the buffer
- * @is_imported: Flag indicating if buffer is imported from an FD in user space
- * @is_internal: Flag indicating kernel allocated buffer
- * @timestamp:   Timestamp at which this entry in tbl was made
+ * @dma_buf:        pointer to the allocated dma_buf in the table
+ * @q_lock:         mutex lock for buffer
+ * @hdls:           list of mapped handles
+ * @num_hdl:        number of handles
+ * @fd:             file descriptor of buffer
+ * @i_ino:          inode number of this dmabuf. Uniquely identifies a buffer
+ * @buf_handle:     unique handle for buffer
+ * @align:          alignment for allocation
+ * @len:            size of buffer
+ * @flags:          attributes of buffer
+ * @vaddr:          IOVA of buffer
+ * @kmdvaddr:       Kernel virtual address
+ * @active:         state of the buffer
+ * @is_imported:    Flag indicating if buffer is imported from an FD in user space
+ * @is_internal:    Flag indicating kernel allocated buffer
+ * @timestamp:      Timestamp at which this entry in tbl was made
+ * @presil_params:  Parameters specific to presil environment
  */
 struct cam_mem_buf_queue {
 	struct dma_buf *dma_buf;
@@ -63,6 +71,10 @@ struct cam_mem_buf_queue {
 	bool is_imported;
 	bool is_internal;
 	struct timespec64 timestamp;
+
+#ifdef CONFIG_CAM_PRESIL
+	struct cam_presil_dmabuf_params presil_params;
+#endif
 };
 
 /**