diff options
author | Konsta Holtta <kholtta@nvidia.com> | 2014-09-10 10:23:31 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2015-03-18 15:11:19 -0400 |
commit | ad178917259b30330e8432e2cd33d50c03e9602b (patch) | |
tree | 194c769517bfa3707bd0fb8f0b89e5d00f4ea5f4 | |
parent | 91ada92f61eeb41026a678b58863acafa7a33674 (diff) |
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>
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 121 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 13 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.c | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gr_gk20a.c | 1 |
4 files changed, 136 insertions, 0 deletions
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) | |||
773 | init_waitqueue_head(&ch->semaphore_wq); | 773 | init_waitqueue_head(&ch->semaphore_wq); |
774 | init_waitqueue_head(&ch->submit_wq); | 774 | init_waitqueue_head(&ch->submit_wq); |
775 | 775 | ||
776 | mutex_init(&ch->poll_events.lock); | ||
777 | ch->poll_events.events_enabled = false; | ||
778 | ch->poll_events.num_pending_events = 0; | ||
779 | |||
776 | return ch; | 780 | return ch; |
777 | } | 781 | } |
778 | 782 | ||
@@ -1891,6 +1895,119 @@ notif_clean_up: | |||
1891 | return ret; | 1895 | return ret; |
1892 | } | 1896 | } |
1893 | 1897 | ||
1898 | /* poll events for semaphores */ | ||
1899 | |||
1900 | static void gk20a_channel_events_enable(struct channel_gk20a_poll_events *ev) | ||
1901 | { | ||
1902 | gk20a_dbg_fn(""); | ||
1903 | |||
1904 | mutex_lock(&ev->lock); | ||
1905 | |||
1906 | ev->events_enabled = true; | ||
1907 | ev->num_pending_events = 0; | ||
1908 | |||
1909 | mutex_unlock(&ev->lock); | ||
1910 | } | ||
1911 | |||
1912 | static void gk20a_channel_events_disable(struct channel_gk20a_poll_events *ev) | ||
1913 | { | ||
1914 | gk20a_dbg_fn(""); | ||
1915 | |||
1916 | mutex_lock(&ev->lock); | ||
1917 | |||
1918 | ev->events_enabled = false; | ||
1919 | ev->num_pending_events = 0; | ||
1920 | |||
1921 | mutex_unlock(&ev->lock); | ||
1922 | } | ||
1923 | |||
1924 | static void gk20a_channel_events_clear(struct channel_gk20a_poll_events *ev) | ||
1925 | { | ||
1926 | gk20a_dbg_fn(""); | ||
1927 | |||
1928 | mutex_lock(&ev->lock); | ||
1929 | |||
1930 | if (ev->events_enabled && | ||
1931 | ev->num_pending_events > 0) | ||
1932 | ev->num_pending_events--; | ||
1933 | |||
1934 | mutex_unlock(&ev->lock); | ||
1935 | } | ||
1936 | |||
1937 | static int gk20a_channel_events_ctrl(struct channel_gk20a *ch, | ||
1938 | struct nvhost_channel_events_ctrl_args *args) | ||
1939 | { | ||
1940 | int ret = 0; | ||
1941 | |||
1942 | gk20a_dbg(gpu_dbg_fn | gpu_dbg_info, | ||
1943 | "channel events ctrl cmd %d", args->cmd); | ||
1944 | |||
1945 | switch (args->cmd) { | ||
1946 | case NVHOST_IOCTL_CHANNEL_EVENTS_CTRL_CMD_ENABLE: | ||
1947 | gk20a_channel_events_enable(&ch->poll_events); | ||
1948 | break; | ||
1949 | |||
1950 | case NVHOST_IOCTL_CHANNEL_EVENTS_CTRL_CMD_DISABLE: | ||
1951 | gk20a_channel_events_disable(&ch->poll_events); | ||
1952 | break; | ||
1953 | |||
1954 | case NVHOST_IOCTL_CHANNEL_EVENTS_CTRL_CMD_CLEAR: | ||
1955 | gk20a_channel_events_clear(&ch->poll_events); | ||
1956 | break; | ||
1957 | |||
1958 | default: | ||
1959 | gk20a_err(dev_from_gk20a(ch->g), | ||
1960 | "unrecognized channel events ctrl cmd: 0x%x", | ||
1961 | args->cmd); | ||
1962 | ret = -EINVAL; | ||
1963 | break; | ||
1964 | } | ||
1965 | |||
1966 | return ret; | ||
1967 | } | ||
1968 | |||
1969 | void gk20a_channel_event(struct channel_gk20a *ch) | ||
1970 | { | ||
1971 | mutex_lock(&ch->poll_events.lock); | ||
1972 | |||
1973 | if (ch->poll_events.events_enabled) { | ||
1974 | gk20a_dbg_info("posting event on channel id %d", | ||
1975 | ch->hw_chid); | ||
1976 | gk20a_dbg_info("%d channel events pending", | ||
1977 | ch->poll_events.num_pending_events); | ||
1978 | |||
1979 | ch->poll_events.num_pending_events++; | ||
1980 | /* not waking up here, caller does that */ | ||
1981 | } | ||
1982 | |||
1983 | mutex_unlock(&ch->poll_events.lock); | ||
1984 | } | ||
1985 | |||
1986 | unsigned int gk20a_channel_poll(struct file *filep, poll_table *wait) | ||
1987 | { | ||
1988 | unsigned int mask = 0; | ||
1989 | struct channel_gk20a *ch = filep->private_data; | ||
1990 | |||
1991 | gk20a_dbg(gpu_dbg_fn | gpu_dbg_info, ""); | ||
1992 | |||
1993 | poll_wait(filep, &ch->semaphore_wq, wait); | ||
1994 | |||
1995 | mutex_lock(&ch->poll_events.lock); | ||
1996 | |||
1997 | if (ch->poll_events.events_enabled && | ||
1998 | ch->poll_events.num_pending_events > 0) { | ||
1999 | gk20a_dbg_info("found pending event on channel id %d", | ||
2000 | ch->hw_chid); | ||
2001 | gk20a_dbg_info("%d channel events pending", | ||
2002 | ch->poll_events.num_pending_events); | ||
2003 | mask = (POLLPRI | POLLIN); | ||
2004 | } | ||
2005 | |||
2006 | mutex_unlock(&ch->poll_events.lock); | ||
2007 | |||
2008 | return mask; | ||
2009 | } | ||
2010 | |||
1894 | static int gk20a_channel_set_priority(struct channel_gk20a *ch, | 2011 | static int gk20a_channel_set_priority(struct channel_gk20a *ch, |
1895 | u32 priority) | 2012 | u32 priority) |
1896 | { | 2013 | { |
@@ -2314,6 +2431,10 @@ long gk20a_channel_ioctl(struct file *filp, | |||
2314 | err = gk20a_fifo_force_reset_ch(ch, true); | 2431 | err = gk20a_fifo_force_reset_ch(ch, true); |
2315 | gk20a_idle(dev); | 2432 | gk20a_idle(dev); |
2316 | break; | 2433 | break; |
2434 | case NVHOST_IOCTL_CHANNEL_EVENTS_CTRL: | ||
2435 | err = gk20a_channel_events_ctrl(ch, | ||
2436 | (struct nvhost_channel_events_ctrl_args *)buf); | ||
2437 | break; | ||
2317 | default: | 2438 | default: |
2318 | dev_err(&dev->dev, "unrecognized ioctl cmd: 0x%x", cmd); | 2439 | dev_err(&dev->dev, "unrecognized ioctl cmd: 0x%x", cmd); |
2319 | err = -ENOTTY; | 2440 | 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 @@ | |||
26 | #include <linux/wait.h> | 26 | #include <linux/wait.h> |
27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
28 | #include <linux/nvhost_ioctl.h> | 28 | #include <linux/nvhost_ioctl.h> |
29 | #include <linux/poll.h> | ||
30 | |||
29 | struct gk20a; | 31 | struct gk20a; |
30 | struct gr_gk20a; | 32 | struct gr_gk20a; |
31 | struct dbg_session_gk20a; | 33 | struct dbg_session_gk20a; |
@@ -74,6 +76,12 @@ struct channel_gk20a_job { | |||
74 | struct list_head list; | 76 | struct list_head list; |
75 | }; | 77 | }; |
76 | 78 | ||
79 | struct channel_gk20a_poll_events { | ||
80 | struct mutex lock; | ||
81 | bool events_enabled; | ||
82 | int num_pending_events; | ||
83 | }; | ||
84 | |||
77 | /* this is the priv element of struct nvhost_channel */ | 85 | /* this is the priv element of struct nvhost_channel */ |
78 | struct channel_gk20a { | 86 | struct channel_gk20a { |
79 | struct gk20a *g; | 87 | struct gk20a *g; |
@@ -148,6 +156,9 @@ struct channel_gk20a { | |||
148 | #ifdef CONFIG_TEGRA_GR_VIRTUALIZATION | 156 | #ifdef CONFIG_TEGRA_GR_VIRTUALIZATION |
149 | u64 virt_ctx; | 157 | u64 virt_ctx; |
150 | #endif | 158 | #endif |
159 | |||
160 | /* event support */ | ||
161 | struct channel_gk20a_poll_events poll_events; | ||
151 | }; | 162 | }; |
152 | 163 | ||
153 | static inline bool gk20a_channel_as_bound(struct channel_gk20a *ch) | 164 | static inline bool gk20a_channel_as_bound(struct channel_gk20a *ch) |
@@ -180,6 +191,8 @@ long gk20a_channel_ioctl(struct file *filp, | |||
180 | int gk20a_channel_release(struct inode *inode, struct file *filp); | 191 | int gk20a_channel_release(struct inode *inode, struct file *filp); |
181 | struct channel_gk20a *gk20a_get_channel_from_file(int fd); | 192 | struct channel_gk20a *gk20a_get_channel_from_file(int fd); |
182 | void gk20a_channel_update(struct channel_gk20a *c, int nr_completed); | 193 | void gk20a_channel_update(struct channel_gk20a *c, int nr_completed); |
194 | unsigned int gk20a_channel_poll(struct file *filep, poll_table *wait); | ||
195 | void gk20a_channel_event(struct channel_gk20a *ch); | ||
183 | 196 | ||
184 | void gk20a_init_channel(struct gpu_ops *gops); | 197 | void gk20a_init_channel(struct gpu_ops *gops); |
185 | 198 | ||
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 = { | |||
100 | .compat_ioctl = gk20a_channel_ioctl, | 100 | .compat_ioctl = gk20a_channel_ioctl, |
101 | #endif | 101 | #endif |
102 | .unlocked_ioctl = gk20a_channel_ioctl, | 102 | .unlocked_ioctl = gk20a_channel_ioctl, |
103 | .poll = gk20a_channel_poll, | ||
103 | }; | 104 | }; |
104 | 105 | ||
105 | static const struct file_operations gk20a_ctrl_ops = { | 106 | 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, | |||
5075 | struct fifo_gk20a *f = &g->fifo; | 5075 | struct fifo_gk20a *f = &g->fifo; |
5076 | struct channel_gk20a *ch = &f->channel[isr_data->chid]; | 5076 | struct channel_gk20a *ch = &f->channel[isr_data->chid]; |
5077 | 5077 | ||
5078 | gk20a_channel_event(ch); | ||
5078 | wake_up(&ch->semaphore_wq); | 5079 | wake_up(&ch->semaphore_wq); |
5079 | 5080 | ||
5080 | return 0; | 5081 | return 0; |