diff --git a/arch/nvgpu-common.yaml b/arch/nvgpu-common.yaml index eacdc2639..1925068e5 100644 --- a/arch/nvgpu-common.yaml +++ b/arch/nvgpu-common.yaml @@ -59,6 +59,12 @@ debugger: include/nvgpu/debugger.h ] deps: +profiler: + safe: no + owner: Deepak N + sources: [ common/profiler/profiler.c, + include/nvgpu/profiler.h ] + defaults: safe: yes sources: [ include/nvgpu/defaults.h ] diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile index b3e75eb27..13b72549d 100644 --- a/drivers/gpu/nvgpu/Makefile +++ b/drivers/gpu/nvgpu/Makefile @@ -50,6 +50,7 @@ ccflags-y += -DCONFIG_NVGPU_GR_FALCON_NON_SECURE_BOOT ccflags-y += -DCONFIG_NVGPU_SET_FALCON_ACCESS_MAP ccflags-y += -DCONFIG_NVGPU_SW_SEMAPHORE ccflags-y += -DCONFIG_NVGPU_FENCE +ccflags-y += -DCONFIG_NVGPU_PROFILER ifeq ($(CONFIG_NVGPU_LOGGING),y) ccflags-y += -DCONFIG_NVGPU_LOGGING=1 @@ -541,7 +542,8 @@ nvgpu-y += \ common/ecc.o \ common/log_common.o \ common/ce/ce.o \ - common/debugger.o + common/debugger.o \ + common/profiler/profiler.o nvgpu-$(CONFIG_NVGPU_GR_VIRTUALIZATION) += \ common/vgpu/ltc/ltc_vgpu.o \ diff --git a/drivers/gpu/nvgpu/Makefile.shared.configs b/drivers/gpu/nvgpu/Makefile.shared.configs index 882ee8e91..8bea08ac1 100644 --- a/drivers/gpu/nvgpu/Makefile.shared.configs +++ b/drivers/gpu/nvgpu/Makefile.shared.configs @@ -156,6 +156,9 @@ NVGPU_COMMON_CFLAGS += -DCONFIG_NVGPU_ENGINE_QUEUE CONFIG_NVGPU_DEBUGGER := 1 NVGPU_COMMON_CFLAGS += -DCONFIG_NVGPU_DEBUGGER +CONFIG_NVGPU_PROFILER := 1 +NVGPU_COMMON_CFLAGS += -DCONFIG_NVGPU_PROFILER + CONFIG_NVGPU_RECOVERY := 1 NVGPU_COMMON_CFLAGS += -DCONFIG_NVGPU_RECOVERY diff --git a/drivers/gpu/nvgpu/Makefile.sources b/drivers/gpu/nvgpu/Makefile.sources index 6aad1299e..6cdefb7ac 100644 --- a/drivers/gpu/nvgpu/Makefile.sources +++ b/drivers/gpu/nvgpu/Makefile.sources @@ -389,6 +389,10 @@ srcs += hal/regops/regops_gm20b.c \ endif endif +ifeq ($(CONFIG_NVGPU_PROFILER),1) +srcs += common/profiler/profiler.c +endif + ifeq ($(CONFIG_NVGPU_KERNEL_MODE_SUBMIT),1) srcs += common/fifo/submit.c \ common/fifo/priv_cmdbuf.c \ diff --git a/drivers/gpu/nvgpu/common/debugger.c b/drivers/gpu/nvgpu/common/debugger.c index b0d468c8e..72d700c2a 100644 --- a/drivers/gpu/nvgpu/common/debugger.c +++ b/drivers/gpu/nvgpu/common/debugger.c @@ -34,6 +34,7 @@ #include #include #include +#include #include /* @@ -281,7 +282,7 @@ void nvgpu_release_profiler_reservation(struct dbg_session_gk20a *dbg_s, } dbg_s->has_profiler_reservation = false; prof_obj->has_reservation = false; - if (prof_obj->ch == NULL) { + if (prof_obj->tsg == NULL) { g->global_profiler_reservation_held = false; } } diff --git a/drivers/gpu/nvgpu/common/profiler/profiler.c b/drivers/gpu/nvgpu/common/profiler/profiler.c new file mode 100644 index 000000000..7da67cc0b --- /dev/null +++ b/drivers/gpu/nvgpu/common/profiler/profiler.c @@ -0,0 +1,64 @@ +/* + * 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 +#include +#include +#include +#include + +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 dbg_profiler_object_data **_prof) +{ + struct dbg_profiler_object_data *prof; + *_prof = NULL; + + nvgpu_log(g, gpu_dbg_fn | gpu_dbg_gpu_dbg, " "); + + prof = nvgpu_kzalloc(g, sizeof(*prof)); + if (prof == NULL) { + return -ENOMEM; + } + + prof->prof_handle = generate_unique_id(); + prof->g = g; + + nvgpu_init_list_node(&prof->prof_obj_entry); + nvgpu_list_add(&prof->prof_obj_entry, &g->profiler_objects); + + *_prof = prof; + return 0; +} + +void nvgpu_profiler_free(struct dbg_profiler_object_data *prof) +{ + struct gk20a *g = prof->g; + + nvgpu_list_del(&prof->prof_obj_entry); + nvgpu_kfree(g, prof); +} diff --git a/drivers/gpu/nvgpu/common/vgpu/debugger_vgpu.c b/drivers/gpu/nvgpu/common/vgpu/debugger_vgpu.c index ff82e91c7..9a24242c0 100644 --- a/drivers/gpu/nvgpu/common/vgpu/debugger_vgpu.c +++ b/drivers/gpu/nvgpu/common/vgpu/debugger_vgpu.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -186,7 +187,7 @@ void vgpu_release_profiler_reservation( dbg_s->has_profiler_reservation = false; prof_obj->has_reservation = false; - if (prof_obj->ch == NULL) { + if (prof_obj->tsg == NULL) { g->global_profiler_reservation_held = false; } diff --git a/drivers/gpu/nvgpu/include/nvgpu/debugger.h b/drivers/gpu/nvgpu/include/nvgpu/debugger.h index ce63603ae..3258439b8 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/debugger.h +++ b/drivers/gpu/nvgpu/include/nvgpu/debugger.h @@ -33,6 +33,7 @@ struct gk20a; struct nvgpu_channel; struct dbg_session_gk20a; +struct dbg_profiler_object_data; struct nvgpu_channel * nvgpu_dbg_gpu_get_session_channel(struct dbg_session_gk20a *dbg_s); @@ -101,21 +102,6 @@ dbg_session_channel_data_from_ch_entry(struct nvgpu_list_node *node) ((uintptr_t)node - offsetof(struct dbg_session_channel_data, ch_entry)); }; -struct dbg_profiler_object_data { - int session_id; - u32 prof_handle; - struct nvgpu_channel *ch; - bool has_reservation; - struct nvgpu_list_node prof_obj_entry; -}; - -static inline struct dbg_profiler_object_data * -dbg_profiler_object_data_from_prof_obj_entry(struct nvgpu_list_node *node) -{ - return (struct dbg_profiler_object_data *) - ((uintptr_t)node - offsetof(struct dbg_profiler_object_data, prof_obj_entry)); -}; - /* used by the interrupt handler to post events */ void nvgpu_dbg_gpu_post_events(struct nvgpu_channel *ch); diff --git a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h index c2005f719..7b0916755 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h +++ b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h @@ -830,7 +830,6 @@ struct gk20a { } perfbuf; /* For profiler reservations */ - struct nvgpu_list_node profiler_objects; bool global_profiler_reservation_held; int profiler_reservation_count; @@ -838,6 +837,10 @@ struct gk20a { u32 mmu_debug_mode_refcnt; #endif /* CONFIG_NVGPU_DEBUGGER */ +#ifdef CONFIG_NVGPU_PROFILER + struct nvgpu_list_node profiler_objects; +#endif + #ifdef CONFIG_NVGPU_FECS_TRACE struct gk20a_ctxsw_trace *ctxsw_trace; struct nvgpu_gr_fecs_trace *fecs_trace; diff --git a/drivers/gpu/nvgpu/include/nvgpu/profiler.h b/drivers/gpu/nvgpu/include/nvgpu/profiler.h new file mode 100644 index 000000000..4614838ee --- /dev/null +++ b/drivers/gpu/nvgpu/include/nvgpu/profiler.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#ifndef NVGPU_PROFILER_H +#define NVGPU_PROFILER_H + +#ifdef CONFIG_NVGPU_PROFILER + +#include + +struct gk20a; +struct nvgpu_channel; + +struct dbg_profiler_object_data { + struct gk20a *g; + int session_id; + u32 prof_handle; + struct nvgpu_tsg *tsg; + bool has_reservation; + struct nvgpu_list_node prof_obj_entry; +}; + +static inline struct dbg_profiler_object_data * +dbg_profiler_object_data_from_prof_obj_entry(struct nvgpu_list_node *node) +{ + return (struct dbg_profiler_object_data *) + ((uintptr_t)node - offsetof(struct dbg_profiler_object_data, prof_obj_entry)); +}; + +int nvgpu_profiler_alloc(struct gk20a *g, + struct dbg_profiler_object_data **_prof); +void nvgpu_profiler_free(struct dbg_profiler_object_data *prof); + +#endif /* CONFIG_NVGPU_PROFILER */ +#endif /* NVGPU_PROFILER_H */ diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c b/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c index af1393d0d..3369cef7f 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -79,23 +80,6 @@ static int generate_unique_id(void) return nvgpu_atomic_add_return(1, &unique_id); } -static int alloc_profiler(struct gk20a *g, - struct dbg_profiler_object_data **_prof) -{ - struct dbg_profiler_object_data *prof; - *_prof = NULL; - - nvgpu_log(g, gpu_dbg_fn | gpu_dbg_gpu_dbg, " "); - - prof = nvgpu_kzalloc(g, sizeof(*prof)); - if (!prof) - return -ENOMEM; - - prof->prof_handle = generate_unique_id(); - *_prof = prof; - return 0; -} - static int alloc_session(struct gk20a *g, struct dbg_session_gk20a_linux **_dbg_s_linux) { struct dbg_session_gk20a_linux *dbg_s_linux; @@ -462,10 +446,12 @@ static int dbg_unbind_single_channel_gk20a(struct dbg_session_gk20a *dbg_s, struct dbg_session_data *session_data; struct dbg_profiler_object_data *prof_obj, *tmp_obj; struct dbg_session_channel_data_linux *ch_data_linux; + struct nvgpu_channel *ch; nvgpu_log(g, gpu_dbg_fn | gpu_dbg_gpu_dbg, " "); chid = ch_data->chid; + ch = &g->fifo.channel[chid]; /* If there's a profiler ctx reservation record associated with this * session/channel pair, release it. @@ -473,7 +459,7 @@ static int dbg_unbind_single_channel_gk20a(struct dbg_session_gk20a *dbg_s, nvgpu_list_for_each_entry_safe(prof_obj, tmp_obj, &g->profiler_objects, dbg_profiler_object_data, prof_obj_entry) { if ((prof_obj->session_id == dbg_s->id) && - (prof_obj->ch->chid == chid)) { + (prof_obj->tsg->tsgid == ch->tsgid)) { if (prof_obj->has_reservation) { g->ops.debugger. release_profiler_reservation(dbg_s, prof_obj); @@ -1186,36 +1172,42 @@ static int nvgpu_ioctl_allocate_profiler_object( struct dbg_session_gk20a *dbg_s = &dbg_session_linux->dbg_s; struct gk20a *g = get_gk20a(dbg_session_linux->dev); struct dbg_profiler_object_data *prof_obj; + struct nvgpu_channel *ch = NULL; + struct nvgpu_tsg *tsg; nvgpu_log_fn(g, "%s", g->name); nvgpu_mutex_acquire(&g->dbg_sessions_lock); - err = alloc_profiler(g, &prof_obj); - if (err) - goto clean_up; - - prof_obj->session_id = dbg_s->id; - - if (dbg_s->is_profiler) - prof_obj->ch = NULL; - else { - prof_obj->ch = nvgpu_dbg_gpu_get_session_channel(dbg_s); - if (prof_obj->ch == NULL) { - nvgpu_err(g, - "bind a channel for dbg session"); - nvgpu_kfree(g, prof_obj); + if (!dbg_s->is_profiler) { + ch = nvgpu_dbg_gpu_get_session_channel(dbg_s); + if (ch == NULL) { + nvgpu_err(g, "no channel for dbg session"); err = -EINVAL; goto clean_up; } } + err = nvgpu_profiler_alloc(g, &prof_obj); + if (err != 0) { + goto clean_up; + } + + if (ch != NULL) { + tsg = nvgpu_tsg_from_ch(ch); + if (tsg == NULL) { + nvgpu_profiler_free(prof_obj); + goto clean_up; + } + + prof_obj->tsg = tsg; + } + + prof_obj->session_id = dbg_s->id; + /* Return handle to client */ args->profiler_handle = prof_obj->prof_handle; - nvgpu_init_list_node(&prof_obj->prof_obj_entry); - - nvgpu_list_add(&prof_obj->prof_obj_entry, &g->profiler_objects); clean_up: nvgpu_mutex_release(&g->dbg_sessions_lock); return err; @@ -1250,8 +1242,7 @@ static int nvgpu_ioctl_free_profiler_object( if (prof_obj->has_reservation) g->ops.debugger. release_profiler_reservation(dbg_s, prof_obj); - nvgpu_list_del(&prof_obj->prof_obj_entry); - nvgpu_kfree(g, prof_obj); + nvgpu_profiler_free(prof_obj); obj_found = true; break; } @@ -1726,7 +1717,6 @@ static int nvgpu_profiler_reserve_acquire(struct dbg_session_gk20a *dbg_s, struct gk20a *g = dbg_s->g; struct dbg_profiler_object_data *prof_obj, *my_prof_obj; int err = 0; - struct nvgpu_tsg *tsg; nvgpu_log_fn(g, "%s profiler_handle = %x", g->name, profiler_handle); @@ -1752,7 +1742,7 @@ static int nvgpu_profiler_reserve_acquire(struct dbg_session_gk20a *dbg_s, goto exit; } - if (my_prof_obj->ch == NULL) { + if (my_prof_obj->tsg == NULL) { /* Global reservations are only allowed if there are no other * global or per-context reservations currently held */ @@ -1769,16 +1759,14 @@ static int nvgpu_profiler_reserve_acquire(struct dbg_session_gk20a *dbg_s, nvgpu_err(g, "per-ctxt reserve: global reservation in effect"); err = -EBUSY; - } else if ((tsg = nvgpu_tsg_from_ch(my_prof_obj->ch)) != NULL) { - /* TSG: check that another channel in the TSG - * doesn't already have the reservation - */ - u32 my_tsgid = tsg->tsgid; + } else { + /* check that this TSG doesn't already have the reservation */ + u32 my_tsgid = my_prof_obj->tsg->tsgid; nvgpu_list_for_each_entry(prof_obj, &g->profiler_objects, dbg_profiler_object_data, prof_obj_entry) { if (prof_obj->has_reservation && - (prof_obj->ch->tsgid == my_tsgid)) { + (prof_obj->tsg->tsgid == my_tsgid)) { nvgpu_err(g, "per-ctxt reserve (tsg): already reserved"); err = -EBUSY; @@ -1786,30 +1774,6 @@ static int nvgpu_profiler_reserve_acquire(struct dbg_session_gk20a *dbg_s, } } - if (!g->ops.debugger.check_and_set_context_reservation( - dbg_s, my_prof_obj)) { - /* Another guest OS has the global reservation */ - nvgpu_err(g, - "per-ctxt reserve: global reservation in effect"); - err = -EBUSY; - } - } else { - /* channel: check that some other profiler object doesn't - * already have the reservation. - */ - struct nvgpu_channel *my_ch = my_prof_obj->ch; - - nvgpu_list_for_each_entry(prof_obj, &g->profiler_objects, - dbg_profiler_object_data, prof_obj_entry) { - if (prof_obj->has_reservation && - (prof_obj->ch == my_ch)) { - nvgpu_err(g, - "per-ctxt reserve (ch): already reserved"); - err = -EBUSY; - goto exit; - } - } - if (!g->ops.debugger.check_and_set_context_reservation( dbg_s, my_prof_obj)) { /* Another guest OS has the global reservation */