/*
|
*
|
* (C) COPYRIGHT 2012-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.
|
*
|
*/
|
|
|
|
|
#include <mali_kbase.h>
|
#include <mali_kbase_config.h>
|
|
/*
|
* Private functions follow
|
*/
|
|
/**
|
* @brief Check whether a ctx has a certain attribute, and if so, retain that
|
* attribute on the runpool.
|
*
|
* Requires:
|
* - jsctx mutex
|
* - runpool_irq spinlock
|
* - ctx is scheduled on the runpool
|
*
|
* @return true indicates a change in ctx attributes state of the runpool.
|
* In this state, the scheduler might be able to submit more jobs than
|
* previously, and so the caller should ensure kbasep_js_try_run_next_job_nolock()
|
* or similar is called sometime later.
|
* @return false indicates no change in ctx attributes state of the runpool.
|
*/
|
static bool kbasep_js_ctx_attr_runpool_retain_attr(struct kbase_device *kbdev, struct kbase_context *kctx, enum kbasep_js_ctx_attr attribute)
|
{
|
struct kbasep_js_device_data *js_devdata;
|
struct kbasep_js_kctx_info *js_kctx_info;
|
bool runpool_state_changed = false;
|
|
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
KBASE_DEBUG_ASSERT(kctx != NULL);
|
KBASE_DEBUG_ASSERT(attribute < KBASEP_JS_CTX_ATTR_COUNT);
|
js_devdata = &kbdev->js_data;
|
js_kctx_info = &kctx->jctx.sched_info;
|
|
lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex);
|
lockdep_assert_held(&kbdev->hwaccess_lock);
|
|
KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED));
|
|
if (kbasep_js_ctx_attr_is_attr_on_ctx(kctx, attribute) != false) {
|
KBASE_DEBUG_ASSERT(js_devdata->runpool_irq.ctx_attr_ref_count[attribute] < S8_MAX);
|
++(js_devdata->runpool_irq.ctx_attr_ref_count[attribute]);
|
|
if (js_devdata->runpool_irq.ctx_attr_ref_count[attribute] == 1) {
|
/* First refcount indicates a state change */
|
runpool_state_changed = true;
|
KBASE_TRACE_ADD(kbdev, JS_CTX_ATTR_NOW_ON_RUNPOOL, kctx, NULL, 0u, attribute);
|
}
|
}
|
|
return runpool_state_changed;
|
}
|
|
/**
|
* @brief Check whether a ctx has a certain attribute, and if so, release that
|
* attribute on the runpool.
|
*
|
* Requires:
|
* - jsctx mutex
|
* - runpool_irq spinlock
|
* - ctx is scheduled on the runpool
|
*
|
* @return true indicates a change in ctx attributes state of the runpool.
|
* In this state, the scheduler might be able to submit more jobs than
|
* previously, and so the caller should ensure kbasep_js_try_run_next_job_nolock()
|
* or similar is called sometime later.
|
* @return false indicates no change in ctx attributes state of the runpool.
|
*/
|
static bool kbasep_js_ctx_attr_runpool_release_attr(struct kbase_device *kbdev, struct kbase_context *kctx, enum kbasep_js_ctx_attr attribute)
|
{
|
struct kbasep_js_device_data *js_devdata;
|
struct kbasep_js_kctx_info *js_kctx_info;
|
bool runpool_state_changed = false;
|
|
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
KBASE_DEBUG_ASSERT(kctx != NULL);
|
KBASE_DEBUG_ASSERT(attribute < KBASEP_JS_CTX_ATTR_COUNT);
|
js_devdata = &kbdev->js_data;
|
js_kctx_info = &kctx->jctx.sched_info;
|
|
lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex);
|
lockdep_assert_held(&kbdev->hwaccess_lock);
|
KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED));
|
|
if (kbasep_js_ctx_attr_is_attr_on_ctx(kctx, attribute) != false) {
|
KBASE_DEBUG_ASSERT(js_devdata->runpool_irq.ctx_attr_ref_count[attribute] > 0);
|
--(js_devdata->runpool_irq.ctx_attr_ref_count[attribute]);
|
|
if (js_devdata->runpool_irq.ctx_attr_ref_count[attribute] == 0) {
|
/* Last de-refcount indicates a state change */
|
runpool_state_changed = true;
|
KBASE_TRACE_ADD(kbdev, JS_CTX_ATTR_NOW_OFF_RUNPOOL, kctx, NULL, 0u, attribute);
|
}
|
}
|
|
return runpool_state_changed;
|
}
|
|
/**
|
* @brief Retain a certain attribute on a ctx, also retaining it on the runpool
|
* if the context is scheduled.
|
*
|
* Requires:
|
* - jsctx mutex
|
* - If the context is scheduled, then runpool_irq spinlock must also be held
|
*
|
* @return true indicates a change in ctx attributes state of the runpool.
|
* This may allow the scheduler to submit more jobs than previously.
|
* @return false indicates no change in ctx attributes state of the runpool.
|
*/
|
static bool kbasep_js_ctx_attr_ctx_retain_attr(struct kbase_device *kbdev, struct kbase_context *kctx, enum kbasep_js_ctx_attr attribute)
|
{
|
struct kbasep_js_kctx_info *js_kctx_info;
|
bool runpool_state_changed = false;
|
|
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
KBASE_DEBUG_ASSERT(kctx != NULL);
|
KBASE_DEBUG_ASSERT(attribute < KBASEP_JS_CTX_ATTR_COUNT);
|
js_kctx_info = &kctx->jctx.sched_info;
|
|
lockdep_assert_held(&kbdev->hwaccess_lock);
|
lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex);
|
KBASE_DEBUG_ASSERT(js_kctx_info->ctx.ctx_attr_ref_count[attribute] < U32_MAX);
|
|
++(js_kctx_info->ctx.ctx_attr_ref_count[attribute]);
|
|
if (kbase_ctx_flag(kctx, KCTX_SCHEDULED) && js_kctx_info->ctx.ctx_attr_ref_count[attribute] == 1) {
|
/* Only ref-count the attribute on the runpool for the first time this contexts sees this attribute */
|
KBASE_TRACE_ADD(kbdev, JS_CTX_ATTR_NOW_ON_CTX, kctx, NULL, 0u, attribute);
|
runpool_state_changed = kbasep_js_ctx_attr_runpool_retain_attr(kbdev, kctx, attribute);
|
}
|
|
return runpool_state_changed;
|
}
|
|
/*
|
* @brief Release a certain attribute on a ctx, also releasing it from the runpool
|
* if the context is scheduled.
|
*
|
* Requires:
|
* - jsctx mutex
|
* - If the context is scheduled, then runpool_irq spinlock must also be held
|
*
|
* @return true indicates a change in ctx attributes state of the runpool.
|
* This may allow the scheduler to submit more jobs than previously.
|
* @return false indicates no change in ctx attributes state of the runpool.
|
*/
|
static bool kbasep_js_ctx_attr_ctx_release_attr(struct kbase_device *kbdev, struct kbase_context *kctx, enum kbasep_js_ctx_attr attribute)
|
{
|
struct kbasep_js_kctx_info *js_kctx_info;
|
bool runpool_state_changed = false;
|
|
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
KBASE_DEBUG_ASSERT(kctx != NULL);
|
KBASE_DEBUG_ASSERT(attribute < KBASEP_JS_CTX_ATTR_COUNT);
|
js_kctx_info = &kctx->jctx.sched_info;
|
|
lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex);
|
KBASE_DEBUG_ASSERT(js_kctx_info->ctx.ctx_attr_ref_count[attribute] > 0);
|
|
if (kbase_ctx_flag(kctx, KCTX_SCHEDULED) && js_kctx_info->ctx.ctx_attr_ref_count[attribute] == 1) {
|
lockdep_assert_held(&kbdev->hwaccess_lock);
|
/* Only de-ref-count the attribute on the runpool when this is the last ctx-reference to it */
|
runpool_state_changed = kbasep_js_ctx_attr_runpool_release_attr(kbdev, kctx, attribute);
|
KBASE_TRACE_ADD(kbdev, JS_CTX_ATTR_NOW_OFF_CTX, kctx, NULL, 0u, attribute);
|
}
|
|
/* De-ref must happen afterwards, because kbasep_js_ctx_attr_runpool_release() needs to check it too */
|
--(js_kctx_info->ctx.ctx_attr_ref_count[attribute]);
|
|
return runpool_state_changed;
|
}
|
|
/*
|
* More commonly used public functions
|
*/
|
|
void kbasep_js_ctx_attr_set_initial_attrs(struct kbase_device *kbdev, struct kbase_context *kctx)
|
{
|
bool runpool_state_changed = false;
|
|
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
KBASE_DEBUG_ASSERT(kctx != NULL);
|
|
if (kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) {
|
/* This context never submits, so don't track any scheduling attributes */
|
return;
|
}
|
|
/* Transfer attributes held in the context flags for contexts that have submit enabled */
|
|
/* ... More attributes can be added here ... */
|
|
/* The context should not have been scheduled yet, so ASSERT if this caused
|
* runpool state changes (note that other threads *can't* affect the value
|
* of runpool_state_changed, due to how it's calculated) */
|
KBASE_DEBUG_ASSERT(runpool_state_changed == false);
|
CSTD_UNUSED(runpool_state_changed);
|
}
|
|
void kbasep_js_ctx_attr_runpool_retain_ctx(struct kbase_device *kbdev, struct kbase_context *kctx)
|
{
|
bool runpool_state_changed;
|
int i;
|
|
/* Retain any existing attributes */
|
for (i = 0; i < KBASEP_JS_CTX_ATTR_COUNT; ++i) {
|
if (kbasep_js_ctx_attr_is_attr_on_ctx(kctx, (enum kbasep_js_ctx_attr) i) != false) {
|
/* The context is being scheduled in, so update the runpool with the new attributes */
|
runpool_state_changed = kbasep_js_ctx_attr_runpool_retain_attr(kbdev, kctx, (enum kbasep_js_ctx_attr) i);
|
|
/* We don't need to know about state changed, because retaining a
|
* context occurs on scheduling it, and that itself will also try
|
* to run new atoms */
|
CSTD_UNUSED(runpool_state_changed);
|
}
|
}
|
}
|
|
bool kbasep_js_ctx_attr_runpool_release_ctx(struct kbase_device *kbdev, struct kbase_context *kctx)
|
{
|
bool runpool_state_changed = false;
|
int i;
|
|
/* Release any existing attributes */
|
for (i = 0; i < KBASEP_JS_CTX_ATTR_COUNT; ++i) {
|
if (kbasep_js_ctx_attr_is_attr_on_ctx(kctx, (enum kbasep_js_ctx_attr) i) != false) {
|
/* The context is being scheduled out, so update the runpool on the removed attributes */
|
runpool_state_changed |= kbasep_js_ctx_attr_runpool_release_attr(kbdev, kctx, (enum kbasep_js_ctx_attr) i);
|
}
|
}
|
|
return runpool_state_changed;
|
}
|
|
void kbasep_js_ctx_attr_ctx_retain_atom(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_jd_atom *katom)
|
{
|
bool runpool_state_changed = false;
|
base_jd_core_req core_req;
|
|
KBASE_DEBUG_ASSERT(katom);
|
core_req = katom->core_req;
|
|
if (core_req & BASE_JD_REQ_ONLY_COMPUTE)
|
runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE);
|
else
|
runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_NON_COMPUTE);
|
|
if ((core_req & (BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE | BASE_JD_REQ_T)) != 0 && (core_req & (BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP)) == 0) {
|
/* Atom that can run on slot1 or slot2, and can use all cores */
|
runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES);
|
}
|
|
/* We don't need to know about state changed, because retaining an
|
* atom occurs on adding it, and that itself will also try to run
|
* new atoms */
|
CSTD_UNUSED(runpool_state_changed);
|
}
|
|
bool kbasep_js_ctx_attr_ctx_release_atom(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbasep_js_atom_retained_state *katom_retained_state)
|
{
|
bool runpool_state_changed = false;
|
base_jd_core_req core_req;
|
|
KBASE_DEBUG_ASSERT(katom_retained_state);
|
core_req = katom_retained_state->core_req;
|
|
/* No-op for invalid atoms */
|
if (kbasep_js_atom_retained_state_is_valid(katom_retained_state) == false)
|
return false;
|
|
if (core_req & BASE_JD_REQ_ONLY_COMPUTE)
|
runpool_state_changed |= kbasep_js_ctx_attr_ctx_release_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE);
|
else
|
runpool_state_changed |= kbasep_js_ctx_attr_ctx_release_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_NON_COMPUTE);
|
|
if ((core_req & (BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE | BASE_JD_REQ_T)) != 0 && (core_req & (BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP)) == 0) {
|
/* Atom that can run on slot1 or slot2, and can use all cores */
|
runpool_state_changed |= kbasep_js_ctx_attr_ctx_release_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES);
|
}
|
|
return runpool_state_changed;
|
}
|