diff --git a/drivers/gpu/nvgpu/common/profiler/profiler.c b/drivers/gpu/nvgpu/common/profiler/profiler.c index 1ceccd30a..a02e36210 100644 --- a/drivers/gpu/nvgpu/common/profiler/profiler.c +++ b/drivers/gpu/nvgpu/common/profiler/profiler.c @@ -109,6 +109,15 @@ int nvgpu_profiler_unbind_context(struct nvgpu_profiler_object *prof) { struct gk20a *g = prof->g; struct nvgpu_tsg *tsg = prof->tsg; + int i; + + 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; diff --git a/drivers/gpu/nvgpu/include/nvgpu/profiler.h b/drivers/gpu/nvgpu/include/nvgpu/profiler.h index b01912195..13def1b2a 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/profiler.h +++ b/drivers/gpu/nvgpu/include/nvgpu/profiler.h @@ -64,6 +64,9 @@ struct nvgpu_profiler_object { /* If profiler object has reservation for each resource. */ bool reserved[NVGPU_PROFILER_PM_RESOURCE_TYPE_COUNT]; + /* If context switch is enabled for each resource */ + bool ctxsw[NVGPU_PROFILER_PM_RESOURCE_TYPE_COUNT]; + /* Scope of the profiler object */ enum nvgpu_profiler_pm_reservation_scope scope; diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_prof.c b/drivers/gpu/nvgpu/os/linux/ioctl_prof.c index 0b96f1fd9..c56129470 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_prof.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_prof.c @@ -174,6 +174,105 @@ static int nvgpu_prof_ioctl_unbind_context(struct nvgpu_profiler_object *prof) return nvgpu_profiler_unbind_context(prof); } +static int nvgpu_prof_ioctl_get_pm_resource_type(u32 resource, + enum nvgpu_profiler_pm_resource_type *pm_resource) +{ + switch (resource) { + case NVGPU_PROFILER_PM_RESOURCE_ARG_HWPM_LEGACY: + *pm_resource = NVGPU_PROFILER_PM_RESOURCE_TYPE_HWPM_LEGACY; + return 0; + case NVGPU_PROFILER_PM_RESOURCE_ARG_SMPC: + *pm_resource = NVGPU_PROFILER_PM_RESOURCE_TYPE_SMPC; + return 0; + default: + break; + } + + return -EINVAL; +} + +static int nvgpu_prof_ioctl_reserve_pm_resource(struct nvgpu_profiler_object *prof, + struct nvgpu_profiler_reserve_pm_resource_args *args) +{ + enum nvgpu_profiler_pm_resource_type pm_resource; + struct gk20a *g = prof->g; + bool flag_ctxsw; + int err; + + if (!prof->context_init) { + nvgpu_err(g, "Context info not initialized"); + return -EINVAL; + } + + err = nvgpu_prof_ioctl_get_pm_resource_type(args->resource, + &pm_resource); + if (err) { + nvgpu_err(prof->g, "invalid resource %u", args->resource); + return err; + } + + flag_ctxsw = ((args->flags & NVGPU_PROFILER_RESERVE_PM_RESOURCE_ARG_FLAG_CTXSW) != 0); + + switch (prof->scope) { + case NVGPU_PROFILER_PM_RESERVATION_SCOPE_DEVICE: + if (flag_ctxsw && (prof->tsg == NULL)) { + nvgpu_err(g, "Context must be bound to enable context switch"); + return -EINVAL; + } + if (!flag_ctxsw && (pm_resource == NVGPU_PROFILER_PM_RESOURCE_TYPE_SMPC) + && !nvgpu_is_enabled(g, NVGPU_SUPPORT_SMPC_GLOBAL_MODE)) { + nvgpu_err(g, "SMPC global mode not supported"); + return -EINVAL; + } + if (flag_ctxsw) { + prof->ctxsw[pm_resource] = true; + } else { + prof->ctxsw[pm_resource] = false; + } + break; + + case NVGPU_PROFILER_PM_RESERVATION_SCOPE_CONTEXT: + if (prof->tsg == NULL) { + nvgpu_err(g, "Context must be bound for context session"); + return -EINVAL; + } + prof->ctxsw[pm_resource] = true; + break; + + default: + return -EINVAL; + } + + err = nvgpu_profiler_pm_resource_reserve(prof, pm_resource); + if (err) { + return err; + } + + return 0; +} + +static int nvgpu_prof_ioctl_release_pm_resource(struct nvgpu_profiler_object *prof, + struct nvgpu_profiler_release_pm_resource_args *args) +{ + enum nvgpu_profiler_pm_resource_type pm_resource; + int err; + + err = nvgpu_prof_ioctl_get_pm_resource_type(args->resource, + &pm_resource); + if (err) { + return err; + } + + err = nvgpu_profiler_pm_resource_release(prof, pm_resource); + if (err) { + return err; + } + + prof->ctxsw[pm_resource] = false; + + return 0; +} + long nvgpu_prof_fops_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -214,6 +313,16 @@ long nvgpu_prof_fops_ioctl(struct file *filp, unsigned int cmd, err = nvgpu_prof_ioctl_unbind_context(prof); break; + case NVGPU_PROFILER_IOCTL_RESERVE_PM_RESOURCE: + err = nvgpu_prof_ioctl_reserve_pm_resource(prof, + (struct nvgpu_profiler_reserve_pm_resource_args *)buf); + break; + + case NVGPU_PROFILER_IOCTL_RELEASE_PM_RESOURCE: + err = nvgpu_prof_ioctl_release_pm_resource(prof, + (struct nvgpu_profiler_release_pm_resource_args *)buf); + break; + default: nvgpu_err(g, "unrecognized profiler ioctl cmd: 0x%x", cmd); err = -ENOTTY; diff --git a/include/uapi/linux/nvgpu.h b/include/uapi/linux/nvgpu.h index abd176b6b..508090e9f 100644 --- a/include/uapi/linux/nvgpu.h +++ b/include/uapi/linux/nvgpu.h @@ -1525,10 +1525,8 @@ struct nvgpu_profiler_bind_context_args { __u32 reserved; }; -enum { - NVGPU_PROFILER_PM_RESOURCE_ARG_HWPM_LEGACY, - NVGPU_PROFILER_PM_RESOURCE_ARG_SMPC, -}; +#define NVGPU_PROFILER_PM_RESOURCE_ARG_HWPM_LEGACY 0U +#define NVGPU_PROFILER_PM_RESOURCE_ARG_SMPC 1U struct nvgpu_profiler_reserve_pm_resource_args { __u32 resource; /* in: NVGPU_PROFILER_PM_RESOURCE_ARG_* resource to be reserved */