Parcourir la source

msm: eva: Use pool allocator to allocate wncc oobs

Keep wncc working in case of kernel heap leakage. wncc buffer
requires 128kb. Driver will pre-allocate and store 8 buffers
in the pool if wncc use case starts.

Save all recently de-register wncc buffer mappings through
deregister_buffer API.

Change-Id: Iaa422bed9d3dd6f6cfe349a4931bfde28a3e3a51
Signed-off-by: George Shen <[email protected]>
George Shen il y a 2 ans
Parent
commit
1f5a03e9a6
4 fichiers modifiés avec 127 ajouts et 6 suppressions
  1. 3 0
      msm/eva/cvp.c
  2. 108 6
      msm/eva/msm_cvp_buf.c
  3. 15 0
      msm/eva/msm_cvp_buf.h
  4. 1 0
      msm/eva/msm_cvp_internal.h

+ 3 - 0
msm/eva/cvp.c

@@ -21,6 +21,7 @@
 #include "msm_cvp_internal.h"
 #include "msm_cvp_res_parse.h"
 #include "msm_cvp_resources.h"
+#include "msm_cvp_buf.h"
 #include "cvp_hfi_api.h"
 #include "cvp_private.h"
 #include "msm_cvp_clocks.h"
@@ -625,6 +626,7 @@ static int __init msm_cvp_init(void)
 	cvp_driver->frame_cache.cache = KMEM_CACHE(msm_cvp_frame, 0);
 	cvp_driver->buf_cache.cache = KMEM_CACHE(cvp_internal_buf, 0);
 	cvp_driver->smem_cache.cache = KMEM_CACHE(msm_cvp_smem, 0);
+	mutex_init(&wncc_buf_pool.lock);
 
 	return rc;
 }
@@ -640,6 +642,7 @@ static void __exit msm_cvp_exit(void)
 	platform_driver_unregister(&msm_cvp_driver);
 	debugfs_remove_recursive(cvp_driver->debugfs_root);
 	mutex_destroy(&cvp_driver->lock);
+	mutex_destroy(&wncc_buf_pool.lock);
 	kfree(cvp_driver);
 	cvp_driver = NULL;
 }

+ 108 - 6
msm/eva/msm_cvp_buf.c

@@ -41,6 +41,8 @@
 			inst->dma_cache.usage_bitmap); \
 	} while (0)
 
+struct cvp_oob_pool wncc_buf_pool;
+
 static void _wncc_print_cvpwnccbufs_table(struct msm_cvp_inst* inst);
 static int _wncc_unmap_metadata_bufs(struct eva_kmd_hfi_packet* in_pkt,
 	unsigned int num_layers, unsigned int metadata_bufs_offset,
@@ -626,6 +628,15 @@ int msm_cvp_unmap_buf_wncc(struct msm_cvp_inst *inst,
 		mutex_unlock(&inst->cvpwnccbufs.lock);
 		return -EINVAL;
 	}
+	if (cbuf->smem->device_addr) {
+		u64 idx = inst->unused_wncc_bufs.ktid;
+		inst->unused_wncc_bufs.smem[idx] = *(cbuf->smem);
+		inst->unused_wncc_bufs.nr++;
+		inst->unused_wncc_bufs.nr =
+			(inst->unused_wncc_bufs.nr > MAX_FRAME_BUFFER_NUMS)?
+			MAX_FRAME_BUFFER_NUMS : inst->unused_wncc_bufs.nr;
+		inst->unused_wncc_bufs.ktid = ++idx % MAX_FRAME_BUFFER_NUMS;
+	}
 	mutex_unlock(&inst->cvpwnccbufs.lock);
 
 	if (cbuf->smem->device_addr) {
@@ -957,11 +968,89 @@ static int _wncc_unmap_metadata_bufs(struct eva_kmd_hfi_packet* in_pkt,
 	return rc;
 }
 
+static int init_wncc_bufs(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_WNCC_BUFS; i++) {
+		wncc_buf_pool.bufs[i] = (struct eva_kmd_oob_wncc*)kzalloc(
+				sizeof(struct eva_kmd_oob_wncc), GFP_KERNEL);
+		if (!wncc_buf_pool.bufs[i]) {
+			i--;
+			goto exit_fail;
+		}
+	}
+	wncc_buf_pool.used_bitmap = 0;
+	wncc_buf_pool.allocated = true;
+	return 0;
+
+exit_fail:
+	while (i >= 0) {
+		kfree(wncc_buf_pool.bufs[i]);
+		i--;
+	}
+	return -ENOMEM;
+}
+
+static int alloc_wncc_buf(struct wncc_oob_buf *wob)
+{
+	int rc, i;
+
+	mutex_lock(&wncc_buf_pool.lock);
+	if (!wncc_buf_pool.allocated) {
+		rc = init_wncc_bufs();
+		if (rc) {
+			mutex_unlock(&wncc_buf_pool.lock);
+			return rc;
+		}
+	}
+
+	for (i = 0; i < NUM_WNCC_BUFS; i++) {
+		if (!(wncc_buf_pool.used_bitmap & BIT(i))) {
+			wncc_buf_pool.used_bitmap |= BIT(i);
+			wob->bitmap_idx = i;
+			wob->buf = wncc_buf_pool.bufs[i];
+			mutex_unlock(&wncc_buf_pool.lock);
+			return 0;
+		}
+	}
+	mutex_unlock(&wncc_buf_pool.lock);
+	wob->bitmap_idx = 0xff;
+	wob->buf = (struct eva_kmd_oob_wncc*)kzalloc(
+			sizeof(struct eva_kmd_oob_wncc), GFP_KERNEL);
+	if (!wob->buf)
+		rc = -ENOMEM;
+	else
+		rc = 0;
+
+	return rc;
+}
+
+static void free_wncc_buf(struct wncc_oob_buf *wob)
+{
+	if (!wob)
+		return;
+
+	if (wob->bitmap_idx == 0xff) {
+		kfree(wob->buf);
+		return;
+	}
+
+	if (wob->bitmap_idx < NUM_WNCC_BUFS) {
+		mutex_lock(&wncc_buf_pool.lock);
+		wncc_buf_pool.used_bitmap &= ~BIT(wob->bitmap_idx);
+		memset(wob->buf, 0, sizeof(struct eva_kmd_oob_wncc));
+		wob->buf = NULL;
+		mutex_unlock(&wncc_buf_pool.lock);
+	}
+}
+
 static int msm_cvp_proc_oob_wncc(struct msm_cvp_inst* inst,
 	struct eva_kmd_hfi_packet* in_pkt)
 {
 	int rc = 0;
 	struct eva_kmd_oob_wncc* wncc_oob;
+	struct wncc_oob_buf wob;
 	struct eva_kmd_wncc_metadata* wncc_metadata[EVA_KMD_WNCC_MAX_LAYERS];
 	unsigned int i, j;
 	bool empty = false;
@@ -972,12 +1061,11 @@ static int msm_cvp_proc_oob_wncc(struct msm_cvp_inst* inst,
 		return -EINVAL;
 	}
 
-	wncc_oob = (struct eva_kmd_oob_wncc*)kzalloc(
-		sizeof(struct eva_kmd_oob_wncc), GFP_KERNEL);
-	if (!wncc_oob) {
-		dprintk(CVP_ERR, "%s: OOB buf allocation failed", __func__);
+	rc = alloc_wncc_buf(&wob);
+	if (rc)
 		return -ENOMEM;
-	}
+
+	wncc_oob = wob.buf;
 	rc = _wncc_copy_oob_from_user(in_pkt, wncc_oob);
 	if (rc) {
 		dprintk(CVP_ERR, "%s: OOB buf copying failed", __func__);
@@ -1062,7 +1150,7 @@ static int msm_cvp_proc_oob_wncc(struct msm_cvp_inst* inst,
 	}
 
 exit:
-	kfree(wncc_oob);
+	free_wncc_buf(&wob);
 	return rc;
 }
 
@@ -1497,6 +1585,15 @@ static void backup_frame_buffers(struct msm_cvp_inst *inst,
 
 	do {
 		i--;
+		if (frame->bufs[i].smem->bitmap_index < MAX_DMABUF_NUMS) {
+			/*
+			 * Frame buffer info can be found in dma_cache table,
+			 * Skip saving
+			 */
+			inst->last_frame.nr = 0;
+			return;
+		}
+
 		inst->last_frame.smem[i] = *(frame->bufs[i].smem);
 	} while (i);
 }
@@ -1846,6 +1943,11 @@ void msm_cvp_print_inst_bufs(struct msm_cvp_inst *inst, bool log)
 	dprintk(CVP_ERR, "last frame ktid %llx\n", inst->last_frame.ktid);
 	for (i = 0; i < inst->last_frame.nr; i++)
 		_log_smem(snap, inst, &inst->last_frame.smem[i], log);
+
+	dprintk(CVP_ERR, "unmapped wncc bufs\n");
+	for (i = 0; i < inst->unused_wncc_bufs.nr; i++)
+		_log_smem(snap, inst, &inst->unused_wncc_bufs.smem[i], log);
+
 }
 
 struct cvp_internal_buf *cvp_allocate_arp_bufs(struct msm_cvp_inst *inst,

+ 15 - 0
msm/eva/msm_cvp_buf.h

@@ -146,6 +146,21 @@ struct cvp_frame_bufs {
 	struct msm_cvp_smem smem[MAX_FRAME_BUFFER_NUMS];
 };
 
+struct wncc_oob_buf {
+	u32 bitmap_idx;
+	struct eva_kmd_oob_wncc *buf;
+};
+
+#define NUM_WNCC_BUFS 8
+struct cvp_oob_pool {
+	struct mutex lock;
+	bool allocated;
+	u32 used_bitmap;
+	struct eva_kmd_oob_wncc *bufs[NUM_WNCC_BUFS];
+};
+
+extern struct cvp_oob_pool wncc_buf_pool;
+
 void print_cvp_buffer(u32 tag, const char *str,
 		struct msm_cvp_inst *inst,
 		struct cvp_internal_buf *cbuf);

+ 1 - 0
msm/eva/msm_cvp_internal.h

@@ -385,6 +385,7 @@ struct msm_cvp_inst {
 	struct msm_cvp_list cvpwnccbufs;
 	struct msm_cvp_list frames;
 	struct cvp_frame_bufs last_frame;
+	struct cvp_frame_bufs unused_wncc_bufs;
 	u32 cvpwnccbufs_num;
 	struct msm_cvp_wncc_buffer* cvpwnccbufs_table;
 	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];