| /* |
| * drivers/amlogic/media/di_multi/di_mem_scatter.c |
| * |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| */ |
| |
| #include <linux/version.h> |
| #include <linux/module.h> |
| #include <linux/types.h> |
| #include <linux/kernel.h> |
| #include <linux/kthread.h> |
| #include <linux/semaphore.h> |
| #include <linux/workqueue.h> |
| #include <linux/spinlock.h> |
| #include <linux/delay.h> |
| #include <linux/interrupt.h> |
| #include <linux/fs.h> |
| #include <linux/init.h> |
| #include <linux/device.h> |
| #include <linux/mm.h> |
| #include <linux/slab.h> |
| #include <linux/major.h> |
| #include <linux/platform_device.h> |
| #include <linux/mutex.h> |
| #include <linux/cdev.h> |
| #include <linux/proc_fs.h> |
| #include <linux/list.h> |
| #include <linux/of_reserved_mem.h> |
| #include <linux/of_irq.h> |
| #include <linux/uaccess.h> |
| #include <linux/of_fdt.h> |
| #include <linux/cma.h> |
| #include <linux/dma-contiguous.h> |
| #include <linux/ctype.h> |
| #include <linux/string.h> |
| #include <linux/of_device.h> |
| |
| #include <linux/amlogic/media/vfm/vframe.h> |
| |
| /*dma_get_cma_size_int_byte*/ |
| #include <linux/amlogic/media/codec_mm/codec_mm.h> |
| #include <linux/amlogic/media/codec_mm/codec_mm_keeper.h> |
| |
| #include "deinterlace_dbg.h" |
| #include "deinterlace.h" |
| #include "di_data_l.h" |
| #include "di_data.h" |
| #include "di_dbg.h" |
| #include "di_vframe.h" |
| #include "di_task.h" |
| #include "di_prc.h" |
| #include "di_sys.h" |
| #include "di_api.h" |
| #include "di_que.h" |
| //#include "sc2/di_hw_ex_v3.h" |
| |
| #include "register.h" |
| #include "di_mem_sct_def.h" |
| |
| /************************************ |
| * bit0: no tail |
| * bit1: some information for each frame |
| * bit2: clear for first |
| * bit3: clear for each frame |
| * bit4: used decoder buffer; |
| * bit5: to sum; |
| ************************************/ |
| |
| static u32 dbg_sct_cfg = DI_BIT5 | DI_BIT6;// = BITS_EAFBC_CFG_4K; |
| |
| module_param_named(dbg_sct_cfg, dbg_sct_cfg, uint, 0664); |
| |
| bool dbg_sct_used_decoder_buffer(void) |
| { |
| if (dbg_sct_cfg & DI_BIT4) |
| return true; |
| return false; |
| } |
| |
| bool dbg_sct_printa(void) |
| { |
| if (dbg_sct_cfg & DI_BIT1) |
| return true; |
| return false; |
| } |
| |
| static bool dbg_sct_clear_first(void) |
| { |
| if (dbg_sct_cfg & DI_BIT2) |
| return true; |
| return false; |
| } |
| |
| bool dbg_sct_clear_by_frame(void) |
| { |
| if (dbg_sct_cfg & DI_BIT3) |
| return true; |
| return false; |
| } |
| |
| static bool dbg_sct_sum(void) |
| { |
| if (dbg_sct_cfg & DI_BIT5) |
| return true; |
| return false; |
| } |
| |
| static bool dbg_limit_ready(void) |
| { |
| if (dbg_sct_cfg & DI_BIT6) |
| return true; |
| return false; |
| } |
| |
| struct dim_msct_s { |
| void *box; |
| unsigned int flg_err; |
| unsigned int max_nub; |
| /*test*/ |
| unsigned int cnt_alloc; |
| struct dim_pat_s *pat_buf; |
| unsigned long tab_addr; |
| unsigned int *tab_vaddr; |
| union { |
| unsigned int d32; |
| struct { |
| unsigned int box : 1, |
| pat : 1, |
| vbit : 1, /*vmap flg*/ |
| tab : 1, |
| tab_resize : 1, |
| flg_rev :27; |
| } b; |
| } flg_act; |
| }; |
| |
| static struct dim_msct_s dim_sct; |
| |
| static struct dim_msct_s *get_msct(void) |
| { |
| return &dim_sct; |
| } |
| |
| static void sct_alloc(struct di_ch_s *pch, |
| unsigned int buffer_size, |
| unsigned int idx) |
| { |
| int ret; |
| struct dim_msct_s *psct = get_msct(); |
| int cur_mmu_4k_number; |
| //unsigned int *vaddr; |
| //struct di_mm_s *mm; |
| //bool flg_vmap; |
| u64 timer_st, timer_end, diff; |
| |
| timer_st = cur_to_usecs(); |
| |
| cur_mmu_4k_number = ((buffer_size + (1 << 12) - 1) >> 12); |
| |
| ret = di_mmu_box_alloc_idx( |
| psct->box, |
| idx, |
| cur_mmu_4k_number, |
| psct->tab_vaddr); |
| if (ret == 0) { |
| psct->flg_act.b.tab = 1; |
| psct->flg_act.b.tab_resize = 0; |
| } else { |
| bset(&psct->flg_err, EDIM_SCT_ERR_ALLOC); |
| PR_ERR("%s:\n", __func__); |
| } |
| |
| timer_end = cur_to_usecs(); |
| diff = timer_end - timer_st; |
| dbg_sct("%s:use %uus\n", __func__, (unsigned int)diff); |
| dim_tr_ops.sct_alloc(idx, timer_st); |
| } |
| |
| static void sct_free_tail(struct di_ch_s *pch, |
| unsigned int buffer_used, |
| unsigned int idx) |
| |
| { |
| struct dim_msct_s *psct = get_msct(); |
| int ret; |
| u64 timer_st, timer_end, diff; |
| |
| timer_st = cur_to_usecs(); |
| ret = di_mmu_box_free_idx_tail( |
| psct->box, |
| idx, |
| buffer_used); |
| if (ret == 0) { |
| psct->flg_act.b.tab_resize = 1; |
| } else { |
| bset(&psct->flg_err, EDIM_SCT_ERR_RESIZE); |
| PR_ERR("%s:\n", __func__); |
| } |
| timer_end = cur_to_usecs(); |
| diff = timer_end - timer_st; |
| dbg_sct("%s:use %uus\n", __func__, (unsigned int)diff); |
| } |
| |
| static void sct_free(unsigned int idx) |
| { |
| int ret; |
| struct dim_msct_s *psct = get_msct(); |
| u64 timer_st, timer_end, diff; |
| |
| timer_st = cur_to_usecs(); |
| |
| ret = di_mmu_box_free_idx(psct->box, idx); |
| if (ret == 0) { |
| psct->flg_act.b.tab_resize = 0; |
| psct->flg_act.b.tab = 0; |
| } else { |
| bset(&psct->flg_err, EDIM_SCT_ERR_FREE); |
| PR_ERR("%s:\n", __func__); |
| } |
| |
| timer_end = cur_to_usecs(); |
| diff = timer_end - timer_st; |
| dbg_sct("%s:use %uus\n", __func__, (unsigned int)diff); |
| } |
| |
| static void sct_reg(struct di_ch_s *pch) |
| { |
| unsigned int ch; |
| struct dim_msct_s *psct = get_msct(); |
| int buf_size = 64; /*?*/ |
| unsigned int max_num; |
| bool tvp; |
| struct dim_pat_s *pat_buf; |
| struct div2_mm_s *mm; |
| bool flg_vmap = false; |
| |
| ch = pch->ch_id; |
| max_num = 2; |
| psct->max_nub = max_num; |
| tvp = 0; |
| psct->box = di_mmu_box_alloc_box(DEVICE_NAME, |
| ch, |
| max_num, |
| buf_size * SZ_1M, |
| tvp); |
| if (!psct->box) { |
| bset(&psct->flg_err, EDIM_SCT_ERR_BOX); |
| PR_ERR("%s\n", __func__); |
| return; |
| } |
| pat_buf = qpat_out_ready(pch); |
| if (!pat_buf) { |
| bset(&psct->flg_err, EDIM_SCT_ERR_PAT); |
| di_mmu_box_free(psct->box); |
| psct->box = NULL; |
| return; |
| } |
| /*vmap*/ |
| mm = dim_mm_get(ch); |
| psct->tab_vaddr = (unsigned int *)dim_vmap(psct->tab_addr, |
| mm->cfg.size_pafbct_one, |
| &flg_vmap); |
| if (!psct->tab_vaddr) { |
| bset(&psct->flg_err, EDIM_SCT_ERR_VMAP); |
| PR_ERR("%s:vmap:0x%lx\n", __func__, psct->tab_addr); |
| return; |
| } |
| psct->flg_act.b.vbit = flg_vmap; |
| |
| psct->tab_addr = pat_buf->mem_start; |
| psct->pat_buf = pat_buf; |
| |
| psct->flg_act.b.box = 1; |
| psct->flg_act.b.pat = 1; |
| } |
| |
| static void sct_unreg(struct di_ch_s *pch) |
| { |
| struct dim_msct_s *psct = get_msct(); |
| |
| /**/ |
| if (psct->flg_act.b.tab) |
| sct_free(0); |
| |
| /* vmap */ |
| if (psct->flg_act.b.vbit) { |
| dim_unmap_phyaddr((u8 *)psct->tab_vaddr); |
| psct->tab_vaddr = NULL; |
| } |
| |
| if (psct->flg_act.b.pat) { |
| qpat_in_ready(pch, psct->pat_buf); |
| psct->pat_buf = NULL; |
| psct->flg_act.b.pat = 0; |
| } |
| |
| if (psct->flg_act.b.box) { |
| di_mmu_box_free(psct->box); |
| psct->box = NULL; |
| psct->flg_act.b.box = 0; |
| } |
| PR_INF("%s:end\n", __func__); |
| } |
| |
| void tst_alloc(struct di_ch_s *pch) |
| { |
| struct dim_msct_s *psct = get_msct(); |
| struct div2_mm_s *mm; |
| unsigned int ch; |
| |
| ch = pch->ch_id; |
| mm = dim_mm_get(ch); |
| |
| if (psct->flg_err) { |
| dbg_sct("%s:0x%x\n", __func__, psct->flg_err); |
| return; |
| } |
| if (psct->flg_act.b.tab) |
| return; |
| sct_alloc(pch, mm->cfg.pst_buf_size, 0); |
| } |
| |
| void tst_resize(struct di_ch_s *pch, unsigned int used_size) |
| { |
| struct dim_msct_s *psct = get_msct(); |
| struct div2_mm_s *mm; |
| unsigned int ch; |
| |
| ch = pch->ch_id; |
| mm = dim_mm_get(ch); |
| |
| if (psct->flg_err) { |
| dbg_sct("%s:0x%x\n", __func__, psct->flg_err); |
| return; |
| } |
| |
| if ((!psct->flg_act.b.tab) || (psct->flg_act.b.tab_resize)) |
| return; |
| sct_free_tail(pch, used_size, 0); |
| } |
| |
| void tst_release(struct di_ch_s *pch) |
| { |
| struct dim_msct_s *psct = get_msct(); |
| |
| if (psct->flg_err) { |
| dbg_sct("%s:0x%x\n", __func__, psct->flg_err); |
| return; |
| } |
| |
| if (!psct->flg_act.b.tab) |
| return; |
| if (!psct->flg_act.b.tab_resize) |
| return; |
| |
| sct_free(0); |
| } |
| |
| void tst_unreg(struct di_ch_s *pch) |
| { |
| sct_unreg(pch); |
| } |
| |
| void tst_reg(struct di_ch_s *pch) |
| { |
| // struct dim_msct_s *psct = get_msct(); |
| sct_reg(pch); |
| } |
| |
| void sct_max_check(struct di_ch_s *pch) |
| { |
| unsigned int ch; |
| struct dim_mscttop_s *psct; |
| struct dim_msc_sum_s *psum; |
| //unsigned int i; |
| //struct qs_cls_s *p; |
| //unsigned int psize; |
| //unsigned int cnt_pst_ready, cnt_pst_dis, cnt_pst_back; |
| //unsigned int cnt_sct_ready, cnt_sct_used,cnt_sct_re; |
| struct buf_que_s *pbufq; |
| //struct dim_sct_s *sct; |
| //unsigned int tt_size; |
| |
| if (!dbg_sct_sum()) |
| return; |
| |
| ch = pch->ch_id; |
| psct = &pch->msct_top; |
| psum = &psct->sum; |
| if (!psct->box) |
| return; |
| |
| pbufq = &pch->sct_qb; |
| psum->mts_sct_rcc = qbufp_count(pbufq, QBF_SCT_Q_RECYCLE); |
| psum->mts_sct_used = qbufp_count(pbufq, QBF_SCT_Q_USED); |
| psum->mts_sct_ready = qbufp_count(pbufq, QBF_SCT_Q_READY); |
| |
| psum->mts_pst_free = di_que_list_count(ch, QUE_POST_FREE); |
| psum->mts_pst_ready = ndrd_cnt(pch); |
| //di_que_list_count(ch, QUE_POST_READY); |
| psum->mts_pst_ready = di_que_list_count(ch, QUE_POST_READY); |
| psum->mts_pst_back = di_que_list_count(ch, QUE_POST_BACK); |
| psum->mts_pst_dispaly = list_count(ch, QUEUE_DISPLAY); |
| } |
| |
| /*because sct is not sync with reg/unreg */ |
| void sct_sw_on(struct di_ch_s *pch, |
| unsigned int max_num, |
| bool tvp, |
| unsigned int buffer_size) |
| { |
| unsigned int ch; |
| struct dim_mscttop_s *psct; |
| int buf_size = 64; /*?*/ |
| |
| // struct dim_pat_s *pat_buf; |
| // struct di_mm_s *mm; |
| // bool flg_vmap = false; |
| |
| ch = pch->ch_id; |
| psct = &pch->msct_top; |
| if (psct->box) { |
| PR_WARN("%s:box is exist\n", __func__); |
| return; |
| } |
| /*int*/ |
| memset(&psct->sum, 0, sizeof(psct->sum)); |
| |
| psct->max_nub = max_num; |
| |
| psct->box = di_mmu_box_alloc_box(DEVICE_NAME, |
| ch, |
| max_num, |
| buf_size * SZ_1M, |
| tvp); |
| if (!psct->box) { |
| bset(&psct->flg_err, EDIM_SCT_ERR_BOX); |
| PR_ERR("%s\n", __func__); |
| return; |
| } |
| psct->buffer_size = buffer_size; |
| psct->buffer_size_nub = ((psct->buffer_size + (1 << 12) - 1) >> 12); |
| psct->flg_act_box = 1; |
| |
| dbg_sct("%s:ch[%d], nub[%d] tvp[%d], buf_size[0x%x]\n", |
| __func__, ch, max_num, tvp, buffer_size); |
| } |
| |
| void sct_sw_off(struct di_ch_s *pch) |
| { |
| unsigned int ch; |
| struct dim_mscttop_s *psct; |
| struct buf_que_s *pbufq; |
| //union q_buf_u q_buf;// = NULL; |
| struct dim_sct_s *sct; |
| int i; |
| unsigned int len; |
| bool ret; |
| |
| ch = pch->ch_id; |
| psct = &pch->msct_top; |
| if (!psct->box) { |
| PR_INF("%s:no box\n", __func__); |
| return; |
| } |
| |
| pbufq = &pch->sct_qb; |
| /* ready clear */ |
| len = qbufp_count(pbufq, QBF_SCT_Q_READY); |
| if (len) { |
| for (i = 0; i < len; i++) { |
| ret = qsct_any_to_recycle(pch, QBF_SCT_Q_READY, &sct); |
| if (!ret) { |
| PR_ERR("%s:used[%d][%d]\n", __func__, len, i); |
| break; |
| } |
| } |
| } |
| /* used clear */ |
| len = qbufp_count(pbufq, QBF_SCT_Q_USED); |
| if (len) { |
| for (i = 0; i < len; i++) { |
| ret = qsct_any_to_recycle(pch, QBF_SCT_Q_USED, &sct); |
| if (!ret) { |
| PR_ERR("%s:used[%d][%d]\n", __func__, len, i); |
| break; |
| } |
| } |
| } |
| /* recycle clear */ |
| len = qbufp_count(pbufq, QBF_SCT_Q_RECYCLE); |
| if (len) { |
| for (i = 0; i < len; i++) { |
| ret = qsct_recycle_to_idle(pch, &sct); |
| if (!ret) { |
| PR_ERR("%s:rcy[%d][%d]\n", __func__, len, i); |
| break; |
| } |
| // if (!sct->flg_act.b.tab_keep) |
| /* pat */ |
| // pat_release_vaddr(sct->pat_buf); |
| // qpat_in_ready(pch,sct->pat_buf); |
| // sct->pat_buf = NULL; |
| sct_free_l(pch, sct); |
| } |
| } |
| bufq_sct_rest(pch); |
| |
| di_mmu_box_free(psct->box); |
| psct->box = NULL; |
| psct->flg_act_box = 0; |
| psct->max_nub = 0; |
| PR_INF("%s:release\n", __func__); |
| } |
| |
| //static |
| unsigned int sct_cnt_crc(struct device *dev, |
| unsigned int *p, |
| unsigned int buf_size) |
| { |
| //bool flg = false; /*dbg*/ |
| |
| int i, cnt; |
| // unsigned int body; |
| unsigned int crc = 0; |
| unsigned long crc_tmp = 0; |
| |
| cnt = (buf_size + 0xfff) >> 12; |
| |
| for (i = 0; i < cnt; i++) { |
| crc_tmp += *(p + i); |
| /*debug*/ |
| if ((dbg_sct_cfg & DI_BIT8) && (i < 5)) |
| PR_INF("\t:0x%x\n", *(p + i)); |
| } |
| //PR_INF("%s:3\n", __func__); |
| crc = (unsigned int)crc_tmp; |
| if (dbg_sct_cfg & DI_BIT8) |
| PR_INF("%s:0x%px:crc:0x%x, cnt[0x%x]\n", __func__, p, crc, cnt); |
| |
| return crc; |
| } |
| |
| static void sct_alloc_l(struct di_ch_s *pch, |
| struct dim_sct_s *sct) |
| { |
| int ret; |
| struct dim_mscttop_s *psct; |
| int cur_mmu_4k_number; |
| //unsigned int *vaddr; |
| //struct di_mm_s *mm; |
| //bool flg_vmap; |
| u64 timer_st, timer_end, diff; |
| struct dim_msc_sum_s *psum; |
| |
| psct = &pch->msct_top; |
| psum = &psct->sum; |
| timer_st = cur_to_usecs(); |
| |
| cur_mmu_4k_number = psct->buffer_size_nub; |
| //((psct->buffer_size + (1 << 12) - 1) >> 12); |
| |
| ret = di_mmu_box_alloc_idx( |
| psct->box, |
| sct->header.index, |
| cur_mmu_4k_number, |
| sct->pat_buf->vaddr); |
| if (ret == 0) { |
| sct->flg_act.b.tab = 1; |
| sct->tail_cnt = cur_mmu_4k_number; |
| /* sum */ |
| psum->curr_nub++; |
| if (psum->curr_nub > psum->max_nub) |
| psum->max_nub = psum->curr_nub; |
| psum->curr_tt_size += cur_mmu_4k_number; |
| if (psum->max_tt_size2 < psum->curr_tt_size) { |
| psum->max_tt_size2 = psum->curr_tt_size; |
| sct_max_check(pch); |
| } |
| } else { |
| bset(&psct->flg_err, EDIM_SCT_ERR_ALLOC); |
| PR_ERR("%s:\n", __func__); |
| } |
| #ifdef HIS_CODE |
| sct->pat_buf->crc = sct_cnt_crc(NULL, |
| (unsigned int *)sct->pat_buf->vaddr, |
| psct->buffer_size); |
| #endif |
| timer_end = cur_to_usecs(); |
| diff = timer_end - timer_st; |
| #ifdef HIS_CODE |
| dbg_sct("%s:pat:[idx=%d]:addr=0x%lx, vaddr=0x%px\n", |
| __func__, |
| sct->pat_buf->header.index, |
| sct->pat_buf->mem_start, |
| sct->pat_buf->vaddr); |
| dbg_sct("%s:use %uus\n", __func__, (unsigned int)diff); |
| #endif |
| dim_tr_ops.sct_alloc(sct->header.index, timer_st); |
| } |
| |
| void sct_free_tail_l(struct di_ch_s *pch, |
| unsigned int buffer_used, |
| struct dim_sct_s *sct) |
| |
| { |
| struct dim_mscttop_s *psct; |
| int ret; |
| u64 timer_st, timer_end, diff; |
| struct dim_msc_sum_s *psum; |
| |
| if ((!sct) || (!pch)) { |
| PR_ERR("%s:no sct\n", __func__); |
| return; |
| } |
| |
| if (dbg_sct_cfg & DI_BIT0) |
| return; |
| |
| timer_st = cur_to_usecs(); |
| psct = &pch->msct_top; |
| psum = &psct->sum; |
| buffer_used += 3; |
| if (buffer_used > psct->buffer_size_nub) { |
| PR_ERR("%s:overflow:0x%x\n", __func__, buffer_used); |
| return; |
| } |
| ret = di_mmu_box_free_idx_tail( |
| psct->box, |
| sct->header.index, |
| buffer_used); |
| if (ret == 0) { |
| sct->flg_act.b.tab_resize = 1; |
| /*sum*/ |
| //psum->max_nub--; |
| psum->curr_tt_size -= (psct->buffer_size_nub - buffer_used); |
| if (buffer_used > psum->max_size) |
| psum->max_size = buffer_used; |
| } else { |
| bset(&psct->flg_err, EDIM_SCT_ERR_RESIZE); |
| PR_ERR("%s:\n", __func__); |
| } |
| sct->tail_cnt = buffer_used; |
| timer_end = cur_to_usecs(); |
| diff = timer_end - timer_st; |
| dim_tr_ops.sct_tail(sct->header.index, buffer_used); |
| //dbg_sct("%s:use %uus 0x%x\n", __func__, |
| //(unsigned int)diff, buffer_used); |
| } |
| |
| void sct_free_l(struct di_ch_s *pch, struct dim_sct_s *sct) |
| { |
| int ret; |
| struct dim_mscttop_s *psct; |
| //u64 timer_st, timer_end, diff; |
| struct dim_msc_sum_s *psum; |
| |
| if ((!pch) || (!sct)) |
| return; |
| psct = &pch->msct_top; |
| psum = &psct->sum; |
| //timer_st = cur_to_usecs(); |
| if (sct->header.index > psct->max_nub) { |
| PR_ERR("%s:sct[%d]\n", __func__, sct->header.index); |
| return; |
| } |
| ret = di_mmu_box_free_idx(psct->box, sct->header.index); |
| if (ret == 0) { |
| sct->flg_act.b.tab_resize = 0; |
| sct->flg_act.b.tab = 0; |
| |
| psum->curr_nub--; |
| psum->curr_tt_size -= sct->tail_cnt; |
| } else { |
| bset(&psct->flg_err, EDIM_SCT_ERR_FREE); |
| PR_ERR("%s:\n", __func__); |
| } |
| |
| //timer_end = cur_to_usecs(); |
| //diff = timer_end - timer_st; |
| #ifdef HIS_CODE |
| dbg_sct("%s:ch[%d], index[%d]\n", |
| __func__, |
| pch->ch_id, |
| sct->header.index); |
| dbg_sct("%s:use %uus\n", __func__, (unsigned int)diff); |
| #endif |
| } |
| |
| unsigned int sct_keep(struct di_ch_s *pch, struct dim_sct_s *sct) |
| { |
| struct dim_mscttop_s *psct; |
| void *mem_handle; |
| int ret; |
| |
| if ((!pch) || (!sct)) |
| return 0xff; |
| psct = &pch->msct_top; |
| |
| mem_handle = |
| di_mmu_box_get_mem_handle( |
| psct->box, sct->header.index); |
| ret = codec_mm_keeper_mask_keep_mem(mem_handle, |
| MEM_TYPE_CODEC_MM_SCATTER); |
| #ifdef HIS_CODE |
| vf->mem_head_handle = |
| decoder_bmmu_box_get_mem_handle( |
| hevc->bmmu_box, VF_BUFFER_IDX(pic->BUF_index)); |
| #endif |
| if (ret >= 0) |
| return ret; |
| return 0xff; |
| } |
| |
| void sct_alloc_in_poling(unsigned int ch) |
| { |
| struct di_ch_s *pch; |
| struct dim_mscttop_s *psct; |
| unsigned int cnt_sct_req; |
| struct buf_que_s *pbufq; |
| int i; |
| struct dim_sct_s *sct, *sct2; |
| //struct dim_pat_s *pat_buf = NULL; |
| |
| pch = get_chdata(ch); |
| if (!pch) |
| return; |
| psct = &pch->msct_top; |
| if (!psct->box) |
| return; |
| pbufq = &pch->sct_qb; |
| cnt_sct_req = qbufp_count(pbufq, QBF_SCT_Q_REQ); |
| |
| if (!cnt_sct_req) |
| return; |
| psct->flg_allocing = 1; |
| for (i = 0; i < cnt_sct_req; i++) { |
| /* peek */ |
| |
| mutex_lock(&psct->lock_ready); |
| sct = qsct_req_peek(pch); |
| mutex_unlock(&psct->lock_ready); |
| if (!sct) |
| break; |
| |
| /* alloc */ |
| sct_alloc_l(pch, sct); |
| |
| /* req to ready */ |
| mutex_lock(&psct->lock_ready); |
| if (sct->flg_act.b.tab) { |
| qsct_req_to_ready(pch, &sct2); |
| if (sct != sct2) |
| PR_ERR("%s:not same\n", __func__); |
| } |
| mutex_unlock(&psct->lock_ready); |
| |
| /* to-do list */ |
| /* if unreg or change mode */ |
| if (psct->flg_trig_dis) { |
| psct->flg_trig_dis = 0; |
| break; |
| } |
| } |
| psct->flg_allocing = 0; |
| } |
| |
| static void pat_set_vaddr(struct dim_pat_s *pat, unsigned int buf_size) |
| { |
| bool flg_vmap = false; |
| |
| if (!pat) |
| return; |
| |
| if (pat->vaddr) { |
| PR_WARN("%s:vaddr exist[%d]\n", __func__, pat->header.index); |
| return; |
| } |
| |
| pat->vaddr = (unsigned int *)dim_vmap(pat->mem_start, |
| buf_size, |
| &flg_vmap); |
| if (!pat->vaddr) { |
| //bset(&psct->flg_err, EDIM_SCT_ERR_VMAP); |
| PR_ERR("%s:vmap:0x%lx\n", __func__, pat->mem_start); |
| return; |
| } |
| pat->flg_vmap = flg_vmap; |
| } |
| |
| void pat_release_vaddr(struct dim_pat_s *pat) |
| { |
| if (!pat) |
| return; |
| if (pat->vaddr && pat->flg_vmap) |
| dim_unmap_phyaddr((u8 *)pat->vaddr); |
| pat->vaddr = NULL; |
| } |
| |
| /* when from 4k to other size use this to recycle 4k buffer */ |
| void sct_mng_working_recycle(struct di_ch_s *pch) |
| { |
| struct div2_mm_s *mm; |
| unsigned int cnt_recycle, cnt_idle; |
| struct buf_que_s *pbufq; |
| struct dim_sct_s *sct; |
| struct dim_mscttop_s *pmsct; |
| int i; |
| |
| pmsct = &pch->msct_top; |
| |
| if (!pmsct->box) |
| return; |
| |
| mm = dim_mm_get(pch->ch_id); |
| if (mm->cfg.pbuf_flg.b.typ == EDIM_BLK_TYP_PSCT) |
| return; |
| |
| pbufq = &pch->sct_qb; |
| /* recycle */ |
| cnt_recycle = qbufp_count(pbufq, QBF_SCT_Q_RECYCLE); |
| if (!cnt_recycle) |
| return; |
| |
| for (i = 0; i < cnt_recycle; i++) { |
| qsct_recycle_to_idle(pch, &sct); |
| |
| /* pat */ |
| pat_release_vaddr(sct->pat_buf); |
| qpat_in_ready(pch, sct->pat_buf); |
| sct->pat_buf = NULL; |
| sct_free_l(pch, sct); |
| } |
| |
| cnt_idle = qbufp_count(pbufq, QBF_SCT_Q_IDLE); |
| |
| if ((cnt_idle == DIM_SCT_NUB) && |
| (pmsct->box)) { |
| di_mmu_box_free(pmsct->box); |
| pmsct->box = NULL; |
| pmsct->flg_act_box = 0; |
| pmsct->max_nub = 0; |
| dbg_sct("%s:release\n", __func__); |
| } else { |
| dbg_sct("%s:cnt_idle=%d\n", __func__, cnt_idle); |
| } |
| } |
| |
| #define DIM_SCT_KEEP_READY (1) |
| void sct_mng_working(struct di_ch_s *pch) |
| { |
| unsigned int ch; |
| unsigned int cnt_pst_free, cnt_sct_ready, cnt_sct_req; |
| unsigned int cnt_idle, cnt_wait, need_req, req_new = 0; |
| unsigned int cnt_recycle, ready_set, cnt_pst_ready; |
| struct buf_que_s *pbufq; |
| struct dim_mscttop_s *pmsct; |
| struct dim_sct_s *sct; |
| //bool f_no_res = false; |
| bool f_req = false; |
| bool f_no_wbuf = false; |
| bool ret; |
| int i; |
| unsigned int err = 0; |
| struct di_mng_s *pbm = get_bufmng(); |
| struct dim_pat_s *pat_buf = NULL; |
| struct div2_mm_s *mm; |
| struct di_buf_s *di_buf = NULL; |
| struct di_dev_s *devp = get_dim_de_devp(); |
| struct di_pre_stru_s *ppre; |
| unsigned int frame_nub; |
| |
| if (!pch) |
| return; |
| |
| pmsct = &pch->msct_top; |
| if (!pmsct->box) |
| return; |
| |
| ch = pch->ch_id; |
| |
| if (atomic_read(&pbm->trig_unreg[ch])) |
| return; |
| |
| mm = dim_mm_get(pch->ch_id); |
| if (mm->cfg.pbuf_flg.b.typ != EDIM_BLK_TYP_PSCT) |
| return; |
| |
| pbufq = &pch->sct_qb; |
| |
| ppre = get_pre_stru(ch); |
| if (!ppre) { |
| PR_ERR("%s:no ppre\n", __func__); |
| return; |
| } |
| |
| frame_nub = ppre->field_count_for_cont; |
| |
| /* recycle */ |
| cnt_recycle = qbufp_count(pbufq, QBF_SCT_Q_RECYCLE); |
| for (i = 0; i < cnt_recycle; i++) { |
| qsct_recycle_to_idle(pch, &sct); |
| |
| /* pat */ |
| pat_release_vaddr(sct->pat_buf); |
| qpat_in_ready(pch, sct->pat_buf); |
| sct->pat_buf = NULL; |
| sct_free_l(pch, sct); |
| } |
| |
| /*summary */ |
| cnt_pst_free = di_que_list_count(ch, QUE_POST_FREE); |
| cnt_pst_ready = ndrd_cnt(pch);//di_que_list_count(ch, QUE_POST_READY); |
| cnt_idle = qbufp_count(pbufq, QBF_SCT_Q_IDLE); |
| cnt_wait = di_que_list_count(ch, QUE_PST_NO_BUF_WAIT); |
| mutex_lock(&pmsct->lock_ready); |
| cnt_sct_ready = qbufp_count(pbufq, QBF_SCT_Q_READY); |
| cnt_sct_req = qbufp_count(pbufq, QBF_SCT_Q_REQ); |
| mutex_unlock(&pmsct->lock_ready); |
| |
| ready_set = cnt_sct_ready; |
| if (cnt_sct_ready && (cnt_wait < cnt_sct_ready)) { |
| //PR_INF("cnt_wait:%d->%d\n", cnt_wait, cnt_sct_ready); |
| //cnt_sct_ready = cnt_wait; |
| ready_set = cnt_wait; |
| if (!cnt_wait) |
| f_no_wbuf = true; |
| } |
| |
| if (ready_set) { |
| /* ready to used */ |
| for (i = 0; i < ready_set; i++) { |
| ret = qsct_ready_to_used(pch, &sct); |
| if (!ret) { |
| bset(&pmsct->flg_err, EDIM_SCT_ERR_QUE_2USED); |
| err++; |
| PR_ERR("%s:ready 2 used no sct\n", __func__); |
| break; |
| } |
| /*flash*/ |
| pat_frash(&devp->pdev->dev, |
| pch, |
| sct->pat_buf); |
| /* set free buffer*/ |
| di_buf = di_que_out_to_di_buf(ch, QUE_PST_NO_BUF_WAIT); |
| if (!di_buf) { |
| di_que_in(ch, QUE_PST_NO_BUF_WAIT, di_buf); |
| break; |
| } |
| di_buf->blk_buf->pat_buf = sct->pat_buf; |
| di_buf->blk_buf->sct = sct; |
| |
| di_buf->afbct_adr = sct->pat_buf->mem_start; |
| di_que_in(ch, QUE_POST_FREE, di_buf); |
| cnt_pst_free++; |
| cnt_sct_ready--; |
| } |
| //cnt_sct_ready = 0; |
| } |
| |
| if ((cnt_pst_free >= DIM_SCT_KEEP_READY) || |
| (dbg_limit_ready() && (cnt_pst_ready >= 3))) { |
| if (pmsct->flg_no_buf) { |
| pmsct->flg_no_buf = 0; |
| pch->rsc_bypass.b.no_buf = 0;/*tmp*/ |
| PR_WARN("no buffer:recover[%d]\n", frame_nub); |
| } |
| return; |
| } |
| if ((cnt_pst_free + cnt_sct_req + cnt_sct_ready) >= DIM_SCT_KEEP_READY) |
| return; |
| |
| need_req = DIM_SCT_KEEP_READY - cnt_pst_free - cnt_sct_req - |
| cnt_sct_ready; |
| |
| if (cnt_idle >= need_req) { |
| f_req = true; |
| } else if (cnt_idle > 0) { |
| need_req = cnt_idle; |
| f_req = true; |
| } |
| |
| if (f_req /*&& pat_buf && pat_buf->vaddr*/) { |
| /* required */ |
| |
| for (i = 0; i < need_req; i++) { |
| pat_buf = qpat_out_ready(pch); |
| //mm = dim_mm_get(pch->ch_id); |
| if (pat_buf) { |
| pat_set_vaddr(pat_buf, |
| mm->cfg.pst_afbct_size); |
| #if 1 |
| /* cash */ |
| if ((dbg_sct_clear_first() && |
| (!pat_buf->flg_mode)) || |
| dbg_sct_clear_by_frame()) { |
| pat_clear_mem(&devp->pdev->dev, |
| pch, |
| pat_buf); |
| pat_buf->flg_mode = 1; |
| } |
| #endif |
| } else { |
| PR_ERR("%s:no pat\n", __func__); |
| err++; |
| break; |
| } |
| |
| mutex_lock(&pmsct->lock_ready); |
| ret = qsct_idle_to_req(pch, &sct); |
| sct->pat_buf = pat_buf; |
| sct->flg_act.b.pat = 1; |
| |
| mutex_unlock(&pmsct->lock_ready); |
| if (!ret) { |
| bset(&pmsct->flg_err, EDIM_SCT_ERR_QUE_2REQ); |
| err++; |
| break; |
| } |
| cnt_sct_req++; |
| req_new++; |
| } |
| //if (req_new) |
| // mtask_wake_for_sct(); |
| } else if (cnt_pst_ready >= 1) { |
| } else { |
| /* no resource */ |
| if (f_no_wbuf) |
| PR_WARN("no_buf:0:cnt_wait:%d[%d]\n", cnt_sct_ready, |
| frame_nub); |
| |
| if (pch->rsc_bypass.b.no_buf) { |
| if (time_after_eq(jiffies, |
| pmsct->jiff_no_buf + HZ * 3)) { |
| //print: |
| PR_WARN("no buffer:3:[%d]\n", frame_nub); |
| pmsct->jiff_no_buf = jiffies; |
| } |
| } else if (pmsct->flg_no_buf) { |
| if (time_after_eq(jiffies, |
| pmsct->jiff_no_buf + HZ)) { |
| pch->rsc_bypass.b.no_buf = 1; |
| PR_WARN("no_buf:2:[%d]\n", frame_nub); |
| } |
| } else { |
| pmsct->flg_no_buf = 1; |
| pmsct->jiff_no_buf = jiffies; |
| PR_WARN("no_buf:1:[%d:%d:%d:%d]\n", |
| frame_nub, |
| cnt_pst_free, |
| cnt_idle, |
| cnt_sct_req); |
| } |
| } |
| if (err) |
| pch->rsc_bypass.b.scr_err = 1; |
| } |
| |
| /* now no use */ |
| void sct_mng_idle(struct di_ch_s *pch) |
| { |
| struct dim_mscttop_s *pmsct; |
| unsigned int cnt_recycle, cnt_idle; |
| struct buf_que_s *pbufq; |
| struct dim_sct_s *sct; |
| int i; |
| |
| pmsct = &pch->msct_top; |
| |
| if (!pmsct->box) |
| return; |
| |
| /* recycle */ |
| pbufq = &pch->sct_qb; |
| cnt_recycle = qbufp_count(pbufq, QBF_SCT_Q_RECYCLE); |
| if (!cnt_recycle) |
| return; |
| for (i = 0; i < cnt_recycle; i++) { |
| qsct_recycle_to_idle(pch, &sct); |
| |
| /* pat */ |
| pat_release_vaddr(sct->pat_buf); |
| qpat_in_ready(pch, sct->pat_buf); |
| sct->pat_buf = NULL; |
| sct_free_l(pch, sct); |
| } |
| |
| cnt_idle = qbufp_count(pbufq, QBF_SCT_Q_IDLE); |
| |
| if ((cnt_idle == DIM_SCT_NUB) && |
| (pmsct->box)) { |
| di_mmu_box_free(pmsct->box); |
| pmsct->box = NULL; |
| pmsct->flg_act_box = 0; |
| pmsct->max_nub = 0; |
| PR_INF("%s:release\n", __func__); |
| } else { |
| PR_INF("%s:cnt_idle=%d\n", __func__, cnt_idle); |
| } |
| } |
| |
| /* sw off when rebuild */ |
| void sct_sw_off_rebuild(struct di_ch_s *pch) |
| { |
| unsigned int ch; |
| struct dim_mscttop_s *psct; |
| struct buf_que_s *pbufq; |
| //union q_buf_u q_buf;// = NULL; |
| struct dim_sct_s *sct; |
| // struct di_buf_s *di_buf; |
| int i; |
| unsigned int len; |
| bool ret; |
| |
| psct = &pch->msct_top; |
| if (!psct->box) { |
| PR_WARN("%s:box is not exist\n", __func__); |
| return; |
| } |
| ch = pch->ch_id; |
| |
| #ifdef HIS_CODE |
| /* clear QUE_POST_FREE */ |
| for (i = 0; i < 2; i++) { |
| di_buf = di_que_peek(ch, QUE_POST_FREE); |
| if (di_buf->blk_buf && di_buf->blk_buf->sct) { |
| di_buf = di_que_out_to_di_buf(ch, QUE_POST_FREE); |
| sct = (struct dim_sct_s *)di_buf->blk_buf->sct; |
| qsct_used_some_to_recycle(pch, sct); |
| di_buf->afbct_adr = 0; |
| di_buf->blk_buf->sct = NULL; |
| di_buf->blk_buf->pat_buf = NULL; |
| di_que_in(ch, QUE_PST_NO_BUF_WAIT, di_buf); |
| } else { |
| break; |
| } |
| } |
| #endif |
| pbufq = &pch->sct_qb; |
| /* clear req */ |
| len = qbufp_count(pbufq, QBF_SCT_Q_REQ); |
| if (len) { |
| for (i = 0; i < len; i++) { |
| ret = qsct_req_to_idle(pch, &sct); |
| if (!ret) { |
| PR_ERR("%s:clear req[%d][%d]\n", __func__, |
| len, i); |
| break; |
| } |
| /*pat*/ |
| if (sct->pat_buf) { |
| pat_release_vaddr(sct->pat_buf); |
| qpat_in_ready(pch, sct->pat_buf); |
| sct->pat_buf = NULL; |
| } |
| } |
| } |
| |
| /* ready clear */ |
| len = qbufp_count(pbufq, QBF_SCT_Q_READY); |
| if (len) { |
| for (i = 0; i < len; i++) { |
| ret = qsct_any_to_recycle(pch, QBF_SCT_Q_READY, &sct); |
| if (!ret) { |
| PR_ERR("%s:used[%d][%d]\n", __func__, len, i); |
| break; |
| } |
| } |
| } |
| } |
| |
| int dim_dbg_sct_top_show(struct seq_file *s, void *what) |
| { |
| int *chp; |
| struct di_ch_s *pch; |
| struct dim_mscttop_s *psct; |
| struct dim_msc_sum_s *psum; |
| |
| chp = (int *)s->private; |
| |
| seq_printf(s, "%s:ch[%d]\n", __func__, *chp); |
| pch = get_chdata(*chp); |
| |
| psct = &pch->msct_top; |
| psum = &psct->sum; |
| seq_printf(s, "\t%s:0x%x\n", "err", psct->flg_err); |
| seq_printf(s, "\t%s:%d\n", "max_nub", psct->max_nub); |
| |
| seq_printf(s, "\t%s:%d\n", "flg_support", psct->flg_support); |
| seq_printf(s, "\t%s:%d\n", "flg_no_buf", psct->flg_no_buf); |
| seq_printf(s, "\t%s:%d\n", "flg_act_box", psct->flg_act_box); |
| seq_printf(s, "\t%s:%d\n", "flg_trig_dis", psct->flg_trig_dis); |
| seq_printf(s, "\t%s:%d\n", "flg_allocing", psct->flg_allocing); |
| seq_printf(s, "%s:\n", "sum"); |
| seq_printf(s, "\t%s:%d\n", "max_nub", psum->max_nub); |
| seq_printf(s, "\t%s:%d\n", "max_size", psum->max_size); |
| //seq_printf(s, "\t%s:%d\n", "sum_max_tt_size", psct->sum_max_tt_size); |
| seq_printf(s, "\t%s:%d\n", "max_tt_size2", psum->max_tt_size2); |
| seq_printf(s, "\t%s:%d\n", "curr_tt_size", psum->curr_tt_size); |
| seq_printf(s, "\t%s:%d\n", "curr_nub", psum->curr_nub); |
| seq_printf(s, "\t%s:\n", "pst"); |
| seq_printf(s, "\t\t%s:%d\n", "free", psum->mts_pst_free); |
| seq_printf(s, "\t\t%s:%d\n", "back", psum->mts_pst_back); |
| seq_printf(s, "\t\t%s:%d\n", "display", psum->mts_pst_dispaly); |
| seq_printf(s, "\t\t%s:%d\n", "ready", psum->mts_pst_ready); |
| seq_printf(s, "\t%s:\n", "sct"); |
| seq_printf(s, "\t\t%s:%d\n", "rcc", psum->mts_sct_rcc); |
| seq_printf(s, "\t\t%s:%d\n", "ready", psum->mts_sct_ready); |
| seq_printf(s, "\t\t%s:%d\n", "used", psum->mts_sct_used); |
| return 0; |
| } |
| |
| void sct_prob(struct di_ch_s *pch) |
| { |
| struct dim_mscttop_s *psct; |
| |
| psct = &pch->msct_top; |
| |
| psct->flg_support = 1; |
| mutex_init(&psct->lock_ready); |
| di_mmu_box_init(); |
| dbg_sct("%s:ch[%d]\n", __func__, pch->ch_id); |
| } |