From e87ba53235151cccee181489ceb5e35b131e7d2d Mon Sep 17 00:00:00 2001 From: Deepak Nibade Date: Thu, 31 Mar 2016 12:33:19 +0530 Subject: 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 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 --- drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 223 ++++++++++++++++++++------------ drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 21 +-- drivers/gpu/nvgpu/gk20a/gk20a.c | 1 - drivers/gpu/nvgpu/gk20a/gr_gk20a.c | 2 +- drivers/gpu/nvgpu/vgpu/gr_vgpu.c | 2 +- include/uapi/linux/nvgpu.h | 29 +++-- 6 files changed, 167 insertions(+), 111 deletions(-) diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 20976992..be9c7cd4 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c @@ -1167,10 +1167,6 @@ struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g) init_waitqueue_head(&ch->semaphore_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_data = NULL; 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); #endif 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); list_add(&c->free_chs, &g->fifo.free_chs); @@ -2495,123 +2493,176 @@ notif_clean_up: return ret; } -/* poll events for semaphores */ - -static void gk20a_channel_events_enable(struct channel_gk20a_poll_events *ev) +unsigned int gk20a_event_id_poll(struct file *filep, poll_table *wait) { - 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; + + gk20a_dbg(gpu_dbg_fn | gpu_dbg_info, ""); + + poll_wait(filep, &event_id_data->event_id_wq, wait); + + mutex_lock(&event_id_data->lock); - mutex_lock(&ev->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); - ev->events_enabled = true; - ev->num_pending_events = 0; + mutex_unlock(&event_id_data->lock); - mutex_unlock(&ev->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; - ev->num_pending_events = 0; + mutex_lock(&ch->event_id_list_lock); + list_del_init(&event_id_data->event_id_node); + mutex_unlock(&ch->event_id_list_lock); + } + + kfree(event_id_data); + filp->private_data = NULL; - mutex_unlock(&ev->lock); + return 0; } -static void gk20a_channel_events_clear(struct channel_gk20a_poll_events *ev) -{ - gk20a_dbg_fn(""); +static const struct file_operations gk20a_event_id_ops = { + .owner = THIS_MODULE, + .poll = gk20a_event_id_poll, + .release = gk20a_event_id_release, +}; - mutex_lock(&ev->lock); +static int gk20a_channel_get_event_data_from_id(struct channel_gk20a *ch, + int event_id, + struct gk20a_event_id_data **event_id_data) +{ + struct gk20a_event_id_data *local_event_id_data; + bool event_found = false; - if (ev->events_enabled && - ev->num_pending_events > 0) - ev->num_pending_events--; + 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); - mutex_unlock(&ev->lock); + if (event_found) { + *event_id_data = local_event_id_data; + return 0; + } else { + return -1; + } } -static int gk20a_channel_events_ctrl(struct channel_gk20a *ch, - struct nvgpu_channel_events_ctrl_args *args) +static int gk20a_channel_event_id_enable(struct channel_gk20a *ch, + int event_id, + int *fd) { - int ret = 0; + int err = 0; + int local_fd; + struct file *file; + char *name; + struct gk20a_event_id_data *event_id_data; - gk20a_dbg(gpu_dbg_fn | gpu_dbg_info, - "channel events ctrl cmd %d", args->cmd); + err = gk20a_channel_get_event_data_from_id(ch, + event_id, &event_id_data); + if (err == 0) /* We already have event enabled */ + return -EINVAL; - switch (args->cmd) { - case NVGPU_IOCTL_CHANNEL_EVENTS_CTRL_CMD_ENABLE: - gk20a_channel_events_enable(&ch->poll_events); - break; + err = get_unused_fd_flags(O_RDWR); + if (err < 0) + return err; + local_fd = err; - case NVGPU_IOCTL_CHANNEL_EVENTS_CTRL_CMD_DISABLE: - gk20a_channel_events_disable(&ch->poll_events); - break; + name = kasprintf(GFP_KERNEL, "nvgpu-event%d-fd%d", + event_id, local_fd); - case NVGPU_IOCTL_CHANNEL_EVENTS_CTRL_CMD_CLEAR: - gk20a_channel_events_clear(&ch->poll_events); - break; + 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; + } - default: - gk20a_err(dev_from_gk20a(ch->g), - "unrecognized channel events ctrl cmd: 0x%x", - args->cmd); - ret = -EINVAL; - break; + 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; - return ret; -} + init_waitqueue_head(&event_id_data->event_id_wq); + mutex_init(&event_id_data->lock); + INIT_LIST_HEAD(&event_id_data->event_id_node); -void gk20a_channel_event(struct channel_gk20a *ch) -{ - mutex_lock(&ch->poll_events.lock); + 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); - 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); + fd_install(local_fd, file); + file->private_data = event_id_data; - ch->poll_events.num_pending_events++; - /* not waking up here, caller does that */ - } + *fd = local_fd; - mutex_unlock(&ch->poll_events.lock); -} + return 0; -void gk20a_channel_post_event(struct channel_gk20a *ch) -{ - gk20a_channel_event(ch); - wake_up_interruptible_all(&ch->semaphore_wq); +clean_up_file: + fput(file); +clean_up: + put_unused_fd(local_fd); + return err; } -unsigned int gk20a_channel_poll(struct file *filep, poll_table *wait) +static int gk20a_channel_event_id_ctrl(struct channel_gk20a *ch, + struct nvgpu_event_id_ctrl_args *args) { - unsigned int mask = 0; - struct channel_gk20a *ch = filep->private_data; + int err = 0; + int fd = -1; - gk20a_dbg(gpu_dbg_fn | gpu_dbg_info, ""); + if (args->event_id < 0 || + args->event_id >= NVGPU_IOCTL_CHANNEL_EVENT_ID_MAX) + return -EINVAL; - poll_wait(filep, &ch->semaphore_wq, wait); + if (gk20a_is_channel_marked_as_tsg(ch)) + return -EINVAL; - mutex_lock(&ch->poll_events.lock); + switch (args->cmd) { + case NVGPU_IOCTL_CHANNEL_EVENT_ID_CMD_ENABLE: + err = gk20a_channel_event_id_enable(ch, args->event_id, &fd); + if (!err) + args->event_fd = fd; + break; - 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); + default: + gk20a_err(dev_from_gk20a(ch->g), + "unrecognized channel event id cmd: 0x%x", + args->cmd); + err = -EINVAL; + break; } - mutex_unlock(&ch->poll_events.lock); - - return mask; + return err; } 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++) { struct channel_gk20a *c = g->fifo.channel+chid; if (gk20a_channel_get(c)) { - gk20a_channel_post_event(c); + wake_up_interruptible_all(&c->semaphore_wq); gk20a_channel_update(c, 0); gk20a_channel_put(c); } @@ -3040,9 +3091,9 @@ long gk20a_channel_ioctl(struct file *filp, err = gk20a_fifo_force_reset_ch(ch, true); gk20a_idle(dev); break; - case NVGPU_IOCTL_CHANNEL_EVENTS_CTRL: - err = gk20a_channel_events_ctrl(ch, - (struct nvgpu_channel_events_ctrl_args *)buf); + case NVGPU_IOCTL_CHANNEL_EVENT_ID_CTRL: + err = gk20a_channel_event_id_ctrl(ch, + (struct nvgpu_event_id_ctrl_args *)buf); break; #ifdef CONFIG_GK20A_CYCLE_STATS case NVGPU_IOCTL_CHANNEL_CYCLE_STATS_SNAPSHOT: diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h index e3fbba3e..cbe0fd59 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h @@ -74,10 +74,16 @@ struct channel_gk20a_timeout { 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; - bool events_enabled; - int num_pending_events; + struct list_head event_id_node; }; struct channel_gk20a_clean_up { @@ -163,6 +169,9 @@ struct channel_gk20a { struct mutex dbg_s_lock; struct list_head dbg_s_list; + struct list_head event_id_list; + struct mutex event_id_list_lock; + bool has_timedout; u32 timeout_ms_max; bool timeout_debug_dump; @@ -178,9 +187,6 @@ struct channel_gk20a { u64 virt_ctx; #endif - /* event support */ - struct channel_gk20a_poll_events poll_events; - /* signal channel owner via a callback, if set, in gk20a_channel_update * via schedule_work */ 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); struct channel_gk20a *gk20a_get_channel_from_file(int fd); 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); diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index fb0a6aa3..2aad3365 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c @@ -108,7 +108,6 @@ static const struct file_operations gk20a_channel_ops = { .compat_ioctl = gk20a_channel_ioctl, #endif .unlocked_ioctl = gk20a_channel_ioctl, - .poll = gk20a_channel_poll, }; static const struct file_operations gk20a_ctrl_ops = { diff --git a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c index a10650be..56d1d505 100644 --- a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c @@ -4983,7 +4983,7 @@ static int gk20a_gr_handle_semaphore_pending(struct gk20a *g, struct fifo_gk20a *f = &g->fifo; struct channel_gk20a *ch = &f->channel[isr_data->chid]; - gk20a_channel_post_event(ch); + wake_up_interruptible_all(&ch->semaphore_wq); return 0; } diff --git a/drivers/gpu/nvgpu/vgpu/gr_vgpu.c b/drivers/gpu/nvgpu/vgpu/gr_vgpu.c index f83f35b8..3baa420f 100644 --- a/drivers/gpu/nvgpu/vgpu/gr_vgpu.c +++ b/drivers/gpu/nvgpu/vgpu/gr_vgpu.c @@ -871,7 +871,7 @@ int vgpu_gr_isr(struct gk20a *g, struct tegra_vgpu_gr_intr_info *info) wake_up(&ch->notifier_wq); break; case TEGRA_VGPU_GR_INTR_SEMAPHORE: - gk20a_channel_post_event(ch); + wake_up_interruptible_all(&ch->semaphore_wq); break; case TEGRA_VGPU_GR_INTR_SEMAPHORE_TIMEOUT: gk20a_set_error_notifier(ch, diff --git a/include/uapi/linux/nvgpu.h b/include/uapi/linux/nvgpu.h index 64ac45b5..6fed9e9f 100644 --- a/include/uapi/linux/nvgpu.h +++ b/include/uapi/linux/nvgpu.h @@ -825,17 +825,6 @@ struct nvgpu_notification { #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 */ struct nvgpu_cycle_stats_snapshot_args { __u32 cmd; /* in: command to handle */ @@ -886,6 +875,20 @@ struct nvgpu_timeslice_args { __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 \ _IOW(NVGPU_IOCTL_MAGIC, 5, struct nvgpu_set_nvmap_fd_args) #define NVGPU_IOCTL_CHANNEL_SET_TIMEOUT \ @@ -922,8 +925,8 @@ struct nvgpu_timeslice_args { _IO(NVGPU_IOCTL_MAGIC, 115) #define NVGPU_IOCTL_CHANNEL_FORCE_RESET \ _IO(NVGPU_IOCTL_MAGIC, 116) -#define NVGPU_IOCTL_CHANNEL_EVENTS_CTRL \ - _IOW(NVGPU_IOCTL_MAGIC, 117, struct nvgpu_channel_events_ctrl_args) +#define NVGPU_IOCTL_CHANNEL_EVENT_ID_CTRL \ + _IOWR(NVGPU_IOCTL_MAGIC, 117, struct nvgpu_event_id_ctrl_args) #define NVGPU_IOCTL_CHANNEL_CYCLE_STATS_SNAPSHOT \ _IOWR(NVGPU_IOCTL_MAGIC, 118, struct nvgpu_cycle_stats_snapshot_args) #define NVGPU_IOCTL_CHANNEL_WDT \ -- cgit v1.2.2