blob: ad9007fcdfcec90abe1d234b28e4989475de53f0 [file] [log] [blame]
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -07001/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/firmware.h>
14#include <linux/slab.h>
15#include <linux/sched.h>
16#include <linux/log2.h>
17
18#include "kgsl.h"
19#include "kgsl_sharedmem.h"
20#include "kgsl_cffdump.h"
21
22#include "adreno.h"
23#include "adreno_pm4types.h"
24#include "adreno_ringbuffer.h"
25
Jeremy Gebbeneebc4612011-08-31 10:15:21 -070026#include "a2xx_reg.h"
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070027#include "a3xx_reg.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029#define GSL_RB_NOP_SIZEDWORDS 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070031void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032{
33 BUG_ON(rb->wptr == 0);
34
Lucille Sylvester958dc942011-09-06 18:19:49 -060035 /* Let the pwrscale policy know that new commands have
36 been submitted. */
37 kgsl_pwrscale_busy(rb->device);
38
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039 /*synchronize memory before informing the hardware of the
40 *new commands.
41 */
42 mb();
43
44 adreno_regwrite(rb->device, REG_CP_RB_WPTR, rb->wptr);
45}
46
Carter Cooper6dd94c82011-10-13 14:43:53 -060047static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, unsigned int numcmds,
49 int wptr_ahead)
50{
51 int nopcount;
52 unsigned int freecmds;
53 unsigned int *cmds;
54 uint cmds_gpu;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060055 unsigned long wait_time;
Jordan Crouse21f75a02012-08-09 15:08:59 -060056 unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
Tarun Karra3335f142012-06-19 14:11:48 -070057 unsigned long wait_time_part;
Tarun Karra3335f142012-06-19 14:11:48 -070058 unsigned int prev_reg_val[hang_detect_regs_count];
59
60 memset(prev_reg_val, 0, sizeof(prev_reg_val));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061
62 /* if wptr ahead, fill the remaining with NOPs */
63 if (wptr_ahead) {
64 /* -1 for header */
65 nopcount = rb->sizedwords - rb->wptr - 1;
66
67 cmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
68 cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*rb->wptr;
69
Jordan Crouse084427d2011-07-28 08:37:58 -060070 GSL_RB_WRITE(cmds, cmds_gpu, cp_nop_packet(nopcount));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071
72 /* Make sure that rptr is not 0 before submitting
73 * commands at the end of ringbuffer. We do not
74 * want the rptr and wptr to become equal when
75 * the ringbuffer is not empty */
76 do {
77 GSL_RB_GET_READPTR(rb, &rb->rptr);
78 } while (!rb->rptr);
79
80 rb->wptr++;
81
82 adreno_ringbuffer_submit(rb);
83
84 rb->wptr = 0;
85 }
86
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060087 wait_time = jiffies + wait_timeout;
Jordan Crouse21f75a02012-08-09 15:08:59 -060088 wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089 /* wait for space in ringbuffer */
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060090 while (1) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 GSL_RB_GET_READPTR(rb, &rb->rptr);
92
93 freecmds = rb->rptr - rb->wptr;
94
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060095 if (freecmds == 0 || freecmds > numcmds)
96 break;
97
Tarun Karra3335f142012-06-19 14:11:48 -070098 /* Dont wait for timeout, detect hang faster.
99 */
100 if (time_after(jiffies, wait_time_part)) {
101 wait_time_part = jiffies +
Jordan Crouse21f75a02012-08-09 15:08:59 -0600102 msecs_to_jiffies(KGSL_TIMEOUT_PART);
Tarun Karra3335f142012-06-19 14:11:48 -0700103 if ((adreno_hang_detect(rb->device,
104 prev_reg_val))){
105 KGSL_DRV_ERR(rb->device,
106 "Hang detected while waiting for freespace in"
107 "ringbuffer rptr: 0x%x, wptr: 0x%x\n",
108 rb->rptr, rb->wptr);
109 goto err;
110 }
111 }
112
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600113 if (time_after(jiffies, wait_time)) {
114 KGSL_DRV_ERR(rb->device,
115 "Timed out while waiting for freespace in ringbuffer "
116 "rptr: 0x%x, wptr: 0x%x\n", rb->rptr, rb->wptr);
Tarun Karra3335f142012-06-19 14:11:48 -0700117 goto err;
118 }
119
Wei Zou50ec3372012-07-17 15:46:52 -0700120 continue;
121
Tarun Karra3335f142012-06-19 14:11:48 -0700122err:
123 if (!adreno_dump_and_recover(rb->device))
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600124 wait_time = jiffies + wait_timeout;
125 else
126 /* GPU is hung and we cannot recover */
127 BUG();
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600128 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129}
130
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700131unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 unsigned int numcmds)
133{
134 unsigned int *ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135
136 BUG_ON(numcmds >= rb->sizedwords);
137
138 GSL_RB_GET_READPTR(rb, &rb->rptr);
139 /* check for available space */
140 if (rb->wptr >= rb->rptr) {
141 /* wptr ahead or equal to rptr */
142 /* reserve dwords for nop packet */
143 if ((rb->wptr + numcmds) > (rb->sizedwords -
144 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600145 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146 } else {
147 /* wptr behind rptr */
148 if ((rb->wptr + numcmds) >= rb->rptr)
Carter Cooper6dd94c82011-10-13 14:43:53 -0600149 adreno_ringbuffer_waitspace(rb, numcmds, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 /* check for remaining space */
151 /* reserve dwords for nop packet */
152 if ((rb->wptr + numcmds) > (rb->sizedwords -
153 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600154 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155 }
156
Carter Cooper6dd94c82011-10-13 14:43:53 -0600157 ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
158 rb->wptr += numcmds;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159
160 return ptr;
161}
162
163static int _load_firmware(struct kgsl_device *device, const char *fwfile,
164 void **data, int *len)
165{
166 const struct firmware *fw = NULL;
167 int ret;
168
169 ret = request_firmware(&fw, fwfile, device->dev);
170
171 if (ret) {
172 KGSL_DRV_ERR(device, "request_firmware(%s) failed: %d\n",
173 fwfile, ret);
174 return ret;
175 }
176
177 *data = kmalloc(fw->size, GFP_KERNEL);
178
179 if (*data) {
180 memcpy(*data, fw->data, fw->size);
181 *len = fw->size;
182 } else
183 KGSL_MEM_ERR(device, "kmalloc(%d) failed\n", fw->size);
184
185 release_firmware(fw);
186 return (*data != NULL) ? 0 : -ENOMEM;
187}
188
189static int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
190{
191 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192 int i, ret = 0;
193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194 if (adreno_dev->pm4_fw == NULL) {
195 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600196 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197
Jordan Crouse505df9c2011-07-28 08:37:59 -0600198 ret = _load_firmware(device, adreno_dev->pm4_fwfile,
199 &ptr, &len);
200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 if (ret)
202 goto err;
203
204 /* PM4 size is 3 dword aligned plus 1 dword of version */
205 if (len % ((sizeof(uint32_t) * 3)) != sizeof(uint32_t)) {
206 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
207 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600208 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209 goto err;
210 }
211
212 adreno_dev->pm4_fw_size = len / sizeof(uint32_t);
213 adreno_dev->pm4_fw = ptr;
214 }
215
216 KGSL_DRV_INFO(device, "loading pm4 ucode version: %d\n",
217 adreno_dev->pm4_fw[0]);
218
219 adreno_regwrite(device, REG_CP_DEBUG, 0x02000000);
220 adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
221 for (i = 1; i < adreno_dev->pm4_fw_size; i++)
222 adreno_regwrite(device, REG_CP_ME_RAM_DATA,
223 adreno_dev->pm4_fw[i]);
224err:
225 return ret;
226}
227
228static int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
229{
230 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 int i, ret = 0;
232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233 if (adreno_dev->pfp_fw == NULL) {
234 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600235 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236
Jordan Crouse505df9c2011-07-28 08:37:59 -0600237 ret = _load_firmware(device, adreno_dev->pfp_fwfile,
238 &ptr, &len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239 if (ret)
240 goto err;
241
242 /* PFP size shold be dword aligned */
243 if (len % sizeof(uint32_t) != 0) {
244 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
245 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600246 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 goto err;
248 }
249
250 adreno_dev->pfp_fw_size = len / sizeof(uint32_t);
251 adreno_dev->pfp_fw = ptr;
252 }
253
254 KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
255 adreno_dev->pfp_fw[0]);
256
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700257 adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 for (i = 1; i < adreno_dev->pfp_fw_size; i++)
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700259 adreno_regwrite(device,
260 adreno_dev->gpudev->reg_cp_pfp_ucode_data,
261 adreno_dev->pfp_fw[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262err:
263 return ret;
264}
265
266int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
267{
268 int status;
269 /*cp_rb_cntl_u cp_rb_cntl; */
270 union reg_cp_rb_cntl cp_rb_cntl;
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700271 unsigned int rb_cntl;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272 struct kgsl_device *device = rb->device;
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700273 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274
275 if (rb->flags & KGSL_FLAGS_STARTED)
276 return 0;
277
Carter Coopercb3e8eb2012-04-11 09:39:40 -0600278 if (init_ram)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700279 rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280
281 kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
282 sizeof(struct kgsl_rbmemptrs));
283
284 kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
285 (rb->sizedwords << 2));
286
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700287 if (adreno_is_a2xx(adreno_dev)) {
288 adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
289 (rb->memptrs_desc.gpuaddr
290 + GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700292 /* setup WPTR delay */
293 adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
294 0 /*0x70000010 */);
295 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296
297 /*setup REG_CP_RB_CNTL */
298 adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
299 cp_rb_cntl.val = rb_cntl;
300
301 /*
302 * The size of the ringbuffer in the hardware is the log2
303 * representation of the size in quadwords (sizedwords / 2)
304 */
305 cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);
306
307 /*
308 * Specify the quadwords to read before updating mem RPTR.
309 * Like above, pass the log2 representation of the blocksize
310 * in quadwords.
311 */
312 cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);
313
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700314 if (adreno_is_a2xx(adreno_dev)) {
315 /* WPTR polling */
316 cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
317 }
318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 /* mem RPTR writebacks */
320 cp_rb_cntl.f.rb_no_update = GSL_RB_CNTL_NO_UPDATE;
321
322 adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);
323
324 adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);
325
326 adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
327 rb->memptrs_desc.gpuaddr +
328 GSL_RB_MEMPTRS_RPTR_OFFSET);
329
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700330 if (adreno_is_a3xx(adreno_dev)) {
331 /* enable access protection to privileged registers */
332 adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);
333
334 /* RBBM registers */
335 adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
336 adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
337 adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
338 adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
339 adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
340 adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);
341
342 /* CP registers */
343 adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
344 adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
345 adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
346 adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
347 adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);
348
349 /* RB registers */
350 adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
351
352 /* VBIF registers */
353 adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
354 }
355
356 if (adreno_is_a2xx(adreno_dev)) {
357 /* explicitly clear all cp interrupts */
358 adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
359 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360
361 /* setup scratch/timestamp */
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700362 adreno_regwrite(device, REG_SCRATCH_ADDR, device->memstore.gpuaddr +
363 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
364 soptimestamp));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365
366 adreno_regwrite(device, REG_SCRATCH_UMSK,
367 GSL_RB_MEMPTRS_SCRATCH_MASK);
368
369 /* load the CP ucode */
370
371 status = adreno_ringbuffer_load_pm4_ucode(device);
372 if (status != 0)
373 return status;
374
375 /* load the prefetch parser ucode */
376 status = adreno_ringbuffer_load_pfp_ucode(device);
377 if (status != 0)
378 return status;
379
Kevin Matlageff806df2012-05-07 18:13:21 -0600380 /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
Kevin Matlagee8d35862012-04-26 12:58:15 -0600381 if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
Kevin Matlageff806df2012-05-07 18:13:21 -0600382 adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383
384 rb->rptr = 0;
385 rb->wptr = 0;
386
387 /* clear ME_HALT to start micro engine */
388 adreno_regwrite(device, REG_CP_ME_CNTL, 0);
389
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700390 /* ME init is GPU specific, so jump into the sub-function */
391 adreno_dev->gpudev->rb_init(adreno_dev, rb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392
393 /* idle device to validate ME INIT */
Jordan Crousea29a2e02012-08-14 09:09:23 -0600394 status = adreno_idle(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395
396 if (status == 0)
397 rb->flags |= KGSL_FLAGS_STARTED;
398
399 return status;
400}
401
Carter Cooper6dd94c82011-10-13 14:43:53 -0600402void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403{
Lucille Sylvester51feb4e2012-07-26 18:58:33 -0600404 if (rb->flags & KGSL_FLAGS_STARTED)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 rb->flags &= ~KGSL_FLAGS_STARTED;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406}
407
408int adreno_ringbuffer_init(struct kgsl_device *device)
409{
410 int status;
411 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
412 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
413
414 rb->device = device;
415 /*
416 * It is silly to convert this to words and then back to bytes
417 * immediately below, but most of the rest of the code deals
418 * in words, so we might as well only do the math once
419 */
420 rb->sizedwords = KGSL_RB_SIZE >> 2;
421
422 /* allocate memory for ringbuffer */
423 status = kgsl_allocate_contiguous(&rb->buffer_desc,
424 (rb->sizedwords << 2));
425
426 if (status != 0) {
427 adreno_ringbuffer_close(rb);
428 return status;
429 }
430
431 /* allocate memory for polling and timestamps */
432 /* This really can be at 4 byte alignment boundry but for using MMU
433 * we need to make it at page boundary */
434 status = kgsl_allocate_contiguous(&rb->memptrs_desc,
435 sizeof(struct kgsl_rbmemptrs));
436
437 if (status != 0) {
438 adreno_ringbuffer_close(rb);
439 return status;
440 }
441
442 /* overlay structure on memptrs memory */
443 rb->memptrs = (struct kgsl_rbmemptrs *) rb->memptrs_desc.hostptr;
444
445 return 0;
446}
447
Carter Cooper6dd94c82011-10-13 14:43:53 -0600448void adreno_ringbuffer_close(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449{
450 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
451
452 kgsl_sharedmem_free(&rb->buffer_desc);
453 kgsl_sharedmem_free(&rb->memptrs_desc);
454
455 kfree(adreno_dev->pfp_fw);
456 kfree(adreno_dev->pm4_fw);
457
458 adreno_dev->pfp_fw = NULL;
459 adreno_dev->pm4_fw = NULL;
460
461 memset(rb, 0, sizeof(struct adreno_ringbuffer));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462}
463
464static uint32_t
465adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700466 struct adreno_context *context,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467 unsigned int flags, unsigned int *cmds,
468 int sizedwords)
469{
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700470 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 unsigned int *ringcmds;
472 unsigned int timestamp;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700473 unsigned int total_sizedwords = sizedwords;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474 unsigned int i;
475 unsigned int rcmd_gpu;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700476 unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
477 unsigned int gpuaddr = rb->device->memstore.gpuaddr;
478
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600479 /*
480 * if the context was not created with per context timestamp
481 * support, we must use the global timestamp since issueibcmds
482 * will be returning that one.
483 */
484 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
485 context_id = context->id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486
487 /* reserve space to temporarily turn off protected mode
488 * error checking if needed
489 */
490 total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600491 /* 2 dwords to store the start of command sequence */
492 total_sizedwords += 2;
Carter Cooper7ffaba62012-05-24 13:59:53 -0600493 total_sizedwords += context ? 7 : 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700495 if (adreno_is_a3xx(adreno_dev))
496 total_sizedwords += 7;
497
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700498 total_sizedwords += 2; /* scratchpad ts for recovery */
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600499 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700500 total_sizedwords += 3; /* sop timestamp */
501 total_sizedwords += 4; /* eop timestamp */
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530502 total_sizedwords += 3; /* global timestamp without cache
503 * flush for non-zero context */
504 } else {
505 total_sizedwords += 4; /* global timestamp for recovery*/
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700506 }
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508 ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600509 /* GPU may hang during space allocation, if thats the case the current
510 * context may have hung the GPU */
511 if (context->flags & CTXT_FLAGS_GPU_HANG) {
512 KGSL_CTXT_WARN(rb->device,
513 "Context %p caused a gpu hang. Will not accept commands for context %d\n",
514 context, context->id);
515 return rb->timestamp[context_id];
516 }
517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518 rcmd_gpu = rb->buffer_desc.gpuaddr
519 + sizeof(uint)*(rb->wptr-total_sizedwords);
520
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600521 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
522 GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700524 if (flags & KGSL_CMD_FLAGS_PMODE) {
525 /* disable protected mode error checking */
526 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600527 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
529 }
530
531 for (i = 0; i < sizedwords; i++) {
532 GSL_RB_WRITE(ringcmds, rcmd_gpu, *cmds);
533 cmds++;
534 }
535
536 if (flags & KGSL_CMD_FLAGS_PMODE) {
537 /* re-enable protected mode error checking */
538 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600539 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700540 GSL_RB_WRITE(ringcmds, rcmd_gpu, 1);
541 }
542
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700543 /* always increment the global timestamp. once. */
544 rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
Carter Cooper7ffaba62012-05-24 13:59:53 -0600545
546 if (context && !(flags & KGSL_CMD_FLAGS_DUMMY_INTR_CMD)) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700547 if (context_id == KGSL_MEMSTORE_GLOBAL)
Carter Cooper7ffaba62012-05-24 13:59:53 -0600548 rb->timestamp[context->id] =
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700549 rb->timestamp[KGSL_MEMSTORE_GLOBAL];
550 else
551 rb->timestamp[context_id]++;
552 }
553 timestamp = rb->timestamp[context_id];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700554
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700555 /* scratchpad ts for recovery */
Jordan Crouse084427d2011-07-28 08:37:58 -0600556 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700557 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700558
559 if (adreno_is_a3xx(adreno_dev)) {
560 /*
561 * FLush HLSQ lazy updates to make sure there are no
562 * rsources pending for indirect loads after the timestamp
563 */
564
565 GSL_RB_WRITE(ringcmds, rcmd_gpu,
566 cp_type3_packet(CP_EVENT_WRITE, 1));
567 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x07); /* HLSQ_FLUSH */
568 GSL_RB_WRITE(ringcmds, rcmd_gpu,
569 cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
570 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
571 }
572
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600573 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700574 /* start-of-pipeline timestamp */
575 GSL_RB_WRITE(ringcmds, rcmd_gpu,
576 cp_type3_packet(CP_MEM_WRITE, 2));
577 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600578 KGSL_MEMSTORE_OFFSET(context_id, soptimestamp)));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700579 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
580
581 /* end-of-pipeline timestamp */
582 GSL_RB_WRITE(ringcmds, rcmd_gpu,
583 cp_type3_packet(CP_EVENT_WRITE, 3));
584 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
585 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600586 KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700587 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700588
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530589 GSL_RB_WRITE(ringcmds, rcmd_gpu,
590 cp_type3_packet(CP_MEM_WRITE, 2));
591 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600592 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
593 eoptimestamp)));
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530594 GSL_RB_WRITE(ringcmds, rcmd_gpu,
595 rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
596 } else {
597 GSL_RB_WRITE(ringcmds, rcmd_gpu,
598 cp_type3_packet(CP_EVENT_WRITE, 3));
599 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
600 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600601 KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
602 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[context_id]);
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530603 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604
Carter Cooper7ffaba62012-05-24 13:59:53 -0600605 if (context) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606 /* Conditional execution based on memory values */
607 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600608 cp_type3_packet(CP_COND_EXEC, 4));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700609 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
610 KGSL_MEMSTORE_OFFSET(
611 context_id, ts_cmp_enable)) >> 2);
612 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
613 KGSL_MEMSTORE_OFFSET(
614 context_id, ref_wait_ts)) >> 2);
615 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700616 /* # of conditional command DWORDs */
617 GSL_RB_WRITE(ringcmds, rcmd_gpu, 2);
618 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600619 cp_type3_packet(CP_INTERRUPT, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
621 }
622
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700623 if (adreno_is_a3xx(adreno_dev)) {
624 /* Dummy set-constant to trigger context rollover */
625 GSL_RB_WRITE(ringcmds, rcmd_gpu,
626 cp_type3_packet(CP_SET_CONSTANT, 2));
627 GSL_RB_WRITE(ringcmds, rcmd_gpu,
628 (0x4<<16)|(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG - 0x2000));
629 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
630 }
631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 adreno_ringbuffer_submit(rb);
633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634 return timestamp;
635}
636
Carter Cooper7ffaba62012-05-24 13:59:53 -0600637void
638adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
639 struct kgsl_context *k_ctxt,
640 unsigned int *cmds,
641 int sizedwords)
642{
643 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
644 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
645 struct adreno_context *a_ctxt = NULL;
646
647 if (!k_ctxt)
648 return;
649
650 a_ctxt = k_ctxt->devctxt;
651
652 if (k_ctxt->id == KGSL_CONTEXT_INVALID ||
653 a_ctxt == NULL ||
654 device->state & KGSL_STATE_HUNG)
655 return;
656
657 adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_DUMMY_INTR_CMD,
658 cmds, sizedwords);
659}
660
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600661unsigned int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662adreno_ringbuffer_issuecmds(struct kgsl_device *device,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600663 struct adreno_context *drawctxt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 unsigned int flags,
665 unsigned int *cmds,
666 int sizedwords)
667{
668 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
669 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
670
671 if (device->state & KGSL_STATE_HUNG)
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600672 return kgsl_readtimestamp(device, KGSL_MEMSTORE_GLOBAL,
673 KGSL_TIMESTAMP_RETIRED);
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600674 return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds, sizedwords);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675}
676
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -0600677static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
678 int sizedwords);
679
680static bool
681_handle_type3(struct kgsl_device_private *dev_priv, uint *hostaddr)
682{
683 unsigned int opcode = cp_type3_opcode(*hostaddr);
684 switch (opcode) {
685 case CP_INDIRECT_BUFFER_PFD:
686 case CP_INDIRECT_BUFFER_PFE:
687 case CP_COND_INDIRECT_BUFFER_PFE:
688 case CP_COND_INDIRECT_BUFFER_PFD:
689 return _parse_ibs(dev_priv, hostaddr[1], hostaddr[2]);
690 case CP_NOP:
691 case CP_WAIT_FOR_IDLE:
692 case CP_WAIT_REG_MEM:
693 case CP_WAIT_REG_EQ:
694 case CP_WAT_REG_GTE:
695 case CP_WAIT_UNTIL_READ:
696 case CP_WAIT_IB_PFD_COMPLETE:
697 case CP_REG_RMW:
698 case CP_REG_TO_MEM:
699 case CP_MEM_WRITE:
700 case CP_MEM_WRITE_CNTR:
701 case CP_COND_EXEC:
702 case CP_COND_WRITE:
703 case CP_EVENT_WRITE:
704 case CP_EVENT_WRITE_SHD:
705 case CP_EVENT_WRITE_CFL:
706 case CP_EVENT_WRITE_ZPD:
707 case CP_DRAW_INDX:
708 case CP_DRAW_INDX_2:
709 case CP_DRAW_INDX_BIN:
710 case CP_DRAW_INDX_2_BIN:
711 case CP_VIZ_QUERY:
712 case CP_SET_STATE:
713 case CP_SET_CONSTANT:
714 case CP_IM_LOAD:
715 case CP_IM_LOAD_IMMEDIATE:
716 case CP_LOAD_CONSTANT_CONTEXT:
717 case CP_INVALIDATE_STATE:
718 case CP_SET_SHADER_BASES:
719 case CP_SET_BIN_MASK:
720 case CP_SET_BIN_SELECT:
721 case CP_SET_BIN_BASE_OFFSET:
722 case CP_SET_BIN_DATA:
723 case CP_CONTEXT_UPDATE:
724 case CP_INTERRUPT:
725 case CP_IM_STORE:
726 case CP_LOAD_STATE:
727 break;
728 /* these shouldn't come from userspace */
729 case CP_ME_INIT:
730 case CP_SET_PROTECTED_MODE:
731 default:
732 KGSL_CMD_ERR(dev_priv->device, "bad CP opcode %0x\n", opcode);
733 return false;
734 break;
735 }
736
737 return true;
738}
739
740static bool
741_handle_type0(struct kgsl_device_private *dev_priv, uint *hostaddr)
742{
743 unsigned int reg = type0_pkt_offset(*hostaddr);
744 unsigned int cnt = type0_pkt_size(*hostaddr);
745 if (reg < 0x0192 || (reg + cnt) >= 0x8000) {
746 KGSL_CMD_ERR(dev_priv->device, "bad type0 reg: 0x%0x cnt: %d\n",
747 reg, cnt);
748 return false;
749 }
750 return true;
751}
752
753/*
754 * Traverse IBs and dump them to test vector. Detect swap by inspecting
755 * register writes, keeping note of the current state, and dump
756 * framebuffer config to test vector
757 */
758static bool _parse_ibs(struct kgsl_device_private *dev_priv,
759 uint gpuaddr, int sizedwords)
760{
761 static uint level; /* recursion level */
762 bool ret = false;
763 uint *hostaddr, *hoststart;
764 int dwords_left = sizedwords; /* dwords left in the current command
765 buffer */
766 struct kgsl_mem_entry *entry;
767
768 spin_lock(&dev_priv->process_priv->mem_lock);
769 entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
770 gpuaddr, sizedwords * sizeof(uint));
771 spin_unlock(&dev_priv->process_priv->mem_lock);
772 if (entry == NULL) {
773 KGSL_CMD_ERR(dev_priv->device,
774 "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
775 return false;
776 }
777
778 hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(&entry->memdesc, gpuaddr);
779 if (hostaddr == NULL) {
780 KGSL_CMD_ERR(dev_priv->device,
781 "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
782 return false;
783 }
784
785 hoststart = hostaddr;
786
787 level++;
788
789 KGSL_CMD_INFO(dev_priv->device, "ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
790 gpuaddr, sizedwords, hostaddr);
791
792 mb();
793 while (dwords_left > 0) {
794 bool cur_ret = true;
795 int count = 0; /* dword count including packet header */
796
797 switch (*hostaddr >> 30) {
798 case 0x0: /* type-0 */
799 count = (*hostaddr >> 16)+2;
800 cur_ret = _handle_type0(dev_priv, hostaddr);
801 break;
802 case 0x1: /* type-1 */
803 count = 2;
804 break;
805 case 0x3: /* type-3 */
806 count = ((*hostaddr >> 16) & 0x3fff) + 2;
807 cur_ret = _handle_type3(dev_priv, hostaddr);
808 break;
809 default:
810 KGSL_CMD_ERR(dev_priv->device, "unexpected type: "
811 "type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
812 *hostaddr >> 30, *hostaddr, hostaddr,
813 gpuaddr+4*(sizedwords-dwords_left));
814 cur_ret = false;
815 count = dwords_left;
816 break;
817 }
818
819 if (!cur_ret) {
820 KGSL_CMD_ERR(dev_priv->device,
821 "bad sub-type: #:%d/%d, v:0x%08x"
822 " @ 0x%p[gb:0x%08x], level:%d\n",
823 sizedwords-dwords_left, sizedwords, *hostaddr,
824 hostaddr, gpuaddr+4*(sizedwords-dwords_left),
825 level);
826
827 if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
828 >= 2)
829 print_hex_dump(KERN_ERR,
830 level == 1 ? "IB1:" : "IB2:",
831 DUMP_PREFIX_OFFSET, 32, 4, hoststart,
832 sizedwords*4, 0);
833 goto done;
834 }
835
836 /* jump to next packet */
837 dwords_left -= count;
838 hostaddr += count;
839 if (dwords_left < 0) {
840 KGSL_CMD_ERR(dev_priv->device,
841 "bad count: c:%d, #:%d/%d, "
842 "v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
843 count, sizedwords-(dwords_left+count),
844 sizedwords, *(hostaddr-count), hostaddr-count,
845 gpuaddr+4*(sizedwords-(dwords_left+count)),
846 level);
847 if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
848 >= 2)
849 print_hex_dump(KERN_ERR,
850 level == 1 ? "IB1:" : "IB2:",
851 DUMP_PREFIX_OFFSET, 32, 4, hoststart,
852 sizedwords*4, 0);
853 goto done;
854 }
855 }
856
857 ret = true;
858done:
859 if (!ret)
860 KGSL_DRV_ERR(dev_priv->device,
861 "parsing failed: gpuaddr:0x%08x, "
862 "host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
863
864 level--;
865
866 return ret;
867}
868
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869int
870adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
871 struct kgsl_context *context,
872 struct kgsl_ibdesc *ibdesc,
873 unsigned int numibs,
874 uint32_t *timestamp,
875 unsigned int flags)
876{
877 struct kgsl_device *device = dev_priv->device;
878 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
879 unsigned int *link;
880 unsigned int *cmds;
881 unsigned int i;
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600882 struct adreno_context *drawctxt;
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700883 unsigned int start_index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884
885 if (device->state & KGSL_STATE_HUNG)
886 return -EBUSY;
887 if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) ||
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600888 context == NULL || ibdesc == 0 || numibs == 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889 return -EINVAL;
890
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600891 drawctxt = context->devctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892
893 if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
894 KGSL_CTXT_WARN(device, "Context %p caused a gpu hang.."
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700895 " will not accept commands for context %d\n",
896 drawctxt, drawctxt->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897 return -EDEADLK;
898 }
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600899
900 cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
901 GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902 if (!link) {
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600903 KGSL_CORE_ERR("kzalloc(%d) failed\n",
904 sizeof(unsigned int) * (numibs * 3 + 4));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905 return -ENOMEM;
906 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700907
908 /*When preamble is enabled, the preamble buffer with state restoration
909 commands are stored in the first node of the IB chain. We can skip that
910 if a context switch hasn't occured */
911
912 if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
913 adreno_dev->drawctxt_active == drawctxt)
914 start_index = 1;
915
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600916 if (!start_index) {
917 *cmds++ = cp_nop_packet(1);
918 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
919 } else {
920 *cmds++ = cp_nop_packet(4);
921 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
922 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
923 *cmds++ = ibdesc[0].gpuaddr;
924 *cmds++ = ibdesc[0].sizedwords;
925 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700926 for (i = start_index; i < numibs; i++) {
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -0600927 if (unlikely(adreno_dev->ib_check_level >= 1 &&
928 !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
929 ibdesc[i].sizedwords))) {
930 kfree(link);
931 return -EINVAL;
932 }
Jordan Crouse084427d2011-07-28 08:37:58 -0600933 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700934 *cmds++ = ibdesc[i].gpuaddr;
935 *cmds++ = ibdesc[i].sizedwords;
936 }
937
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600938 *cmds++ = cp_nop_packet(1);
939 *cmds++ = KGSL_END_OF_IB_IDENTIFIER;
940
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600941 kgsl_setstate(&device->mmu, context->id,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600942 kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 device->id));
944
945 adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
946
947 *timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600948 drawctxt, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700949 &link[0], (cmds - link));
950
951 KGSL_CMD_INFO(device, "ctxt %d g %08x numibs %d ts %d\n",
952 context->id, (unsigned int)ibdesc, numibs, *timestamp);
953
954 kfree(link);
955
956#ifdef CONFIG_MSM_KGSL_CFF_DUMP
957 /*
958 * insert wait for idle after every IB1
959 * this is conservative but works reliably and is ok
960 * even for performance simulations
961 */
Jordan Crousea29a2e02012-08-14 09:09:23 -0600962 adreno_idle(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963#endif
Shubhraprakash Das32240ef2012-06-06 20:27:46 -0600964 /* If context hung and recovered then return error so that the
965 * application may handle it */
966 if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_RECOVERED)
967 return -EDEADLK;
968 else
969 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971}
972
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -0600973static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
974 unsigned int *ptr,
975 bool inc)
976{
977 int status = -EINVAL;
978 unsigned int val1;
979 unsigned int size = rb->buffer_desc.size;
980 unsigned int start_ptr = *ptr;
981
982 while ((start_ptr / sizeof(unsigned int)) != rb->wptr) {
983 if (inc)
984 start_ptr = adreno_ringbuffer_inc_wrapped(start_ptr,
985 size);
986 else
987 start_ptr = adreno_ringbuffer_dec_wrapped(start_ptr,
988 size);
989 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, start_ptr);
990 if (KGSL_CMD_IDENTIFIER == val1) {
991 if ((start_ptr / sizeof(unsigned int)) != rb->wptr)
992 start_ptr = adreno_ringbuffer_dec_wrapped(
993 start_ptr, size);
994 *ptr = start_ptr;
995 status = 0;
996 break;
997 }
998 }
999 return status;
1000}
1001
1002static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb,
1003 unsigned int *rb_rptr,
1004 unsigned int global_eop,
1005 bool inc)
1006{
1007 int status = -EINVAL;
1008 unsigned int temp_rb_rptr = *rb_rptr;
1009 unsigned int size = rb->buffer_desc.size;
1010 unsigned int val[3];
1011 int i = 0;
1012 bool check = false;
1013
1014 if (inc && temp_rb_rptr / sizeof(unsigned int) != rb->wptr)
1015 return status;
1016
1017 do {
1018 /* when decrementing we need to decrement first and
1019 * then read make sure we cover all the data */
1020 if (!inc)
1021 temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
1022 temp_rb_rptr, size);
1023 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i],
1024 temp_rb_rptr);
1025
1026 if (check && ((inc && val[i] == global_eop) ||
1027 (!inc && (val[i] ==
1028 cp_type3_packet(CP_MEM_WRITE, 2) ||
1029 val[i] == CACHE_FLUSH_TS)))) {
1030 /* decrement i, i.e i = (i - 1 + 3) % 3 if
1031 * we are going forward, else increment i */
1032 i = (i + 2) % 3;
1033 if (val[i] == rb->device->memstore.gpuaddr +
1034 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
1035 eoptimestamp)) {
1036 int j = ((i + 2) % 3);
1037 if ((inc && (val[j] == CACHE_FLUSH_TS ||
1038 val[j] == cp_type3_packet(
1039 CP_MEM_WRITE, 2))) ||
1040 (!inc && val[j] == global_eop)) {
1041 /* Found the global eop */
1042 status = 0;
1043 break;
1044 }
1045 }
1046 /* if no match found then increment i again
1047 * since we decremented before matching */
1048 i = (i + 1) % 3;
1049 }
1050 if (inc)
1051 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(
1052 temp_rb_rptr, size);
1053
1054 i = (i + 1) % 3;
1055 if (2 == i)
1056 check = true;
1057 } while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr);
Shubhraprakash Das6f6ecb32012-06-13 12:17:11 -06001058 /* temp_rb_rptr points to the command stream after global eop,
1059 * move backward till the start of command sequence */
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001060 if (!status) {
Shubhraprakash Das6f6ecb32012-06-13 12:17:11 -06001061 status = _find_start_of_cmd_seq(rb, &temp_rb_rptr, false);
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001062 if (!status) {
1063 *rb_rptr = temp_rb_rptr;
1064 KGSL_DRV_ERR(rb->device,
1065 "Offset of cmd sequence after eop timestamp: 0x%x\n",
1066 temp_rb_rptr / sizeof(unsigned int));
1067 }
1068 }
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001069 if (status)
1070 KGSL_DRV_ERR(rb->device,
1071 "Failed to find the command sequence after eop timestamp\n");
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001072 return status;
1073}
1074
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001075static int _find_hanging_ib_sequence(struct adreno_ringbuffer *rb,
1076 unsigned int *rb_rptr,
1077 unsigned int ib1)
1078{
1079 int status = -EINVAL;
1080 unsigned int temp_rb_rptr = *rb_rptr;
1081 unsigned int size = rb->buffer_desc.size;
1082 unsigned int val[2];
1083 int i = 0;
1084 bool check = false;
1085 bool ctx_switch = false;
1086
1087 while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
1088 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
1089
1090 if (check && val[i] == ib1) {
1091 /* decrement i, i.e i = (i - 1 + 2) % 2 */
1092 i = (i + 1) % 2;
1093 if (adreno_cmd_is_ib(val[i])) {
1094 /* go till start of command sequence */
1095 status = _find_start_of_cmd_seq(rb,
1096 &temp_rb_rptr, false);
1097 KGSL_DRV_ERR(rb->device,
1098 "Found the hanging IB at offset 0x%x\n",
1099 temp_rb_rptr / sizeof(unsigned int));
1100 break;
1101 }
1102 /* if no match the increment i since we decremented
1103 * before checking */
1104 i = (i + 1) % 2;
1105 }
1106 /* Make sure you do not encounter a context switch twice, we can
1107 * encounter it once for the bad context as the start of search
1108 * can point to the context switch */
1109 if (val[i] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
1110 if (ctx_switch) {
1111 KGSL_DRV_ERR(rb->device,
1112 "Context switch encountered before bad "
1113 "IB found\n");
1114 break;
1115 }
1116 ctx_switch = true;
1117 }
1118 i = (i + 1) % 2;
1119 if (1 == i)
1120 check = true;
1121 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
1122 size);
1123 }
1124 if (!status)
1125 *rb_rptr = temp_rb_rptr;
1126 return status;
1127}
1128
1129static void _turn_preamble_on_for_ib_seq(struct adreno_ringbuffer *rb,
1130 unsigned int rb_rptr)
1131{
1132 unsigned int temp_rb_rptr = rb_rptr;
1133 unsigned int size = rb->buffer_desc.size;
1134 unsigned int val[2];
1135 int i = 0;
1136 bool check = false;
1137 bool cmd_start = false;
1138
1139 /* Go till the start of the ib sequence and turn on preamble */
1140 while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
1141 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
1142 if (check && KGSL_START_OF_IB_IDENTIFIER == val[i]) {
1143 /* decrement i */
1144 i = (i + 1) % 2;
1145 if (val[i] == cp_nop_packet(4)) {
1146 temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
1147 temp_rb_rptr, size);
1148 kgsl_sharedmem_writel(&rb->buffer_desc,
1149 temp_rb_rptr, cp_nop_packet(1));
1150 }
1151 KGSL_DRV_ERR(rb->device,
1152 "Turned preamble on at offset 0x%x\n",
1153 temp_rb_rptr / 4);
1154 break;
1155 }
1156 /* If you reach beginning of next command sequence then exit
1157 * First command encountered is the current one so don't break
1158 * on that. */
1159 if (KGSL_CMD_IDENTIFIER == val[i]) {
1160 if (cmd_start)
1161 break;
1162 cmd_start = true;
1163 }
1164
1165 i = (i + 1) % 2;
1166 if (1 == i)
1167 check = true;
1168 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
1169 size);
1170 }
1171}
1172
Shubhraprakash Das1d577fe2012-05-31 18:28:22 -06001173static void _copy_valid_rb_content(struct adreno_ringbuffer *rb,
1174 unsigned int rb_rptr, unsigned int *temp_rb_buffer,
1175 int *rb_size, unsigned int *bad_rb_buffer,
1176 int *bad_rb_size,
1177 int *last_valid_ctx_id)
1178{
1179 unsigned int good_rb_idx = 0, cmd_start_idx = 0;
1180 unsigned int val1 = 0;
1181 struct kgsl_context *k_ctxt;
1182 struct adreno_context *a_ctxt;
1183 unsigned int bad_rb_idx = 0;
1184 int copy_rb_contents = 0;
1185 unsigned int temp_rb_rptr;
1186 unsigned int size = rb->buffer_desc.size;
1187 unsigned int good_cmd_start_idx = 0;
1188
1189 /* Walk the rb from the context switch. Omit any commands
1190 * for an invalid context. */
1191 while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
1192 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
1193
1194 if (KGSL_CMD_IDENTIFIER == val1) {
1195 /* Start is the NOP dword that comes before
1196 * KGSL_CMD_IDENTIFIER */
1197 cmd_start_idx = bad_rb_idx - 1;
1198 if (copy_rb_contents)
1199 good_cmd_start_idx = good_rb_idx - 1;
1200 }
1201
1202 /* check for context switch indicator */
1203 if (val1 == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
1204 unsigned int temp_idx, val2;
1205 /* increment by 3 to get to the context_id */
1206 temp_rb_rptr = rb_rptr + (3 * sizeof(unsigned int)) %
1207 size;
1208 kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
1209 temp_rb_rptr);
1210
1211 /* if context switches to a context that did not cause
1212 * hang then start saving the rb contents as those
1213 * commands can be executed */
1214 k_ctxt = idr_find(&rb->device->context_idr, val2);
1215 if (k_ctxt) {
1216 a_ctxt = k_ctxt->devctxt;
1217
1218 /* If we are changing to a good context and were not
1219 * copying commands then copy over commands to the good
1220 * context */
1221 if (!copy_rb_contents && ((k_ctxt &&
1222 !(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
1223 !k_ctxt)) {
1224 for (temp_idx = cmd_start_idx;
1225 temp_idx < bad_rb_idx;
1226 temp_idx++)
1227 temp_rb_buffer[good_rb_idx++] =
1228 bad_rb_buffer[temp_idx];
1229 *last_valid_ctx_id = val2;
1230 copy_rb_contents = 1;
1231 } else if (copy_rb_contents && k_ctxt &&
1232 (a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
1233 /* If we are changing to bad context then remove
1234 * the dwords we copied for this sequence from
1235 * the good buffer */
1236 good_rb_idx = good_cmd_start_idx;
1237 copy_rb_contents = 0;
1238 }
1239 }
1240 }
1241
1242 if (copy_rb_contents)
1243 temp_rb_buffer[good_rb_idx++] = val1;
1244 /* Copy both good and bad commands for replay to the bad
1245 * buffer */
1246 bad_rb_buffer[bad_rb_idx++] = val1;
1247
1248 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
1249 }
1250 *rb_size = good_rb_idx;
1251 *bad_rb_size = bad_rb_idx;
1252}
1253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
Shubhraprakash Dasba6c70b2012-05-31 02:53:06 -06001255 struct adreno_recovery_data *rec_data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256{
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001257 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 struct kgsl_device *device = rb->device;
Shubhraprakash Dasadb16022012-05-31 16:19:37 -06001259 unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001260 struct kgsl_context *context;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001261 struct adreno_context *adreno_context;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262
Shubhraprakash Dasadb16022012-05-31 16:19:37 -06001263 context = idr_find(&device->context_idr, rec_data->context_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264
Shubhraprakash Das6f6ecb32012-06-13 12:17:11 -06001265 /* Look for the command stream that is right after the global eop */
1266 status = _find_cmd_seq_after_eop_ts(rb, &rb_rptr,
1267 rec_data->global_eop + 1, false);
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001268 if (status)
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001269 goto done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001271 if (context) {
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001272 adreno_context = context->devctxt;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001273
1274 if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
1275 if (rec_data->ib1) {
1276 status = _find_hanging_ib_sequence(rb, &rb_rptr,
1277 rec_data->ib1);
1278 if (status)
1279 goto copy_rb_contents;
1280 }
1281 _turn_preamble_on_for_ib_seq(rb, rb_rptr);
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001282 } else {
1283 status = -EINVAL;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001284 }
1285 }
1286
1287copy_rb_contents:
Shubhraprakash Das1d577fe2012-05-31 18:28:22 -06001288 _copy_valid_rb_content(rb, rb_rptr, rec_data->rb_buffer,
1289 &rec_data->rb_size,
1290 rec_data->bad_rb_buffer,
1291 &rec_data->bad_rb_size,
1292 &rec_data->last_valid_ctx_id);
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001293 /* If we failed to get the hanging IB sequence then we cannot execute
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001294 * commands from the bad context or preambles not supported */
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001295 if (status) {
1296 rec_data->bad_rb_size = 0;
1297 status = 0;
1298 }
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001299 /* If there is no context then that means there are no commands for
1300 * good case */
1301 if (!context)
1302 rec_data->rb_size = 0;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001303done:
1304 return status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305}
1306
1307void
1308adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
1309 int num_rb_contents)
1310{
1311 int i;
1312 unsigned int *ringcmds;
1313 unsigned int rcmd_gpu;
1314
1315 if (!num_rb_contents)
1316 return;
1317
1318 if (num_rb_contents > (rb->buffer_desc.size - rb->wptr)) {
1319 adreno_regwrite(rb->device, REG_CP_RB_RPTR, 0);
1320 rb->rptr = 0;
1321 BUG_ON(num_rb_contents > rb->buffer_desc.size);
1322 }
1323 ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
1324 rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
1325 for (i = 0; i < num_rb_contents; i++)
1326 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb_buff[i]);
1327 rb->wptr += num_rb_contents;
1328 adreno_ringbuffer_submit(rb);
1329}