From ad178917259b30330e8432e2cd33d50c03e9602b Mon Sep 17 00:00:00 2001 From: Konsta Holtta Date: Wed, 10 Sep 2014 17:23:31 +0300 Subject: gpu: nvgpu: implement poll() for semaphores Add poll interface and control ioctls for waiting for GPU job completion via semaphores. Poll on a gk20a channel file waits for events from pending semaphore interrupts (stalling) of that channel. New ioctls enable and disable the events, and clear a single interrupt event so that next poll doesn't wake up for it again. Bug 1528781 Change-Id: I5c6238966b5d0900c8ab263c6a7f8f2611901f33 Signed-off-by: Konsta Holtta Reviewed-on: http://git-master/r/497750 Reviewed-by: Terje Bergstrom Tested-by: Terje Bergstrom --- drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 121 ++++++++++++++++++++++++++++++++ drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 13 ++++ drivers/gpu/nvgpu/gk20a/gk20a.c | 1 + drivers/gpu/nvgpu/gk20a/gr_gk20a.c | 1 + 4 files changed, 136 insertions(+) (limited to 'drivers/gpu/nvgpu/gk20a') diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 1e71c1c7..2c6013c8 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c @@ -773,6 +773,10 @@ 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; + return ch; } @@ -1891,6 +1895,119 @@ notif_clean_up: return ret; } +/* poll events for semaphores */ + +static void gk20a_channel_events_enable(struct channel_gk20a_poll_events *ev) +{ + gk20a_dbg_fn(""); + + mutex_lock(&ev->lock); + + ev->events_enabled = true; + ev->num_pending_events = 0; + + mutex_unlock(&ev->lock); +} + +static void gk20a_channel_events_disable(struct channel_gk20a_poll_events *ev) +{ + gk20a_dbg_fn(""); + + mutex_lock(&ev->lock); + + ev->events_enabled = false; + ev->num_pending_events = 0; + + mutex_unlock(&ev->lock); +} + +static void gk20a_channel_events_clear(struct channel_gk20a_poll_events *ev) +{ + gk20a_dbg_fn(""); + + mutex_lock(&ev->lock); + + 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, + struct nvhost_channel_events_ctrl_args *args) +{ + int ret = 0; + + gk20a_dbg(gpu_dbg_fn | gpu_dbg_info, + "channel events ctrl cmd %d", args->cmd); + + switch (args->cmd) { + case NVHOST_IOCTL_CHANNEL_EVENTS_CTRL_CMD_ENABLE: + gk20a_channel_events_enable(&ch->poll_events); + break; + + case NVHOST_IOCTL_CHANNEL_EVENTS_CTRL_CMD_DISABLE: + gk20a_channel_events_disable(&ch->poll_events); + break; + + case NVHOST_IOCTL_CHANNEL_EVENTS_CTRL_CMD_CLEAR: + gk20a_channel_events_clear(&ch->poll_events); + break; + + default: + gk20a_err(dev_from_gk20a(ch->g), + "unrecognized channel events ctrl cmd: 0x%x", + args->cmd); + ret = -EINVAL; + break; + } + + return ret; +} + +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); +} + +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; +} + static int gk20a_channel_set_priority(struct channel_gk20a *ch, u32 priority) { @@ -2314,6 +2431,10 @@ long gk20a_channel_ioctl(struct file *filp, err = gk20a_fifo_force_reset_ch(ch, true); gk20a_idle(dev); break; + case NVHOST_IOCTL_CHANNEL_EVENTS_CTRL: + err = gk20a_channel_events_ctrl(ch, + (struct nvhost_channel_events_ctrl_args *)buf); + break; default: dev_err(&dev->dev, "unrecognized ioctl cmd: 0x%x", cmd); err = -ENOTTY; diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h index 37ca8244..bb9f314c 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h @@ -26,6 +26,8 @@ #include #include #include +#include + struct gk20a; struct gr_gk20a; struct dbg_session_gk20a; @@ -74,6 +76,12 @@ struct channel_gk20a_job { struct list_head list; }; +struct channel_gk20a_poll_events { + struct mutex lock; + bool events_enabled; + int num_pending_events; +}; + /* this is the priv element of struct nvhost_channel */ struct channel_gk20a { struct gk20a *g; @@ -148,6 +156,9 @@ struct channel_gk20a { #ifdef CONFIG_TEGRA_GR_VIRTUALIZATION u64 virt_ctx; #endif + + /* event support */ + struct channel_gk20a_poll_events poll_events; }; static inline bool gk20a_channel_as_bound(struct channel_gk20a *ch) @@ -180,6 +191,8 @@ 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_init_channel(struct gpu_ops *gops); diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index 7d744f42..acae38aa 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c @@ -100,6 +100,7 @@ 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 f5c3bd62..db655c32 100644 --- a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c @@ -5075,6 +5075,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_event(ch); wake_up(&ch->semaphore_wq); return 0; -- cgit v1.2.2