video: rockchip: vpu: fix page fault crash

Change-Id: I71c3629cec0ee7903770170de15acb73e67298d2
Signed-off-by: Jung Zhao <jung.zhao@rock-chips.com>
This commit is contained in:
Jung Zhao
2018-01-02 15:51:46 +08:00
committed by Tao Huang
parent 1d4da5168e
commit 87e3d09740
2 changed files with 22 additions and 22 deletions

View File

@@ -309,15 +309,10 @@ vcodec_drm_map_iommu_with_iova(struct vcodec_iommu_session_info *session_info,
drm_buffer->iova_out = iova;
iommu_map_sg(drm_info->domain,
iova,
drm_buffer->copy_sgt->sgl,
drm_buffer->copy_sgt->nents,
IOMMU_READ | IOMMU_WRITE);
return vcodec_finalise_sg(drm_buffer->copy_sgt->sgl,
drm_buffer->copy_sgt->nents,
iova);
return iommu_map(drm_info->domain,
iova,
sg_phys(drm_buffer->copy_sgt->sgl),
size, IOMMU_READ | IOMMU_WRITE);
}
static void*
@@ -836,11 +831,11 @@ static int vcodec_drm_alloc(struct vcodec_iommu_session_info *session_info,
while (size_remaining > 0) {
gfp_t gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN |
__GFP_NORETRY) & ~__GFP_DIRECT_RECLAIM;
page = alloc_pages(gfp_flags | __GFP_COMP, 8);
page = alloc_pages(gfp_flags | __GFP_COMP, 1);
if (!page)
goto free_pages;
size_remaining -= PAGE_SIZE << compound_order(page);
size_remaining -= PAGE_SIZE;
list_add_tail(&page->lru, &pages);
i++;
}
@@ -854,7 +849,7 @@ static int vcodec_drm_alloc(struct vcodec_iommu_session_info *session_info,
sg = table->sgl;
list_for_each_entry_safe(page, tmp_page, &pages, lru) {
sg_set_page(sg, page, PAGE_SIZE << compound_order(page), 0);
sg_set_page(sg, page, PAGE_SIZE, 0);
sg = sg_next(sg);
list_del(&page->lru);
}

View File

@@ -717,7 +717,10 @@ static void vpu_reset(struct vpu_subdev_data *data)
mutex_lock(&pservice->reset_lock);
_vpu_reset(data);
mutex_unlock(&pservice->reset_lock);
if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
if (data->mmu_dev && test_bit(MMU_PAGEFAULT, &data->state)) {
clear_bit(MMU_ACTIVATED, &data->state);
clear_bit(MMU_PAGEFAULT, &data->state);
} else if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
clear_bit(MMU_ACTIVATED, &data->state);
if (atomic_read(&pservice->enabled)) {
/* Need to reset iommu */
@@ -2174,7 +2177,7 @@ static void vcodec_power_off_default(struct vpu_service_info *pservice)
clk_disable_unprepare(pservice->clk_core);
if (pservice->clk_cabac)
clk_disable_unprepare(pservice->clk_cabac);
pm_runtime_get_sync(pservice->dev);
pm_runtime_put(pservice->dev);
}
static void vcodec_power_off_rk322x(struct vpu_service_info *pservice)
@@ -2439,12 +2442,14 @@ _vcodec_sys_fault_hdl(struct device *dev, unsigned long iova, int status)
struct vpu_reg *reg = pservice->reg_codec;
struct vcodec_mem_region *mem = NULL, *n = NULL;
int i = 0;
unsigned long tmp_iova = mem->iova;
dev_err(dev, "vcodec, fault addr 0x%08lx\n", iova);
dev_err(dev, "vcodec, fault addr 0x%08lx status %x\n", iova,
status);
if (!list_empty(&reg->mem_region_list)) {
list_for_each_entry_safe(mem, n, &reg->mem_region_list,
reg_lnk) {
unsigned long tmp_iova = mem->iova;
dev_err(dev, "vcodec, reg[%02u] mem region [%02d] 0x%lx %lx\n",
mem->reg_idx, i, tmp_iova, mem->len);
i++;
@@ -2471,9 +2476,9 @@ _vcodec_sys_fault_hdl(struct device *dev, unsigned long iova, int status)
* defeat workaround, invalidate address generated when rk322x
* vdec pre-fetch colmv data.
*/
if (IOMMU_GET_BUS_ID(status) == 2 && data->pa_hdl) {
if (IOMMU_GET_BUS_ID(status) == 2 && data->pa_hdl >= 0) {
/* avoid another page fault occur after page fault */
if (data->pa_iova)
if (data->pa_iova != -1)
vcodec_iommu_unmap_iommu_with_iova(data->iommu_info,
session,
data->pa_hdl);
@@ -2487,7 +2492,7 @@ _vcodec_sys_fault_hdl(struct device *dev, unsigned long iova, int status)
data->pa_iova,
IOMMU_PAGE_SIZE);
} else {
_vpu_reset(data);
vpu_reset(data);
}
}
@@ -2778,7 +2783,7 @@ static int vcodec_subdev_probe(struct platform_device *pdev,
vcodec_iommu_map_iommu(data->iommu_info, session,
data->pa_hdl, NULL, NULL);
data->pa_iova = 0;
data->pa_iova = -1;
vcodec_exit_mode(data);
hw_info = data->hw_info;
@@ -3551,11 +3556,11 @@ static irqreturn_t vdpu_isr(int irq, void *dev_id)
vpu_err("error: dec isr with no task waiting\n");
} else {
if (test_bit(MMU_PAGEFAULT, &data->state) &&
data->pa_iova) {
data->pa_iova != -1) {
vcodec_iommu_unmap_iommu_with_iova(data->iommu_info,
session,
data->pa_hdl);
data->pa_iova = 0;
data->pa_iova = -1;
clear_bit(MMU_PAGEFAULT, &data->state);
}
reg_from_run_to_done(data, pservice->reg_codec);