/*
|
*
|
* (C) COPYRIGHT 2014-2017 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 <mali_kbase.h>
|
#include <mali_kbase_hwaccess_jm.h>
|
#include <mali_kbase_ctx_sched.h>
|
|
/**
|
* 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;
|
|
lockdep_assert_held(&kctx->jctx.sched_info.ctx.jsctx_mutex);
|
lockdep_assert_held(&js_devdata->runpool_mutex);
|
lockdep_assert_held(&kbdev->hwaccess_lock);
|
|
/* Attribute handling */
|
kbasep_js_ctx_attr_runpool_retain_ctx(kbdev, kctx);
|
|
/* Allow it to run jobs */
|
kbasep_js_set_submit_allowed(js_devdata, kctx);
|
|
kbase_js_runpool_inc_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++) {
|
if (kbdev->as_to_kctx[i] == 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)
|
{
|
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);
|
|
if (atomic_read(&kctx->refcount) != 1) {
|
WARN(1, "Attempting to release active ASID\n");
|
return;
|
}
|
|
kbasep_js_clear_submit_allowed(&kbdev->js_data, kctx);
|
|
kbase_ctx_sched_release_ctx(kctx);
|
kbase_js_runpool_dec_context_count(kbdev, kctx);
|
}
|
|
void kbase_backend_release_ctx_noirq(struct kbase_device *kbdev,
|
struct kbase_context *kctx)
|
{
|
}
|
|
int kbase_backend_find_and_release_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);
|
|
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
|
|
for (i = 0; i < kbdev->nr_hw_address_spaces; i++) {
|
struct kbasep_js_kctx_info *as_js_kctx_info;
|
struct kbase_context *as_kctx;
|
|
as_kctx = kbdev->as_to_kctx[i];
|
as_js_kctx_info = &as_kctx->jctx.sched_info;
|
|
/* Don't release privileged or active contexts, or contexts with
|
* jobs running.
|
* Note that a context will have at least 1 reference (which
|
* was previously taken by kbasep_js_schedule_ctx()) until
|
* descheduled.
|
*/
|
if (as_kctx && !kbase_ctx_flag(as_kctx, KCTX_PRIVILEGED) &&
|
atomic_read(&as_kctx->refcount) == 1) {
|
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);
|
|
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) {
|
WARN(1, "Context is already scheduled in\n");
|
return false;
|
}
|
|
new_address_space = &kbdev->as[as_nr];
|
|
lockdep_assert_held(&js_devdata->runpool_mutex);
|
lockdep_assert_held(&kbdev->mmu_hw_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;
|
}
|