summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/mc_gk20a.c
diff options
context:
space:
mode:
authorDavid Nieto <dmartineznie@nvidia.com>2017-02-06 18:44:55 -0500
committermobile promotions <svcmobile_promotions@nvidia.com>2017-03-14 14:46:38 -0400
commit403874fa75dbb00e974a8d0f88b6e92be01ba42e (patch)
tree0492e82ded3c4ce7ee4438b29bcadc2db9472279 /drivers/gpu/nvgpu/gk20a/mc_gk20a.c
parent4deb494ad114088f5253d02d9ec31f9aaeb2778a (diff)
gpu: nvgpu: refactor interrupt handling
JIRA: EVLR-1004 (*) Refactor the non-stalling interrupt path to execute clear on the top half, so on dGPU case processing of stalling interrupts does not block non-stalling one. (*) Use a worker thread to do semaphore wakeups and allow batching of the non-stalling operations. (*) Fix a bug where some gpus will not properly track the completion of interrupts, preventing safe driver unloads Change-Id: Icc90a3acba544c97ec6a9285ab235d337ab9eefa Signed-off-by: David Nieto <dmartineznie@nvidia.com> Reviewed-on: http://git-master/r/1312796 Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Lakshmanan M <lm@nvidia.com> Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-by: Navneet Kumar <navneetk@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/mc_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/mc_gk20a.c98
1 files changed, 60 insertions, 38 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/mc_gk20a.c b/drivers/gpu/nvgpu/gk20a/mc_gk20a.c
index 65f1a119..caab6b5e 100644
--- a/drivers/gpu/nvgpu/gk20a/mc_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/mc_gk20a.c
@@ -21,6 +21,24 @@
21 21
22#include <nvgpu/hw/gk20a/hw_mc_gk20a.h> 22#include <nvgpu/hw/gk20a/hw_mc_gk20a.h>
23 23
24void mc_gk20a_nonstall_cb(struct work_struct *work)
25{
26 struct gk20a *g = container_of(work, struct gk20a, nonstall_fn_work);
27 u32 ops;
28 bool semaphore_wakeup, post_events;
29
30 do {
31 ops = atomic_xchg(&g->nonstall_ops, 0);
32
33 semaphore_wakeup = ops & gk20a_nonstall_ops_wakeup_semaphore;
34 post_events = ops & gk20a_nonstall_ops_post_events;
35
36 if (semaphore_wakeup)
37 gk20a_channel_semaphore_wakeup(g, post_events);
38
39 } while (atomic_read(&g->nonstall_ops) != 0);
40}
41
24irqreturn_t mc_gk20a_isr_stall(struct gk20a *g) 42irqreturn_t mc_gk20a_isr_stall(struct gk20a *g)
25{ 43{
26 u32 mc_intr_0; 44 u32 mc_intr_0;
@@ -51,6 +69,7 @@ irqreturn_t mc_gk20a_isr_stall(struct gk20a *g)
51irqreturn_t mc_gk20a_isr_nonstall(struct gk20a *g) 69irqreturn_t mc_gk20a_isr_nonstall(struct gk20a *g)
52{ 70{
53 u32 mc_intr_1; 71 u32 mc_intr_1;
72 u32 hw_irq_count;
54 73
55 if (!g->power_on) 74 if (!g->power_on)
56 return IRQ_NONE; 75 return IRQ_NONE;
@@ -66,9 +85,23 @@ irqreturn_t mc_gk20a_isr_nonstall(struct gk20a *g)
66 /* flush previous write */ 85 /* flush previous write */
67 gk20a_readl(g, mc_intr_en_1_r()); 86 gk20a_readl(g, mc_intr_en_1_r());
68 87
69 atomic_inc(&g->hw_irq_nonstall_count); 88 if (g->ops.mc.isr_thread_nonstall)
89 g->ops.mc.isr_thread_nonstall(g, mc_intr_1);
70 90
71 return IRQ_WAKE_THREAD; 91 hw_irq_count = atomic_inc_return(&g->hw_irq_nonstall_count);
92
93 /* sync handled irq counter before re-enabling interrupts */
94 atomic_set(&g->sw_irq_nonstall_last_handled, hw_irq_count);
95
96 gk20a_writel(g, mc_intr_en_1_r(),
97 mc_intr_en_1_inta_hardware_f());
98
99 /* flush previous write */
100 gk20a_readl(g, mc_intr_en_1_r());
101
102 wake_up_all(&g->sw_irq_nonstall_last_handled_wq);
103
104 return IRQ_HANDLED;
72} 105}
73 106
74irqreturn_t mc_gk20a_intr_thread_stall(struct gk20a *g) 107irqreturn_t mc_gk20a_intr_thread_stall(struct gk20a *g)
@@ -137,59 +170,47 @@ irqreturn_t mc_gk20a_intr_thread_stall(struct gk20a *g)
137 return IRQ_HANDLED; 170 return IRQ_HANDLED;
138} 171}
139 172
140irqreturn_t mc_gk20a_intr_thread_nonstall(struct gk20a *g) 173void mc_gk20a_intr_thread_nonstall(struct gk20a *g, u32 mc_intr_1)
141{ 174{
142 u32 mc_intr_1;
143 int hw_irq_count;
144 u32 engine_id_idx; 175 u32 engine_id_idx;
145 u32 active_engine_id = 0; 176 u32 active_engine_id = 0;
146 u32 engine_enum = ENGINE_INVAL_GK20A; 177 u32 engine_enum = ENGINE_INVAL_GK20A;
147 178 int ops_old, ops_new, ops = 0;
148 gk20a_dbg(gpu_dbg_intr, "interrupt thread launched");
149
150 mc_intr_1 = gk20a_readl(g, mc_intr_1_r());
151 hw_irq_count = atomic_read(&g->hw_irq_nonstall_count);
152
153 gk20a_dbg(gpu_dbg_intr, "non-stall intr %08x\n", mc_intr_1);
154 179
155 if (mc_intr_1 & mc_intr_0_pfifo_pending_f()) 180 if (mc_intr_1 & mc_intr_0_pfifo_pending_f())
156 gk20a_fifo_nonstall_isr(g); 181 ops |= gk20a_fifo_nonstall_isr(g);
157 if (mc_intr_1 & mc_intr_0_priv_ring_pending_f())
158 gk20a_priv_ring_isr(g);
159 182
160 for (engine_id_idx = 0; engine_id_idx < g->fifo.num_engines; engine_id_idx++) { 183 for (engine_id_idx = 0; engine_id_idx < g->fifo.num_engines;
184 engine_id_idx++) {
161 active_engine_id = g->fifo.active_engines_list[engine_id_idx]; 185 active_engine_id = g->fifo.active_engines_list[engine_id_idx];
162 186
163 if (mc_intr_1 & g->fifo.engine_info[active_engine_id].intr_mask) { 187 if (mc_intr_1 &
188 g->fifo.engine_info[active_engine_id].intr_mask) {
164 engine_enum = g->fifo.engine_info[active_engine_id].engine_enum; 189 engine_enum = g->fifo.engine_info[active_engine_id].engine_enum;
165 /* GR Engine */ 190 /* GR Engine */
166 if (engine_enum == ENGINE_GR_GK20A) { 191 if (engine_enum == ENGINE_GR_GK20A)
167 gk20a_gr_nonstall_isr(g); 192 ops |= gk20a_gr_nonstall_isr(g);
168 }
169 193
170 /* CE Engine */ 194 /* CE Engine */
171 if (((engine_enum == ENGINE_GRCE_GK20A) || 195 if (((engine_enum == ENGINE_GRCE_GK20A) ||
172 (engine_enum == ENGINE_ASYNC_CE_GK20A)) && 196 (engine_enum == ENGINE_ASYNC_CE_GK20A)) &&
173 g->ops.ce2.isr_nonstall) { 197 g->ops.ce2.isr_nonstall)
174 g->ops.ce2.isr_nonstall(g, 198 ops |= g->ops.ce2.isr_nonstall(g,
175 g->fifo.engine_info[active_engine_id].inst_id, 199 g->fifo.engine_info[active_engine_id].
176 g->fifo.engine_info[active_engine_id].pri_base); 200 inst_id,
177 } 201 g->fifo.engine_info[active_engine_id].
202 pri_base);
178 } 203 }
179 } 204 }
180 205 if (ops) {
181 /* sync handled irq counter before re-enabling interrupts */ 206 do {
182 atomic_set(&g->sw_irq_nonstall_last_handled, hw_irq_count); 207 ops_old = atomic_read(&g->nonstall_ops);
183 208 ops_new = ops_old | ops;
184 gk20a_writel(g, mc_intr_en_1_r(), 209 } while (ops_old != atomic_cmpxchg(&g->nonstall_ops,
185 mc_intr_en_1_inta_hardware_f()); 210 ops_old, ops_new));
186 211
187 /* flush previous write */ 212 queue_work(g->nonstall_work_queue, &g->nonstall_fn_work);
188 gk20a_readl(g, mc_intr_en_1_r()); 213 }
189
190 wake_up_all(&g->sw_irq_nonstall_last_handled_wq);
191
192 return IRQ_HANDLED;
193} 214}
194 215
195void mc_gk20a_intr_enable(struct gk20a *g) 216void mc_gk20a_intr_enable(struct gk20a *g)
@@ -237,4 +258,5 @@ void gk20a_init_mc(struct gpu_ops *gops)
237 gops->mc.isr_nonstall = mc_gk20a_isr_nonstall; 258 gops->mc.isr_nonstall = mc_gk20a_isr_nonstall;
238 gops->mc.isr_thread_stall = mc_gk20a_intr_thread_stall; 259 gops->mc.isr_thread_stall = mc_gk20a_intr_thread_stall;
239 gops->mc.isr_thread_nonstall = mc_gk20a_intr_thread_nonstall; 260 gops->mc.isr_thread_nonstall = mc_gk20a_intr_thread_nonstall;
261 gops->mc.isr_nonstall_cb = mc_gk20a_nonstall_cb;
240} 262}