mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-23 01:50:07 +03:00
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:
committed by
Terje Bergstrom
parent
c651adbeaa
commit
dfac8ce704
@@ -857,6 +857,8 @@ static void gk20a_free_channel(struct channel_gk20a *ch)
|
|||||||
struct vm_gk20a *ch_vm = ch->vm;
|
struct vm_gk20a *ch_vm = ch->vm;
|
||||||
unsigned long timeout = gk20a_get_gr_idle_timeout(g);
|
unsigned long timeout = gk20a_get_gr_idle_timeout(g);
|
||||||
struct dbg_session_gk20a *dbg_s;
|
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;
|
bool was_reset;
|
||||||
|
|
||||||
gk20a_dbg_fn("");
|
gk20a_dbg_fn("");
|
||||||
@@ -992,14 +994,21 @@ unbind:
|
|||||||
WARN_ON(ch->sync);
|
WARN_ON(ch->sync);
|
||||||
|
|
||||||
/* unlink all debug sessions */
|
/* 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) {
|
list_for_each_entry_safe(session_data, tmp_s,
|
||||||
dbg_s->ch = NULL;
|
&ch->dbg_s_list, dbg_s_entry) {
|
||||||
list_del_init(&dbg_s->dbg_s_list_node);
|
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:
|
release:
|
||||||
/* make sure we catch accesses of unopened channels in case
|
/* make sure we catch accesses of unopened channels in case
|
||||||
|
|||||||
@@ -35,6 +35,33 @@ struct dbg_gpu_session_ops dbg_gpu_session_ops_gk20a = {
|
|||||||
.exec_reg_ops = exec_regops_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 */
|
/* silly allocator - just increment session id */
|
||||||
static atomic_t session_id = ATOMIC_INIT(0);
|
static atomic_t session_id = ATOMIC_INIT(0);
|
||||||
static int generate_session_id(void)
|
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))
|
if (gk20a_gpu_is_virtual(dev))
|
||||||
dbg_session->is_pg_disabled = true;
|
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_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.events_enabled = false;
|
||||||
dbg_session->dbg_events.num_pending_events = 0;
|
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. */
|
* since it might not have an associated channel. */
|
||||||
static void gk20a_dbg_session_mutex_lock(struct dbg_session_gk20a *dbg_s)
|
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);
|
mutex_lock(&dbg_s->g->dbg_sessions_lock);
|
||||||
else
|
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)
|
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);
|
mutex_unlock(&dbg_s->g->dbg_sessions_lock);
|
||||||
else
|
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)
|
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)
|
struct nvgpu_dbg_gpu_events_ctrl_args *args)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct channel_gk20a *ch;
|
||||||
|
|
||||||
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "dbg events ctrl cmd %d", args->cmd);
|
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),
|
gk20a_err(dev_from_gk20a(dbg_s->g),
|
||||||
"no channel bound to dbg session\n");
|
"no channel bound to dbg session\n");
|
||||||
return -EINVAL;
|
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)
|
void gk20a_dbg_gpu_post_events(struct channel_gk20a *ch)
|
||||||
{
|
{
|
||||||
|
struct dbg_session_data *session_data;
|
||||||
struct dbg_session_gk20a *dbg_s;
|
struct dbg_session_gk20a *dbg_s;
|
||||||
|
|
||||||
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "");
|
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 */
|
/* guard against the session list being modified */
|
||||||
mutex_lock(&ch->dbg_s_lock);
|
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) {
|
if (dbg_s->dbg_events.events_enabled) {
|
||||||
gk20a_dbg(gpu_dbg_gpu_dbg, "posting event on session id %d",
|
gk20a_dbg(gpu_dbg_gpu_dbg, "posting event on session id %d",
|
||||||
dbg_s->id);
|
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)
|
bool gk20a_dbg_gpu_broadcast_stop_trigger(struct channel_gk20a *ch)
|
||||||
{
|
{
|
||||||
|
struct dbg_session_data *session_data;
|
||||||
struct dbg_session_gk20a *dbg_s;
|
struct dbg_session_gk20a *dbg_s;
|
||||||
bool broadcast = false;
|
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 */
|
/* guard against the session list being modified */
|
||||||
mutex_lock(&ch->dbg_s_lock);
|
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) {
|
if (dbg_s->broadcast_stop_trigger) {
|
||||||
gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn | gpu_dbg_intr,
|
gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn | gpu_dbg_intr,
|
||||||
"stop trigger broadcast enabled");
|
"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)
|
int gk20a_dbg_gpu_clear_broadcast_stop_trigger(struct channel_gk20a *ch)
|
||||||
{
|
{
|
||||||
|
struct dbg_session_data *session_data;
|
||||||
struct dbg_session_gk20a *dbg_s;
|
struct dbg_session_gk20a *dbg_s;
|
||||||
|
|
||||||
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg | gpu_dbg_intr, "");
|
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 */
|
/* guard against the session list being modified */
|
||||||
mutex_lock(&ch->dbg_s_lock);
|
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) {
|
if (dbg_s->broadcast_stop_trigger) {
|
||||||
gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn | gpu_dbg_intr,
|
gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn | gpu_dbg_intr,
|
||||||
"stop trigger broadcast disabled");
|
"stop trigger broadcast disabled");
|
||||||
@@ -347,36 +387,87 @@ static int nvgpu_dbg_timeout_enable(struct dbg_session_gk20a *dbg_s,
|
|||||||
return err;
|
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;
|
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, "");
|
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "");
|
||||||
|
|
||||||
/* wasn't bound to start with ? */
|
chid = ch_data->chid;
|
||||||
if (!ch_gk20a) {
|
ch = g->fifo.channel + chid;
|
||||||
gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn, "not bound already?");
|
|
||||||
return -ENODEV;
|
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(&g->dbg_sessions_lock);
|
||||||
mutex_lock(&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)
|
||||||
--g->dbg_sessions;
|
dbg_unbind_single_channel_gk20a(dbg_s, ch_data);
|
||||||
|
mutex_unlock(&dbg_s->ch_list_lock);
|
||||||
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_unlock(&g->dbg_sessions_lock);
|
mutex_unlock(&g->dbg_sessions_lock);
|
||||||
|
|
||||||
return 0;
|
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)
|
int gk20a_dbg_gpu_dev_release(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
struct dbg_session_gk20a *dbg_s = filp->private_data;
|
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));
|
gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn, "%s", dev_name(dbg_s->dev));
|
||||||
|
|
||||||
/* unbind if it was bound */
|
/* unbind channels */
|
||||||
if (dbg_s->ch)
|
dbg_unbind_all_channels_gk20a(dbg_s);
|
||||||
dbg_unbind_channel_gk20a(dbg_s);
|
|
||||||
|
|
||||||
/* Powergate/Timeout enable is called here as possibility of dbg_session
|
/* Powergate/Timeout enable is called here as possibility of dbg_session
|
||||||
* which called powergate/timeout disable ioctl, to be killed without
|
* 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 nvgpu_dbg_gpu_bind_channel_args *args)
|
||||||
{
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
struct gk20a *g;
|
struct gk20a *g = dbg_s->g;
|
||||||
struct channel_gk20a *ch;
|
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",
|
gk20a_dbg(gpu_dbg_fn|gpu_dbg_gpu_dbg, "%s fd=%d",
|
||||||
dev_name(dbg_s->dev), args->channel_fd);
|
dev_name(dbg_s->dev), args->channel_fd);
|
||||||
|
|
||||||
if (args->channel_fd == ~0)
|
if (args->channel_fd == ~0) {
|
||||||
return dbg_unbind_channel_gk20a(dbg_s);
|
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 */
|
/* 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
|
/* 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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
g = dbg_s->g;
|
|
||||||
gk20a_dbg_fn("%s hwchid=%d", dev_name(dbg_s->dev), ch->hw_chid);
|
gk20a_dbg_fn("%s hwchid=%d", dev_name(dbg_s->dev), ch->hw_chid);
|
||||||
|
|
||||||
mutex_lock(&g->dbg_sessions_lock);
|
mutex_lock(&g->dbg_sessions_lock);
|
||||||
mutex_lock(&ch->dbg_s_lock);
|
mutex_lock(&ch->dbg_s_lock);
|
||||||
|
|
||||||
dbg_s->ch_f = f;
|
ch_data = kzalloc(sizeof(*ch_data), GFP_KERNEL);
|
||||||
dbg_s->ch = ch;
|
if (!ch_data) {
|
||||||
list_add(&dbg_s->dbg_s_list_node, &dbg_s->ch->dbg_s_list);
|
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(&ch->dbg_s_lock);
|
||||||
mutex_unlock(&g->dbg_sessions_lock);
|
mutex_unlock(&g->dbg_sessions_lock);
|
||||||
|
|
||||||
return 0;
|
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,
|
static int gk20a_dbg_pc_sampling(struct dbg_session_gk20a *dbg_s,
|
||||||
struct nvgpu_dbg_gpu_pc_sampling_args *args)
|
struct nvgpu_dbg_gpu_pc_sampling_args *args)
|
||||||
{
|
{
|
||||||
struct channel_gk20a *ch = dbg_s->ch;
|
struct channel_gk20a *ch;
|
||||||
struct gk20a *g = ch->g;
|
struct gk20a *g = dbg_s->g;
|
||||||
|
|
||||||
|
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
|
||||||
|
if (!ch)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
gk20a_dbg_fn("");
|
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 gk20a *g = get_gk20a(dbg_s->dev);
|
||||||
struct gr_gk20a *gr = &g->gr;
|
struct gr_gk20a *gr = &g->gr;
|
||||||
u32 sm_id;
|
u32 sm_id;
|
||||||
struct channel_gk20a *ch = dbg_s->ch;
|
struct channel_gk20a *ch;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
|
||||||
|
if (!ch)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
sm_id = args->sm_id;
|
sm_id = args->sm_id;
|
||||||
|
|
||||||
if (sm_id >= gr->no_of_sm)
|
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 gk20a *g = get_gk20a(dbg_s->dev);
|
||||||
struct gr_gk20a *gr = &g->gr;
|
struct gr_gk20a *gr = &g->gr;
|
||||||
u32 sm_id;
|
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;
|
struct nvgpu_dbg_gpu_sm_error_state_record *sm_error_state;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
|
||||||
|
if (!ch)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
sm_id = args->sm_id;
|
sm_id = args->sm_id;
|
||||||
if (sm_id >= gr->no_of_sm)
|
if (sm_id >= gr->no_of_sm)
|
||||||
return -EINVAL;
|
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);
|
(struct nvgpu_dbg_gpu_write_single_sm_error_state_args *)buf);
|
||||||
break;
|
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:
|
default:
|
||||||
gk20a_err(dev_from_gk20a(g),
|
gk20a_err(dev_from_gk20a(g),
|
||||||
"unrecognized dbg gpu ioctl cmd: 0x%x",
|
"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 device *dev = dbg_s->dev;
|
||||||
struct gk20a *g = get_gk20a(dbg_s->dev);
|
struct gk20a *g = get_gk20a(dbg_s->dev);
|
||||||
struct nvgpu_dbg_gpu_reg_op *ops;
|
struct nvgpu_dbg_gpu_reg_op *ops;
|
||||||
|
struct channel_gk20a *ch;
|
||||||
u64 ops_size = sizeof(ops[0]) * args->num_ops;
|
u64 ops_size = sizeof(ops[0]) * args->num_ops;
|
||||||
|
|
||||||
gk20a_dbg_fn("%d ops, total size %llu", args->num_ops, ops_size);
|
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;
|
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");
|
gk20a_err(dev, "bind a channel before regops for a debugging session");
|
||||||
return -EINVAL;
|
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 */
|
/* Take the global lock, since we'll be doing global regops */
|
||||||
mutex_lock(&g->dbg_sessions_lock);
|
mutex_lock(&g->dbg_sessions_lock);
|
||||||
|
|
||||||
ch_gk20a = dbg_s->ch;
|
ch_gk20a = nvgpu_dbg_gpu_get_session_channel(dbg_s);
|
||||||
|
|
||||||
if (!ch_gk20a) {
|
if (!ch_gk20a) {
|
||||||
gk20a_err(dev_from_gk20a(g),
|
gk20a_err(dev_from_gk20a(g),
|
||||||
"no bound channel for smpc ctxsw mode update\n");
|
"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 */
|
/* Take the global lock, since we'll be doing global regops */
|
||||||
mutex_lock(&g->dbg_sessions_lock);
|
mutex_lock(&g->dbg_sessions_lock);
|
||||||
|
|
||||||
ch_gk20a = dbg_s->ch;
|
ch_gk20a = nvgpu_dbg_gpu_get_session_channel(dbg_s);
|
||||||
|
|
||||||
if (!ch_gk20a) {
|
if (!ch_gk20a) {
|
||||||
gk20a_err(dev_from_gk20a(g),
|
gk20a_err(dev_from_gk20a(g),
|
||||||
"no bound channel for pm ctxsw mode update\n");
|
"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 nvgpu_dbg_gpu_suspend_resume_all_sms_args *args)
|
||||||
{
|
{
|
||||||
struct gk20a *g = get_gk20a(dbg_s->dev);
|
struct gk20a *g = get_gk20a(dbg_s->dev);
|
||||||
struct channel_gk20a *ch = dbg_s->ch;
|
struct channel_gk20a *ch;
|
||||||
bool ch_is_curr_ctx;
|
bool ch_is_curr_ctx;
|
||||||
int err = 0, action = args->mode;
|
int err = 0, action = args->mode;
|
||||||
|
|
||||||
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "action: %d", 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);
|
mutex_lock(&g->dbg_sessions_lock);
|
||||||
|
|
||||||
/* Suspend GPU context switching */
|
/* Suspend GPU context switching */
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ int gk20a_prof_gpu_dev_open(struct inode *inode, struct file *filp);
|
|||||||
/* used by the interrupt handler to post events */
|
/* used by the interrupt handler to post events */
|
||||||
void gk20a_dbg_gpu_post_events(struct channel_gk20a *fault_ch);
|
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 {
|
struct dbg_gpu_session_ops {
|
||||||
int (*exec_reg_ops)(struct dbg_session_gk20a *dbg_s,
|
int (*exec_reg_ops)(struct dbg_session_gk20a *dbg_s,
|
||||||
struct nvgpu_dbg_gpu_reg_op *ops,
|
struct nvgpu_dbg_gpu_reg_op *ops,
|
||||||
@@ -68,22 +71,37 @@ struct dbg_session_gk20a {
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct gk20a *g;
|
struct gk20a *g;
|
||||||
|
|
||||||
/* bound channel, if any */
|
/* list of bound channels, if any */
|
||||||
struct file *ch_f;
|
struct list_head ch_list;
|
||||||
struct channel_gk20a *ch;
|
struct mutex ch_list_lock;
|
||||||
|
|
||||||
/* session operations */
|
/* session operations */
|
||||||
struct dbg_gpu_session_ops *ops;
|
struct dbg_gpu_session_ops *ops;
|
||||||
|
|
||||||
/* event support */
|
/* event support */
|
||||||
struct dbg_gpu_session_events dbg_events;
|
struct dbg_gpu_session_events dbg_events;
|
||||||
struct list_head dbg_s_list_node;
|
|
||||||
|
|
||||||
bool broadcast_stop_trigger;
|
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;
|
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);
|
bool gk20a_dbg_gpu_broadcast_stop_trigger(struct channel_gk20a *ch);
|
||||||
int gk20a_dbg_gpu_clear_broadcast_stop_trigger(struct channel_gk20a *ch);
|
int gk20a_dbg_gpu_clear_broadcast_stop_trigger(struct channel_gk20a *ch);
|
||||||
|
|
||||||
|
|||||||
@@ -647,7 +647,6 @@ struct gk20a {
|
|||||||
/* held while manipulating # of debug/profiler sessions present */
|
/* held while manipulating # of debug/profiler sessions present */
|
||||||
/* also prevents debug sessions from attaching until released */
|
/* also prevents debug sessions from attaching until released */
|
||||||
struct mutex dbg_sessions_lock;
|
struct mutex dbg_sessions_lock;
|
||||||
int dbg_sessions; /* number attached */
|
|
||||||
int dbg_powergating_disabled_refcount; /*refcount for pg disable */
|
int dbg_powergating_disabled_refcount; /*refcount for pg disable */
|
||||||
int dbg_timeout_disabled_refcount; /*refcount for timeout disable */
|
int dbg_timeout_disabled_refcount; /*refcount for timeout disable */
|
||||||
|
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ int exec_regops_gk20a(struct dbg_session_gk20a *dbg_s,
|
|||||||
|
|
||||||
gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "");
|
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
|
/* For vgpu, the regops routines need to be handled in the
|
||||||
* context of the server and support for that does not exist.
|
* 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;
|
struct gk20a *g = dbg_s->g;
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
|
struct channel_gk20a *ch;
|
||||||
|
|
||||||
|
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
|
||||||
|
|
||||||
if (op->type == REGOP(TYPE_GLOBAL)) {
|
if (op->type == REGOP(TYPE_GLOBAL)) {
|
||||||
/* search global list */
|
/* search global list */
|
||||||
@@ -570,7 +573,7 @@ static bool check_whitelists(struct dbg_session_gk20a *dbg_s,
|
|||||||
regop_bsearch_range_cmp);
|
regop_bsearch_range_cmp);
|
||||||
|
|
||||||
/* if debug session and channel is bound search context list */
|
/* 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 */
|
/* binary search context list */
|
||||||
valid = g->ops.regops.get_context_whitelist_ranges &&
|
valid = g->ops.regops.get_context_whitelist_ranges &&
|
||||||
!!bsearch(&offset,
|
!!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 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 &&
|
valid = g->ops.regops.get_runcontrol_whitelist &&
|
||||||
linear_search(offset,
|
linear_search(offset,
|
||||||
g->ops.regops.get_runcontrol_whitelist(),
|
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)) {
|
} else if (op->type == REGOP(TYPE_GR_CTX)) {
|
||||||
/* it's a context-relative op */
|
/* it's a context-relative op */
|
||||||
if (!dbg_s->ch) {
|
if (!ch) {
|
||||||
gk20a_err(dbg_s->dev, "can't perform ctx regop unless bound");
|
gk20a_err(dbg_s->dev, "can't perform ctx regop unless bound");
|
||||||
op->status = REGOP(STATUS_UNSUPPORTED_OP);
|
op->status = REGOP(STATUS_UNSUPPORTED_OP);
|
||||||
return valid;
|
return valid;
|
||||||
@@ -604,7 +607,7 @@ static bool check_whitelists(struct dbg_session_gk20a *dbg_s,
|
|||||||
regop_bsearch_range_cmp);
|
regop_bsearch_range_cmp);
|
||||||
|
|
||||||
/* if debug session and channel is bound search runcontrol list */
|
/* 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 &&
|
valid = g->ops.regops.get_runcontrol_whitelist &&
|
||||||
linear_search(offset,
|
linear_search(offset,
|
||||||
g->ops.regops.get_runcontrol_whitelist(),
|
g->ops.regops.get_runcontrol_whitelist(),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ static int vgpu_exec_regops(struct dbg_session_gk20a *dbg_s,
|
|||||||
struct nvgpu_dbg_gpu_reg_op *ops,
|
struct nvgpu_dbg_gpu_reg_op *ops,
|
||||||
u64 num_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 gk20a_platform *platform = gk20a_get_platform(dbg_s->g->dev);
|
||||||
struct tegra_vgpu_cmd_msg msg;
|
struct tegra_vgpu_cmd_msg msg;
|
||||||
struct tegra_vgpu_reg_ops_params *p = &msg.params.reg_ops;
|
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.cmd = TEGRA_VGPU_CMD_REG_OPS;
|
||||||
msg.handle = platform->virt_handle;
|
msg.handle = platform->virt_handle;
|
||||||
|
ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
|
||||||
p->handle = ch ? ch->virt_ctx : 0;
|
p->handle = ch ? ch->virt_ctx : 0;
|
||||||
p->num_ops = num_ops;
|
p->num_ops = num_ops;
|
||||||
p->is_profiler = dbg_s->is_profiler;
|
p->is_profiler = dbg_s->is_profiler;
|
||||||
|
|||||||
@@ -496,8 +496,7 @@ struct nvgpu_gpu_get_gpu_time_args {
|
|||||||
* Binding/attaching a debugger session to an nvgpu channel
|
* Binding/attaching a debugger session to an nvgpu channel
|
||||||
*
|
*
|
||||||
* The 'channel_fd' given here is the fd used to allocate the
|
* The 'channel_fd' given here is the fd used to allocate the
|
||||||
* gpu channel context. To detach/unbind the debugger session
|
* gpu channel context.
|
||||||
* use a channel_fd of -1.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct nvgpu_dbg_gpu_bind_channel_args {
|
struct nvgpu_dbg_gpu_bind_channel_args {
|
||||||
@@ -510,6 +509,8 @@ struct nvgpu_dbg_gpu_bind_channel_args {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Register operations
|
* Register operations
|
||||||
|
* All operations are targeted towards first channel
|
||||||
|
* attached to debug session
|
||||||
*/
|
*/
|
||||||
/* valid op values */
|
/* valid op values */
|
||||||
#define NVGPU_DBG_GPU_REG_OP_READ_32 (0x00000000)
|
#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 \
|
#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)
|
_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 \
|
#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 \
|
#define NVGPU_DBG_GPU_IOCTL_MAX_ARG_SIZE \
|
||||||
sizeof(struct nvgpu_dbg_gpu_perfbuf_map_args)
|
sizeof(struct nvgpu_dbg_gpu_perfbuf_map_args)
|
||||||
|
|||||||
Reference in New Issue
Block a user