gpu: nvgpu: add channel event id support

With NVGPU_IOCTL_CHANNEL_EVENTS_CTRL, nvgpu can
raise events to User space. But user space
cannot distinguish between various types of events.
To overcome this, we need finer-grained API to
deliver various events to user space.

Remove old API NVGPU_IOCTL_CHANNEL_EVENTS_CTRL,
and all the support for this API (we can remove
this since User space has not started using this
API at all)

Add new API NVGPU_IOCTL_CHANNEL_EVENT_ID_CTRL
which will accept an event_id (like BPT.INT or
BPT.PAUSE), a command to enable the event,
and return a file descriptor on which
we can raise the event (if cmd=enable)
Event is disabled when file descriptor is closed

Add file operations "gk20a_event_id_ops"
to support polling on event fd

Also add API gk20a_channel_get_event_data_from_id()
to get event_data of event from its id

Bug 200089620

Change-Id: I5288f19f38ff49448c46338c33b2a927c9e02254
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/1030775
(cherry picked from commit 5721ce2735950440bedc2b86f851db08ed593275)
Reviewed-on: http://git-master/r/1120318
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
This commit is contained in:
Deepak Nibade
2016-03-31 12:33:19 +05:30
committed by Terje Bergstrom
parent 76ab6c1e5b
commit e87ba53235
6 changed files with 177 additions and 121 deletions

View File

@@ -1167,10 +1167,6 @@ struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g)
init_waitqueue_head(&ch->semaphore_wq); init_waitqueue_head(&ch->semaphore_wq);
init_waitqueue_head(&ch->submit_wq); init_waitqueue_head(&ch->submit_wq);
mutex_init(&ch->poll_events.lock);
ch->poll_events.events_enabled = false;
ch->poll_events.num_pending_events = 0;
ch->update_fn = NULL; ch->update_fn = NULL;
ch->update_fn_data = NULL; ch->update_fn_data = NULL;
spin_lock_init(&ch->update_fn_lock); spin_lock_init(&ch->update_fn_lock);
@@ -2322,6 +2318,8 @@ int gk20a_init_channel_support(struct gk20a *g, u32 chid)
mutex_init(&c->cs_client_mutex); mutex_init(&c->cs_client_mutex);
#endif #endif
INIT_LIST_HEAD(&c->dbg_s_list); INIT_LIST_HEAD(&c->dbg_s_list);
INIT_LIST_HEAD(&c->event_id_list);
mutex_init(&c->event_id_list_lock);
mutex_init(&c->dbg_s_lock); mutex_init(&c->dbg_s_lock);
list_add(&c->free_chs, &g->fifo.free_chs); list_add(&c->free_chs, &g->fifo.free_chs);
@@ -2495,123 +2493,176 @@ notif_clean_up:
return ret; return ret;
} }
/* poll events for semaphores */ unsigned int gk20a_event_id_poll(struct file *filep, poll_table *wait)
static void gk20a_channel_events_enable(struct channel_gk20a_poll_events *ev)
{ {
gk20a_dbg_fn(""); unsigned int mask = 0;
struct gk20a_event_id_data *event_id_data = filep->private_data;
struct gk20a *g = event_id_data->g;
u32 event_id = event_id_data->event_id;
mutex_lock(&ev->lock); gk20a_dbg(gpu_dbg_fn | gpu_dbg_info, "");
ev->events_enabled = true; poll_wait(filep, &event_id_data->event_id_wq, wait);
ev->num_pending_events = 0;
mutex_unlock(&ev->lock); mutex_lock(&event_id_data->lock);
if (!event_id_data->is_tsg) {
struct channel_gk20a *ch = g->fifo.channel
+ event_id_data->id;
gk20a_dbg_info(
"found pending event_id=%d on chid=%d\n",
event_id, ch->hw_chid);
}
mask = (POLLPRI | POLLIN);
mutex_unlock(&event_id_data->lock);
return mask;
} }
static void gk20a_channel_events_disable(struct channel_gk20a_poll_events *ev) int gk20a_event_id_release(struct inode *inode, struct file *filp)
{ {
gk20a_dbg_fn(""); struct gk20a_event_id_data *event_id_data = filp->private_data;
struct gk20a *g = event_id_data->g;
mutex_lock(&ev->lock); if (!event_id_data->is_tsg) {
struct channel_gk20a *ch = g->fifo.channel + event_id_data->id;
ev->events_enabled = false; mutex_lock(&ch->event_id_list_lock);
ev->num_pending_events = 0; list_del_init(&event_id_data->event_id_node);
mutex_unlock(&ch->event_id_list_lock);
mutex_unlock(&ev->lock);
} }
static void gk20a_channel_events_clear(struct channel_gk20a_poll_events *ev) kfree(event_id_data);
{ filp->private_data = NULL;
gk20a_dbg_fn("");
mutex_lock(&ev->lock); return 0;
if (ev->events_enabled &&
ev->num_pending_events > 0)
ev->num_pending_events--;
mutex_unlock(&ev->lock);
} }
static int gk20a_channel_events_ctrl(struct channel_gk20a *ch, static const struct file_operations gk20a_event_id_ops = {
struct nvgpu_channel_events_ctrl_args *args) .owner = THIS_MODULE,
{ .poll = gk20a_event_id_poll,
int ret = 0; .release = gk20a_event_id_release,
};
gk20a_dbg(gpu_dbg_fn | gpu_dbg_info, static int gk20a_channel_get_event_data_from_id(struct channel_gk20a *ch,
"channel events ctrl cmd %d", args->cmd); int event_id,
struct gk20a_event_id_data **event_id_data)
{
struct gk20a_event_id_data *local_event_id_data;
bool event_found = false;
mutex_lock(&ch->event_id_list_lock);
list_for_each_entry(local_event_id_data, &ch->event_id_list,
event_id_node) {
if (local_event_id_data->event_id == event_id) {
event_found = true;
break;
}
}
mutex_unlock(&ch->event_id_list_lock);
if (event_found) {
*event_id_data = local_event_id_data;
return 0;
} else {
return -1;
}
}
static int gk20a_channel_event_id_enable(struct channel_gk20a *ch,
int event_id,
int *fd)
{
int err = 0;
int local_fd;
struct file *file;
char *name;
struct gk20a_event_id_data *event_id_data;
err = gk20a_channel_get_event_data_from_id(ch,
event_id, &event_id_data);
if (err == 0) /* We already have event enabled */
return -EINVAL;
err = get_unused_fd_flags(O_RDWR);
if (err < 0)
return err;
local_fd = err;
name = kasprintf(GFP_KERNEL, "nvgpu-event%d-fd%d",
event_id, local_fd);
file = anon_inode_getfile(name, &gk20a_event_id_ops,
NULL, O_RDWR);
kfree(name);
if (IS_ERR(file)) {
err = PTR_ERR(file);
goto clean_up;
}
event_id_data = kzalloc(sizeof(*event_id_data), GFP_KERNEL);
if (!event_id_data) {
err = -ENOMEM;
goto clean_up_file;
}
event_id_data->g = ch->g;
event_id_data->id = ch->hw_chid;
event_id_data->is_tsg = false;
event_id_data->event_id = event_id;
init_waitqueue_head(&event_id_data->event_id_wq);
mutex_init(&event_id_data->lock);
INIT_LIST_HEAD(&event_id_data->event_id_node);
mutex_lock(&ch->event_id_list_lock);
list_add_tail(&event_id_data->event_id_node, &ch->event_id_list);
mutex_unlock(&ch->event_id_list_lock);
fd_install(local_fd, file);
file->private_data = event_id_data;
*fd = local_fd;
return 0;
clean_up_file:
fput(file);
clean_up:
put_unused_fd(local_fd);
return err;
}
static int gk20a_channel_event_id_ctrl(struct channel_gk20a *ch,
struct nvgpu_event_id_ctrl_args *args)
{
int err = 0;
int fd = -1;
if (args->event_id < 0 ||
args->event_id >= NVGPU_IOCTL_CHANNEL_EVENT_ID_MAX)
return -EINVAL;
if (gk20a_is_channel_marked_as_tsg(ch))
return -EINVAL;
switch (args->cmd) { switch (args->cmd) {
case NVGPU_IOCTL_CHANNEL_EVENTS_CTRL_CMD_ENABLE: case NVGPU_IOCTL_CHANNEL_EVENT_ID_CMD_ENABLE:
gk20a_channel_events_enable(&ch->poll_events); err = gk20a_channel_event_id_enable(ch, args->event_id, &fd);
break; if (!err)
args->event_fd = fd;
case NVGPU_IOCTL_CHANNEL_EVENTS_CTRL_CMD_DISABLE:
gk20a_channel_events_disable(&ch->poll_events);
break;
case NVGPU_IOCTL_CHANNEL_EVENTS_CTRL_CMD_CLEAR:
gk20a_channel_events_clear(&ch->poll_events);
break; break;
default: default:
gk20a_err(dev_from_gk20a(ch->g), gk20a_err(dev_from_gk20a(ch->g),
"unrecognized channel events ctrl cmd: 0x%x", "unrecognized channel event id cmd: 0x%x",
args->cmd); args->cmd);
ret = -EINVAL; err = -EINVAL;
break; break;
} }
return ret; return err;
}
void gk20a_channel_event(struct channel_gk20a *ch)
{
mutex_lock(&ch->poll_events.lock);
if (ch->poll_events.events_enabled) {
gk20a_dbg_info("posting event on channel id %d",
ch->hw_chid);
gk20a_dbg_info("%d channel events pending",
ch->poll_events.num_pending_events);
ch->poll_events.num_pending_events++;
/* not waking up here, caller does that */
}
mutex_unlock(&ch->poll_events.lock);
}
void gk20a_channel_post_event(struct channel_gk20a *ch)
{
gk20a_channel_event(ch);
wake_up_interruptible_all(&ch->semaphore_wq);
}
unsigned int gk20a_channel_poll(struct file *filep, poll_table *wait)
{
unsigned int mask = 0;
struct channel_gk20a *ch = filep->private_data;
gk20a_dbg(gpu_dbg_fn | gpu_dbg_info, "");
poll_wait(filep, &ch->semaphore_wq, wait);
mutex_lock(&ch->poll_events.lock);
if (ch->poll_events.events_enabled &&
ch->poll_events.num_pending_events > 0) {
gk20a_dbg_info("found pending event on channel id %d",
ch->hw_chid);
gk20a_dbg_info("%d channel events pending",
ch->poll_events.num_pending_events);
mask = (POLLPRI | POLLIN);
}
mutex_unlock(&ch->poll_events.lock);
return mask;
} }
int gk20a_channel_set_priority(struct channel_gk20a *ch, u32 priority) int gk20a_channel_set_priority(struct channel_gk20a *ch, u32 priority)
@@ -2756,7 +2807,7 @@ void gk20a_channel_semaphore_wakeup(struct gk20a *g)
for (chid = 0; chid < f->num_channels; chid++) { for (chid = 0; chid < f->num_channels; chid++) {
struct channel_gk20a *c = g->fifo.channel+chid; struct channel_gk20a *c = g->fifo.channel+chid;
if (gk20a_channel_get(c)) { if (gk20a_channel_get(c)) {
gk20a_channel_post_event(c); wake_up_interruptible_all(&c->semaphore_wq);
gk20a_channel_update(c, 0); gk20a_channel_update(c, 0);
gk20a_channel_put(c); gk20a_channel_put(c);
} }
@@ -3040,9 +3091,9 @@ long gk20a_channel_ioctl(struct file *filp,
err = gk20a_fifo_force_reset_ch(ch, true); err = gk20a_fifo_force_reset_ch(ch, true);
gk20a_idle(dev); gk20a_idle(dev);
break; break;
case NVGPU_IOCTL_CHANNEL_EVENTS_CTRL: case NVGPU_IOCTL_CHANNEL_EVENT_ID_CTRL:
err = gk20a_channel_events_ctrl(ch, err = gk20a_channel_event_id_ctrl(ch,
(struct nvgpu_channel_events_ctrl_args *)buf); (struct nvgpu_event_id_ctrl_args *)buf);
break; break;
#ifdef CONFIG_GK20A_CYCLE_STATS #ifdef CONFIG_GK20A_CYCLE_STATS
case NVGPU_IOCTL_CHANNEL_CYCLE_STATS_SNAPSHOT: case NVGPU_IOCTL_CHANNEL_CYCLE_STATS_SNAPSHOT:

View File

@@ -74,10 +74,16 @@ struct channel_gk20a_timeout {
struct channel_gk20a_job *job; struct channel_gk20a_job *job;
}; };
struct channel_gk20a_poll_events { struct gk20a_event_id_data {
struct gk20a *g;
int id; /* ch or tsg */
bool is_tsg;
u32 event_id;
wait_queue_head_t event_id_wq;
struct mutex lock; struct mutex lock;
bool events_enabled; struct list_head event_id_node;
int num_pending_events;
}; };
struct channel_gk20a_clean_up { struct channel_gk20a_clean_up {
@@ -163,6 +169,9 @@ struct channel_gk20a {
struct mutex dbg_s_lock; struct mutex dbg_s_lock;
struct list_head dbg_s_list; struct list_head dbg_s_list;
struct list_head event_id_list;
struct mutex event_id_list_lock;
bool has_timedout; bool has_timedout;
u32 timeout_ms_max; u32 timeout_ms_max;
bool timeout_debug_dump; bool timeout_debug_dump;
@@ -178,9 +187,6 @@ struct channel_gk20a {
u64 virt_ctx; u64 virt_ctx;
#endif #endif
/* event support */
struct channel_gk20a_poll_events poll_events;
/* signal channel owner via a callback, if set, in gk20a_channel_update /* signal channel owner via a callback, if set, in gk20a_channel_update
* via schedule_work */ * via schedule_work */
void (*update_fn)(struct channel_gk20a *, void *); void (*update_fn)(struct channel_gk20a *, void *);
@@ -227,9 +233,6 @@ long gk20a_channel_ioctl(struct file *filp,
int gk20a_channel_release(struct inode *inode, struct file *filp); int gk20a_channel_release(struct inode *inode, struct file *filp);
struct channel_gk20a *gk20a_get_channel_from_file(int fd); struct channel_gk20a *gk20a_get_channel_from_file(int fd);
void gk20a_channel_update(struct channel_gk20a *c, int nr_completed); void gk20a_channel_update(struct channel_gk20a *c, int nr_completed);
unsigned int gk20a_channel_poll(struct file *filep, poll_table *wait);
void gk20a_channel_event(struct channel_gk20a *ch);
void gk20a_channel_post_event(struct channel_gk20a *ch);
void gk20a_init_channel(struct gpu_ops *gops); void gk20a_init_channel(struct gpu_ops *gops);

View File

@@ -108,7 +108,6 @@ static const struct file_operations gk20a_channel_ops = {
.compat_ioctl = gk20a_channel_ioctl, .compat_ioctl = gk20a_channel_ioctl,
#endif #endif
.unlocked_ioctl = gk20a_channel_ioctl, .unlocked_ioctl = gk20a_channel_ioctl,
.poll = gk20a_channel_poll,
}; };
static const struct file_operations gk20a_ctrl_ops = { static const struct file_operations gk20a_ctrl_ops = {

View File

@@ -4983,7 +4983,7 @@ static int gk20a_gr_handle_semaphore_pending(struct gk20a *g,
struct fifo_gk20a *f = &g->fifo; struct fifo_gk20a *f = &g->fifo;
struct channel_gk20a *ch = &f->channel[isr_data->chid]; struct channel_gk20a *ch = &f->channel[isr_data->chid];
gk20a_channel_post_event(ch); wake_up_interruptible_all(&ch->semaphore_wq);
return 0; return 0;
} }

View File

@@ -871,7 +871,7 @@ int vgpu_gr_isr(struct gk20a *g, struct tegra_vgpu_gr_intr_info *info)
wake_up(&ch->notifier_wq); wake_up(&ch->notifier_wq);
break; break;
case TEGRA_VGPU_GR_INTR_SEMAPHORE: case TEGRA_VGPU_GR_INTR_SEMAPHORE:
gk20a_channel_post_event(ch); wake_up_interruptible_all(&ch->semaphore_wq);
break; break;
case TEGRA_VGPU_GR_INTR_SEMAPHORE_TIMEOUT: case TEGRA_VGPU_GR_INTR_SEMAPHORE_TIMEOUT:
gk20a_set_error_notifier(ch, gk20a_set_error_notifier(ch,

View File

@@ -825,17 +825,6 @@ struct nvgpu_notification {
#define NVGPU_CHANNEL_SUBMIT_TIMEOUT 1 #define NVGPU_CHANNEL_SUBMIT_TIMEOUT 1
}; };
/* Enable/disable/clear event notifications */
struct nvgpu_channel_events_ctrl_args {
__u32 cmd; /* in */
__u32 _pad0[1];
};
/* valid event ctrl values */
#define NVGPU_IOCTL_CHANNEL_EVENTS_CTRL_CMD_DISABLE 0
#define NVGPU_IOCTL_CHANNEL_EVENTS_CTRL_CMD_ENABLE 1
#define NVGPU_IOCTL_CHANNEL_EVENTS_CTRL_CMD_CLEAR 2
/* cycle stats snapshot buffer support for mode E */ /* cycle stats snapshot buffer support for mode E */
struct nvgpu_cycle_stats_snapshot_args { struct nvgpu_cycle_stats_snapshot_args {
__u32 cmd; /* in: command to handle */ __u32 cmd; /* in: command to handle */
@@ -886,6 +875,20 @@ struct nvgpu_timeslice_args {
__u32 reserved; __u32 reserved;
}; };
struct nvgpu_event_id_ctrl_args {
__u32 cmd; /* in */
__u32 event_id; /* in */
__s32 event_fd; /* out */
__u32 padding;
};
#define NVGPU_IOCTL_CHANNEL_EVENT_ID_BPT_INT 0
#define NVGPU_IOCTL_CHANNEL_EVENT_ID_BPT_PAUSE 1
#define NVGPU_IOCTL_CHANNEL_EVENT_ID_BLOCKING_SYNC 2
#define NVGPU_IOCTL_CHANNEL_EVENT_ID_MAX 5
#define NVGPU_IOCTL_CHANNEL_EVENT_ID_CMD_ENABLE 1
#define NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD \ #define NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD \
_IOW(NVGPU_IOCTL_MAGIC, 5, struct nvgpu_set_nvmap_fd_args) _IOW(NVGPU_IOCTL_MAGIC, 5, struct nvgpu_set_nvmap_fd_args)
#define NVGPU_IOCTL_CHANNEL_SET_TIMEOUT \ #define NVGPU_IOCTL_CHANNEL_SET_TIMEOUT \
@@ -922,8 +925,8 @@ struct nvgpu_timeslice_args {
_IO(NVGPU_IOCTL_MAGIC, 115) _IO(NVGPU_IOCTL_MAGIC, 115)
#define NVGPU_IOCTL_CHANNEL_FORCE_RESET \ #define NVGPU_IOCTL_CHANNEL_FORCE_RESET \
_IO(NVGPU_IOCTL_MAGIC, 116) _IO(NVGPU_IOCTL_MAGIC, 116)
#define NVGPU_IOCTL_CHANNEL_EVENTS_CTRL \ #define NVGPU_IOCTL_CHANNEL_EVENT_ID_CTRL \
_IOW(NVGPU_IOCTL_MAGIC, 117, struct nvgpu_channel_events_ctrl_args) _IOWR(NVGPU_IOCTL_MAGIC, 117, struct nvgpu_event_id_ctrl_args)
#define NVGPU_IOCTL_CHANNEL_CYCLE_STATS_SNAPSHOT \ #define NVGPU_IOCTL_CHANNEL_CYCLE_STATS_SNAPSHOT \
_IOWR(NVGPU_IOCTL_MAGIC, 118, struct nvgpu_cycle_stats_snapshot_args) _IOWR(NVGPU_IOCTL_MAGIC, 118, struct nvgpu_cycle_stats_snapshot_args)
#define NVGPU_IOCTL_CHANNEL_WDT \ #define NVGPU_IOCTL_CHANNEL_WDT \