gpu: nvgpu: support binding multiple channels to a debug session

We currently bind only one channel to a debug session
But some use cases might need multiple channels bound
to same debug session

Add this support by adding a list of channels to debug session.
List structure is implemented as struct dbg_session_channel_data

List node dbg_s_list_node is currently defined in struct
dbg_session_gk20a. But this is inefficient when we need to
add debug session to multiple channels

Hence add new reference structure dbg_session_data to
store dbg_session pointer and list entry

For each NVGPU_DBG_GPU_IOCTL_BIND_CHANNEL call, create
two reference structure dbg_session_channel_data for channel
and dbg_session_data for debug session and bind them together

Define API nvgpu_dbg_gpu_get_session_channel() which will
get first channel in the list of debug session
Use this API wherever we refer to channel bound to debug
session

Remove dbg_sessions define in struct gk20a since it is
not being used anywhere

Add new API NVGPU_DBG_GPU_IOCTL_UNBIND_CHANNEL to support
unbinding of channel from debug sesssion

Bug 200156699

Change-Id: I3bfa6f9cd5b90e7254a75c7e64ac893739776b7f
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/1120331
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
This commit is contained in:
Deepak Nibade
2016-03-29 15:01:25 +05:30
committed by Terje Bergstrom
parent c651adbeaa
commit dfac8ce704
7 changed files with 257 additions and 67 deletions

View File

@@ -857,6 +857,8 @@ static void gk20a_free_channel(struct channel_gk20a *ch)
struct vm_gk20a *ch_vm = ch->vm;
unsigned long timeout = gk20a_get_gr_idle_timeout(g);
struct dbg_session_gk20a *dbg_s;
struct dbg_session_data *session_data, *tmp_s;
struct dbg_session_channel_data *ch_data, *tmp;
bool was_reset;
gk20a_dbg_fn("");
@@ -992,14 +994,21 @@ unbind:
WARN_ON(ch->sync);
/* unlink all debug sessions */
mutex_lock(&ch->dbg_s_lock);
mutex_lock(&g->dbg_sessions_lock);
list_for_each_entry(dbg_s, &ch->dbg_s_list, dbg_s_list_node) {
dbg_s->ch = NULL;
list_del_init(&dbg_s->dbg_s_list_node);
list_for_each_entry_safe(session_data, tmp_s,
&ch->dbg_s_list, dbg_s_entry) {
dbg_s = session_data->dbg_s;
mutex_lock(&dbg_s->ch_list_lock);
list_for_each_entry_safe(ch_data, tmp,
&dbg_s->ch_list, ch_entry) {
if (ch_data->chid == ch->hw_chid)
dbg_unbind_single_channel_gk20a(dbg_s, ch_data);
}
mutex_unlock(&dbg_s->ch_list_lock);
}
mutex_unlock(&ch->dbg_s_lock);
mutex_unlock(&g->dbg_sessions_lock);
release:
/* make sure we catch accesses of unopened channels in case

View File

@@ -35,6 +35,33 @@ struct dbg_gpu_session_ops dbg_gpu_session_ops_gk20a = {
.exec_reg_ops = exec_regops_gk20a,
};
/*
* API to get first channel from the list of all channels
* bound to the debug session
*/
struct channel_gk20a *
nvgpu_dbg_gpu_get_session_channel(struct dbg_session_gk20a *dbg_s)
{
struct dbg_session_channel_data *ch_data;
struct channel_gk20a *ch;
struct gk20a *g = dbg_s->g;
mutex_lock(&dbg_s->ch_list_lock);
if (list_empty(&dbg_s->ch_list)) {
mutex_unlock(&dbg_s->ch_list_lock);
return NULL;
}
ch_data = list_first_entry(&dbg_s->ch_list,
struct dbg_session_channel_data,
ch_entry);
ch = g->fifo.channel + ch_data->chid;
mutex_unlock(&dbg_s->ch_list_lock);
return ch;
}
/* silly allocator - just increment session id */
static atomic_t session_id = ATOMIC_INIT(0);
static int generate_session_id(void)
@@ -95,8 +122,9 @@ static int gk20a_dbg_gpu_do_dev_open(struct inode *inode,
if (gk20a_gpu_is_virtual(dev))
dbg_session->is_pg_disabled = true;
INIT_LIST_HEAD(&dbg_session->dbg_s_list_node);
init_waitqueue_head(&dbg_session->dbg_events.wait_queue);
INIT_LIST_HEAD(&dbg_session->ch_list);
mutex_init(&dbg_session->ch_list_lock);
dbg_session->dbg_events.events_enabled = false;
dbg_session->dbg_events.num_pending_events = 0;
@@ -108,18 +136,22 @@ static int gk20a_dbg_gpu_do_dev_open(struct inode *inode,
* since it might not have an associated channel. */
static void gk20a_dbg_session_mutex_lock(struct dbg_session_gk20a *dbg_s)
{
if (dbg_s->is_profiler)
struct channel_gk20a *ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (dbg_s->is_profiler || !ch)
mutex_lock(&dbg_s->g->dbg_sessions_lock);
else
mutex_lock(&dbg_s->ch->dbg_s_lock);
mutex_lock(&ch->dbg_s_lock);
}
static void gk20a_dbg_session_mutex_unlock(struct dbg_session_gk20a *dbg_s)
{
if (dbg_s->is_profiler)
struct channel_gk20a *ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (dbg_s->is_profiler || !ch)
mutex_unlock(&dbg_s->g->dbg_sessions_lock);
else
mutex_unlock(&dbg_s->ch->dbg_s_lock);
mutex_unlock(&ch->dbg_s_lock);
}
static void gk20a_dbg_gpu_events_enable(struct dbg_session_gk20a *dbg_s)
@@ -163,10 +195,12 @@ static int gk20a_dbg_gpu_events_ctrl(struct dbg_session_gk20a *dbg_s,
struct nvgpu_dbg_gpu_events_ctrl_args *args)
{
int ret = 0;
struct channel_gk20a *ch;
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "dbg events ctrl cmd %d", args->cmd);
if (!dbg_s->ch) {
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (!ch) {
gk20a_err(dev_from_gk20a(dbg_s->g),
"no channel bound to dbg session\n");
return -EINVAL;
@@ -235,6 +269,7 @@ int gk20a_prof_gpu_dev_open(struct inode *inode, struct file *filp)
void gk20a_dbg_gpu_post_events(struct channel_gk20a *ch)
{
struct dbg_session_data *session_data;
struct dbg_session_gk20a *dbg_s;
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "");
@@ -242,7 +277,8 @@ void gk20a_dbg_gpu_post_events(struct channel_gk20a *ch)
/* guard against the session list being modified */
mutex_lock(&ch->dbg_s_lock);
list_for_each_entry(dbg_s, &ch->dbg_s_list, dbg_s_list_node) {
list_for_each_entry(session_data, &ch->dbg_s_list, dbg_s_entry) {
dbg_s = session_data->dbg_s;
if (dbg_s->dbg_events.events_enabled) {
gk20a_dbg(gpu_dbg_gpu_dbg, "posting event on session id %d",
dbg_s->id);
@@ -260,6 +296,7 @@ void gk20a_dbg_gpu_post_events(struct channel_gk20a *ch)
bool gk20a_dbg_gpu_broadcast_stop_trigger(struct channel_gk20a *ch)
{
struct dbg_session_data *session_data;
struct dbg_session_gk20a *dbg_s;
bool broadcast = false;
@@ -268,7 +305,8 @@ bool gk20a_dbg_gpu_broadcast_stop_trigger(struct channel_gk20a *ch)
/* guard against the session list being modified */
mutex_lock(&ch->dbg_s_lock);
list_for_each_entry(dbg_s, &ch->dbg_s_list, dbg_s_list_node) {
list_for_each_entry(session_data, &ch->dbg_s_list, dbg_s_entry) {
dbg_s = session_data->dbg_s;
if (dbg_s->broadcast_stop_trigger) {
gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn | gpu_dbg_intr,
"stop trigger broadcast enabled");
@@ -284,6 +322,7 @@ bool gk20a_dbg_gpu_broadcast_stop_trigger(struct channel_gk20a *ch)
int gk20a_dbg_gpu_clear_broadcast_stop_trigger(struct channel_gk20a *ch)
{
struct dbg_session_data *session_data;
struct dbg_session_gk20a *dbg_s;
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg | gpu_dbg_intr, "");
@@ -291,7 +330,8 @@ int gk20a_dbg_gpu_clear_broadcast_stop_trigger(struct channel_gk20a *ch)
/* guard against the session list being modified */
mutex_lock(&ch->dbg_s_lock);
list_for_each_entry(dbg_s, &ch->dbg_s_list, dbg_s_list_node) {
list_for_each_entry(session_data, &ch->dbg_s_list, dbg_s_entry) {
dbg_s = session_data->dbg_s;
if (dbg_s->broadcast_stop_trigger) {
gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn | gpu_dbg_intr,
"stop trigger broadcast disabled");
@@ -347,36 +387,87 @@ static int nvgpu_dbg_timeout_enable(struct dbg_session_gk20a *dbg_s,
return err;
}
static int dbg_unbind_channel_gk20a(struct dbg_session_gk20a *dbg_s)
int dbg_unbind_single_channel_gk20a(struct dbg_session_gk20a *dbg_s,
struct dbg_session_channel_data *ch_data)
{
struct channel_gk20a *ch_gk20a = dbg_s->ch;
struct gk20a *g = dbg_s->g;
int chid;
struct channel_gk20a *ch;
struct dbg_session_data *session_data;
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "");
/* wasn't bound to start with ? */
if (!ch_gk20a) {
gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn, "not bound already?");
return -ENODEV;
chid = ch_data->chid;
ch = g->fifo.channel + chid;
list_del_init(&ch_data->ch_entry);
session_data = ch_data->session_data;
list_del_init(&session_data->dbg_s_entry);
kfree(session_data);
fput(ch_data->ch_f);
kfree(ch_data);
return 0;
}
static int dbg_unbind_all_channels_gk20a(struct dbg_session_gk20a *dbg_s)
{
struct dbg_session_channel_data *ch_data, *tmp;
struct gk20a *g = dbg_s->g;
mutex_lock(&g->dbg_sessions_lock);
mutex_lock(&ch_gk20a->dbg_s_lock);
--g->dbg_sessions;
dbg_s->ch = NULL;
fput(dbg_s->ch_f);
dbg_s->ch_f = NULL;
list_del_init(&dbg_s->dbg_s_list_node);
mutex_unlock(&ch_gk20a->dbg_s_lock);
mutex_lock(&dbg_s->ch_list_lock);
list_for_each_entry_safe(ch_data, tmp, &dbg_s->ch_list, ch_entry)
dbg_unbind_single_channel_gk20a(dbg_s, ch_data);
mutex_unlock(&dbg_s->ch_list_lock);
mutex_unlock(&g->dbg_sessions_lock);
return 0;
}
static int dbg_unbind_channel_gk20a(struct dbg_session_gk20a *dbg_s,
struct nvgpu_dbg_gpu_unbind_channel_args *args)
{
struct dbg_session_channel_data *ch_data;
struct gk20a *g = dbg_s->g;
bool channel_found = false;
struct channel_gk20a *ch;
int err;
gk20a_dbg(gpu_dbg_fn|gpu_dbg_gpu_dbg, "%s fd=%d",
dev_name(dbg_s->dev), args->channel_fd);
ch = gk20a_get_channel_from_file(args->channel_fd);
if (!ch) {
gk20a_dbg_fn("no channel found for fd");
return -EINVAL;
}
mutex_lock(&dbg_s->ch_list_lock);
list_for_each_entry(ch_data, &dbg_s->ch_list, ch_entry) {
if (ch->hw_chid == ch_data->chid) {
channel_found = true;
break;
}
}
mutex_unlock(&dbg_s->ch_list_lock);
if (!channel_found) {
gk20a_dbg_fn("channel not bounded, fd=%d\n", args->channel_fd);
return -EINVAL;
}
mutex_lock(&g->dbg_sessions_lock);
mutex_lock(&dbg_s->ch_list_lock);
err = dbg_unbind_single_channel_gk20a(dbg_s, ch_data);
mutex_unlock(&dbg_s->ch_list_lock);
mutex_unlock(&g->dbg_sessions_lock);
return err;
}
int gk20a_dbg_gpu_dev_release(struct inode *inode, struct file *filp)
{
struct dbg_session_gk20a *dbg_s = filp->private_data;
@@ -384,9 +475,8 @@ int gk20a_dbg_gpu_dev_release(struct inode *inode, struct file *filp)
gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn, "%s", dev_name(dbg_s->dev));
/* unbind if it was bound */
if (dbg_s->ch)
dbg_unbind_channel_gk20a(dbg_s);
/* unbind channels */
dbg_unbind_all_channels_gk20a(dbg_s);
/* Powergate/Timeout enable is called here as possibility of dbg_session
* which called powergate/timeout disable ioctl, to be killed without
@@ -405,14 +495,28 @@ static int dbg_bind_channel_gk20a(struct dbg_session_gk20a *dbg_s,
struct nvgpu_dbg_gpu_bind_channel_args *args)
{
struct file *f;
struct gk20a *g;
struct gk20a *g = dbg_s->g;
struct channel_gk20a *ch;
struct dbg_session_channel_data *ch_data, *tmp;
struct dbg_session_data *session_data;
gk20a_dbg(gpu_dbg_fn|gpu_dbg_gpu_dbg, "%s fd=%d",
dev_name(dbg_s->dev), args->channel_fd);
if (args->channel_fd == ~0)
return dbg_unbind_channel_gk20a(dbg_s);
if (args->channel_fd == ~0) {
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (!ch)
return -EINVAL;
mutex_lock(&dbg_s->ch_list_lock);
list_for_each_entry_safe(ch_data, tmp,
&dbg_s->ch_list, ch_entry) {
if (ch_data->chid == ch->hw_chid)
dbg_unbind_single_channel_gk20a(dbg_s, ch_data);
}
mutex_unlock(&dbg_s->ch_list_lock);
return 0;
}
/* even though get_file_channel is doing this it releases it as well */
/* by holding it here we'll keep it from disappearing while the
@@ -428,20 +532,40 @@ static int dbg_bind_channel_gk20a(struct dbg_session_gk20a *dbg_s,
return -EINVAL;
}
g = dbg_s->g;
gk20a_dbg_fn("%s hwchid=%d", dev_name(dbg_s->dev), ch->hw_chid);
mutex_lock(&g->dbg_sessions_lock);
mutex_lock(&ch->dbg_s_lock);
dbg_s->ch_f = f;
dbg_s->ch = ch;
list_add(&dbg_s->dbg_s_list_node, &dbg_s->ch->dbg_s_list);
ch_data = kzalloc(sizeof(*ch_data), GFP_KERNEL);
if (!ch_data) {
fput(f);
return -ENOMEM;
}
ch_data->ch_f = f;
ch_data->channel_fd = args->channel_fd;
ch_data->chid = ch->hw_chid;
INIT_LIST_HEAD(&ch_data->ch_entry);
g->dbg_sessions++;
session_data = kzalloc(sizeof(*session_data), GFP_KERNEL);
if (!session_data) {
kfree(ch_data);
fput(f);
return -ENOMEM;
}
session_data->dbg_s = dbg_s;
INIT_LIST_HEAD(&session_data->dbg_s_entry);
ch_data->session_data = session_data;
list_add(&session_data->dbg_s_entry, &ch->dbg_s_list);
mutex_lock(&dbg_s->ch_list_lock);
list_add_tail(&ch_data->ch_entry, &dbg_s->ch_list);
mutex_unlock(&dbg_s->ch_list_lock);
mutex_unlock(&ch->dbg_s_lock);
mutex_unlock(&g->dbg_sessions_lock);
return 0;
}
@@ -470,8 +594,12 @@ static int gk20a_perfbuf_unmap(struct dbg_session_gk20a *dbg_s,
static int gk20a_dbg_pc_sampling(struct dbg_session_gk20a *dbg_s,
struct nvgpu_dbg_gpu_pc_sampling_args *args)
{
struct channel_gk20a *ch = dbg_s->ch;
struct gk20a *g = ch->g;
struct channel_gk20a *ch;
struct gk20a *g = dbg_s->g;
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (!ch)
return -EINVAL;
gk20a_dbg_fn("");
@@ -571,9 +699,13 @@ static int nvgpu_dbg_gpu_ioctl_clear_single_sm_error_state(
struct gk20a *g = get_gk20a(dbg_s->dev);
struct gr_gk20a *gr = &g->gr;
u32 sm_id;
struct channel_gk20a *ch = dbg_s->ch;
struct channel_gk20a *ch;
int err = 0;
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (!ch)
return -EINVAL;
sm_id = args->sm_id;
if (sm_id >= gr->no_of_sm)
@@ -598,10 +730,14 @@ static int nvgpu_dbg_gpu_ioctl_write_single_sm_error_state(
struct gk20a *g = get_gk20a(dbg_s->dev);
struct gr_gk20a *gr = &g->gr;
u32 sm_id;
struct channel_gk20a *ch = dbg_s->ch;
struct channel_gk20a *ch;
struct nvgpu_dbg_gpu_sm_error_state_record *sm_error_state;
int err = 0;
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (!ch)
return -EINVAL;
sm_id = args->sm_id;
if (sm_id >= gr->no_of_sm)
return -EINVAL;
@@ -756,6 +892,11 @@ long gk20a_dbg_gpu_dev_ioctl(struct file *filp, unsigned int cmd,
(struct nvgpu_dbg_gpu_write_single_sm_error_state_args *)buf);
break;
case NVGPU_DBG_GPU_IOCTL_UNBIND_CHANNEL:
err = dbg_unbind_channel_gk20a(dbg_s,
(struct nvgpu_dbg_gpu_unbind_channel_args *)buf);
break;
default:
gk20a_err(dev_from_gk20a(g),
"unrecognized dbg gpu ioctl cmd: 0x%x",
@@ -805,6 +946,7 @@ static int nvgpu_ioctl_channel_reg_ops(struct dbg_session_gk20a *dbg_s,
struct device *dev = dbg_s->dev;
struct gk20a *g = get_gk20a(dbg_s->dev);
struct nvgpu_dbg_gpu_reg_op *ops;
struct channel_gk20a *ch;
u64 ops_size = sizeof(ops[0]) * args->num_ops;
gk20a_dbg_fn("%d ops, total size %llu", args->num_ops, ops_size);
@@ -814,7 +956,8 @@ static int nvgpu_ioctl_channel_reg_ops(struct dbg_session_gk20a *dbg_s,
return -EINVAL;
}
if (!dbg_s->is_profiler && !dbg_s->ch) {
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (!dbg_s->is_profiler && !ch) {
gk20a_err(dev, "bind a channel before regops for a debugging session");
return -EINVAL;
}
@@ -1016,8 +1159,7 @@ static int nvgpu_dbg_gpu_ioctl_smpc_ctxsw_mode(struct dbg_session_gk20a *dbg_s,
/* Take the global lock, since we'll be doing global regops */
mutex_lock(&g->dbg_sessions_lock);
ch_gk20a = dbg_s->ch;
ch_gk20a = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (!ch_gk20a) {
gk20a_err(dev_from_gk20a(g),
"no bound channel for smpc ctxsw mode update\n");
@@ -1052,8 +1194,7 @@ static int nvgpu_dbg_gpu_ioctl_hwpm_ctxsw_mode(struct dbg_session_gk20a *dbg_s,
/* Take the global lock, since we'll be doing global regops */
mutex_lock(&g->dbg_sessions_lock);
ch_gk20a = dbg_s->ch;
ch_gk20a = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (!ch_gk20a) {
gk20a_err(dev_from_gk20a(g),
"no bound channel for pm ctxsw mode update\n");
@@ -1080,12 +1221,16 @@ static int nvgpu_dbg_gpu_ioctl_suspend_resume_sm(
struct nvgpu_dbg_gpu_suspend_resume_all_sms_args *args)
{
struct gk20a *g = get_gk20a(dbg_s->dev);
struct channel_gk20a *ch = dbg_s->ch;
struct channel_gk20a *ch;
bool ch_is_curr_ctx;
int err = 0, action = args->mode;
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "action: %d", args->mode);
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (!ch)
return -EINVAL;
mutex_lock(&g->dbg_sessions_lock);
/* Suspend GPU context switching */

View File

@@ -31,6 +31,9 @@ int gk20a_prof_gpu_dev_open(struct inode *inode, struct file *filp);
/* used by the interrupt handler to post events */
void gk20a_dbg_gpu_post_events(struct channel_gk20a *fault_ch);
struct channel_gk20a *
nvgpu_dbg_gpu_get_session_channel(struct dbg_session_gk20a *dbg_s);
struct dbg_gpu_session_ops {
int (*exec_reg_ops)(struct dbg_session_gk20a *dbg_s,
struct nvgpu_dbg_gpu_reg_op *ops,
@@ -68,22 +71,37 @@ struct dbg_session_gk20a {
struct device *dev;
struct gk20a *g;
/* bound channel, if any */
struct file *ch_f;
struct channel_gk20a *ch;
/* list of bound channels, if any */
struct list_head ch_list;
struct mutex ch_list_lock;
/* session operations */
struct dbg_gpu_session_ops *ops;
/* event support */
struct dbg_gpu_session_events dbg_events;
struct list_head dbg_s_list_node;
bool broadcast_stop_trigger;
};
struct dbg_session_data {
struct dbg_session_gk20a *dbg_s;
struct list_head dbg_s_entry;
};
struct dbg_session_channel_data {
struct file *ch_f;
int channel_fd;
int chid;
struct list_head ch_entry;
struct dbg_session_data *session_data;
};
extern struct dbg_gpu_session_ops dbg_gpu_session_ops_gk20a;
int dbg_unbind_single_channel_gk20a(struct dbg_session_gk20a *dbg_s,
struct dbg_session_channel_data *ch_data);
bool gk20a_dbg_gpu_broadcast_stop_trigger(struct channel_gk20a *ch);
int gk20a_dbg_gpu_clear_broadcast_stop_trigger(struct channel_gk20a *ch);

View File

@@ -647,7 +647,6 @@ struct gk20a {
/* held while manipulating # of debug/profiler sessions present */
/* also prevents debug sessions from attaching until released */
struct mutex dbg_sessions_lock;
int dbg_sessions; /* number attached */
int dbg_powergating_disabled_refcount; /*refcount for pg disable */
int dbg_timeout_disabled_refcount; /*refcount for timeout disable */

View File

@@ -390,7 +390,7 @@ int exec_regops_gk20a(struct dbg_session_gk20a *dbg_s,
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "");
ch = dbg_s->ch;
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
/* For vgpu, the regops routines need to be handled in the
* context of the server and support for that does not exist.
@@ -559,6 +559,9 @@ static bool check_whitelists(struct dbg_session_gk20a *dbg_s,
{
struct gk20a *g = dbg_s->g;
bool valid = false;
struct channel_gk20a *ch;
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
if (op->type == REGOP(TYPE_GLOBAL)) {
/* search global list */
@@ -570,7 +573,7 @@ static bool check_whitelists(struct dbg_session_gk20a *dbg_s,
regop_bsearch_range_cmp);
/* if debug session and channel is bound search context list */
if ((!valid) && (!dbg_s->is_profiler && dbg_s->ch)) {
if ((!valid) && (!dbg_s->is_profiler && ch)) {
/* binary search context list */
valid = g->ops.regops.get_context_whitelist_ranges &&
!!bsearch(&offset,
@@ -581,7 +584,7 @@ static bool check_whitelists(struct dbg_session_gk20a *dbg_s,
}
/* if debug session and channel is bound search runcontrol list */
if ((!valid) && (!dbg_s->is_profiler && dbg_s->ch)) {
if ((!valid) && (!dbg_s->is_profiler && ch)) {
valid = g->ops.regops.get_runcontrol_whitelist &&
linear_search(offset,
g->ops.regops.get_runcontrol_whitelist(),
@@ -589,7 +592,7 @@ static bool check_whitelists(struct dbg_session_gk20a *dbg_s,
}
} else if (op->type == REGOP(TYPE_GR_CTX)) {
/* it's a context-relative op */
if (!dbg_s->ch) {
if (!ch) {
gk20a_err(dbg_s->dev, "can't perform ctx regop unless bound");
op->status = REGOP(STATUS_UNSUPPORTED_OP);
return valid;
@@ -604,7 +607,7 @@ static bool check_whitelists(struct dbg_session_gk20a *dbg_s,
regop_bsearch_range_cmp);
/* if debug session and channel is bound search runcontrol list */
if ((!valid) && (!dbg_s->is_profiler && dbg_s->ch)) {
if ((!valid) && (!dbg_s->is_profiler && ch)) {
valid = g->ops.regops.get_runcontrol_whitelist &&
linear_search(offset,
g->ops.regops.get_runcontrol_whitelist(),

View File

@@ -26,7 +26,7 @@ static int vgpu_exec_regops(struct dbg_session_gk20a *dbg_s,
struct nvgpu_dbg_gpu_reg_op *ops,
u64 num_ops)
{
struct channel_gk20a *ch = dbg_s->ch;
struct channel_gk20a *ch;
struct gk20a_platform *platform = gk20a_get_platform(dbg_s->g->dev);
struct tegra_vgpu_cmd_msg msg;
struct tegra_vgpu_reg_ops_params *p = &msg.params.reg_ops;
@@ -55,6 +55,7 @@ static int vgpu_exec_regops(struct dbg_session_gk20a *dbg_s,
msg.cmd = TEGRA_VGPU_CMD_REG_OPS;
msg.handle = platform->virt_handle;
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
p->handle = ch ? ch->virt_ctx : 0;
p->num_ops = num_ops;
p->is_profiler = dbg_s->is_profiler;

View File

@@ -496,8 +496,7 @@ struct nvgpu_gpu_get_gpu_time_args {
* Binding/attaching a debugger session to an nvgpu channel
*
* The 'channel_fd' given here is the fd used to allocate the
* gpu channel context. To detach/unbind the debugger session
* use a channel_fd of -1.
* gpu channel context.
*
*/
struct nvgpu_dbg_gpu_bind_channel_args {
@@ -510,6 +509,8 @@ struct nvgpu_dbg_gpu_bind_channel_args {
/*
* Register operations
* All operations are targeted towards first channel
* attached to debug session
*/
/* valid op values */
#define NVGPU_DBG_GPU_REG_OP_READ_32 (0x00000000)
@@ -722,9 +723,23 @@ struct nvgpu_dbg_gpu_write_single_sm_error_state_args {
#define NVGPU_DBG_GPU_IOCTL_WRITE_SINGLE_SM_ERROR_STATE \
_IOW(NVGPU_DBG_GPU_IOCTL_MAGIC, 16, struct nvgpu_dbg_gpu_write_single_sm_error_state_args)
/*
* Unbinding/detaching a debugger session from a nvgpu channel
*
* The 'channel_fd' given here is the fd used to allocate the
* gpu channel context.
*/
struct nvgpu_dbg_gpu_unbind_channel_args {
__u32 channel_fd; /* in */
__u32 _pad0[1];
};
#define NVGPU_DBG_GPU_IOCTL_UNBIND_CHANNEL \
_IOW(NVGPU_DBG_GPU_IOCTL_MAGIC, 17, struct nvgpu_dbg_gpu_unbind_channel_args)
#define NVGPU_DBG_GPU_IOCTL_LAST \
_IOC_NR(NVGPU_DBG_GPU_IOCTL_WRITE_SINGLE_SM_ERROR_STATE)
_IOC_NR(NVGPU_DBG_GPU_IOCTL_UNBIND_CHANNEL)
#define NVGPU_DBG_GPU_IOCTL_MAX_ARG_SIZE \
sizeof(struct nvgpu_dbg_gpu_perfbuf_map_args)