Files
linux-nvgpu/drivers/gpu/nvgpu/common/profiler/profiler.c
Deepak Nibade 9963b94b4b gpu: nvgpu: unbind resources during reservation release
nvgpu_profiler_pm_resource_release() right now returns error if PM
resources are already bound. Update this to unbind the resources
explicitly as per the user requirement.

Bug 2510974
Jira NVGPU-5360

Change-Id: Ib71e2d8d3caacd3bc5e29a06af0b90983468d33a
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2398354
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-misra <svc-mobile-misra@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2020-12-15 14:13:28 -06:00

493 lines
12 KiB
C

/*
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <nvgpu/gk20a.h>
#include <nvgpu/pm_reservation.h>
#include <nvgpu/profiler.h>
#include <nvgpu/atomic.h>
#include <nvgpu/log.h>
#include <nvgpu/lock.h>
#include <nvgpu/kmem.h>
#include <nvgpu/tsg.h>
#include <nvgpu/nvgpu_init.h>
#include <nvgpu/gr/ctx.h>
static nvgpu_atomic_t unique_id = NVGPU_ATOMIC_INIT(0);
static int generate_unique_id(void)
{
return nvgpu_atomic_add_return(1, &unique_id);
}
int nvgpu_profiler_alloc(struct gk20a *g,
struct nvgpu_profiler_object **_prof,
enum nvgpu_profiler_pm_reservation_scope scope)
{
struct nvgpu_profiler_object *prof;
*_prof = NULL;
nvgpu_log(g, gpu_dbg_prof, " ");
prof = nvgpu_kzalloc(g, sizeof(*prof));
if (prof == NULL) {
return -ENOMEM;
}
prof->prof_handle = generate_unique_id();
prof->scope = scope;
prof->g = g;
nvgpu_mutex_init(&prof->ioctl_lock);
nvgpu_init_list_node(&prof->prof_obj_entry);
nvgpu_list_add(&prof->prof_obj_entry, &g->profiler_objects);
nvgpu_log(g, gpu_dbg_prof, "Allocated profiler handle %u",
prof->prof_handle);
*_prof = prof;
return 0;
}
void nvgpu_profiler_free(struct nvgpu_profiler_object *prof)
{
struct gk20a *g = prof->g;
nvgpu_log(g, gpu_dbg_prof, "Free profiler handle %u",
prof->prof_handle);
nvgpu_profiler_unbind_context(prof);
nvgpu_list_del(&prof->prof_obj_entry);
nvgpu_kfree(g, prof);
}
int nvgpu_profiler_bind_context(struct nvgpu_profiler_object *prof,
struct nvgpu_tsg *tsg)
{
struct gk20a *g = prof->g;
nvgpu_log(g, gpu_dbg_prof, "Request to bind tsgid %u with profiler handle %u",
tsg->tsgid, prof->prof_handle);
if (tsg->prof != NULL) {
nvgpu_err(g, "TSG %u is already bound", tsg->tsgid);
return -EINVAL;
}
if (prof->tsg != NULL) {
nvgpu_err(g, "Profiler object %u already bound!", prof->prof_handle);
return -EINVAL;
}
prof->tsg = tsg;
tsg->prof = prof;
nvgpu_log(g, gpu_dbg_prof, "Bind tsgid %u with profiler handle %u successful",
tsg->tsgid, prof->prof_handle);
prof->context_init = true;
return 0;
}
int nvgpu_profiler_unbind_context(struct nvgpu_profiler_object *prof)
{
struct gk20a *g = prof->g;
struct nvgpu_tsg *tsg = prof->tsg;
int i;
if (prof->bound) {
nvgpu_warn(g, "Unbinding resources for handle %u",
prof->prof_handle);
nvgpu_profiler_unbind_pm_resources(prof);
}
for (i = 0; i < NVGPU_PROFILER_PM_RESOURCE_TYPE_COUNT; i++) {
if (prof->reserved[i]) {
nvgpu_warn(g, "Releasing reserved resource %u for handle %u",
i, prof->prof_handle);
nvgpu_profiler_pm_resource_release(prof, i);
}
}
if (!prof->context_init) {
return -EINVAL;
}
if (tsg != NULL) {
tsg->prof = NULL;
prof->tsg = NULL;
nvgpu_log(g, gpu_dbg_prof, "Unbind profiler handle %u and tsgid %u",
prof->prof_handle, tsg->tsgid);
}
prof->context_init = false;
return 0;
}
int nvgpu_profiler_pm_resource_reserve(struct nvgpu_profiler_object *prof,
enum nvgpu_profiler_pm_resource_type pm_resource)
{
struct gk20a *g = prof->g;
enum nvgpu_profiler_pm_reservation_scope scope = prof->scope;
u32 reservation_id = prof->prof_handle;
int err;
nvgpu_log(g, gpu_dbg_prof,
"Request reservation for profiler handle %u, resource %u, scope %u",
prof->prof_handle, pm_resource, prof->scope);
if (prof->reserved[pm_resource]) {
nvgpu_err(g, "Profiler handle %u already has the reservation",
prof->prof_handle);
return -EEXIST;
}
if (prof->bound) {
nvgpu_log(g, gpu_dbg_prof,
"PM resources alredy bound with profiler handle %u,"
" unbinding for new reservation",
prof->prof_handle);
err = nvgpu_profiler_unbind_pm_resources(prof);
if (err != 0) {
nvgpu_err(g, "Profiler handle %u failed to unbound, err %d",
prof->prof_handle, err);
return err;
}
}
err = g->ops.pm_reservation.acquire(g, reservation_id, pm_resource,
scope, 0);
if (err != 0) {
nvgpu_err(g, "Profiler handle %u denied the reservation, err %d",
prof->prof_handle, err);
return err;
}
prof->reserved[pm_resource] = true;
nvgpu_log(g, gpu_dbg_prof,
"Granted reservation for profiler handle %u, resource %u, scope %u",
prof->prof_handle, pm_resource, prof->scope);
return 0;
}
int nvgpu_profiler_pm_resource_release(struct nvgpu_profiler_object *prof,
enum nvgpu_profiler_pm_resource_type pm_resource)
{
struct gk20a *g = prof->g;
u32 reservation_id = prof->prof_handle;
int err;
nvgpu_log(g, gpu_dbg_prof,
"Release reservation for profiler handle %u, resource %u, scope %u",
prof->prof_handle, pm_resource, prof->scope);
if (!prof->reserved[pm_resource]) {
nvgpu_log(g, gpu_dbg_prof,
"Profiler handle %u resource is not reserved",
prof->prof_handle);
return -EINVAL;
}
if (prof->bound) {
nvgpu_log(g, gpu_dbg_prof,
"PM resources alredy bound with profiler handle %u,"
" unbinding for reservation release",
prof->prof_handle);
err = nvgpu_profiler_unbind_pm_resources(prof);
if (err != 0) {
nvgpu_err(g, "Profiler handle %u failed to unbound, err %d",
prof->prof_handle, err);
return err;
}
}
err = g->ops.pm_reservation.release(g, reservation_id, pm_resource, 0);
if (err != 0) {
nvgpu_err(g, "Profiler handle %u does not have valid reservation, err %d",
prof->prof_handle, err);
prof->reserved[pm_resource] = false;
return err;
}
prof->reserved[pm_resource] = false;
nvgpu_log(g, gpu_dbg_prof,
"Released reservation for profiler handle %u, resource %u, scope %u",
prof->prof_handle, pm_resource, prof->scope);
return 0;
}
static int nvgpu_profiler_bind_smpc(struct nvgpu_profiler_object *prof)
{
struct gk20a *g = prof->g;
int err;
if (prof->scope == NVGPU_PROFILER_PM_RESERVATION_SCOPE_DEVICE) {
if (prof->ctxsw[NVGPU_PROFILER_PM_RESOURCE_TYPE_SMPC]) {
err = g->ops.gr.update_smpc_ctxsw_mode(g, prof->tsg, true);
if (err != 0) {
return err;
}
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_SMPC_GLOBAL_MODE)) {
err = g->ops.gr.update_smpc_global_mode(g, false);
}
} else {
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_SMPC_GLOBAL_MODE)) {
err = g->ops.gr.update_smpc_global_mode(g, true);
} else {
err = -EINVAL;
}
}
} else {
err = g->ops.gr.update_smpc_ctxsw_mode(g, prof->tsg, true);
}
return err;
}
static int nvgpu_profiler_unbind_smpc(struct nvgpu_profiler_object *prof)
{
struct gk20a *g = prof->g;
int err;
if (prof->scope == NVGPU_PROFILER_PM_RESERVATION_SCOPE_DEVICE) {
if (prof->ctxsw[NVGPU_PROFILER_PM_RESOURCE_TYPE_SMPC]) {
err = g->ops.gr.update_smpc_ctxsw_mode(g, prof->tsg, false);
} else {
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_SMPC_GLOBAL_MODE)) {
err = g->ops.gr.update_smpc_global_mode(g, false);
} else {
err = -EINVAL;
}
}
} else {
err = g->ops.gr.update_smpc_ctxsw_mode(g, prof->tsg, false);
}
return err;
}
static int nvgpu_profiler_bind_hwpm(struct nvgpu_profiler_object *prof, bool streamout)
{
struct gk20a *g = prof->g;
int err = 0;
u32 mode = streamout ? NVGPU_GR_CTX_HWPM_CTXSW_MODE_STREAM_OUT_CTXSW :
NVGPU_GR_CTX_HWPM_CTXSW_MODE_CTXSW;
if (prof->scope == NVGPU_PROFILER_PM_RESERVATION_SCOPE_DEVICE) {
if (prof->ctxsw[NVGPU_PROFILER_PM_RESOURCE_TYPE_HWPM_LEGACY]) {
err = g->ops.gr.update_hwpm_ctxsw_mode(g, prof->tsg, 0, mode);
} else {
g->ops.gr.init_hwpm_pmm_register(g);
}
} else {
err = g->ops.gr.update_hwpm_ctxsw_mode(g, prof->tsg, 0, mode);
}
return err;
}
static int nvgpu_profiler_unbind_hwpm(struct nvgpu_profiler_object *prof)
{
struct gk20a *g = prof->g;
int err = 0;
u32 mode = NVGPU_GR_CTX_HWPM_CTXSW_MODE_NO_CTXSW;
if (prof->scope == NVGPU_PROFILER_PM_RESERVATION_SCOPE_DEVICE) {
if (prof->ctxsw[NVGPU_PROFILER_PM_RESOURCE_TYPE_HWPM_LEGACY]) {
err = g->ops.gr.update_hwpm_ctxsw_mode(g, prof->tsg, 0, mode);
}
} else {
err = g->ops.gr.update_hwpm_ctxsw_mode(g, prof->tsg, 0, mode);
}
return err;
}
static int nvgpu_profiler_bind_hwpm_streamout(struct nvgpu_profiler_object *prof)
{
int err;
err = nvgpu_profiler_bind_hwpm(prof, true);
if (err) {
return err;
}
return 0;
}
static int nvgpu_profiler_unbind_hwpm_streamout(struct nvgpu_profiler_object *prof)
{
int err;
err = nvgpu_profiler_unbind_hwpm(prof);
if (err) {
return err;
}
return 0;
}
int nvgpu_profiler_bind_pm_resources(struct nvgpu_profiler_object *prof)
{
struct gk20a *g = prof->g;
int err;
nvgpu_log(g, gpu_dbg_prof,
"Request to bind PM resources with profiler handle %u",
prof->prof_handle);
if (prof->bound) {
nvgpu_err(g, "PM resources are already bound with profiler handle %u",
prof->prof_handle);
return -EINVAL;
}
if (!prof->reserved[NVGPU_PROFILER_PM_RESOURCE_TYPE_HWPM_LEGACY] &&
!prof->reserved[NVGPU_PROFILER_PM_RESOURCE_TYPE_SMPC]) {
nvgpu_err(g, "No PM resources reserved for profiler handle %u",
prof->prof_handle);
return -EINVAL;
}
err = gk20a_busy(g);
if (err) {
nvgpu_err(g, "failed to poweron");
return err;
}
if (prof->reserved[NVGPU_PROFILER_PM_RESOURCE_TYPE_HWPM_LEGACY]) {
if (prof->reserved[NVGPU_PROFILER_PM_RESOURCE_TYPE_PMA_STREAM]) {
err = nvgpu_profiler_bind_hwpm_streamout(prof);
if (err != 0) {
nvgpu_err(g,
"failed to bind HWPM streamout with profiler handle %u",
prof->prof_handle);
goto fail;
}
nvgpu_log(g, gpu_dbg_prof,
"HWPM streamout bound with profiler handle %u",
prof->prof_handle);
} else {
err = nvgpu_profiler_bind_hwpm(prof, false);
if (err != 0) {
nvgpu_err(g,
"failed to bind HWPM with profiler handle %u",
prof->prof_handle);
goto fail;
}
nvgpu_log(g, gpu_dbg_prof,
"HWPM bound with profiler handle %u",
prof->prof_handle);
}
}
if (prof->reserved[NVGPU_PROFILER_PM_RESOURCE_TYPE_SMPC]) {
err = nvgpu_profiler_bind_smpc(prof);
if (err) {
nvgpu_err(g, "failed to bind SMPC with profiler handle %u",
prof->prof_handle);
goto fail;
}
nvgpu_log(g, gpu_dbg_prof,
"SMPC bound with profiler handle %u", prof->prof_handle);
}
prof->bound = true;
fail:
gk20a_idle(g);
return err;
}
int nvgpu_profiler_unbind_pm_resources(struct nvgpu_profiler_object *prof)
{
struct gk20a *g = prof->g;
int err;
if (!prof->bound) {
nvgpu_err(g, "No PM resources bound to profiler handle %u",
prof->prof_handle);
return -EINVAL;
}
err = gk20a_busy(g);
if (err) {
nvgpu_err(g, "failed to poweron");
return err;
}
if (prof->reserved[NVGPU_PROFILER_PM_RESOURCE_TYPE_HWPM_LEGACY]) {
if (prof->reserved[NVGPU_PROFILER_PM_RESOURCE_TYPE_PMA_STREAM]) {
err = nvgpu_profiler_unbind_hwpm_streamout(prof);
if (err) {
nvgpu_err(g,
"failed to unbind HWPM streamout from profiler handle %u",
prof->prof_handle);
goto fail;
}
nvgpu_log(g, gpu_dbg_prof,
"HWPM streamout unbound from profiler handle %u",
prof->prof_handle);
} else {
err = nvgpu_profiler_unbind_hwpm(prof);
if (err) {
nvgpu_err(g,
"failed to unbind HWPM from profiler handle %u",
prof->prof_handle);
goto fail;
}
nvgpu_log(g, gpu_dbg_prof,
"HWPM unbound from profiler handle %u",
prof->prof_handle);
}
}
if (prof->reserved[NVGPU_PROFILER_PM_RESOURCE_TYPE_SMPC]) {
err = nvgpu_profiler_unbind_smpc(prof);
if (err) {
nvgpu_err(g,
"failed to unbind SMPC from profiler handle %u",
prof->prof_handle);
goto fail;
}
nvgpu_log(g, gpu_dbg_prof,
"SMPC unbound from profiler handle %u", prof->prof_handle);
}
prof->bound = false;
fail:
gk20a_idle(g);
return err;
}