diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 15 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 2 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/debug_gk20a.c | 132 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/fifo_gk20a.c | 6 |
4 files changed, 132 insertions, 23 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 0f805214..486e815c 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c | |||
@@ -929,6 +929,21 @@ static void channel_gk20a_free_priv_cmdbuf(struct channel_gk20a *c) | |||
929 | memset(q, 0, sizeof(struct priv_cmd_queue)); | 929 | memset(q, 0, sizeof(struct priv_cmd_queue)); |
930 | } | 930 | } |
931 | 931 | ||
932 | int gk20a_find_from_priv_cmdbuf(struct channel_gk20a *c, | ||
933 | u64 gpu_va, u32 **cpu_va) | ||
934 | { | ||
935 | struct priv_cmd_queue *q = &c->priv_cmd_q; | ||
936 | int ret; | ||
937 | |||
938 | if (gpu_va >= q->base_gpuva && gpu_va < (q->base_gpuva + q->size)) { | ||
939 | *cpu_va = gpu_va - q->base_gpuva + q->mem.base_cpuva; | ||
940 | ret = 0; | ||
941 | } else | ||
942 | ret = -EINVAL; | ||
943 | |||
944 | return ret; | ||
945 | } | ||
946 | |||
932 | /* allocate a cmd buffer with given size. size is number of u32 entries */ | 947 | /* allocate a cmd buffer with given size. size is number of u32 entries */ |
933 | int gk20a_channel_alloc_priv_cmdbuf(struct channel_gk20a *c, u32 orig_size, | 948 | int gk20a_channel_alloc_priv_cmdbuf(struct channel_gk20a *c, u32 orig_size, |
934 | struct priv_cmd_entry **entry) | 949 | struct priv_cmd_entry **entry) |
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h index 60437e66..36697e02 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h | |||
@@ -159,6 +159,8 @@ void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error); | |||
159 | void gk20a_channel_semaphore_wakeup(struct gk20a *g); | 159 | void gk20a_channel_semaphore_wakeup(struct gk20a *g); |
160 | int gk20a_channel_alloc_priv_cmdbuf(struct channel_gk20a *c, u32 size, | 160 | int gk20a_channel_alloc_priv_cmdbuf(struct channel_gk20a *c, u32 size, |
161 | struct priv_cmd_entry **entry); | 161 | struct priv_cmd_entry **entry); |
162 | int gk20a_find_from_priv_cmdbuf(struct channel_gk20a *c, | ||
163 | u64 addr, u32 **cpu_va); | ||
162 | 164 | ||
163 | int gk20a_channel_suspend(struct gk20a *g); | 165 | int gk20a_channel_suspend(struct gk20a *g); |
164 | int gk20a_channel_resume(struct gk20a *g); | 166 | int gk20a_channel_resume(struct gk20a *g); |
diff --git a/drivers/gpu/nvgpu/gk20a/debug_gk20a.c b/drivers/gpu/nvgpu/gk20a/debug_gk20a.c index f5e0b73d..c607b138 100644 --- a/drivers/gpu/nvgpu/gk20a/debug_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/debug_gk20a.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
20 | 20 | ||
21 | #include <linux/io.h> | 21 | #include <linux/io.h> |
22 | #include <linux/dma-buf.h> | ||
22 | 23 | ||
23 | #include "gk20a.h" | 24 | #include "gk20a.h" |
24 | #include "debug_gk20a.h" | 25 | #include "debug_gk20a.h" |
@@ -33,6 +34,7 @@ struct platform_device *gk20a_device; | |||
33 | 34 | ||
34 | struct gk20a_debug_output { | 35 | struct gk20a_debug_output { |
35 | void (*fn)(void *ctx, const char *str, size_t len); | 36 | void (*fn)(void *ctx, const char *str, size_t len); |
37 | void (*cont)(void *ctx, const char *str, size_t len); | ||
36 | void *ctx; | 38 | void *ctx; |
37 | char buf[256]; | 39 | char buf[256]; |
38 | }; | 40 | }; |
@@ -80,6 +82,12 @@ static inline void gk20a_debug_write_printk(void *ctx, const char *str, | |||
80 | pr_info("%s", str); | 82 | pr_info("%s", str); |
81 | } | 83 | } |
82 | 84 | ||
85 | static inline void gk20a_debug_cont_printk(void *ctx, const char *str, | ||
86 | size_t len) | ||
87 | { | ||
88 | pr_cont("%s", str); | ||
89 | } | ||
90 | |||
83 | static inline void gk20a_debug_write_to_seqfile(void *ctx, const char *str, | 91 | static inline void gk20a_debug_write_to_seqfile(void *ctx, const char *str, |
84 | size_t len) | 92 | size_t len) |
85 | { | 93 | { |
@@ -97,6 +105,17 @@ void gk20a_debug_output(struct gk20a_debug_output *o, const char *fmt, ...) | |||
97 | o->fn(o->ctx, o->buf, len); | 105 | o->fn(o->ctx, o->buf, len); |
98 | } | 106 | } |
99 | 107 | ||
108 | void gk20a_debug_output_cont(struct gk20a_debug_output *o, const char *fmt, ...) | ||
109 | { | ||
110 | va_list args; | ||
111 | int len; | ||
112 | |||
113 | va_start(args, fmt); | ||
114 | len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); | ||
115 | va_end(args); | ||
116 | o->cont(o->ctx, o->buf, len); | ||
117 | } | ||
118 | |||
100 | static void gk20a_debug_show_channel(struct gk20a *g, | 119 | static void gk20a_debug_show_channel(struct gk20a *g, |
101 | struct gk20a_debug_output *o, | 120 | struct gk20a_debug_output *o, |
102 | struct channel_gk20a *ch) | 121 | struct channel_gk20a *ch) |
@@ -113,14 +132,14 @@ static void gk20a_debug_show_channel(struct gk20a *g, | |||
113 | syncpointa = gk20a_mem_rd32(inst_ptr, ram_fc_syncpointa_w()); | 132 | syncpointa = gk20a_mem_rd32(inst_ptr, ram_fc_syncpointa_w()); |
114 | syncpointb = gk20a_mem_rd32(inst_ptr, ram_fc_syncpointb_w()); | 133 | syncpointb = gk20a_mem_rd32(inst_ptr, ram_fc_syncpointb_w()); |
115 | 134 | ||
116 | gk20a_debug_output(o, "%d-%s, pid %d: ", ch->hw_chid, | 135 | gk20a_debug_output_cont(o, "%d-%s, pid %d: ", ch->hw_chid, |
117 | ch->g->dev->name, | 136 | ch->g->dev->name, |
118 | ch->pid); | 137 | ch->pid); |
119 | gk20a_debug_output(o, "%s in use %s %s\n", | 138 | gk20a_debug_output_cont(o, "%s in use %s %s\n", |
120 | ccsr_channel_enable_v(channel) ? "" : "not", | 139 | ccsr_channel_enable_v(channel) ? "" : "not", |
121 | ccsr_chan_status_str[status], | 140 | ccsr_chan_status_str[status], |
122 | ccsr_channel_busy_v(channel) ? "busy" : "not busy"); | 141 | ccsr_channel_busy_v(channel) ? "busy" : "not busy"); |
123 | gk20a_debug_output(o, "TOP: %016llx PUT: %016llx GET: %016llx " | 142 | gk20a_debug_output_cont(o, "TOP: %016llx PUT: %016llx GET: %016llx " |
124 | "FETCH: %016llx\nHEADER: %08x COUNT: %08x\n" | 143 | "FETCH: %016llx\nHEADER: %08x COUNT: %08x\n" |
125 | "SYNCPOINT %08x %08x SEMAPHORE %08x %08x %08x %08x\n", | 144 | "SYNCPOINT %08x %08x SEMAPHORE %08x %08x %08x %08x\n", |
126 | (u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_top_level_get_w()) + | 145 | (u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_top_level_get_w()) + |
@@ -144,14 +163,81 @@ static void gk20a_debug_show_channel(struct gk20a *g, | |||
144 | if ((pbdma_syncpointb_op_v(syncpointb) == pbdma_syncpointb_op_wait_v()) | 163 | if ((pbdma_syncpointb_op_v(syncpointb) == pbdma_syncpointb_op_wait_v()) |
145 | && (pbdma_syncpointb_wait_switch_v(syncpointb) == | 164 | && (pbdma_syncpointb_wait_switch_v(syncpointb) == |
146 | pbdma_syncpointb_wait_switch_en_v())) | 165 | pbdma_syncpointb_wait_switch_en_v())) |
147 | gk20a_debug_output(o, "%s on syncpt %u (%s) val %u\n", | 166 | gk20a_debug_output_cont(o, "%s on syncpt %u (%s) val %u\n", |
148 | (status == 3 || status == 8) ? "Waiting" : "Waited", | 167 | (status == 3 || status == 8) ? "Waiting" : "Waited", |
149 | pbdma_syncpointb_syncpt_index_v(syncpointb), | 168 | pbdma_syncpointb_syncpt_index_v(syncpointb), |
150 | nvhost_syncpt_get_name(g->host1x_dev, | 169 | nvhost_syncpt_get_name(g->host1x_dev, |
151 | pbdma_syncpointb_syncpt_index_v(syncpointb)), | 170 | pbdma_syncpointb_syncpt_index_v(syncpointb)), |
152 | pbdma_syncpointa_payload_v(syncpointa)); | 171 | pbdma_syncpointa_payload_v(syncpointa)); |
153 | 172 | ||
154 | gk20a_debug_output(o, "\n"); | 173 | gk20a_debug_output_cont(o, "\n"); |
174 | } | ||
175 | |||
176 | static void gk20a_dump_gpfifo(struct channel_gk20a *ch, | ||
177 | struct gpfifo *g, struct gk20a_debug_output *o) | ||
178 | { | ||
179 | struct dma_buf *pb = NULL; | ||
180 | u32 *pb_cpu_va = NULL; | ||
181 | u64 pb_offset = 0; | ||
182 | int i, err = 0; | ||
183 | |||
184 | u64 gpu_va = (u64)g->entry0 | ||
185 | | (u64)pbdma_gp_entry1_get_hi_v(g->entry1) << 32ULL; | ||
186 | u32 length = pbdma_gp_entry1_length_v(g->entry1); | ||
187 | |||
188 | if (gk20a_find_from_priv_cmdbuf(ch, gpu_va, &pb_cpu_va)) { | ||
189 | gk20a_debug_output_cont(o, "U: "); | ||
190 | err = gk20a_vm_find_buffer(ch->vm, gpu_va, &pb, &pb_offset); | ||
191 | } | ||
192 | if (err) { | ||
193 | gk20a_debug_output_cont(o, "Couldn't find push buffer\n"); | ||
194 | return; | ||
195 | } | ||
196 | |||
197 | if (pb) | ||
198 | pb_cpu_va = dma_buf_vmap(pb); | ||
199 | for (i = 0; i < length; i++) { | ||
200 | if (i && i % 8 == 0) | ||
201 | gk20a_debug_output_cont(o, "\n"); | ||
202 | gk20a_debug_output_cont(o, "%08x ", *(pb_cpu_va + (pb_offset/4) + i)); | ||
203 | } | ||
204 | |||
205 | if (pb) | ||
206 | dma_buf_vunmap(pb, pb_cpu_va); | ||
207 | |||
208 | gk20a_debug_output_cont(o, "\n"); | ||
209 | } | ||
210 | |||
211 | static void gk20a_dump_pb(struct gk20a *g, | ||
212 | u32 pbdma_id, struct gk20a_debug_output *o) | ||
213 | { | ||
214 | u32 gp_get = gk20a_readl(g, pbdma_gp_get_r(pbdma_id)); | ||
215 | u32 status = gk20a_readl(g, fifo_pbdma_status_r(pbdma_id)); | ||
216 | u32 chan_status = fifo_pbdma_status_chan_status_v(status); | ||
217 | u32 hw_chid = fifo_pbdma_status_id_v(status); | ||
218 | struct channel_gk20a *ch = g->fifo.channel+ hw_chid; | ||
219 | |||
220 | gk20a_debug_output_cont(o, "%s pbdma %d: ", g->dev->name, pbdma_id); | ||
221 | gk20a_debug_output_cont(o, | ||
222 | "id: %d (%s), next_id: %d (%s) status: %s\n", | ||
223 | fifo_pbdma_status_id_v(status), | ||
224 | fifo_pbdma_status_id_type_v(status) ? | ||
225 | "tsg" : "channel", | ||
226 | fifo_pbdma_status_next_id_v(status), | ||
227 | fifo_pbdma_status_next_id_type_v(status) ? | ||
228 | "tsg" : "channel", | ||
229 | chan_status_str[chan_status]); | ||
230 | gk20a_debug_output_cont(o, "PUT: %08x GET: %08x " | ||
231 | "FETCH: %08x HEADER: %08x\n", | ||
232 | gk20a_readl(g, pbdma_gp_put_r(pbdma_id)), | ||
233 | gk20a_readl(g, pbdma_gp_get_r(pbdma_id)), | ||
234 | gk20a_readl(g, pbdma_gp_fetch_r(pbdma_id)), | ||
235 | gk20a_readl(g, pbdma_pb_header_r(pbdma_id))); | ||
236 | |||
237 | if (ch->in_use) { | ||
238 | gk20a_dump_gpfifo(ch, &ch->gpfifo.cpu_va[(gp_get-2) % ch->gpfifo.entry_num], o); | ||
239 | gk20a_dump_gpfifo(ch, &ch->gpfifo.cpu_va[(gp_get-1) % ch->gpfifo.entry_num], o); | ||
240 | } | ||
155 | } | 241 | } |
156 | 242 | ||
157 | void gk20a_debug_show_dump(struct platform_device *pdev, | 243 | void gk20a_debug_show_dump(struct platform_device *pdev, |
@@ -164,12 +250,13 @@ void gk20a_debug_show_dump(struct platform_device *pdev, | |||
164 | int i; | 250 | int i; |
165 | 251 | ||
166 | gk20a_busy(g->dev); | 252 | gk20a_busy(g->dev); |
253 | gk20a_debug_output(o, ""); | ||
167 | for (i = 0; i < fifo_pbdma_status__size_1_v(); i++) { | 254 | for (i = 0; i < fifo_pbdma_status__size_1_v(); i++) { |
168 | u32 status = gk20a_readl(g, fifo_pbdma_status_r(i)); | 255 | u32 status = gk20a_readl(g, fifo_pbdma_status_r(i)); |
169 | u32 chan_status = fifo_pbdma_status_chan_status_v(status); | 256 | u32 chan_status = fifo_pbdma_status_chan_status_v(status); |
170 | 257 | ||
171 | gk20a_debug_output(o, "%s pbdma %d: ", g->dev->name, i); | 258 | gk20a_debug_output_cont(o, "%s pbdma %d: ", g->dev->name, i); |
172 | gk20a_debug_output(o, | 259 | gk20a_debug_output_cont(o, |
173 | "id: %d (%s), next_id: %d (%s) status: %s\n", | 260 | "id: %d (%s), next_id: %d (%s) status: %s\n", |
174 | fifo_pbdma_status_id_v(status), | 261 | fifo_pbdma_status_id_v(status), |
175 | fifo_pbdma_status_id_type_v(status) ? | 262 | fifo_pbdma_status_id_type_v(status) ? |
@@ -178,23 +265,23 @@ void gk20a_debug_show_dump(struct platform_device *pdev, | |||
178 | fifo_pbdma_status_next_id_type_v(status) ? | 265 | fifo_pbdma_status_next_id_type_v(status) ? |
179 | "tsg" : "channel", | 266 | "tsg" : "channel", |
180 | chan_status_str[chan_status]); | 267 | chan_status_str[chan_status]); |
181 | gk20a_debug_output(o, "PUT: %016llx GET: %016llx " | 268 | gk20a_debug_output_cont(o, "PUT: %08x GET: %08x " |
182 | "FETCH: %08x HEADER: %08x\n", | 269 | "FETCH: %08x HEADER: %08x\n", |
183 | (u64)gk20a_readl(g, pbdma_put_r(i)) + | 270 | gk20a_readl(g, pbdma_gp_put_r(i)), |
184 | ((u64)gk20a_readl(g, pbdma_put_hi_r(i)) << 32ULL), | 271 | gk20a_readl(g, pbdma_gp_get_r(i)), |
185 | (u64)gk20a_readl(g, pbdma_get_r(i)) + | ||
186 | ((u64)gk20a_readl(g, pbdma_get_hi_r(i)) << 32ULL), | ||
187 | gk20a_readl(g, pbdma_gp_fetch_r(i)), | 272 | gk20a_readl(g, pbdma_gp_fetch_r(i)), |
188 | gk20a_readl(g, pbdma_pb_header_r(i))); | 273 | gk20a_readl(g, pbdma_pb_header_r(i))); |
274 | |||
275 | gk20a_dump_pb(g, i, o); | ||
189 | } | 276 | } |
190 | gk20a_debug_output(o, "\n"); | 277 | gk20a_debug_output_cont(o, "\n"); |
191 | 278 | ||
192 | for (i = 0; i < fifo_engine_status__size_1_v(); i++) { | 279 | for (i = 0; i < fifo_engine_status__size_1_v(); i++) { |
193 | u32 status = gk20a_readl(g, fifo_engine_status_r(i)); | 280 | u32 status = gk20a_readl(g, fifo_engine_status_r(i)); |
194 | u32 ctx_status = fifo_engine_status_ctx_status_v(status); | 281 | u32 ctx_status = fifo_engine_status_ctx_status_v(status); |
195 | 282 | ||
196 | gk20a_debug_output(o, "%s eng %d: ", g->dev->name, i); | 283 | gk20a_debug_output_cont(o, "%s eng %d: ", g->dev->name, i); |
197 | gk20a_debug_output(o, | 284 | gk20a_debug_output_cont(o, |
198 | "id: %d (%s), next_id: %d (%s), ctx: %s ", | 285 | "id: %d (%s), next_id: %d (%s), ctx: %s ", |
199 | fifo_engine_status_id_v(status), | 286 | fifo_engine_status_id_v(status), |
200 | fifo_engine_status_id_type_v(status) ? | 287 | fifo_engine_status_id_type_v(status) ? |
@@ -205,12 +292,12 @@ void gk20a_debug_show_dump(struct platform_device *pdev, | |||
205 | ctx_status_str[ctx_status]); | 292 | ctx_status_str[ctx_status]); |
206 | 293 | ||
207 | if (fifo_engine_status_faulted_v(status)) | 294 | if (fifo_engine_status_faulted_v(status)) |
208 | gk20a_debug_output(o, "faulted "); | 295 | gk20a_debug_output_cont(o, "faulted "); |
209 | if (fifo_engine_status_engine_v(status)) | 296 | if (fifo_engine_status_engine_v(status)) |
210 | gk20a_debug_output(o, "busy "); | 297 | gk20a_debug_output_cont(o, "busy "); |
211 | gk20a_debug_output(o, "\n"); | 298 | gk20a_debug_output_cont(o, "\n"); |
212 | } | 299 | } |
213 | gk20a_debug_output(o, "\n"); | 300 | gk20a_debug_output_cont(o, "\n"); |
214 | 301 | ||
215 | for (chid = 0; chid < f->num_channels; chid++) { | 302 | for (chid = 0; chid < f->num_channels; chid++) { |
216 | if (f->channel[chid].in_use) { | 303 | if (f->channel[chid].in_use) { |
@@ -225,7 +312,8 @@ void gk20a_debug_dump(struct platform_device *pdev) | |||
225 | { | 312 | { |
226 | struct gk20a_platform *platform = gk20a_get_platform(pdev); | 313 | struct gk20a_platform *platform = gk20a_get_platform(pdev); |
227 | struct gk20a_debug_output o = { | 314 | struct gk20a_debug_output o = { |
228 | .fn = gk20a_debug_write_printk | 315 | .fn = gk20a_debug_write_printk, |
316 | .cont = gk20a_debug_cont_printk | ||
229 | }; | 317 | }; |
230 | 318 | ||
231 | if (platform->dump_platform_dependencies) | 319 | if (platform->dump_platform_dependencies) |
@@ -237,7 +325,8 @@ void gk20a_debug_dump(struct platform_device *pdev) | |||
237 | void gk20a_debug_dump_device(struct platform_device *pdev) | 325 | void gk20a_debug_dump_device(struct platform_device *pdev) |
238 | { | 326 | { |
239 | struct gk20a_debug_output o = { | 327 | struct gk20a_debug_output o = { |
240 | .fn = gk20a_debug_write_printk | 328 | .fn = gk20a_debug_write_printk, |
329 | .cont = gk20a_debug_cont_printk | ||
241 | }; | 330 | }; |
242 | 331 | ||
243 | /* Dump the first device if no info is provided */ | 332 | /* Dump the first device if no info is provided */ |
@@ -253,6 +342,7 @@ static int gk20a_debug_show(struct seq_file *s, void *unused) | |||
253 | struct platform_device *pdev = s->private; | 342 | struct platform_device *pdev = s->private; |
254 | struct gk20a_debug_output o = { | 343 | struct gk20a_debug_output o = { |
255 | .fn = gk20a_debug_write_to_seqfile, | 344 | .fn = gk20a_debug_write_to_seqfile, |
345 | .cont = gk20a_debug_write_to_seqfile, | ||
256 | .ctx = s, | 346 | .ctx = s, |
257 | }; | 347 | }; |
258 | gk20a_debug_show_dump(pdev, &o); | 348 | gk20a_debug_show_dump(pdev, &o); |
diff --git a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c index cba1f0fd..3c0611e6 100644 --- a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c | |||
@@ -1180,13 +1180,15 @@ void gk20a_fifo_recover_ch(struct gk20a *g, u32 hw_chid, bool verbose) | |||
1180 | struct channel_gk20a *ch = | 1180 | struct channel_gk20a *ch = |
1181 | g->fifo.channel + hw_chid; | 1181 | g->fifo.channel + hw_chid; |
1182 | 1182 | ||
1183 | if (verbose) | ||
1184 | gk20a_debug_dump(g->dev); | ||
1185 | |||
1183 | gk20a_channel_abort(ch); | 1186 | gk20a_channel_abort(ch); |
1184 | for (i = 0; i < g->fifo.max_runlists; i++) | 1187 | for (i = 0; i < g->fifo.max_runlists; i++) |
1185 | gk20a_fifo_update_runlist(g, i, | 1188 | gk20a_fifo_update_runlist(g, i, |
1186 | hw_chid, false, false); | 1189 | hw_chid, false, false); |
1187 | 1190 | ||
1188 | if (gk20a_fifo_set_ctx_mmu_error(g, ch)) | 1191 | gk20a_fifo_set_ctx_mmu_error(g, ch); |
1189 | gk20a_debug_dump(g->dev); | ||
1190 | } | 1192 | } |
1191 | } | 1193 | } |
1192 | 1194 | ||