video: rockchip: mpp: fix iep2 page-fault issue

The issue occurs when mode is I1O1T in 1080p.

Change-Id: I3ac5167d1bf0eb13dd4b48056f38bee3cf0dedf1
Signed-off-by: Xueman Ruan <xueman.ruan@rock-chips.com>
This commit is contained in:
Xueman Ruan
2024-07-01 09:31:40 +08:00
parent 8449b4d2c2
commit cdc9ee0588

View File

@@ -36,6 +36,9 @@
#define MVL 28
#define MVR 27
#define IOMMU_GET_BUS_ID(x) (((x) >> 6) & 0x1f)
#define AUX_PAGE_SIZE SZ_4K
enum rockchip_iep2_fmt {
ROCKCHIP_IEP2_FMT_YUV422 = 2,
ROCKCHIP_IEP2_FMT_YUV420
@@ -193,6 +196,12 @@ struct iep2_output {
u32 y_end[8];
};
struct iep2_session_priv {
/* workaround for pagefault */
unsigned long aux_iova;
struct page *aux_page;
};
struct iep_task {
struct mpp_task mpp_task;
struct mpp_hw_info *hw_info;
@@ -247,6 +256,8 @@ static int iep2_process_reg_fd(struct mpp_session *session,
ARRAY_SIZE(task->params.dst) * 3 + 2;
u32 *paddr = &task->params.src[0].y;
struct mpp_dev *mpp = session->mpp;
struct iep2_session_priv *priv = session->priv;
for (i = 0; i < addr_num; ++i) {
int usr_fd;
@@ -279,6 +290,27 @@ static int iep2_process_reg_fd(struct mpp_session *session,
mpp_debug(DEBUG_IOMMU, "reg[%3d]: %3d => %pad + offset %u\n",
iep2_addr_rnum[i], usr_fd, &mem_region->iova, offset);
paddr[i] = mem_region->iova + offset;
/* workaround for invalid access to src image */
if (task->params.dil_mode == ROCKCHIP_IEP2_DIL_MODE_I1O1T &&
iep2_addr_rnum[i] == 24 && priv->aux_page) {
int ret = 0;
unsigned long page_iova = mem_region->iova + mem_region->len;
if (priv->aux_iova != -1) {
iommu_unmap(mpp->iommu_info->domain, priv->aux_iova, AUX_PAGE_SIZE);
priv->aux_iova = -1;
}
page_iova = round_down(page_iova, AUX_PAGE_SIZE);
ret = iommu_map(mpp->iommu_info->domain, page_iova,
page_to_phys(priv->aux_page), AUX_PAGE_SIZE,
IOMMU_READ);
if (!ret) {
priv->aux_iova = page_iova;
mpp_debug(DEBUG_IOMMU, "aux iova %lx\n", page_iova);
}
}
}
return 0;
@@ -765,6 +797,12 @@ static int iep2_free_task(struct mpp_session *session,
struct mpp_task *mpp_task)
{
struct iep_task *task = to_iep_task(mpp_task);
struct iep2_session_priv *priv = session->priv;
if (priv->aux_iova != -1) {
iommu_unmap(session->mpp->iommu_info->domain, priv->aux_iova, AUX_PAGE_SIZE);
priv->aux_iova = -1;
}
mpp_task_finalize(session, mpp_task);
kfree(task);
@@ -928,6 +966,55 @@ static int iep2_reset(struct mpp_dev *mpp)
return 0;
}
static int iep2_init_session(struct mpp_session *session)
{
struct iep2_session_priv *priv;
if (!session) {
mpp_err("session is null\n");
return -EINVAL;
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* warkaround for mmu pagefault */
priv->aux_iova = -1;
priv->aux_page = alloc_page(GFP_KERNEL);
if (!priv->aux_page) {
dev_err(session->mpp->dev, "allocate a page for auxiliary usage\n");
priv->aux_page = NULL;
}
session->priv = priv;
return 0;
}
static int iep2_free_session(struct mpp_session *session)
{
if (session && session->priv) {
struct iep2_session_priv *priv = session->priv;
struct mpp_dev *mpp = session->mpp;
if (priv->aux_iova != -1) {
iommu_unmap(mpp->iommu_info->domain, priv->aux_iova, AUX_PAGE_SIZE);
priv->aux_iova = -1;
}
if (priv->aux_page) {
__free_page(priv->aux_page);
priv->aux_page = NULL;
}
kfree(session->priv);
session->priv = NULL;
}
return 0;
}
static struct mpp_hw_ops iep_v2_hw_ops = {
.init = iep2_init,
.clk_on = iep2_clk_on,
@@ -944,6 +1031,8 @@ static struct mpp_dev_ops iep_v2_dev_ops = {
.finish = iep2_finish,
.result = iep2_result,
.free_task = iep2_free_task,
.init_session = iep2_init_session,
.free_session = iep2_free_session,
};
static struct mpp_hw_info iep2_hw_info = {