diff options
author | Jung Zhao <jung.zhao@rock-chips.com> | 2018-01-02 15:51:46 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2018-01-05 09:22:00 +0800 |
commit | 87e3d09740dc42582101869a577edf0cd249d609 (patch) | |
tree | 013cc55c6215105f7e4b03d6a49f7a0d2bbd6541 /drivers | |
parent | 1d4da5168ece408f7830b5e2fe8459889f454c59 (diff) |
video: rockchip: vpu: fix page fault crash
Change-Id: I71c3629cec0ee7903770170de15acb73e67298d2
Signed-off-by: Jung Zhao <jung.zhao@rock-chips.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/rockchip/vcodec/vcodec_iommu_drm.c | 19 | ||||
-rw-r--r-- | drivers/video/rockchip/vcodec/vcodec_service.c | 25 |
2 files changed, 22 insertions, 22 deletions
diff --git a/drivers/video/rockchip/vcodec/vcodec_iommu_drm.c b/drivers/video/rockchip/vcodec/vcodec_iommu_drm.c index dcf9d15d1e6b..cbc47b92b3e1 100644 --- a/drivers/video/rockchip/vcodec/vcodec_iommu_drm.c +++ b/drivers/video/rockchip/vcodec/vcodec_iommu_drm.c @@ -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); } diff --git a/drivers/video/rockchip/vcodec/vcodec_service.c b/drivers/video/rockchip/vcodec/vcodec_service.c index a357a3332ea7..629d3ac44f14 100644 --- a/drivers/video/rockchip/vcodec/vcodec_service.c +++ b/drivers/video/rockchip/vcodec/vcodec_service.c @@ -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(®->mem_region_list)) { list_for_each_entry_safe(mem, n, ®->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); |