mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
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 <kholtta@nvidia.com> Reviewed-on: http://git-master/r/497750 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
This commit is contained in:
committed by
Dan Willemsen
parent
91ada92f61
commit
ad17891725
@@ -773,6 +773,10 @@ 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;
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1891,6 +1895,119 @@ notif_clean_up:
|
|||||||
return ret;
|
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,
|
static int gk20a_channel_set_priority(struct channel_gk20a *ch,
|
||||||
u32 priority)
|
u32 priority)
|
||||||
{
|
{
|
||||||
@@ -2314,6 +2431,10 @@ 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 NVHOST_IOCTL_CHANNEL_EVENTS_CTRL:
|
||||||
|
err = gk20a_channel_events_ctrl(ch,
|
||||||
|
(struct nvhost_channel_events_ctrl_args *)buf);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(&dev->dev, "unrecognized ioctl cmd: 0x%x", cmd);
|
dev_err(&dev->dev, "unrecognized ioctl cmd: 0x%x", cmd);
|
||||||
err = -ENOTTY;
|
err = -ENOTTY;
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/nvhost_ioctl.h>
|
#include <linux/nvhost_ioctl.h>
|
||||||
|
#include <linux/poll.h>
|
||||||
|
|
||||||
struct gk20a;
|
struct gk20a;
|
||||||
struct gr_gk20a;
|
struct gr_gk20a;
|
||||||
struct dbg_session_gk20a;
|
struct dbg_session_gk20a;
|
||||||
@@ -74,6 +76,12 @@ struct channel_gk20a_job {
|
|||||||
struct list_head list;
|
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 */
|
/* this is the priv element of struct nvhost_channel */
|
||||||
struct channel_gk20a {
|
struct channel_gk20a {
|
||||||
struct gk20a *g;
|
struct gk20a *g;
|
||||||
@@ -148,6 +156,9 @@ struct channel_gk20a {
|
|||||||
#ifdef CONFIG_TEGRA_GR_VIRTUALIZATION
|
#ifdef CONFIG_TEGRA_GR_VIRTUALIZATION
|
||||||
u64 virt_ctx;
|
u64 virt_ctx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* event support */
|
||||||
|
struct channel_gk20a_poll_events poll_events;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool gk20a_channel_as_bound(struct channel_gk20a *ch)
|
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);
|
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_init_channel(struct gpu_ops *gops);
|
void gk20a_init_channel(struct gpu_ops *gops);
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ 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 = {
|
||||||
|
|||||||
@@ -5075,6 +5075,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_event(ch);
|
||||||
wake_up(&ch->semaphore_wq);
|
wake_up(&ch->semaphore_wq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user