summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
diff options
context:
space:
mode:
authorAingara Paramakuru <aparamakuru@nvidia.com>2016-02-22 12:35:49 -0500
committerTerje Bergstrom <tbergstrom@nvidia.com>2016-03-15 19:23:44 -0400
commit2a58d3c27b45ca9d0d9dc2136377b7a41b9ed82d (patch)
tree9d7464bfd0eea8e4b65f591996db59a98f4070e2 /drivers/gpu/nvgpu/gk20a/channel_gk20a.c
parentf07a046a52e7a8074bd1572a12ac65747d3f827d (diff)
gpu: nvgpu: improve channel interleave support
Previously, only "high" priority bare channels were interleaved between all other bare channels and TSGs. This patch decouples priority from interleaving and introduces 3 levels for interleaving a bare channel or TSG: high, medium, and low. The levels define the number of times a channel or TSG will appear on a runlist (see nvgpu.h for details). By default, all bare channels and TSGs are set to interleave level low. Userspace can then request the interleave level to be increased via the CHANNEL_SET_RUNLIST_INTERLEAVE ioctl (TSG-specific ioctl will be added later). As timeslice settings will soon be coming from userspace, the default timeslice for "high" priority channels has been restored. JIRA VFND-1302 Bug 1729664 Change-Id: I178bc1cecda23f5002fec6d791e6dcaedfa05c0c Signed-off-by: Aingara Paramakuru <aparamakuru@nvidia.com> Reviewed-on: http://git-master/r/1014962 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/channel_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.c85
1 files changed, 41 insertions, 44 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
index 2c2850c6..6eecebf5 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
@@ -177,7 +177,7 @@ int gk20a_channel_get_timescale_from_timeslice(struct gk20a *g,
177} 177}
178 178
179static int channel_gk20a_set_schedule_params(struct channel_gk20a *c, 179static int channel_gk20a_set_schedule_params(struct channel_gk20a *c,
180 u32 timeslice_period, bool interleave) 180 u32 timeslice_period)
181{ 181{
182 void *inst_ptr; 182 void *inst_ptr;
183 int shift = 0, value = 0; 183 int shift = 0, value = 0;
@@ -205,30 +205,6 @@ static int channel_gk20a_set_schedule_params(struct channel_gk20a *c,
205 gk20a_readl(c->g, ccsr_channel_r(c->hw_chid)) | 205 gk20a_readl(c->g, ccsr_channel_r(c->hw_chid)) |
206 ccsr_channel_enable_set_true_f()); 206 ccsr_channel_enable_set_true_f());
207 207
208 if (c->interleave != interleave) {
209 mutex_lock(&c->g->interleave_lock);
210 c->interleave = interleave;
211 if (interleave)
212 if (c->g->num_interleaved_channels >=
213 MAX_INTERLEAVED_CHANNELS) {
214 gk20a_err(dev_from_gk20a(c->g),
215 "Change of priority would exceed runlist length, only changing timeslice\n");
216 c->interleave = false;
217 } else
218 c->g->num_interleaved_channels += 1;
219 else
220 c->g->num_interleaved_channels -= 1;
221
222 mutex_unlock(&c->g->interleave_lock);
223 gk20a_dbg_info("Set channel %d to interleave %d",
224 c->hw_chid, c->interleave);
225
226 gk20a_fifo_set_channel_priority(
227 c->g, 0, c->hw_chid, c->interleave);
228 c->g->ops.fifo.update_runlist(
229 c->g, 0, ~0, true, false);
230 }
231
232 return 0; 208 return 0;
233} 209}
234 210
@@ -711,6 +687,32 @@ static int gk20a_channel_set_wdt_status(struct channel_gk20a *ch,
711 return 0; 687 return 0;
712} 688}
713 689
690static int gk20a_channel_set_runlist_interleave(struct channel_gk20a *ch,
691 u32 level)
692{
693 struct gk20a *g = ch->g;
694 int ret;
695
696 if (gk20a_is_channel_marked_as_tsg(ch)) {
697 gk20a_err(dev_from_gk20a(g), "invalid operation for TSG!\n");
698 return -EINVAL;
699 }
700
701 switch (level) {
702 case NVGPU_RUNLIST_INTERLEAVE_LEVEL_LOW:
703 case NVGPU_RUNLIST_INTERLEAVE_LEVEL_MEDIUM:
704 case NVGPU_RUNLIST_INTERLEAVE_LEVEL_HIGH:
705 ret = g->ops.fifo.set_runlist_interleave(g, ch->hw_chid,
706 false, 0, level);
707 break;
708 default:
709 ret = -EINVAL;
710 break;
711 }
712
713 return ret ? ret : g->ops.fifo.update_runlist(g, 0, ~0, true, true);
714}
715
714static int gk20a_init_error_notifier(struct channel_gk20a *ch, 716static int gk20a_init_error_notifier(struct channel_gk20a *ch,
715 struct nvgpu_set_error_notifier *args) 717 struct nvgpu_set_error_notifier *args)
716{ 718{
@@ -899,17 +901,6 @@ static void gk20a_free_channel(struct channel_gk20a *ch)
899 } 901 }
900 mutex_unlock(&f->deferred_reset_mutex); 902 mutex_unlock(&f->deferred_reset_mutex);
901 903
902 if (ch->interleave) {
903 ch->interleave = false;
904 gk20a_fifo_set_channel_priority(
905 ch->g, 0, ch->hw_chid, ch->interleave);
906
907 mutex_lock(&f->g->interleave_lock);
908 WARN_ON(f->g->num_interleaved_channels == 0);
909 f->g->num_interleaved_channels -= 1;
910 mutex_unlock(&f->g->interleave_lock);
911 }
912
913 if (!ch->bound) 904 if (!ch->bound)
914 goto release; 905 goto release;
915 906
@@ -1154,11 +1145,8 @@ struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g)
1154 ch->has_timedout = false; 1145 ch->has_timedout = false;
1155 ch->wdt_enabled = true; 1146 ch->wdt_enabled = true;
1156 ch->obj_class = 0; 1147 ch->obj_class = 0;
1157 ch->interleave = false;
1158 ch->clean_up.scheduled = false; 1148 ch->clean_up.scheduled = false;
1159 gk20a_fifo_set_channel_priority( 1149 ch->interleave_level = NVGPU_RUNLIST_INTERLEAVE_LEVEL_LOW;
1160 ch->g, 0, ch->hw_chid, ch->interleave);
1161
1162 1150
1163 /* The channel is *not* runnable at this point. It still needs to have 1151 /* The channel is *not* runnable at this point. It still needs to have
1164 * an address space bound and allocate a gpfifo and grctx. */ 1152 * an address space bound and allocate a gpfifo and grctx. */
@@ -2613,7 +2601,6 @@ unsigned int gk20a_channel_poll(struct file *filep, poll_table *wait)
2613int gk20a_channel_set_priority(struct channel_gk20a *ch, u32 priority) 2601int gk20a_channel_set_priority(struct channel_gk20a *ch, u32 priority)
2614{ 2602{
2615 u32 timeslice_timeout; 2603 u32 timeslice_timeout;
2616 bool interleave = false;
2617 2604
2618 if (gk20a_is_channel_marked_as_tsg(ch)) { 2605 if (gk20a_is_channel_marked_as_tsg(ch)) {
2619 gk20a_err(dev_from_gk20a(ch->g), 2606 gk20a_err(dev_from_gk20a(ch->g),
@@ -2630,8 +2617,6 @@ int gk20a_channel_set_priority(struct channel_gk20a *ch, u32 priority)
2630 timeslice_timeout = ch->g->timeslice_medium_priority_us; 2617 timeslice_timeout = ch->g->timeslice_medium_priority_us;
2631 break; 2618 break;
2632 case NVGPU_PRIORITY_HIGH: 2619 case NVGPU_PRIORITY_HIGH:
2633 if (ch->g->interleave_high_priority)
2634 interleave = true;
2635 timeslice_timeout = ch->g->timeslice_high_priority_us; 2620 timeslice_timeout = ch->g->timeslice_high_priority_us;
2636 break; 2621 break;
2637 default: 2622 default:
@@ -2640,7 +2625,7 @@ int gk20a_channel_set_priority(struct channel_gk20a *ch, u32 priority)
2640 } 2625 }
2641 2626
2642 return channel_gk20a_set_schedule_params(ch, 2627 return channel_gk20a_set_schedule_params(ch,
2643 timeslice_timeout, interleave); 2628 timeslice_timeout);
2644} 2629}
2645 2630
2646static int gk20a_channel_zcull_bind(struct channel_gk20a *ch, 2631static int gk20a_channel_zcull_bind(struct channel_gk20a *ch,
@@ -3045,6 +3030,18 @@ long gk20a_channel_ioctl(struct file *filp,
3045 err = gk20a_channel_set_wdt_status(ch, 3030 err = gk20a_channel_set_wdt_status(ch,
3046 (struct nvgpu_channel_wdt_args *)buf); 3031 (struct nvgpu_channel_wdt_args *)buf);
3047 break; 3032 break;
3033 case NVGPU_IOCTL_CHANNEL_SET_RUNLIST_INTERLEAVE:
3034 err = gk20a_busy(dev);
3035 if (err) {
3036 dev_err(&dev->dev,
3037 "%s: failed to host gk20a for ioctl cmd: 0x%x",
3038 __func__, cmd);
3039 break;
3040 }
3041 err = gk20a_channel_set_runlist_interleave(ch,
3042 ((struct nvgpu_runlist_interleave_args *)buf)->level);
3043 gk20a_idle(dev);
3044 break;
3048 default: 3045 default:
3049 dev_dbg(&dev->dev, "unrecognized ioctl cmd: 0x%x", cmd); 3046 dev_dbg(&dev->dev, "unrecognized ioctl cmd: 0x%x", cmd);
3050 err = -ENOTTY; 3047 err = -ENOTTY;