diff options
Diffstat (limited to 'drivers/gpu/arm/midgard/mali_kbase_jd.c')
-rw-r--r-- | drivers/gpu/arm/midgard/mali_kbase_jd.c | 939 |
1 files changed, 549 insertions, 390 deletions
diff --git a/drivers/gpu/arm/midgard/mali_kbase_jd.c b/drivers/gpu/arm/midgard/mali_kbase_jd.c index 3e0a5892cc7a..1f9fbd9ee6d0 100644 --- a/drivers/gpu/arm/midgard/mali_kbase_jd.c +++ b/drivers/gpu/arm/midgard/mali_kbase_jd.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -25,15 +25,20 @@ #endif #include <mali_kbase.h> #include <mali_kbase_uku.h> +#ifdef CONFIG_UMP +#include <linux/ump.h> +#endif /* CONFIG_UMP */ #include <linux/random.h> #include <linux/version.h> #include <linux/ratelimit.h> +#include <linux/pagemap.h> #include <mali_kbase_jm.h> #include <mali_kbase_hwaccess_jm.h> -#include <mali_kbase_tlstream.h> -#include "mali_kbase_dma_fence.h" +#if defined(CONFIG_MALI_MIPE_ENABLED) +#include <mali_kbase_tlstream.h> +#endif #define beenthere(kctx, f, a...) dev_dbg(kctx->kbdev->dev, "%s:" f, __func__, ##a) @@ -45,7 +50,7 @@ /* Return whether katom will run on the GPU or not. Currently only soft jobs and * dependency-only atoms do not run on the GPU */ #define IS_GPU_ATOM(katom) (!((katom->core_req & BASE_JD_REQ_SOFT_JOB) || \ - ((katom->core_req & BASE_JD_REQ_ATOM_TYPE) == \ + ((katom->core_req & BASEP_JD_REQ_ATOM_TYPE) == \ BASE_JD_REQ_DEP))) /* * This is the kernel side of the API. Only entry points are: @@ -80,23 +85,22 @@ static int jd_run_atom(struct kbase_jd_atom *katom) KBASE_DEBUG_ASSERT(katom->status != KBASE_JD_ATOM_STATE_UNUSED); - if ((katom->core_req & BASE_JD_REQ_ATOM_TYPE) == BASE_JD_REQ_DEP) { + if ((katom->core_req & BASEP_JD_REQ_ATOM_TYPE) == BASE_JD_REQ_DEP) { /* Dependency only atom */ katom->status = KBASE_JD_ATOM_STATE_COMPLETED; return 0; } else if (katom->core_req & BASE_JD_REQ_SOFT_JOB) { /* Soft-job */ - if (katom->will_fail_event_code) { - katom->status = KBASE_JD_ATOM_STATE_COMPLETED; - return 0; - } - if ((katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) + if ((katom->core_req & BASEP_JD_REQ_ATOM_TYPE) == BASE_JD_REQ_SOFT_REPLAY) { if (!kbase_replay_process(katom)) katom->status = KBASE_JD_ATOM_STATE_COMPLETED; } else if (kbase_process_soft_job(katom) == 0) { kbase_finish_soft_job(katom); katom->status = KBASE_JD_ATOM_STATE_COMPLETED; + } else { + /* The job has not completed */ + list_add_tail(&katom->dep_item[0], &kctx->waiting_soft_jobs); } return 0; } @@ -106,39 +110,6 @@ static int jd_run_atom(struct kbase_jd_atom *katom) return kbasep_js_add_job(kctx, katom); } -#if defined(CONFIG_KDS) || defined(CONFIG_MALI_DMA_FENCE) -void kbase_jd_dep_clear_locked(struct kbase_jd_atom *katom) -{ - struct kbase_device *kbdev; - - KBASE_DEBUG_ASSERT(katom); - kbdev = katom->kctx->kbdev; - KBASE_DEBUG_ASSERT(kbdev); - - /* Check whether the atom's other dependencies were already met. If - * katom is a GPU atom then the job scheduler may be able to represent - * the dependencies, hence we may attempt to submit it before they are - * met. Other atoms must have had both dependencies resolved. - */ - if (IS_GPU_ATOM(katom) || - (!kbase_jd_katom_dep_atom(&katom->dep[0]) && - !kbase_jd_katom_dep_atom(&katom->dep[1]))) { - /* katom dep complete, attempt to run it */ - bool resched = false; - - resched = jd_run_atom(katom); - - if (katom->status == KBASE_JD_ATOM_STATE_COMPLETED) { - /* The atom has already finished */ - resched |= jd_done_nolock(katom, NULL); - } - - if (resched) - kbase_js_sched_all(kbdev); - } -} -#endif - #ifdef CONFIG_KDS /* Add the katom to the kds waiting list. @@ -171,20 +142,44 @@ static void kds_dep_clear(void *callback_parameter, void *callback_extra_paramet { struct kbase_jd_atom *katom; struct kbase_jd_context *ctx; + struct kbase_device *kbdev; katom = (struct kbase_jd_atom *)callback_parameter; KBASE_DEBUG_ASSERT(katom); - ctx = &katom->kctx->jctx; + kbdev = katom->kctx->kbdev; + KBASE_DEBUG_ASSERT(kbdev); - /* If KDS resource has already been satisfied (e.g. due to zapping) - * do nothing. - */ mutex_lock(&ctx->lock); - if (!katom->kds_dep_satisfied) { - katom->kds_dep_satisfied = true; - kbase_jd_dep_clear_locked(katom); + + /* KDS resource has already been satisfied (e.g. due to zapping) */ + if (katom->kds_dep_satisfied) + goto out; + + /* This atom's KDS dependency has now been met */ + katom->kds_dep_satisfied = true; + + /* Check whether the atom's other dependencies were already met. If + * katom is a GPU atom then the job scheduler may be able to represent + * the dependencies, hence we may attempt to submit it before they are + * met. Other atoms must have had both dependencies resolved */ + if (IS_GPU_ATOM(katom) || + (!kbase_jd_katom_dep_atom(&katom->dep[0]) && + !kbase_jd_katom_dep_atom(&katom->dep[1]))) { + /* katom dep complete, attempt to run it */ + bool resched = false; + + resched = jd_run_atom(katom); + + if (katom->status == KBASE_JD_ATOM_STATE_COMPLETED) { + /* The atom has already finished */ + resched |= jd_done_nolock(katom, NULL); + } + + if (resched) + kbase_js_sched_all(kbdev); } + out: mutex_unlock(&ctx->lock); } @@ -204,6 +199,208 @@ static void kbase_cancel_kds_wait_job(struct kbase_jd_atom *katom) } #endif /* CONFIG_KDS */ +static int kbase_jd_user_buf_map(struct kbase_context *kctx, + struct kbase_va_region *reg) +{ + long pinned_pages; + struct kbase_mem_phy_alloc *alloc; + struct page **pages; + phys_addr_t *pa; + long i; + int err = -ENOMEM; + unsigned long address; + struct task_struct *owner; + struct device *dev; + unsigned long offset; + unsigned long local_size; + + alloc = reg->gpu_alloc; + pa = kbase_get_gpu_phy_pages(reg); + address = alloc->imported.user_buf.address; + owner = alloc->imported.user_buf.owner; + + KBASE_DEBUG_ASSERT(alloc->type == KBASE_MEM_TYPE_IMPORTED_USER_BUF); + + pages = alloc->imported.user_buf.pages; + + down_read(&owner->mm->mmap_sem); + pinned_pages = get_user_pages(owner, owner->mm, + address, + alloc->imported.user_buf.nr_pages, + reg->flags & KBASE_REG_GPU_WR, + 0, pages, NULL); + up_read(&owner->mm->mmap_sem); + + if (pinned_pages <= 0) + return pinned_pages; + + if (pinned_pages != alloc->imported.user_buf.nr_pages) { + for (i = 0; i < pinned_pages; i++) + put_page(pages[i]); + return -ENOMEM; + } + + dev = kctx->kbdev->dev; + offset = address & ~PAGE_MASK; + local_size = alloc->imported.user_buf.size; + + for (i = 0; i < pinned_pages; i++) { + dma_addr_t dma_addr; + unsigned long min; + + min = MIN(PAGE_SIZE - offset, local_size); + dma_addr = dma_map_page(dev, pages[i], + offset, min, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, dma_addr)) + goto unwind; + + alloc->imported.user_buf.dma_addrs[i] = dma_addr; + pa[i] = page_to_phys(pages[i]); + + local_size -= min; + offset = 0; + } + + alloc->nents = pinned_pages; + + err = kbase_mmu_insert_pages(kctx, reg->start_pfn, pa, + kbase_reg_current_backed_size(reg), + reg->flags); + if (err == 0) + return 0; + + alloc->nents = 0; + /* fall down */ +unwind: + while (i--) { + dma_unmap_page(kctx->kbdev->dev, + alloc->imported.user_buf.dma_addrs[i], + PAGE_SIZE, DMA_BIDIRECTIONAL); + put_page(pages[i]); + pages[i] = NULL; + } + + return err; +} + +static void kbase_jd_user_buf_unmap(struct kbase_context *kctx, + struct kbase_mem_phy_alloc *alloc, bool writeable) +{ + long i; + struct page **pages; + unsigned long size = alloc->imported.user_buf.size; + + KBASE_DEBUG_ASSERT(alloc->type == KBASE_MEM_TYPE_IMPORTED_USER_BUF); + pages = alloc->imported.user_buf.pages; + for (i = 0; i < alloc->imported.user_buf.nr_pages; i++) { + unsigned long local_size; + dma_addr_t dma_addr = alloc->imported.user_buf.dma_addrs[i]; + + local_size = MIN(size, PAGE_SIZE - (dma_addr & ~PAGE_MASK)); + dma_unmap_page(kctx->kbdev->dev, dma_addr, local_size, + DMA_BIDIRECTIONAL); + if (writeable) + set_page_dirty_lock(pages[i]); + put_page(pages[i]); + pages[i] = NULL; + + size -= local_size; + } + alloc->nents = 0; +} + +/* not to use sg_dma_len. */ +#define MALI_SG_DMA_LEN(sg) ((sg)->length) + +#ifdef CONFIG_DMA_SHARED_BUFFER +static int kbase_jd_umm_map(struct kbase_context *kctx, struct kbase_va_region *reg) +{ + struct sg_table *sgt; /* scatterlist_table */ + struct scatterlist *s; + int i; + phys_addr_t *pa; + int err; + size_t count = 0; + struct kbase_mem_phy_alloc *alloc; + + alloc = reg->gpu_alloc; + + KBASE_DEBUG_ASSERT(alloc->type == KBASE_MEM_TYPE_IMPORTED_UMM); + KBASE_DEBUG_ASSERT(NULL == alloc->imported.umm.sgt); + sgt = dma_buf_map_attachment(alloc->imported.umm.dma_attachment, DMA_BIDIRECTIONAL); + + if (IS_ERR_OR_NULL(sgt)) + return -EINVAL; + + /* save for later */ + alloc->imported.umm.sgt = sgt; + + pa = kbase_get_gpu_phy_pages(reg); + KBASE_DEBUG_ASSERT(pa); + + for_each_sg(sgt->sgl, s, sgt->nents, i) { + int j; + /* size_t pages = PFN_UP(sg_dma_len(s)); */ + size_t pages = PFN_UP(MALI_SG_DMA_LEN(s)); + + WARN_ONCE(MALI_SG_DMA_LEN(s) & (PAGE_SIZE-1), + "MALI_SG_DMA_LEN(s)=%u is not a multiple of PAGE_SIZE\n", + MALI_SG_DMA_LEN(s)); + /* + WARN_ONCE(sg_dma_len(s) & (PAGE_SIZE-1), + "sg_dma_len(s)=%u is not a multiple of PAGE_SIZE\n", + sg_dma_len(s)); + */ + + WARN_ONCE(sg_dma_address(s) & (PAGE_SIZE-1), + "sg_dma_address(s)=%llx is not aligned to PAGE_SIZE\n", + (unsigned long long) sg_dma_address(s)); + + for (j = 0; (j < pages) && (count < reg->nr_pages); j++, count++) + *pa++ = sg_dma_address(s) + (j << PAGE_SHIFT); + + WARN_ONCE(j < pages, + "sg list from dma_buf_map_attachment > dma_buf->size=%zu\n", + alloc->imported.umm.dma_buf->size); + } + + if (WARN_ONCE(count < reg->nr_pages, + "sg list from dma_buf_map_attachment < dma_buf->size=%zu, count : %zu, reg->nr_pages : %zu. \n", + alloc->imported.umm.dma_buf->size, + count, + reg->nr_pages)) { + err = -EINVAL; + goto out; + } + + /* Update nents as we now have pages to map */ + alloc->nents = count; + + err = kbase_mmu_insert_pages(kctx, reg->start_pfn, kbase_get_gpu_phy_pages(reg), kbase_reg_current_backed_size(reg), reg->flags | KBASE_REG_GPU_WR | KBASE_REG_GPU_RD); + +out: + if (err) { + dma_buf_unmap_attachment(alloc->imported.umm.dma_attachment, alloc->imported.umm.sgt, DMA_BIDIRECTIONAL); + alloc->imported.umm.sgt = NULL; + } + + return err; +} + +static void kbase_jd_umm_unmap(struct kbase_context *kctx, struct kbase_mem_phy_alloc *alloc) +{ + KBASE_DEBUG_ASSERT(kctx); + KBASE_DEBUG_ASSERT(alloc); + KBASE_DEBUG_ASSERT(alloc->imported.umm.dma_attachment); + KBASE_DEBUG_ASSERT(alloc->imported.umm.sgt); + dma_buf_unmap_attachment(alloc->imported.umm.dma_attachment, + alloc->imported.umm.sgt, DMA_BIDIRECTIONAL); + alloc->imported.umm.sgt = NULL; + alloc->nents = 0; +} +#endif /* CONFIG_DMA_SHARED_BUFFER */ + void kbase_jd_free_external_resources(struct kbase_jd_atom *katom) { #ifdef CONFIG_KDS @@ -223,16 +420,6 @@ void kbase_jd_free_external_resources(struct kbase_jd_atom *katom) kds_resource_set_release_sync(&katom->kds_rset); } #endif /* CONFIG_KDS */ - -#ifdef CONFIG_MALI_DMA_FENCE - /* Flush dma-fence workqueue to ensure that any callbacks that may have - * been queued are done before continuing. - * Any successfully completed atom would have had all it's callbacks - * completed before the atom was run, so only flush for failed atoms. - */ - if (katom->event_code != BASE_JD_EVENT_DONE) - flush_workqueue(katom->kctx->dma_fence.wq); -#endif /* CONFIG_MALI_DMA_FENCE */ } static void kbase_jd_post_external_resources(struct kbase_jd_atom *katom) @@ -246,10 +433,6 @@ static void kbase_jd_post_external_resources(struct kbase_jd_atom *katom) katom->kds_dep_satisfied = true; #endif /* CONFIG_KDS */ -#ifdef CONFIG_MALI_DMA_FENCE - kbase_dma_fence_signal(katom); -#endif /* CONFIG_MALI_DMA_FENCE */ - kbase_gpu_vm_lock(katom->kctx); /* only roll back if extres is non-NULL */ if (katom->extres) { @@ -258,12 +441,56 @@ static void kbase_jd_post_external_resources(struct kbase_jd_atom *katom) res_no = katom->nr_extres; while (res_no-- > 0) { struct kbase_mem_phy_alloc *alloc = katom->extres[res_no].alloc; - struct kbase_va_region *reg; - reg = kbase_region_tracker_find_region_base_address( - katom->kctx, - katom->extres[res_no].gpu_address); - kbase_unmap_external_resource(katom->kctx, reg, alloc); + switch (alloc->type) { +#ifdef CONFIG_DMA_SHARED_BUFFER + case KBASE_MEM_TYPE_IMPORTED_UMM: { + alloc->imported.umm.current_mapping_usage_count--; + + if (0 == alloc->imported.umm.current_mapping_usage_count) { + struct kbase_va_region *reg; + + reg = kbase_region_tracker_find_region_base_address( + katom->kctx, + katom->extres[res_no].gpu_address); + + if (reg && reg->gpu_alloc == alloc) + kbase_mmu_teardown_pages( + katom->kctx, + reg->start_pfn, + kbase_reg_current_backed_size(reg)); + + kbase_jd_umm_unmap(katom->kctx, alloc); + } + } + break; +#endif /* CONFIG_DMA_SHARED_BUFFER */ + case KBASE_MEM_TYPE_IMPORTED_USER_BUF: { + alloc->imported.user_buf.current_mapping_usage_count--; + + if (0 == alloc->imported.user_buf.current_mapping_usage_count) { + struct kbase_va_region *reg; + + reg = kbase_region_tracker_find_region_base_address( + katom->kctx, + katom->extres[res_no].gpu_address); + + if (reg && reg->gpu_alloc == alloc) + kbase_mmu_teardown_pages( + katom->kctx, + reg->start_pfn, + kbase_reg_current_backed_size(reg)); + + kbase_jd_user_buf_unmap(katom->kctx, + alloc, + reg->flags & KBASE_REG_GPU_WR); + } + } + break; + default: + break; + } + kbase_mem_phy_alloc_put(katom->extres[res_no].alloc); } kfree(katom->extres); katom->extres = NULL; @@ -271,6 +498,24 @@ static void kbase_jd_post_external_resources(struct kbase_jd_atom *katom) kbase_gpu_vm_unlock(katom->kctx); } +#if (defined(CONFIG_KDS) && defined(CONFIG_UMP)) || defined(CONFIG_DMA_SHARED_BUFFER_USES_KDS) +static void add_kds_resource(struct kds_resource *kds_res, struct kds_resource **kds_resources, u32 *kds_res_count, unsigned long *kds_access_bitmap, bool exclusive) +{ + u32 i; + + for (i = 0; i < *kds_res_count; i++) { + /* Duplicate resource, ignore */ + if (kds_resources[i] == kds_res) + return; + } + + kds_resources[*kds_res_count] = kds_res; + if (exclusive) + set_bit(*kds_res_count, kds_access_bitmap); + (*kds_res_count)++; +} +#endif + /* * Set up external resources needed by this job. * @@ -286,11 +531,6 @@ static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const st struct kds_resource **kds_resources = NULL; unsigned long *kds_access_bitmap = NULL; #endif /* CONFIG_KDS */ -#ifdef CONFIG_MALI_DMA_FENCE - struct kbase_dma_fence_resv_info info = { - .dma_fence_resv_count = 0, - }; -#endif struct base_external_resource *input_extres; KBASE_DEBUG_ASSERT(katom); @@ -326,53 +566,27 @@ static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const st KBASE_DEBUG_ASSERT(0 != katom->nr_extres); kds_resources = kmalloc_array(katom->nr_extres, sizeof(struct kds_resource *), GFP_KERNEL); - if (!kds_resources) { + if (NULL == kds_resources) { err_ret_val = -ENOMEM; goto early_err_out; } KBASE_DEBUG_ASSERT(0 != katom->nr_extres); - kds_access_bitmap = kcalloc(BITS_TO_LONGS(katom->nr_extres), - sizeof(unsigned long), - GFP_KERNEL); - if (!kds_access_bitmap) { - err_ret_val = -ENOMEM; - goto early_err_out; - } -#endif /* CONFIG_KDS */ - -#ifdef CONFIG_MALI_DMA_FENCE - info.resv_objs = kmalloc_array(katom->nr_extres, - sizeof(struct reservation_object *), - GFP_KERNEL); - if (!info.resv_objs) { - err_ret_val = -ENOMEM; - goto early_err_out; - } + kds_access_bitmap = kzalloc(sizeof(unsigned long) * ((katom->nr_extres + BITS_PER_LONG - 1) / BITS_PER_LONG), GFP_KERNEL); - info.dma_fence_excl_bitmap = kcalloc(BITS_TO_LONGS(katom->nr_extres), - sizeof(unsigned long), - GFP_KERNEL); - if (!info.dma_fence_excl_bitmap) { + if (NULL == kds_access_bitmap) { err_ret_val = -ENOMEM; goto early_err_out; } -#endif /* CONFIG_MALI_DMA_FENCE */ - - /* Take the processes mmap lock */ - down_read(¤t->mm->mmap_sem); +#endif /* CONFIG_KDS */ /* need to keep the GPU VM locked while we set up UMM buffers */ kbase_gpu_vm_lock(katom->kctx); for (res_no = 0; res_no < katom->nr_extres; res_no++) { struct base_external_resource *res; struct kbase_va_region *reg; - struct kbase_mem_phy_alloc *alloc; - bool exclusive; res = &input_extres[res_no]; - exclusive = (res->ext_resource & BASE_EXT_RES_ACCESS_EXCLUSIVE) - ? true : false; reg = kbase_region_tracker_find_region_enclosing_address( katom->kctx, res->ext_resource & ~BASE_EXT_RES_ACCESS_EXCLUSIVE); @@ -384,31 +598,79 @@ static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const st if (!(katom->core_req & BASE_JD_REQ_SOFT_JOB) && (reg->flags & KBASE_REG_SECURE)) { - katom->atom_flags |= KBASE_KATOM_FLAG_PROTECTED; + katom->atom_flags |= KBASE_KATOM_FLAG_SECURE; + if ((katom->core_req & BASE_JD_REQ_FS) == 0) { + WARN_RATELIMIT(1, "Secure non-fragment jobs not supported"); + goto failed_loop; + } } - alloc = kbase_map_external_resource(katom->kctx, reg, - current->mm -#ifdef CONFIG_KDS - , &kds_res_count, kds_resources, - kds_access_bitmap, exclusive + /* decide what needs to happen for this resource */ + switch (reg->gpu_alloc->type) { + case BASE_MEM_IMPORT_TYPE_USER_BUFFER: { + reg->gpu_alloc->imported.user_buf.current_mapping_usage_count++; + if (1 == reg->gpu_alloc->imported.user_buf.current_mapping_usage_count) { + /* use a local variable to not pollute + * err_ret_val with a potential success + * value as some other gotos depend on + * the default error code stored in + * err_ret_val */ + int tmp; + + tmp = kbase_jd_user_buf_map(katom->kctx, + reg); + if (0 != tmp) { + /* failed to map this buffer, + * roll back */ + err_ret_val = tmp; + reg->gpu_alloc->imported.user_buf.current_mapping_usage_count--; + goto failed_loop; + } + } + } + break; + case BASE_MEM_IMPORT_TYPE_UMP: { +#if defined(CONFIG_KDS) && defined(CONFIG_UMP) + struct kds_resource *kds_res; + + kds_res = ump_dd_kds_resource_get(reg->gpu_alloc->imported.ump_handle); + if (kds_res) + add_kds_resource(kds_res, kds_resources, &kds_res_count, + kds_access_bitmap, + res->ext_resource & BASE_EXT_RES_ACCESS_EXCLUSIVE); +#endif /*defined(CONFIG_KDS) && defined(CONFIG_UMP) */ + break; + } +#ifdef CONFIG_DMA_SHARED_BUFFER + case BASE_MEM_IMPORT_TYPE_UMM: { +#ifdef CONFIG_DMA_SHARED_BUFFER_USES_KDS + struct kds_resource *kds_res; + + kds_res = get_dma_buf_kds_resource(reg->gpu_alloc->imported.umm.dma_buf); + if (kds_res) + add_kds_resource(kds_res, kds_resources, &kds_res_count, kds_access_bitmap, res->ext_resource & BASE_EXT_RES_ACCESS_EXCLUSIVE); #endif - ); - if (!alloc) { - err_ret_val = -EINVAL; - goto failed_loop; + reg->gpu_alloc->imported.umm.current_mapping_usage_count++; + if (1 == reg->gpu_alloc->imported.umm.current_mapping_usage_count) { + /* use a local variable to not pollute err_ret_val + * with a potential success value as some other gotos depend + * on the default error code stored in err_ret_val */ + int tmp; + + tmp = kbase_jd_umm_map(katom->kctx, reg); + if (tmp) { + /* failed to map this buffer, roll back */ + err_ret_val = tmp; + reg->gpu_alloc->imported.umm.current_mapping_usage_count--; + goto failed_loop; + } + } + break; } - -#ifdef CONFIG_MALI_DMA_FENCE - if (reg->gpu_alloc->type == KBASE_MEM_TYPE_IMPORTED_UMM) { - struct reservation_object *resv; - - resv = reg->gpu_alloc->imported.umm.dma_buf->resv; - if (resv) - kbase_dma_fence_add_reservation(resv, &info, - exclusive); +#endif + default: + goto failed_loop; } -#endif /* CONFIG_MALI_DMA_FENCE */ /* finish with updating out array with the data we found */ /* NOTE: It is important that this is the last thing we do (or @@ -417,15 +679,12 @@ static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const st * until the last read for an element. * */ katom->extres[res_no].gpu_address = reg->start_pfn << PAGE_SHIFT; /* save the start_pfn (as an address, not pfn) to use fast lookup later */ - katom->extres[res_no].alloc = alloc; + katom->extres[res_no].alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc); } /* successfully parsed the extres array */ /* drop the vm lock before we call into kds */ kbase_gpu_vm_unlock(katom->kctx); - /* Release the processes mmap lock */ - up_read(¤t->mm->mmap_sem); - #ifdef CONFIG_KDS if (kds_res_count) { int wait_failed; @@ -450,63 +709,46 @@ static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const st kfree(kds_access_bitmap); #endif /* CONFIG_KDS */ -#ifdef CONFIG_MALI_DMA_FENCE - if (info.dma_fence_resv_count) { - int ret; - - ret = kbase_dma_fence_wait(katom, &info); - if (ret < 0) - goto failed_dma_fence_setup; - } - - kfree(info.resv_objs); - kfree(info.dma_fence_excl_bitmap); -#endif /* CONFIG_MALI_DMA_FENCE */ - /* all done OK */ return 0; /* error handling section */ -#ifdef CONFIG_MALI_DMA_FENCE -failed_dma_fence_setup: #ifdef CONFIG_KDS - /* If we are here, dma_fence setup failed but KDS didn't. - * Revert KDS setup if any. - */ - if (kds_res_count) { - mutex_unlock(&katom->kctx->jctx.lock); - kds_resource_set_release_sync(&katom->kds_rset); - mutex_lock(&katom->kctx->jctx.lock); - - kbase_jd_kds_waiters_remove(katom); - katom->kds_dep_satisfied = true; - } -#endif /* CONFIG_KDS */ -#endif /* CONFIG_MALI_DMA_FENCE */ -#ifdef CONFIG_KDS -failed_kds_setup: -#endif -#if defined(CONFIG_KDS) || defined(CONFIG_MALI_DMA_FENCE) - /* Lock the processes mmap lock */ - down_read(¤t->mm->mmap_sem); + failed_kds_setup: /* lock before we unmap */ kbase_gpu_vm_lock(katom->kctx); -#endif +#endif /* CONFIG_KDS */ failed_loop: /* undo the loop work */ while (res_no-- > 0) { struct kbase_mem_phy_alloc *alloc = katom->extres[res_no].alloc; +#ifdef CONFIG_DMA_SHARED_BUFFER + if (alloc->type == KBASE_MEM_TYPE_IMPORTED_UMM) { + alloc->imported.umm.current_mapping_usage_count--; + + if (0 == alloc->imported.umm.current_mapping_usage_count) { + struct kbase_va_region *reg; + + reg = kbase_region_tracker_find_region_base_address( + katom->kctx, + katom->extres[res_no].gpu_address); - kbase_unmap_external_resource(katom->kctx, NULL, alloc); + if (reg && reg->gpu_alloc == alloc) + kbase_mmu_teardown_pages(katom->kctx, + reg->start_pfn, + kbase_reg_current_backed_size(reg)); + + kbase_jd_umm_unmap(katom->kctx, alloc); + } + } +#endif /* CONFIG_DMA_SHARED_BUFFER */ + kbase_mem_phy_alloc_put(alloc); } kbase_gpu_vm_unlock(katom->kctx); - /* Release the processes mmap lock */ - up_read(¤t->mm->mmap_sem); - early_err_out: kfree(katom->extres); katom->extres = NULL; @@ -514,33 +756,35 @@ failed_kds_setup: kfree(kds_resources); kfree(kds_access_bitmap); #endif /* CONFIG_KDS */ -#ifdef CONFIG_MALI_DMA_FENCE - kfree(info.resv_objs); - kfree(info.dma_fence_excl_bitmap); -#endif return err_ret_val; } static inline void jd_resolve_dep(struct list_head *out_list, struct kbase_jd_atom *katom, - u8 d, bool ctx_is_dying) + u8 d, + bool ctx_is_dying) { u8 other_d = !d; while (!list_empty(&katom->dep_head[d])) { struct kbase_jd_atom *dep_atom; - struct kbase_jd_atom *other_dep_atom; u8 dep_type; dep_atom = list_entry(katom->dep_head[d].next, struct kbase_jd_atom, dep_item[d]); + list_del(katom->dep_head[d].next); dep_type = kbase_jd_katom_dep_type(&dep_atom->dep[d]); kbase_jd_katom_dep_clear(&dep_atom->dep[d]); if (katom->event_code != BASE_JD_EVENT_DONE && - (dep_type != BASE_JD_DEP_TYPE_ORDER)) { + (dep_type != BASE_JD_DEP_TYPE_ORDER || ctx_is_dying)) { + /* Atom failed, so remove the other dependencies and immediately fail the atom */ + if (kbase_jd_katom_dep_atom(&dep_atom->dep[other_d])) { + list_del(&dep_atom->dep_item[other_d]); + kbase_jd_katom_dep_clear(&dep_atom->dep[other_d]); + } #ifdef CONFIG_KDS if (!dep_atom->kds_dep_satisfied) { /* Just set kds_dep_satisfied to true. If the callback happens after this then it will early out and @@ -550,67 +794,17 @@ static inline void jd_resolve_dep(struct list_head *out_list, } #endif -#ifdef CONFIG_MALI_DMA_FENCE - kbase_dma_fence_cancel_callbacks(dep_atom); -#endif - dep_atom->event_code = katom->event_code; KBASE_DEBUG_ASSERT(dep_atom->status != KBASE_JD_ATOM_STATE_UNUSED); + dep_atom->status = KBASE_JD_ATOM_STATE_COMPLETED; - if ((dep_atom->core_req & BASE_JD_REQ_SOFT_REPLAY) - != BASE_JD_REQ_SOFT_REPLAY) { - dep_atom->will_fail_event_code = - dep_atom->event_code; - } else { - dep_atom->status = - KBASE_JD_ATOM_STATE_COMPLETED; - } - } - other_dep_atom = (struct kbase_jd_atom *) - kbase_jd_katom_dep_atom(&dep_atom->dep[other_d]); - - if (!dep_atom->in_jd_list && (!other_dep_atom || - (IS_GPU_ATOM(dep_atom) && !ctx_is_dying && - !dep_atom->will_fail_event_code && - !other_dep_atom->will_fail_event_code))) { - bool dep_satisfied = true; -#ifdef CONFIG_MALI_DMA_FENCE - int dep_count; - - dep_count = atomic_read(&dep_atom->dma_fence.dep_count); - if (likely(dep_count == -1)) { - dep_satisfied = true; - } else if (dep_count == 0) { - /* - * All fences for this atom has signaled, but - * the worker that will queue the atom has not - * yet run. - * - * Mark the atom as handled by setting - * dep_count to -1 so that the worker doesn't - * queue the atom again. - */ - atomic_set(&dep_atom->dma_fence.dep_count, -1); - /* - * Remove the atom from the list of dma-fence - * waiting atoms. - */ - kbase_dma_fence_waiters_remove(dep_atom); - dep_satisfied = true; - } else { - dep_satisfied = false; - } -#endif /* CONFIG_MALI_DMA_FENCE */ - + list_add_tail(&dep_atom->dep_item[0], out_list); + } else if (!kbase_jd_katom_dep_atom(&dep_atom->dep[other_d])) { #ifdef CONFIG_KDS - dep_satisfied = dep_satisfied && dep_atom->kds_dep_satisfied; + if (dep_atom->kds_dep_satisfied) #endif - - if (dep_satisfied) { - dep_atom->in_jd_list = true; - list_add_tail(&dep_atom->jd_item, out_list); - } + list_add_tail(&dep_atom->dep_item[0], out_list); } } } @@ -653,7 +847,7 @@ static void jd_check_force_failure(struct kbase_jd_atom *katom) kbase_jd_katom_dep_atom(&kctx->jctx.atoms[i].dep[1]) == katom) { struct kbase_jd_atom *dep_atom = &kctx->jctx.atoms[i]; - if ((dep_atom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) == + if ((dep_atom->core_req & BASEP_JD_REQ_ATOM_TYPE) == BASE_JD_REQ_SOFT_REPLAY && (dep_atom->core_req & kbdev->force_replay_core_req) == kbdev->force_replay_core_req) { @@ -665,36 +859,6 @@ static void jd_check_force_failure(struct kbase_jd_atom *katom) } #endif -static void jd_try_submitting_deps(struct list_head *out_list, - struct kbase_jd_atom *node) -{ - int i; - - for (i = 0; i < 2; i++) { - struct list_head *pos; - - list_for_each(pos, &node->dep_head[i]) { - struct kbase_jd_atom *dep_atom = list_entry(pos, - struct kbase_jd_atom, dep_item[i]); - - if (IS_GPU_ATOM(dep_atom) && !dep_atom->in_jd_list) { - /*Check if atom deps look sane*/ - bool dep0_valid = !dep_atom->dep[0].atom || - (dep_atom->dep[0].atom->status - >= KBASE_JD_ATOM_STATE_IN_JS); - bool dep1_valid = !dep_atom->dep[1].atom || - (dep_atom->dep[1].atom->status - >= KBASE_JD_ATOM_STATE_IN_JS); - - if (dep0_valid && dep1_valid) { - dep_atom->in_jd_list = true; - list_add(&dep_atom->jd_item, out_list); - } - } - } - } -} - /* * Perform the necessary handling of an atom that has finished running * on the GPU. @@ -709,6 +873,7 @@ bool jd_done_nolock(struct kbase_jd_atom *katom, { struct kbase_context *kctx = katom->kctx; struct kbase_device *kbdev = kctx->kbdev; + struct kbasep_js_kctx_info *js_kctx_info = &kctx->jctx.sched_info; struct list_head completed_jobs; struct list_head runnable_jobs; bool need_to_try_schedule_context = false; @@ -723,6 +888,7 @@ bool jd_done_nolock(struct kbase_jd_atom *katom, jd_check_force_failure(katom); #endif + /* This is needed in case an atom is failed due to being invalid, this * can happen *before* the jobs that the atom depends on have completed */ for (i = 0; i < 2; i++) { @@ -749,16 +915,17 @@ bool jd_done_nolock(struct kbase_jd_atom *katom, } katom->status = KBASE_JD_ATOM_STATE_COMPLETED; - list_add_tail(&katom->jd_item, &completed_jobs); + list_add_tail(&katom->dep_item[0], &completed_jobs); while (!list_empty(&completed_jobs)) { - katom = list_entry(completed_jobs.prev, struct kbase_jd_atom, jd_item); + katom = list_entry(completed_jobs.prev, struct kbase_jd_atom, dep_item[0]); list_del(completed_jobs.prev); + KBASE_DEBUG_ASSERT(katom->status == KBASE_JD_ATOM_STATE_COMPLETED); for (i = 0; i < 2; i++) jd_resolve_dep(&runnable_jobs, katom, i, - kctx->jctx.sched_info.ctx.is_dying); + js_kctx_info->ctx.is_dying); if (katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) kbase_jd_post_external_resources(katom); @@ -767,47 +934,35 @@ bool jd_done_nolock(struct kbase_jd_atom *katom, struct kbase_jd_atom *node; node = list_entry(runnable_jobs.next, - struct kbase_jd_atom, jd_item); + struct kbase_jd_atom, dep_item[0]); + list_del(runnable_jobs.next); - node->in_jd_list = false; KBASE_DEBUG_ASSERT(node->status != KBASE_JD_ATOM_STATE_UNUSED); - if (node->status != KBASE_JD_ATOM_STATE_COMPLETED && - !kctx->jctx.sched_info.ctx.is_dying) { + if (node->status != KBASE_JD_ATOM_STATE_COMPLETED) { need_to_try_schedule_context |= jd_run_atom(node); } else { node->event_code = katom->event_code; - if ((node->core_req & - BASE_JD_REQ_SOFT_JOB_TYPE) == - BASE_JD_REQ_SOFT_REPLAY) { + if ((node->core_req & BASEP_JD_REQ_ATOM_TYPE) + == BASE_JD_REQ_SOFT_REPLAY) { if (kbase_replay_process(node)) /* Don't complete this atom */ continue; } else if (node->core_req & BASE_JD_REQ_SOFT_JOB) { - /* If this is a fence wait soft job - * then remove it from the list of sync - * waiters. - */ + /* If this is a fence wait then remove it from the list of sync waiters. */ if (BASE_JD_REQ_SOFT_FENCE_WAIT == node->core_req) - kbasep_remove_waiting_soft_job(node); + list_del(&node->dep_item[0]); kbase_finish_soft_job(node); } node->status = KBASE_JD_ATOM_STATE_COMPLETED; } - if (node->status == KBASE_JD_ATOM_STATE_COMPLETED) { - list_add_tail(&node->jd_item, &completed_jobs); - } else if (node->status == KBASE_JD_ATOM_STATE_IN_JS && - !node->will_fail_event_code) { - /* Node successfully submitted, try submitting - * dependencies as they may now be representable - * in JS */ - jd_try_submitting_deps(&runnable_jobs, node); - } + if (node->status == KBASE_JD_ATOM_STATE_COMPLETED) + list_add_tail(&node->dep_item[0], &completed_jobs); } /* Register a completed job as a disjoint event when the GPU @@ -815,7 +970,7 @@ bool jd_done_nolock(struct kbase_jd_atom *katom, */ kbase_disjoint_event_potential(kctx->kbdev); if (completed_jobs_ctx) - list_add_tail(&katom->jd_item, completed_jobs_ctx); + list_add_tail(&katom->dep_item[0], completed_jobs_ctx); else kbase_event_post(kctx, katom); @@ -887,19 +1042,23 @@ static const char *kbasep_map_core_reqs_to_string(base_jd_core_req core_req) } #endif -bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *user_atom, struct kbase_jd_atom *katom) +bool jd_submit_atom(struct kbase_context *kctx, + const struct base_jd_atom_v2 *user_atom, + struct kbase_jd_atom *katom) { struct kbase_jd_context *jctx = &kctx->jctx; + base_jd_core_req core_req; int queued = 0; int i; int sched_prio; bool ret; - bool will_fail = false; /* Update the TOTAL number of jobs. This includes those not tracked by * the scheduler: 'not ready to run' and 'dependency-only' jobs. */ jctx->job_nr++; + core_req = user_atom->core_req; + katom->start_timestamp.tv64 = 0; katom->time_spent_us = 0; katom->udata = user_atom->udata; @@ -910,28 +1069,18 @@ bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *us katom->affinity = 0; katom->jc = user_atom->jc; katom->coreref_state = KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED; - katom->core_req = user_atom->core_req; + katom->core_req = core_req; katom->atom_flags = 0; katom->retry_count = 0; katom->need_cache_flush_cores_retained = 0; - katom->pre_dep = NULL; - katom->post_dep = NULL; katom->x_pre_dep = NULL; katom->x_post_dep = NULL; - katom->will_fail_event_code = BASE_JD_EVENT_NOT_STARTED; - katom->exit_protected_state = KBASE_ATOM_EXIT_PROTECTED_CHECK; - katom->age = kctx->age_count++; - - INIT_LIST_HEAD(&katom->jd_item); #ifdef CONFIG_KDS /* Start by assuming that the KDS dependencies are satisfied, * kbase_jd_pre_external_resources will correct this if there are dependencies */ katom->kds_dep_satisfied = true; katom->kds_rset = NULL; #endif /* CONFIG_KDS */ -#ifdef CONFIG_MALI_DMA_FENCE - atomic_set(&katom->dma_fence.dep_count, -1); -#endif /* Don't do anything if there is a mess up with dependencies. This is done in a separate cycle to check both the dependencies at ones, otherwise @@ -947,7 +1096,7 @@ bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *us dep_atom_type != BASE_JD_DEP_TYPE_DATA) { katom->event_code = BASE_JD_EVENT_JOB_CONFIG_FAULT; katom->status = KBASE_JD_ATOM_STATE_COMPLETED; - +#if defined(CONFIG_MALI_MIPE_ENABLED) /* Wrong dependency setup. Atom will be sent * back to user space. Do not record any * dependencies. */ @@ -956,7 +1105,7 @@ bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *us kbase_jd_atom_id(kctx, katom)); kbase_tlstream_tl_ret_atom_ctx( katom, kctx); - +#endif ret = jd_done_nolock(katom, NULL); goto out; } @@ -989,10 +1138,16 @@ bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *us continue; } + if (i == 1 && kbase_jd_katom_dep_atom(&katom->dep[0])) { + /* Remove the previous dependency */ + list_del(&katom->dep_item[0]); + kbase_jd_katom_dep_clear(&katom->dep[0]); + } + /* Atom has completed, propagate the error code if any */ katom->event_code = dep_atom->event_code; katom->status = KBASE_JD_ATOM_STATE_QUEUED; - +#if defined(CONFIG_MALI_MIPE_ENABLED) /* This atom is going through soft replay or * will be sent back to user space. Do not record any * dependencies. */ @@ -1000,16 +1155,17 @@ bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *us katom, kbase_jd_atom_id(kctx, katom)); kbase_tlstream_tl_ret_atom_ctx(katom, kctx); - - if ((katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) +#endif + if ((katom->core_req & BASEP_JD_REQ_ATOM_TYPE) == BASE_JD_REQ_SOFT_REPLAY) { if (kbase_replay_process(katom)) { ret = false; goto out; } } - will_fail = true; + ret = jd_done_nolock(katom, NULL); + goto out; } else { /* Atom is in progress, add this atom to the list */ list_add_tail(&katom->dep_item[i], &dep_atom->dep_head[i]); @@ -1018,25 +1174,12 @@ bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *us } } - if (will_fail) { - if (!queued) { - ret = jd_done_nolock(katom, NULL); - - goto out; - } else { - katom->will_fail_event_code = katom->event_code; - ret = false; - - goto out; - } - } else { - /* These must occur after the above loop to ensure that an atom - * that depends on a previous atom with the same number behaves - * as expected */ - katom->event_code = BASE_JD_EVENT_DONE; - katom->status = KBASE_JD_ATOM_STATE_QUEUED; - } + /* These must occur after the above loop to ensure that an atom that + * depends on a previous atom with the same number behaves as expected */ + katom->event_code = BASE_JD_EVENT_DONE; + katom->status = KBASE_JD_ATOM_STATE_QUEUED; +#if defined(CONFIG_MALI_MIPE_ENABLED) /* Create a new atom recording all dependencies it was set up with. */ kbase_tlstream_tl_new_atom( katom, @@ -1044,26 +1187,15 @@ bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *us kbase_tlstream_tl_ret_atom_ctx(katom, kctx); for (i = 0; i < 2; i++) if (BASE_JD_DEP_TYPE_INVALID != kbase_jd_katom_dep_type( - &katom->dep[i])) { + &katom->dep[i])) kbase_tlstream_tl_dep_atom_atom( (void *)kbase_jd_katom_dep_atom( &katom->dep[i]), (void *)katom); - } else if (BASE_JD_DEP_TYPE_INVALID != - user_atom->pre_dep[i].dependency_type) { - /* Resolved dependency. */ - int dep_atom_number = - user_atom->pre_dep[i].atom_id; - struct kbase_jd_atom *dep_atom = - &jctx->atoms[dep_atom_number]; - - kbase_tlstream_tl_rdep_atom_atom( - (void *)dep_atom, - (void *)katom); - } +#endif /* Reject atoms with job chain = NULL, as these cause issues with soft-stop */ - if (!katom->jc && (katom->core_req & BASE_JD_REQ_ATOM_TYPE) != BASE_JD_REQ_DEP) { + if (!katom->jc && (katom->core_req & BASEP_JD_REQ_ATOM_TYPE) != BASE_JD_REQ_DEP) { dev_warn(kctx->kbdev->dev, "Rejecting atom with jc = NULL"); katom->event_code = BASE_JD_EVENT_JOB_INVALID; ret = jd_done_nolock(katom, NULL); @@ -1081,17 +1213,6 @@ bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *us goto out; } - /* Reject atoms with invalid core requirements */ - if ((katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) && - (katom->core_req & BASE_JD_REQ_EVENT_COALESCE)) { - dev_warn(kctx->kbdev->dev, - "Rejecting atom with invalid core requirements"); - katom->event_code = BASE_JD_EVENT_JOB_INVALID; - katom->core_req &= ~BASE_JD_REQ_EVENT_COALESCE; - ret = jd_done_nolock(katom, NULL); - goto out; - } - /* For invalid priority, be most lenient and choose the default */ sched_prio = kbasep_js_atom_prio_to_sched_prio(user_atom->prio); if (sched_prio == KBASE_JS_ATOM_SCHED_PRIO_INVALID) @@ -1148,15 +1269,7 @@ bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *us } #endif /* CONFIG_KDS */ - -#ifdef CONFIG_MALI_DMA_FENCE - if (atomic_read(&katom->dma_fence.dep_count) != -1) { - ret = false; - goto out; - } -#endif /* CONFIG_MALI_DMA_FENCE */ - - if ((katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) + if ((katom->core_req & BASEP_JD_REQ_ATOM_TYPE) == BASE_JD_REQ_SOFT_REPLAY) { if (kbase_replay_process(katom)) ret = false; @@ -1170,9 +1283,10 @@ bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *us ret = jd_done_nolock(katom, NULL); goto out; } - + /* The job has not yet completed */ + list_add_tail(&katom->dep_item[0], &kctx->waiting_soft_jobs); ret = false; - } else if ((katom->core_req & BASE_JD_REQ_ATOM_TYPE) != BASE_JD_REQ_DEP) { + } else if ((katom->core_req & BASEP_JD_REQ_ATOM_TYPE) != BASE_JD_REQ_DEP) { katom->status = KBASE_JD_ATOM_STATE_IN_JS; ret = kbasep_js_add_job(kctx, katom); /* If job was cancelled then resolve immediately */ @@ -1258,7 +1372,7 @@ int kbase_jd_submit(struct kbase_context *kctx, user_atom.udata = user_atom_v6.udata; user_atom.extres_list = user_atom_v6.extres_list; user_atom.nr_extres = user_atom_v6.nr_extres; - user_atom.core_req = (u32)(user_atom_v6.core_req & 0x7fff); + user_atom.core_req = user_atom_v6.core_req; /* atom number 0 is used for no dependency atoms */ if (!user_atom_v6.pre_dep[0]) @@ -1290,12 +1404,6 @@ int kbase_jd_submit(struct kbase_context *kctx, } #endif /* BASE_LEGACY_UK6_SUPPORT */ -#ifdef BASE_LEGACY_UK10_2_SUPPORT - if (KBASE_API_VERSION(10, 3) > kctx->api_version) - user_atom.core_req = (u32)(user_atom.compat_core_req - & 0x7fff); -#endif /* BASE_LEGACY_UK10_2_SUPPORT */ - user_addr = (void __user *)((uintptr_t) user_addr + submit_data->stride); mutex_lock(&jctx->lock); @@ -1370,6 +1478,7 @@ void kbase_jd_done_worker(struct work_struct *data) struct kbase_jd_context *jctx; struct kbase_context *kctx; struct kbasep_js_kctx_info *js_kctx_info; + union kbasep_js_policy *js_policy; struct kbase_device *kbdev; struct kbasep_js_device_data *js_devdata; u64 cache_jc = katom->jc; @@ -1388,6 +1497,7 @@ void kbase_jd_done_worker(struct work_struct *data) kbdev = kctx->kbdev; js_kctx_info = &kctx->jctx.sched_info; js_devdata = &kbdev->js_data; + js_policy = &kbdev->js_data.policy; KBASE_TRACE_ADD(kbdev, JD_DONE_WORKER, kctx, katom, katom->jc, 0); @@ -1412,6 +1522,7 @@ void kbase_jd_done_worker(struct work_struct *data) mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); mutex_unlock(&js_devdata->queue_mutex); + mutex_unlock(&jctx->lock); spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags); @@ -1419,7 +1530,6 @@ void kbase_jd_done_worker(struct work_struct *data) kbase_js_unpull(kctx, katom); spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags); - mutex_unlock(&jctx->lock); return; } @@ -1529,7 +1639,7 @@ void kbase_jd_done_worker(struct work_struct *data) while (!list_empty(&kctx->completed_jobs)) { struct kbase_jd_atom *atom = list_entry( kctx->completed_jobs.next, - struct kbase_jd_atom, jd_item); + struct kbase_jd_atom, dep_item[0]); list_del(kctx->completed_jobs.next); kbase_event_post(kctx, atom); @@ -1605,6 +1715,51 @@ static void jd_cancel_worker(struct work_struct *data) } /** + * jd_evict_worker - Work queue job evict function + * @data: a &struct work_struct + * + * Only called as part of evicting failed jobs. This is only called on jobs that + * were never submitted to HW Access. Jobs that were submitted are handled + * through kbase_jd_done_worker(). + * Operates serially with the kbase_jd_done_worker() on the work queue. + * + * We don't need to release most of the resources that would occur on + * kbase_jd_done() or kbase_jd_done_worker(), because the atoms here must not be + * running (by virtue of having not been submitted to HW Access). + */ +static void jd_evict_worker(struct work_struct *data) +{ + struct kbase_jd_atom *katom = container_of(data, struct kbase_jd_atom, + work); + struct kbase_jd_context *jctx; + struct kbase_context *kctx; + struct kbasep_js_kctx_info *js_kctx_info; + struct kbase_device *kbdev; + + /* Soft jobs should never reach this function */ + KBASE_DEBUG_ASSERT((katom->core_req & BASE_JD_REQ_SOFT_JOB) == 0); + + kctx = katom->kctx; + kbdev = kctx->kbdev; + jctx = &kctx->jctx; + js_kctx_info = &kctx->jctx.sched_info; + + KBASE_TRACE_ADD(kbdev, JD_CANCEL_WORKER, kctx, katom, katom->jc, 0); + + /* Scheduler: Remove the job from the system */ + mutex_lock(&js_kctx_info->ctx.jsctx_mutex); + kbasep_js_remove_cancelled_job(kbdev, kctx, katom); + mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); + + mutex_lock(&jctx->lock); + jd_done_nolock(katom, NULL); + /* katom may have been freed now, do not use! */ + mutex_unlock(&jctx->lock); + + kbase_js_sched_all(kbdev); +} + +/** * kbase_jd_done - Complete a job that has been removed from the Hardware * @katom: atom which has been completed * @slot_nr: slot the atom was on @@ -1647,8 +1802,7 @@ void kbase_jd_done(struct kbase_jd_atom *katom, int slot_nr, #ifdef CONFIG_DEBUG_FS /* a failed job happened and is waiting for dumping*/ - if (!katom->will_fail_event_code && - kbase_debug_job_fault_process(katom, katom->event_code)) + if (kbase_debug_job_fault_process(katom, katom->event_code)) return; #endif @@ -1686,6 +1840,30 @@ void kbase_jd_cancel(struct kbase_device *kbdev, struct kbase_jd_atom *katom) queue_work(kctx->jctx.job_done_wq, &katom->work); } +void kbase_jd_evict(struct kbase_device *kbdev, struct kbase_jd_atom *katom) +{ + struct kbase_context *kctx; + struct kbasep_js_kctx_info *js_kctx_info; + + KBASE_DEBUG_ASSERT(NULL != kbdev); + KBASE_DEBUG_ASSERT(NULL != katom); + kctx = katom->kctx; + KBASE_DEBUG_ASSERT(NULL != kctx); + + js_kctx_info = &kctx->jctx.sched_info; + + KBASE_TRACE_ADD(kbdev, JD_CANCEL, kctx, katom, katom->jc, 0); + + /* This should only be done from a context that is currently scheduled + */ + KBASE_DEBUG_ASSERT(js_kctx_info->ctx.is_scheduled); + + WARN_ON(work_pending(&katom->work)); + + KBASE_DEBUG_ASSERT(0 == object_is_on_stack(&katom->work)); + INIT_WORK(&katom->work, jd_evict_worker); + queue_work(kctx->jctx.job_done_wq, &katom->work); +} void kbase_jd_zap_context(struct kbase_context *kctx) { @@ -1708,9 +1886,8 @@ void kbase_jd_zap_context(struct kbase_context *kctx) * queued outside the job scheduler. */ - del_timer_sync(&kctx->soft_job_timeout); list_for_each_safe(entry, tmp, &kctx->waiting_soft_jobs) { - katom = list_entry(entry, struct kbase_jd_atom, queue); + katom = list_entry(entry, struct kbase_jd_atom, dep_item[0]); kbase_cancel_soft_job(katom); } @@ -1733,19 +1910,8 @@ void kbase_jd_zap_context(struct kbase_context *kctx) } #endif -#ifdef CONFIG_MALI_DMA_FENCE - kbase_dma_fence_cancel_all_atoms(kctx); -#endif - mutex_unlock(&kctx->jctx.lock); -#ifdef CONFIG_MALI_DMA_FENCE - /* Flush dma-fence workqueue to ensure that any callbacks that may have - * been queued are done before continuing. - */ - flush_workqueue(kctx->dma_fence.wq); -#endif - kbase_jm_wait_for_zero_jobs(kctx); } @@ -1761,8 +1927,7 @@ int kbase_jd_init(struct kbase_context *kctx) KBASE_DEBUG_ASSERT(kctx); - kctx->jctx.job_done_wq = alloc_workqueue("mali_jd", - WQ_HIGHPRI | WQ_UNBOUND, 1); + kctx->jctx.job_done_wq = alloc_workqueue("mali_jd", 0, 1); if (NULL == kctx->jctx.job_done_wq) { mali_err = -ENOMEM; goto out1; @@ -1777,12 +1942,6 @@ int kbase_jd_init(struct kbase_context *kctx) /* Catch userspace attempting to use an atom which doesn't exist as a pre-dependency */ kctx->jctx.atoms[i].event_code = BASE_JD_EVENT_JOB_INVALID; kctx->jctx.atoms[i].status = KBASE_JD_ATOM_STATE_UNUSED; - -#ifdef CONFIG_MALI_DMA_FENCE - kctx->jctx.atoms[i].dma_fence.context = fence_context_alloc(1); - atomic_set(&kctx->jctx.atoms[i].dma_fence.seqno, 0); - INIT_LIST_HEAD(&kctx->jctx.atoms[i].dma_fence.callbacks); -#endif } mutex_init(&kctx->jctx.lock); |