From bca6272f79877458413f316b63d829e82bb4cbc5 Mon Sep 17 00:00:00 2001 From: Wookey Date: Fri, 16 Feb 2018 01:58:08 +0000 Subject: Use upstream source layout --- .../gpu/arm/midgard/backend/gpu/mali_kbase_jm_as.c | 378 +++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100755 driver/product/kernel/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_as.c (limited to 'driver/product/kernel/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_as.c') diff --git a/driver/product/kernel/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_as.c b/driver/product/kernel/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_as.c new file mode 100755 index 0000000..202dcfa --- /dev/null +++ b/driver/product/kernel/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_as.c @@ -0,0 +1,378 @@ +/* + * + * (C) COPYRIGHT 2014-2016 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 + * Foundation, and any use by you of this program is subject to the terms + * of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained + * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + + + +/* + * Register backend context / address space management + */ + +#include +#include + +/** + * assign_and_activate_kctx_addr_space - Assign an AS to a context + * @kbdev: Kbase device + * @kctx: Kbase context + * @current_as: Address Space to assign + * + * Assign an Address Space (AS) to a context, and add the context to the Policy. + * + * This includes + * setting up the global runpool_irq structure and the context on the AS, + * Activating the MMU on the AS, + * Allowing jobs to be submitted on the AS. + * + * Context: + * kbasep_js_kctx_info.jsctx_mutex held, + * kbasep_js_device_data.runpool_mutex held, + * AS transaction mutex held, + * Runpool IRQ lock held + */ +static void assign_and_activate_kctx_addr_space(struct kbase_device *kbdev, + struct kbase_context *kctx, + struct kbase_as *current_as) +{ + struct kbasep_js_device_data *js_devdata = &kbdev->js_data; + struct kbasep_js_per_as_data *js_per_as_data; + int as_nr = current_as->number; + + lockdep_assert_held(&kctx->jctx.sched_info.ctx.jsctx_mutex); + lockdep_assert_held(&js_devdata->runpool_mutex); + lockdep_assert_held(&kbdev->hwaccess_lock); + + js_per_as_data = &js_devdata->runpool_irq.per_as_data[as_nr]; + + /* Attribute handling */ + kbasep_js_ctx_attr_runpool_retain_ctx(kbdev, kctx); + + /* Assign addr space */ + kctx->as_nr = as_nr; + + /* If the GPU is currently powered, activate this address space on the + * MMU */ + if (kbdev->pm.backend.gpu_powered) + kbase_mmu_update(kctx); + /* If the GPU was not powered then the MMU will be reprogrammed on the + * next pm_context_active() */ + + /* Allow it to run jobs */ + kbasep_js_set_submit_allowed(js_devdata, kctx); + + /* Book-keeping */ + js_per_as_data->kctx = kctx; + js_per_as_data->as_busy_refcount = 0; + + kbase_js_runpool_inc_context_count(kbdev, kctx); +} + +/** + * release_addr_space - Release an address space + * @kbdev: Kbase device + * @kctx_as_nr: Address space of context to release + * @kctx: Context being released + * + * Context: kbasep_js_device_data.runpool_mutex must be held + * + * Release an address space, making it available for being picked again. + */ +static void release_addr_space(struct kbase_device *kbdev, int kctx_as_nr, + struct kbase_context *kctx) +{ + struct kbasep_js_device_data *js_devdata; + u16 as_bit = (1u << kctx_as_nr); + + js_devdata = &kbdev->js_data; + lockdep_assert_held(&js_devdata->runpool_mutex); + + /* The address space must not already be free */ + KBASE_DEBUG_ASSERT(!(js_devdata->as_free & as_bit)); + + js_devdata->as_free |= as_bit; + + kbase_js_runpool_dec_context_count(kbdev, kctx); +} + +bool kbase_backend_use_ctx_sched(struct kbase_device *kbdev, + struct kbase_context *kctx) +{ + int i; + + if (kbdev->hwaccess.active_kctx == kctx) { + /* Context is already active */ + return true; + } + + for (i = 0; i < kbdev->nr_hw_address_spaces; i++) { + struct kbasep_js_per_as_data *js_per_as_data = + &kbdev->js_data.runpool_irq.per_as_data[i]; + + if (js_per_as_data->kctx == kctx) { + /* Context already has ASID - mark as active */ + return true; + } + } + + /* Context does not have address space assigned */ + return false; +} + +void kbase_backend_release_ctx_irq(struct kbase_device *kbdev, + struct kbase_context *kctx) +{ + struct kbasep_js_per_as_data *js_per_as_data; + int as_nr = kctx->as_nr; + + if (as_nr == KBASEP_AS_NR_INVALID) { + WARN(1, "Attempting to release context without ASID\n"); + return; + } + + lockdep_assert_held(&kbdev->hwaccess_lock); + + js_per_as_data = &kbdev->js_data.runpool_irq.per_as_data[kctx->as_nr]; + if (js_per_as_data->as_busy_refcount != 0) { + WARN(1, "Attempting to release active ASID\n"); + return; + } + + /* Release context from address space */ + js_per_as_data->kctx = NULL; + + kbasep_js_clear_submit_allowed(&kbdev->js_data, kctx); + /* If the GPU is currently powered, de-activate this address space on + * the MMU */ + if (kbdev->pm.backend.gpu_powered) + kbase_mmu_disable(kctx); + /* If the GPU was not powered then the MMU will be reprogrammed on the + * next pm_context_active() */ + + release_addr_space(kbdev, as_nr, kctx); + kctx->as_nr = KBASEP_AS_NR_INVALID; +} + +void kbase_backend_release_ctx_noirq(struct kbase_device *kbdev, + struct kbase_context *kctx) +{ +} + +void kbase_backend_release_free_address_space(struct kbase_device *kbdev, + int as_nr) +{ + struct kbasep_js_device_data *js_devdata; + + js_devdata = &kbdev->js_data; + + lockdep_assert_held(&js_devdata->runpool_mutex); + + js_devdata->as_free |= (1 << as_nr); +} + +/** + * check_is_runpool_full - check whether the runpool is full for a specified + * context + * @kbdev: Kbase device + * @kctx: Kbase context + * + * If kctx == NULL, then this makes the least restrictive check on the + * runpool. A specific context that is supplied immediately after could fail + * the check, even under the same conditions. + * + * Therefore, once a context is obtained you \b must re-check it with this + * function, since the return value could change to false. + * + * Context: + * In all cases, the caller must hold kbasep_js_device_data.runpool_mutex. + * When kctx != NULL the caller must hold the + * kbasep_js_kctx_info.ctx.jsctx_mutex. + * When kctx == NULL, then the caller need not hold any jsctx_mutex locks (but + * it doesn't do any harm to do so). + * + * Return: true if the runpool is full + */ +static bool check_is_runpool_full(struct kbase_device *kbdev, + struct kbase_context *kctx) +{ + struct kbasep_js_device_data *js_devdata; + bool is_runpool_full; + + js_devdata = &kbdev->js_data; + lockdep_assert_held(&js_devdata->runpool_mutex); + + /* Regardless of whether a context is submitting or not, can't have more + * than there are HW address spaces */ + is_runpool_full = (bool) (js_devdata->nr_all_contexts_running >= + kbdev->nr_hw_address_spaces); + + if (kctx && !kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) { + lockdep_assert_held(&kctx->jctx.sched_info.ctx.jsctx_mutex); + /* Contexts that submit might use less of the address spaces + * available, due to HW workarounds. In which case, the runpool + * is also full when the number of submitting contexts exceeds + * the number of submittable address spaces. + * + * Both checks must be made: can have nr_user_address_spaces == + * nr_hw_address spaces, and at the same time can have + * nr_user_contexts_running < nr_all_contexts_running. */ + is_runpool_full |= (bool) + (js_devdata->nr_user_contexts_running >= + kbdev->nr_user_address_spaces); + } + + return is_runpool_full; +} + +int kbase_backend_find_free_address_space(struct kbase_device *kbdev, + struct kbase_context *kctx) +{ + struct kbasep_js_device_data *js_devdata; + struct kbasep_js_kctx_info *js_kctx_info; + unsigned long flags; + int i; + + js_devdata = &kbdev->js_data; + js_kctx_info = &kctx->jctx.sched_info; + + mutex_lock(&js_kctx_info->ctx.jsctx_mutex); + mutex_lock(&js_devdata->runpool_mutex); + + /* First try to find a free address space */ + if (check_is_runpool_full(kbdev, kctx)) + i = -1; + else + i = ffs(js_devdata->as_free) - 1; + + if (i >= 0 && i < kbdev->nr_hw_address_spaces) { + js_devdata->as_free &= ~(1 << i); + + mutex_unlock(&js_devdata->runpool_mutex); + mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); + + return i; + } + + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); + + /* No address space currently free, see if we can release one */ + for (i = 0; i < kbdev->nr_hw_address_spaces; i++) { + struct kbasep_js_per_as_data *js_per_as_data; + struct kbasep_js_kctx_info *as_js_kctx_info; + struct kbase_context *as_kctx; + + js_per_as_data = &kbdev->js_data.runpool_irq.per_as_data[i]; + as_kctx = js_per_as_data->kctx; + as_js_kctx_info = &as_kctx->jctx.sched_info; + + /* Don't release privileged or active contexts, or contexts with + * jobs running */ + if (as_kctx && !kbase_ctx_flag(as_kctx, KCTX_PRIVILEGED) && + js_per_as_data->as_busy_refcount == 0) { + if (!kbasep_js_runpool_retain_ctx_nolock(kbdev, + as_kctx)) { + WARN(1, "Failed to retain active context\n"); + + spin_unlock_irqrestore(&kbdev->hwaccess_lock, + flags); + mutex_unlock(&js_devdata->runpool_mutex); + mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); + + return KBASEP_AS_NR_INVALID; + } + + kbasep_js_clear_submit_allowed(js_devdata, as_kctx); + + /* Drop and retake locks to take the jsctx_mutex on the + * context we're about to release without violating lock + * ordering + */ + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); + mutex_unlock(&js_devdata->runpool_mutex); + mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); + + + /* Release context from address space */ + mutex_lock(&as_js_kctx_info->ctx.jsctx_mutex); + mutex_lock(&js_devdata->runpool_mutex); + + kbasep_js_runpool_release_ctx_nolock(kbdev, as_kctx); + + if (!kbase_ctx_flag(as_kctx, KCTX_SCHEDULED)) { + kbasep_js_runpool_requeue_or_kill_ctx(kbdev, + as_kctx, + true); + + js_devdata->as_free &= ~(1 << i); + + mutex_unlock(&js_devdata->runpool_mutex); + mutex_unlock(&as_js_kctx_info->ctx.jsctx_mutex); + + return i; + } + + /* Context was retained while locks were dropped, + * continue looking for free AS */ + + mutex_unlock(&js_devdata->runpool_mutex); + mutex_unlock(&as_js_kctx_info->ctx.jsctx_mutex); + + mutex_lock(&js_kctx_info->ctx.jsctx_mutex); + mutex_lock(&js_devdata->runpool_mutex); + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); + } + } + + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); + + mutex_unlock(&js_devdata->runpool_mutex); + mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); + + return KBASEP_AS_NR_INVALID; +} + +bool kbase_backend_use_ctx(struct kbase_device *kbdev, + struct kbase_context *kctx, + int as_nr) +{ + struct kbasep_js_device_data *js_devdata; + struct kbasep_js_kctx_info *js_kctx_info; + struct kbase_as *new_address_space = NULL; + + js_devdata = &kbdev->js_data; + js_kctx_info = &kctx->jctx.sched_info; + + if (kbdev->hwaccess.active_kctx == kctx || + kctx->as_nr != KBASEP_AS_NR_INVALID || + as_nr == KBASEP_AS_NR_INVALID) { + WARN(1, "Invalid parameters to use_ctx()\n"); + return false; + } + + new_address_space = &kbdev->as[as_nr]; + + lockdep_assert_held(&js_devdata->runpool_mutex); + lockdep_assert_held(&kbdev->hwaccess_lock); + + assign_and_activate_kctx_addr_space(kbdev, kctx, new_address_space); + + if (kbase_ctx_flag(kctx, KCTX_PRIVILEGED)) { + /* We need to retain it to keep the corresponding address space + */ + kbasep_js_runpool_retain_ctx_nolock(kbdev, kctx); + } + + return true; +} + -- cgit v1.2.3