blob: 9eca36737c5ddbadc82548a891a79d86e5a40540 [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"
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -060025#include "adreno_debugfs.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026
Jeremy Gebbeneebc4612011-08-31 10:15:21 -070027#include "a2xx_reg.h"
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070028#include "a3xx_reg.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030#define GSL_RB_NOP_SIZEDWORDS 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070032void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033{
34 BUG_ON(rb->wptr == 0);
35
Lucille Sylvester958dc942011-09-06 18:19:49 -060036 /* Let the pwrscale policy know that new commands have
37 been submitted. */
38 kgsl_pwrscale_busy(rb->device);
39
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040 /*synchronize memory before informing the hardware of the
41 *new commands.
42 */
43 mb();
44
45 adreno_regwrite(rb->device, REG_CP_RB_WPTR, rb->wptr);
46}
47
Carter Cooper6dd94c82011-10-13 14:43:53 -060048static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, unsigned int numcmds,
50 int wptr_ahead)
51{
52 int nopcount;
53 unsigned int freecmds;
54 unsigned int *cmds;
55 uint cmds_gpu;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060056 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
57 unsigned long wait_timeout = msecs_to_jiffies(adreno_dev->wait_timeout);
58 unsigned long wait_time;
Tarun Karra3335f142012-06-19 14:11:48 -070059 unsigned long wait_time_part;
60 unsigned int msecs_part = KGSL_TIMEOUT_PART;
61 unsigned int prev_reg_val[hang_detect_regs_count];
62
63 memset(prev_reg_val, 0, sizeof(prev_reg_val));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064
65 /* if wptr ahead, fill the remaining with NOPs */
66 if (wptr_ahead) {
67 /* -1 for header */
68 nopcount = rb->sizedwords - rb->wptr - 1;
69
70 cmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
71 cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*rb->wptr;
72
Jordan Crouse084427d2011-07-28 08:37:58 -060073 GSL_RB_WRITE(cmds, cmds_gpu, cp_nop_packet(nopcount));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074
75 /* Make sure that rptr is not 0 before submitting
76 * commands at the end of ringbuffer. We do not
77 * want the rptr and wptr to become equal when
78 * the ringbuffer is not empty */
79 do {
80 GSL_RB_GET_READPTR(rb, &rb->rptr);
81 } while (!rb->rptr);
82
83 rb->wptr++;
84
85 adreno_ringbuffer_submit(rb);
86
87 rb->wptr = 0;
88 }
89
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060090 wait_time = jiffies + wait_timeout;
Tarun Karra3335f142012-06-19 14:11:48 -070091 wait_time_part = jiffies + msecs_to_jiffies(msecs_part);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092 /* wait for space in ringbuffer */
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060093 while (1) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 GSL_RB_GET_READPTR(rb, &rb->rptr);
95
96 freecmds = rb->rptr - rb->wptr;
97
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060098 if (freecmds == 0 || freecmds > numcmds)
99 break;
100
Tarun Karra3335f142012-06-19 14:11:48 -0700101 /* Dont wait for timeout, detect hang faster.
102 */
103 if (time_after(jiffies, wait_time_part)) {
104 wait_time_part = jiffies +
105 msecs_to_jiffies(msecs_part);
106 if ((adreno_hang_detect(rb->device,
107 prev_reg_val))){
108 KGSL_DRV_ERR(rb->device,
109 "Hang detected while waiting for freespace in"
110 "ringbuffer rptr: 0x%x, wptr: 0x%x\n",
111 rb->rptr, rb->wptr);
112 goto err;
113 }
114 }
115
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600116 if (time_after(jiffies, wait_time)) {
117 KGSL_DRV_ERR(rb->device,
118 "Timed out while waiting for freespace in ringbuffer "
119 "rptr: 0x%x, wptr: 0x%x\n", rb->rptr, rb->wptr);
Tarun Karra3335f142012-06-19 14:11:48 -0700120 goto err;
121 }
122
123err:
124 if (!adreno_dump_and_recover(rb->device))
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600125 wait_time = jiffies + wait_timeout;
126 else
127 /* GPU is hung and we cannot recover */
128 BUG();
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600129 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130}
131
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700132unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 unsigned int numcmds)
134{
135 unsigned int *ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136
137 BUG_ON(numcmds >= rb->sizedwords);
138
139 GSL_RB_GET_READPTR(rb, &rb->rptr);
140 /* check for available space */
141 if (rb->wptr >= rb->rptr) {
142 /* wptr ahead or equal to rptr */
143 /* reserve dwords for nop packet */
144 if ((rb->wptr + numcmds) > (rb->sizedwords -
145 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600146 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 } else {
148 /* wptr behind rptr */
149 if ((rb->wptr + numcmds) >= rb->rptr)
Carter Cooper6dd94c82011-10-13 14:43:53 -0600150 adreno_ringbuffer_waitspace(rb, numcmds, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151 /* check for remaining space */
152 /* reserve dwords for nop packet */
153 if ((rb->wptr + numcmds) > (rb->sizedwords -
154 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600155 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156 }
157
Carter Cooper6dd94c82011-10-13 14:43:53 -0600158 ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
159 rb->wptr += numcmds;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160
161 return ptr;
162}
163
164static int _load_firmware(struct kgsl_device *device, const char *fwfile,
165 void **data, int *len)
166{
167 const struct firmware *fw = NULL;
168 int ret;
169
170 ret = request_firmware(&fw, fwfile, device->dev);
171
172 if (ret) {
173 KGSL_DRV_ERR(device, "request_firmware(%s) failed: %d\n",
174 fwfile, ret);
175 return ret;
176 }
177
178 *data = kmalloc(fw->size, GFP_KERNEL);
179
180 if (*data) {
181 memcpy(*data, fw->data, fw->size);
182 *len = fw->size;
183 } else
184 KGSL_MEM_ERR(device, "kmalloc(%d) failed\n", fw->size);
185
186 release_firmware(fw);
187 return (*data != NULL) ? 0 : -ENOMEM;
188}
189
190static int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
191{
192 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193 int i, ret = 0;
194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195 if (adreno_dev->pm4_fw == NULL) {
196 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600197 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198
Jordan Crouse505df9c2011-07-28 08:37:59 -0600199 ret = _load_firmware(device, adreno_dev->pm4_fwfile,
200 &ptr, &len);
201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202 if (ret)
203 goto err;
204
205 /* PM4 size is 3 dword aligned plus 1 dword of version */
206 if (len % ((sizeof(uint32_t) * 3)) != sizeof(uint32_t)) {
207 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
208 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600209 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210 goto err;
211 }
212
213 adreno_dev->pm4_fw_size = len / sizeof(uint32_t);
214 adreno_dev->pm4_fw = ptr;
215 }
216
217 KGSL_DRV_INFO(device, "loading pm4 ucode version: %d\n",
218 adreno_dev->pm4_fw[0]);
219
220 adreno_regwrite(device, REG_CP_DEBUG, 0x02000000);
221 adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
222 for (i = 1; i < adreno_dev->pm4_fw_size; i++)
223 adreno_regwrite(device, REG_CP_ME_RAM_DATA,
224 adreno_dev->pm4_fw[i]);
225err:
226 return ret;
227}
228
229static int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
230{
231 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232 int i, ret = 0;
233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 if (adreno_dev->pfp_fw == NULL) {
235 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600236 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237
Jordan Crouse505df9c2011-07-28 08:37:59 -0600238 ret = _load_firmware(device, adreno_dev->pfp_fwfile,
239 &ptr, &len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 if (ret)
241 goto err;
242
243 /* PFP size shold be dword aligned */
244 if (len % sizeof(uint32_t) != 0) {
245 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
246 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600247 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 goto err;
249 }
250
251 adreno_dev->pfp_fw_size = len / sizeof(uint32_t);
252 adreno_dev->pfp_fw = ptr;
253 }
254
255 KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
256 adreno_dev->pfp_fw[0]);
257
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700258 adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 for (i = 1; i < adreno_dev->pfp_fw_size; i++)
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700260 adreno_regwrite(device,
261 adreno_dev->gpudev->reg_cp_pfp_ucode_data,
262 adreno_dev->pfp_fw[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263err:
264 return ret;
265}
266
267int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
268{
269 int status;
270 /*cp_rb_cntl_u cp_rb_cntl; */
271 union reg_cp_rb_cntl cp_rb_cntl;
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700272 unsigned int rb_cntl;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273 struct kgsl_device *device = rb->device;
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700274 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275
276 if (rb->flags & KGSL_FLAGS_STARTED)
277 return 0;
278
Carter Coopercb3e8eb2012-04-11 09:39:40 -0600279 if (init_ram)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700280 rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281
282 kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
283 sizeof(struct kgsl_rbmemptrs));
284
285 kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
286 (rb->sizedwords << 2));
287
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700288 if (adreno_is_a2xx(adreno_dev)) {
289 adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
290 (rb->memptrs_desc.gpuaddr
291 + GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700293 /* setup WPTR delay */
294 adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
295 0 /*0x70000010 */);
296 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297
298 /*setup REG_CP_RB_CNTL */
299 adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
300 cp_rb_cntl.val = rb_cntl;
301
302 /*
303 * The size of the ringbuffer in the hardware is the log2
304 * representation of the size in quadwords (sizedwords / 2)
305 */
306 cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);
307
308 /*
309 * Specify the quadwords to read before updating mem RPTR.
310 * Like above, pass the log2 representation of the blocksize
311 * in quadwords.
312 */
313 cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);
314
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700315 if (adreno_is_a2xx(adreno_dev)) {
316 /* WPTR polling */
317 cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
318 }
319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320 /* mem RPTR writebacks */
321 cp_rb_cntl.f.rb_no_update = GSL_RB_CNTL_NO_UPDATE;
322
323 adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);
324
325 adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);
326
327 adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
328 rb->memptrs_desc.gpuaddr +
329 GSL_RB_MEMPTRS_RPTR_OFFSET);
330
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700331 if (adreno_is_a3xx(adreno_dev)) {
332 /* enable access protection to privileged registers */
333 adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);
334
335 /* RBBM registers */
336 adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
337 adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
338 adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
339 adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
340 adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
341 adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);
342
343 /* CP registers */
344 adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
345 adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
346 adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
347 adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
348 adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);
349
350 /* RB registers */
351 adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
352
353 /* VBIF registers */
354 adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
355 }
356
357 if (adreno_is_a2xx(adreno_dev)) {
358 /* explicitly clear all cp interrupts */
359 adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
360 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700361
362 /* setup scratch/timestamp */
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700363 adreno_regwrite(device, REG_SCRATCH_ADDR, device->memstore.gpuaddr +
364 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
365 soptimestamp));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366
367 adreno_regwrite(device, REG_SCRATCH_UMSK,
368 GSL_RB_MEMPTRS_SCRATCH_MASK);
369
370 /* load the CP ucode */
371
372 status = adreno_ringbuffer_load_pm4_ucode(device);
373 if (status != 0)
374 return status;
375
376 /* load the prefetch parser ucode */
377 status = adreno_ringbuffer_load_pfp_ucode(device);
378 if (status != 0)
379 return status;
380
Kevin Matlageff806df2012-05-07 18:13:21 -0600381 /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
Kevin Matlagee8d35862012-04-26 12:58:15 -0600382 if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
Kevin Matlageff806df2012-05-07 18:13:21 -0600383 adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384
385 rb->rptr = 0;
386 rb->wptr = 0;
387
388 /* clear ME_HALT to start micro engine */
389 adreno_regwrite(device, REG_CP_ME_CNTL, 0);
390
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700391 /* ME init is GPU specific, so jump into the sub-function */
392 adreno_dev->gpudev->rb_init(adreno_dev, rb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393
394 /* idle device to validate ME INIT */
395 status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
396
397 if (status == 0)
398 rb->flags |= KGSL_FLAGS_STARTED;
399
400 return status;
401}
402
Carter Cooper6dd94c82011-10-13 14:43:53 -0600403void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404{
405 if (rb->flags & KGSL_FLAGS_STARTED) {
406 /* ME_HALT */
407 adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 rb->flags &= ~KGSL_FLAGS_STARTED;
409 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410}
411
412int adreno_ringbuffer_init(struct kgsl_device *device)
413{
414 int status;
415 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
416 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
417
418 rb->device = device;
419 /*
420 * It is silly to convert this to words and then back to bytes
421 * immediately below, but most of the rest of the code deals
422 * in words, so we might as well only do the math once
423 */
424 rb->sizedwords = KGSL_RB_SIZE >> 2;
425
426 /* allocate memory for ringbuffer */
427 status = kgsl_allocate_contiguous(&rb->buffer_desc,
428 (rb->sizedwords << 2));
429
430 if (status != 0) {
431 adreno_ringbuffer_close(rb);
432 return status;
433 }
434
435 /* allocate memory for polling and timestamps */
436 /* This really can be at 4 byte alignment boundry but for using MMU
437 * we need to make it at page boundary */
438 status = kgsl_allocate_contiguous(&rb->memptrs_desc,
439 sizeof(struct kgsl_rbmemptrs));
440
441 if (status != 0) {
442 adreno_ringbuffer_close(rb);
443 return status;
444 }
445
446 /* overlay structure on memptrs memory */
447 rb->memptrs = (struct kgsl_rbmemptrs *) rb->memptrs_desc.hostptr;
448
449 return 0;
450}
451
Carter Cooper6dd94c82011-10-13 14:43:53 -0600452void adreno_ringbuffer_close(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700453{
454 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
455
456 kgsl_sharedmem_free(&rb->buffer_desc);
457 kgsl_sharedmem_free(&rb->memptrs_desc);
458
459 kfree(adreno_dev->pfp_fw);
460 kfree(adreno_dev->pm4_fw);
461
462 adreno_dev->pfp_fw = NULL;
463 adreno_dev->pm4_fw = NULL;
464
465 memset(rb, 0, sizeof(struct adreno_ringbuffer));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466}
467
468static uint32_t
469adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700470 struct adreno_context *context,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 unsigned int flags, unsigned int *cmds,
472 int sizedwords)
473{
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700474 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475 unsigned int *ringcmds;
476 unsigned int timestamp;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700477 unsigned int total_sizedwords = sizedwords;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478 unsigned int i;
479 unsigned int rcmd_gpu;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700480 unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
481 unsigned int gpuaddr = rb->device->memstore.gpuaddr;
482
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600483 /*
484 * if the context was not created with per context timestamp
485 * support, we must use the global timestamp since issueibcmds
486 * will be returning that one.
487 */
488 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
489 context_id = context->id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490
491 /* reserve space to temporarily turn off protected mode
492 * error checking if needed
493 */
494 total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
Zhoulu Luo552905e2012-06-21 15:21:52 -0700495 total_sizedwords += !(flags & KGSL_CMD_FLAGS_NO_TS_CMP) ? 7 : 0;
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600496 /* 2 dwords to store the start of command sequence */
497 total_sizedwords += 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700499 if (adreno_is_a3xx(adreno_dev))
500 total_sizedwords += 7;
501
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700502 total_sizedwords += 2; /* scratchpad ts for recovery */
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600503 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700504 total_sizedwords += 3; /* sop timestamp */
505 total_sizedwords += 4; /* eop timestamp */
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530506 total_sizedwords += 3; /* global timestamp without cache
507 * flush for non-zero context */
508 } else {
509 total_sizedwords += 4; /* global timestamp for recovery*/
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700510 }
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512 ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600513 /* GPU may hang during space allocation, if thats the case the current
514 * context may have hung the GPU */
515 if (context->flags & CTXT_FLAGS_GPU_HANG) {
516 KGSL_CTXT_WARN(rb->device,
517 "Context %p caused a gpu hang. Will not accept commands for context %d\n",
518 context, context->id);
519 return rb->timestamp[context_id];
520 }
521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522 rcmd_gpu = rb->buffer_desc.gpuaddr
523 + sizeof(uint)*(rb->wptr-total_sizedwords);
524
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600525 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
526 GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528 if (flags & KGSL_CMD_FLAGS_PMODE) {
529 /* disable protected mode error checking */
530 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600531 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700532 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
533 }
534
535 for (i = 0; i < sizedwords; i++) {
536 GSL_RB_WRITE(ringcmds, rcmd_gpu, *cmds);
537 cmds++;
538 }
539
540 if (flags & KGSL_CMD_FLAGS_PMODE) {
541 /* re-enable protected mode error checking */
542 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600543 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544 GSL_RB_WRITE(ringcmds, rcmd_gpu, 1);
545 }
546
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700547 /* always increment the global timestamp. once. */
548 rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
Zhoulu Luo552905e2012-06-21 15:21:52 -0700549 if (context) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700550 if (context_id == KGSL_MEMSTORE_GLOBAL)
Zhoulu Luo552905e2012-06-21 15:21:52 -0700551 rb->timestamp[context_id] =
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700552 rb->timestamp[KGSL_MEMSTORE_GLOBAL];
553 else
554 rb->timestamp[context_id]++;
555 }
556 timestamp = rb->timestamp[context_id];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700557
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700558 /* scratchpad ts for recovery */
Jordan Crouse084427d2011-07-28 08:37:58 -0600559 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700560 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700561
562 if (adreno_is_a3xx(adreno_dev)) {
563 /*
564 * FLush HLSQ lazy updates to make sure there are no
565 * rsources pending for indirect loads after the timestamp
566 */
567
568 GSL_RB_WRITE(ringcmds, rcmd_gpu,
569 cp_type3_packet(CP_EVENT_WRITE, 1));
570 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x07); /* HLSQ_FLUSH */
571 GSL_RB_WRITE(ringcmds, rcmd_gpu,
572 cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
573 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
574 }
575
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600576 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700577 /* start-of-pipeline timestamp */
578 GSL_RB_WRITE(ringcmds, rcmd_gpu,
579 cp_type3_packet(CP_MEM_WRITE, 2));
580 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Zhoulu Luo552905e2012-06-21 15:21:52 -0700581 KGSL_MEMSTORE_OFFSET(context->id, soptimestamp)));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700582 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
583
584 /* end-of-pipeline timestamp */
585 GSL_RB_WRITE(ringcmds, rcmd_gpu,
586 cp_type3_packet(CP_EVENT_WRITE, 3));
587 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
588 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Zhoulu Luo552905e2012-06-21 15:21:52 -0700589 KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp)));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700590 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700591
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530592 GSL_RB_WRITE(ringcmds, rcmd_gpu,
593 cp_type3_packet(CP_MEM_WRITE, 2));
594 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Zhoulu Luo552905e2012-06-21 15:21:52 -0700595 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
596 eoptimestamp)));
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530597 GSL_RB_WRITE(ringcmds, rcmd_gpu,
598 rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
599 } else {
600 GSL_RB_WRITE(ringcmds, rcmd_gpu,
601 cp_type3_packet(CP_EVENT_WRITE, 3));
602 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
603 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Zhoulu Luo552905e2012-06-21 15:21:52 -0700604 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
605 eoptimestamp)));
606 GSL_RB_WRITE(ringcmds, rcmd_gpu,
607 rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530608 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609
Zhoulu Luo552905e2012-06-21 15:21:52 -0700610 if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 /* Conditional execution based on memory values */
612 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600613 cp_type3_packet(CP_COND_EXEC, 4));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700614 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
615 KGSL_MEMSTORE_OFFSET(
616 context_id, ts_cmp_enable)) >> 2);
617 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
618 KGSL_MEMSTORE_OFFSET(
619 context_id, ref_wait_ts)) >> 2);
620 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 /* # of conditional command DWORDs */
622 GSL_RB_WRITE(ringcmds, rcmd_gpu, 2);
623 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600624 cp_type3_packet(CP_INTERRUPT, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625 GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
626 }
627
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700628 if (adreno_is_a3xx(adreno_dev)) {
629 /* Dummy set-constant to trigger context rollover */
630 GSL_RB_WRITE(ringcmds, rcmd_gpu,
631 cp_type3_packet(CP_SET_CONSTANT, 2));
632 GSL_RB_WRITE(ringcmds, rcmd_gpu,
633 (0x4<<16)|(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG - 0x2000));
634 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
635 }
636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 adreno_ringbuffer_submit(rb);
638
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639 return timestamp;
640}
641
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600642unsigned int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643adreno_ringbuffer_issuecmds(struct kgsl_device *device,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600644 struct adreno_context *drawctxt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645 unsigned int flags,
646 unsigned int *cmds,
647 int sizedwords)
648{
649 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
650 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
651
652 if (device->state & KGSL_STATE_HUNG)
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600653 return kgsl_readtimestamp(device, KGSL_MEMSTORE_GLOBAL,
654 KGSL_TIMESTAMP_RETIRED);
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600655 return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds, sizedwords);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656}
657
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -0600658static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
659 int sizedwords);
660
661static bool
662_handle_type3(struct kgsl_device_private *dev_priv, uint *hostaddr)
663{
664 unsigned int opcode = cp_type3_opcode(*hostaddr);
665 switch (opcode) {
666 case CP_INDIRECT_BUFFER_PFD:
667 case CP_INDIRECT_BUFFER_PFE:
668 case CP_COND_INDIRECT_BUFFER_PFE:
669 case CP_COND_INDIRECT_BUFFER_PFD:
670 return _parse_ibs(dev_priv, hostaddr[1], hostaddr[2]);
671 case CP_NOP:
672 case CP_WAIT_FOR_IDLE:
673 case CP_WAIT_REG_MEM:
674 case CP_WAIT_REG_EQ:
675 case CP_WAT_REG_GTE:
676 case CP_WAIT_UNTIL_READ:
677 case CP_WAIT_IB_PFD_COMPLETE:
678 case CP_REG_RMW:
679 case CP_REG_TO_MEM:
680 case CP_MEM_WRITE:
681 case CP_MEM_WRITE_CNTR:
682 case CP_COND_EXEC:
683 case CP_COND_WRITE:
684 case CP_EVENT_WRITE:
685 case CP_EVENT_WRITE_SHD:
686 case CP_EVENT_WRITE_CFL:
687 case CP_EVENT_WRITE_ZPD:
688 case CP_DRAW_INDX:
689 case CP_DRAW_INDX_2:
690 case CP_DRAW_INDX_BIN:
691 case CP_DRAW_INDX_2_BIN:
692 case CP_VIZ_QUERY:
693 case CP_SET_STATE:
694 case CP_SET_CONSTANT:
695 case CP_IM_LOAD:
696 case CP_IM_LOAD_IMMEDIATE:
697 case CP_LOAD_CONSTANT_CONTEXT:
698 case CP_INVALIDATE_STATE:
699 case CP_SET_SHADER_BASES:
700 case CP_SET_BIN_MASK:
701 case CP_SET_BIN_SELECT:
702 case CP_SET_BIN_BASE_OFFSET:
703 case CP_SET_BIN_DATA:
704 case CP_CONTEXT_UPDATE:
705 case CP_INTERRUPT:
706 case CP_IM_STORE:
707 case CP_LOAD_STATE:
708 break;
709 /* these shouldn't come from userspace */
710 case CP_ME_INIT:
711 case CP_SET_PROTECTED_MODE:
712 default:
713 KGSL_CMD_ERR(dev_priv->device, "bad CP opcode %0x\n", opcode);
714 return false;
715 break;
716 }
717
718 return true;
719}
720
721static bool
722_handle_type0(struct kgsl_device_private *dev_priv, uint *hostaddr)
723{
724 unsigned int reg = type0_pkt_offset(*hostaddr);
725 unsigned int cnt = type0_pkt_size(*hostaddr);
726 if (reg < 0x0192 || (reg + cnt) >= 0x8000) {
727 KGSL_CMD_ERR(dev_priv->device, "bad type0 reg: 0x%0x cnt: %d\n",
728 reg, cnt);
729 return false;
730 }
731 return true;
732}
733
734/*
735 * Traverse IBs and dump them to test vector. Detect swap by inspecting
736 * register writes, keeping note of the current state, and dump
737 * framebuffer config to test vector
738 */
739static bool _parse_ibs(struct kgsl_device_private *dev_priv,
740 uint gpuaddr, int sizedwords)
741{
742 static uint level; /* recursion level */
743 bool ret = false;
744 uint *hostaddr, *hoststart;
745 int dwords_left = sizedwords; /* dwords left in the current command
746 buffer */
747 struct kgsl_mem_entry *entry;
748
749 spin_lock(&dev_priv->process_priv->mem_lock);
750 entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
751 gpuaddr, sizedwords * sizeof(uint));
752 spin_unlock(&dev_priv->process_priv->mem_lock);
753 if (entry == NULL) {
754 KGSL_CMD_ERR(dev_priv->device,
755 "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
756 return false;
757 }
758
759 hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(&entry->memdesc, gpuaddr);
760 if (hostaddr == NULL) {
761 KGSL_CMD_ERR(dev_priv->device,
762 "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
763 return false;
764 }
765
766 hoststart = hostaddr;
767
768 level++;
769
770 KGSL_CMD_INFO(dev_priv->device, "ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
771 gpuaddr, sizedwords, hostaddr);
772
773 mb();
774 while (dwords_left > 0) {
775 bool cur_ret = true;
776 int count = 0; /* dword count including packet header */
777
778 switch (*hostaddr >> 30) {
779 case 0x0: /* type-0 */
780 count = (*hostaddr >> 16)+2;
781 cur_ret = _handle_type0(dev_priv, hostaddr);
782 break;
783 case 0x1: /* type-1 */
784 count = 2;
785 break;
786 case 0x3: /* type-3 */
787 count = ((*hostaddr >> 16) & 0x3fff) + 2;
788 cur_ret = _handle_type3(dev_priv, hostaddr);
789 break;
790 default:
791 KGSL_CMD_ERR(dev_priv->device, "unexpected type: "
792 "type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
793 *hostaddr >> 30, *hostaddr, hostaddr,
794 gpuaddr+4*(sizedwords-dwords_left));
795 cur_ret = false;
796 count = dwords_left;
797 break;
798 }
799
800 if (!cur_ret) {
801 KGSL_CMD_ERR(dev_priv->device,
802 "bad sub-type: #:%d/%d, v:0x%08x"
803 " @ 0x%p[gb:0x%08x], level:%d\n",
804 sizedwords-dwords_left, sizedwords, *hostaddr,
805 hostaddr, gpuaddr+4*(sizedwords-dwords_left),
806 level);
807
808 if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
809 >= 2)
810 print_hex_dump(KERN_ERR,
811 level == 1 ? "IB1:" : "IB2:",
812 DUMP_PREFIX_OFFSET, 32, 4, hoststart,
813 sizedwords*4, 0);
814 goto done;
815 }
816
817 /* jump to next packet */
818 dwords_left -= count;
819 hostaddr += count;
820 if (dwords_left < 0) {
821 KGSL_CMD_ERR(dev_priv->device,
822 "bad count: c:%d, #:%d/%d, "
823 "v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
824 count, sizedwords-(dwords_left+count),
825 sizedwords, *(hostaddr-count), hostaddr-count,
826 gpuaddr+4*(sizedwords-(dwords_left+count)),
827 level);
828 if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
829 >= 2)
830 print_hex_dump(KERN_ERR,
831 level == 1 ? "IB1:" : "IB2:",
832 DUMP_PREFIX_OFFSET, 32, 4, hoststart,
833 sizedwords*4, 0);
834 goto done;
835 }
836 }
837
838 ret = true;
839done:
840 if (!ret)
841 KGSL_DRV_ERR(dev_priv->device,
842 "parsing failed: gpuaddr:0x%08x, "
843 "host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
844
845 level--;
846
847 return ret;
848}
849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850int
851adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
852 struct kgsl_context *context,
853 struct kgsl_ibdesc *ibdesc,
854 unsigned int numibs,
855 uint32_t *timestamp,
856 unsigned int flags)
857{
858 struct kgsl_device *device = dev_priv->device;
859 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
860 unsigned int *link;
861 unsigned int *cmds;
862 unsigned int i;
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600863 struct adreno_context *drawctxt;
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700864 unsigned int start_index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865
866 if (device->state & KGSL_STATE_HUNG)
867 return -EBUSY;
868 if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) ||
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600869 context == NULL || ibdesc == 0 || numibs == 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870 return -EINVAL;
871
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600872 drawctxt = context->devctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700873
874 if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
875 KGSL_CTXT_WARN(device, "Context %p caused a gpu hang.."
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700876 " will not accept commands for context %d\n",
877 drawctxt, drawctxt->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878 return -EDEADLK;
879 }
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600880
881 cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
882 GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883 if (!link) {
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600884 KGSL_CORE_ERR("kzalloc(%d) failed\n",
885 sizeof(unsigned int) * (numibs * 3 + 4));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 return -ENOMEM;
887 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700888
889 /*When preamble is enabled, the preamble buffer with state restoration
890 commands are stored in the first node of the IB chain. We can skip that
891 if a context switch hasn't occured */
892
893 if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
894 adreno_dev->drawctxt_active == drawctxt)
895 start_index = 1;
896
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600897 if (!start_index) {
898 *cmds++ = cp_nop_packet(1);
899 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
900 } else {
901 *cmds++ = cp_nop_packet(4);
902 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
903 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
904 *cmds++ = ibdesc[0].gpuaddr;
905 *cmds++ = ibdesc[0].sizedwords;
906 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700907 for (i = start_index; i < numibs; i++) {
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -0600908 if (unlikely(adreno_dev->ib_check_level >= 1 &&
909 !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
910 ibdesc[i].sizedwords))) {
911 kfree(link);
912 return -EINVAL;
913 }
Jordan Crouse084427d2011-07-28 08:37:58 -0600914 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 *cmds++ = ibdesc[i].gpuaddr;
916 *cmds++ = ibdesc[i].sizedwords;
917 }
918
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600919 *cmds++ = cp_nop_packet(1);
920 *cmds++ = KGSL_END_OF_IB_IDENTIFIER;
921
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600922 kgsl_setstate(&device->mmu, context->id,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600923 kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700924 device->id));
925
926 adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
927
928 *timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600929 drawctxt, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930 &link[0], (cmds - link));
931
932 KGSL_CMD_INFO(device, "ctxt %d g %08x numibs %d ts %d\n",
933 context->id, (unsigned int)ibdesc, numibs, *timestamp);
934
935 kfree(link);
936
937#ifdef CONFIG_MSM_KGSL_CFF_DUMP
938 /*
939 * insert wait for idle after every IB1
940 * this is conservative but works reliably and is ok
941 * even for performance simulations
942 */
943 adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
944#endif
945
946 return 0;
947}
948
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -0600949static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
950 unsigned int *ptr,
951 bool inc)
952{
953 int status = -EINVAL;
954 unsigned int val1;
955 unsigned int size = rb->buffer_desc.size;
956 unsigned int start_ptr = *ptr;
957
958 while ((start_ptr / sizeof(unsigned int)) != rb->wptr) {
959 if (inc)
960 start_ptr = adreno_ringbuffer_inc_wrapped(start_ptr,
961 size);
962 else
963 start_ptr = adreno_ringbuffer_dec_wrapped(start_ptr,
964 size);
965 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, start_ptr);
966 if (KGSL_CMD_IDENTIFIER == val1) {
967 if ((start_ptr / sizeof(unsigned int)) != rb->wptr)
968 start_ptr = adreno_ringbuffer_dec_wrapped(
969 start_ptr, size);
970 *ptr = start_ptr;
971 status = 0;
972 break;
973 }
974 }
975 return status;
976}
977
978static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb,
979 unsigned int *rb_rptr,
980 unsigned int global_eop,
981 bool inc)
982{
983 int status = -EINVAL;
984 unsigned int temp_rb_rptr = *rb_rptr;
985 unsigned int size = rb->buffer_desc.size;
986 unsigned int val[3];
987 int i = 0;
988 bool check = false;
989
990 if (inc && temp_rb_rptr / sizeof(unsigned int) != rb->wptr)
991 return status;
992
993 do {
994 /* when decrementing we need to decrement first and
995 * then read make sure we cover all the data */
996 if (!inc)
997 temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
998 temp_rb_rptr, size);
999 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i],
1000 temp_rb_rptr);
1001
1002 if (check && ((inc && val[i] == global_eop) ||
1003 (!inc && (val[i] ==
1004 cp_type3_packet(CP_MEM_WRITE, 2) ||
1005 val[i] == CACHE_FLUSH_TS)))) {
1006 /* decrement i, i.e i = (i - 1 + 3) % 3 if
1007 * we are going forward, else increment i */
1008 i = (i + 2) % 3;
1009 if (val[i] == rb->device->memstore.gpuaddr +
1010 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
1011 eoptimestamp)) {
1012 int j = ((i + 2) % 3);
1013 if ((inc && (val[j] == CACHE_FLUSH_TS ||
1014 val[j] == cp_type3_packet(
1015 CP_MEM_WRITE, 2))) ||
1016 (!inc && val[j] == global_eop)) {
1017 /* Found the global eop */
1018 status = 0;
1019 break;
1020 }
1021 }
1022 /* if no match found then increment i again
1023 * since we decremented before matching */
1024 i = (i + 1) % 3;
1025 }
1026 if (inc)
1027 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(
1028 temp_rb_rptr, size);
1029
1030 i = (i + 1) % 3;
1031 if (2 == i)
1032 check = true;
1033 } while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr);
1034 /* temp_rb_rptr points to the global eop, move forward till
1035 * the next command */
1036 if (!status) {
1037 status = _find_start_of_cmd_seq(rb, &temp_rb_rptr, true);
1038 if (!status) {
1039 *rb_rptr = temp_rb_rptr;
1040 KGSL_DRV_ERR(rb->device,
1041 "Offset of cmd sequence after eop timestamp: 0x%x\n",
1042 temp_rb_rptr / sizeof(unsigned int));
1043 }
1044 }
1045 return status;
1046}
1047
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001048static int _find_hanging_ib_sequence(struct adreno_ringbuffer *rb,
1049 unsigned int *rb_rptr,
1050 unsigned int ib1)
1051{
1052 int status = -EINVAL;
1053 unsigned int temp_rb_rptr = *rb_rptr;
1054 unsigned int size = rb->buffer_desc.size;
1055 unsigned int val[2];
1056 int i = 0;
1057 bool check = false;
1058 bool ctx_switch = false;
1059
1060 while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
1061 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
1062
1063 if (check && val[i] == ib1) {
1064 /* decrement i, i.e i = (i - 1 + 2) % 2 */
1065 i = (i + 1) % 2;
1066 if (adreno_cmd_is_ib(val[i])) {
1067 /* go till start of command sequence */
1068 status = _find_start_of_cmd_seq(rb,
1069 &temp_rb_rptr, false);
1070 KGSL_DRV_ERR(rb->device,
1071 "Found the hanging IB at offset 0x%x\n",
1072 temp_rb_rptr / sizeof(unsigned int));
1073 break;
1074 }
1075 /* if no match the increment i since we decremented
1076 * before checking */
1077 i = (i + 1) % 2;
1078 }
1079 /* Make sure you do not encounter a context switch twice, we can
1080 * encounter it once for the bad context as the start of search
1081 * can point to the context switch */
1082 if (val[i] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
1083 if (ctx_switch) {
1084 KGSL_DRV_ERR(rb->device,
1085 "Context switch encountered before bad "
1086 "IB found\n");
1087 break;
1088 }
1089 ctx_switch = true;
1090 }
1091 i = (i + 1) % 2;
1092 if (1 == i)
1093 check = true;
1094 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
1095 size);
1096 }
1097 if (!status)
1098 *rb_rptr = temp_rb_rptr;
1099 return status;
1100}
1101
1102static void _turn_preamble_on_for_ib_seq(struct adreno_ringbuffer *rb,
1103 unsigned int rb_rptr)
1104{
1105 unsigned int temp_rb_rptr = rb_rptr;
1106 unsigned int size = rb->buffer_desc.size;
1107 unsigned int val[2];
1108 int i = 0;
1109 bool check = false;
1110 bool cmd_start = false;
1111
1112 /* Go till the start of the ib sequence and turn on preamble */
1113 while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
1114 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
1115 if (check && KGSL_START_OF_IB_IDENTIFIER == val[i]) {
1116 /* decrement i */
1117 i = (i + 1) % 2;
1118 if (val[i] == cp_nop_packet(4)) {
1119 temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
1120 temp_rb_rptr, size);
1121 kgsl_sharedmem_writel(&rb->buffer_desc,
1122 temp_rb_rptr, cp_nop_packet(1));
1123 }
1124 KGSL_DRV_ERR(rb->device,
1125 "Turned preamble on at offset 0x%x\n",
1126 temp_rb_rptr / 4);
1127 break;
1128 }
1129 /* If you reach beginning of next command sequence then exit
1130 * First command encountered is the current one so don't break
1131 * on that. */
1132 if (KGSL_CMD_IDENTIFIER == val[i]) {
1133 if (cmd_start)
1134 break;
1135 cmd_start = true;
1136 }
1137
1138 i = (i + 1) % 2;
1139 if (1 == i)
1140 check = true;
1141 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
1142 size);
1143 }
1144}
1145
Shubhraprakash Das1d577fe2012-05-31 18:28:22 -06001146static void _copy_valid_rb_content(struct adreno_ringbuffer *rb,
1147 unsigned int rb_rptr, unsigned int *temp_rb_buffer,
1148 int *rb_size, unsigned int *bad_rb_buffer,
1149 int *bad_rb_size,
1150 int *last_valid_ctx_id)
1151{
1152 unsigned int good_rb_idx = 0, cmd_start_idx = 0;
1153 unsigned int val1 = 0;
1154 struct kgsl_context *k_ctxt;
1155 struct adreno_context *a_ctxt;
1156 unsigned int bad_rb_idx = 0;
1157 int copy_rb_contents = 0;
1158 unsigned int temp_rb_rptr;
1159 unsigned int size = rb->buffer_desc.size;
1160 unsigned int good_cmd_start_idx = 0;
1161
1162 /* Walk the rb from the context switch. Omit any commands
1163 * for an invalid context. */
1164 while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
1165 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
1166
1167 if (KGSL_CMD_IDENTIFIER == val1) {
1168 /* Start is the NOP dword that comes before
1169 * KGSL_CMD_IDENTIFIER */
1170 cmd_start_idx = bad_rb_idx - 1;
1171 if (copy_rb_contents)
1172 good_cmd_start_idx = good_rb_idx - 1;
1173 }
1174
1175 /* check for context switch indicator */
1176 if (val1 == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
1177 unsigned int temp_idx, val2;
1178 /* increment by 3 to get to the context_id */
1179 temp_rb_rptr = rb_rptr + (3 * sizeof(unsigned int)) %
1180 size;
1181 kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
1182 temp_rb_rptr);
1183
1184 /* if context switches to a context that did not cause
1185 * hang then start saving the rb contents as those
1186 * commands can be executed */
1187 k_ctxt = idr_find(&rb->device->context_idr, val2);
1188 if (k_ctxt) {
1189 a_ctxt = k_ctxt->devctxt;
1190
1191 /* If we are changing to a good context and were not
1192 * copying commands then copy over commands to the good
1193 * context */
1194 if (!copy_rb_contents && ((k_ctxt &&
1195 !(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
1196 !k_ctxt)) {
1197 for (temp_idx = cmd_start_idx;
1198 temp_idx < bad_rb_idx;
1199 temp_idx++)
1200 temp_rb_buffer[good_rb_idx++] =
1201 bad_rb_buffer[temp_idx];
1202 *last_valid_ctx_id = val2;
1203 copy_rb_contents = 1;
1204 } else if (copy_rb_contents && k_ctxt &&
1205 (a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
1206 /* If we are changing to bad context then remove
1207 * the dwords we copied for this sequence from
1208 * the good buffer */
1209 good_rb_idx = good_cmd_start_idx;
1210 copy_rb_contents = 0;
1211 }
1212 }
1213 }
1214
1215 if (copy_rb_contents)
1216 temp_rb_buffer[good_rb_idx++] = val1;
1217 /* Copy both good and bad commands for replay to the bad
1218 * buffer */
1219 bad_rb_buffer[bad_rb_idx++] = val1;
1220
1221 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
1222 }
1223 *rb_size = good_rb_idx;
1224 *bad_rb_size = bad_rb_idx;
1225}
1226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
Shubhraprakash Dasba6c70b2012-05-31 02:53:06 -06001228 struct adreno_recovery_data *rec_data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001229{
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001230 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001231 struct kgsl_device *device = rb->device;
Shubhraprakash Dasadb16022012-05-31 16:19:37 -06001232 unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001233 struct kgsl_context *context;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001234 struct adreno_context *adreno_context;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235
Shubhraprakash Dasadb16022012-05-31 16:19:37 -06001236 context = idr_find(&device->context_idr, rec_data->context_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001238 status = _find_cmd_seq_after_eop_ts(rb, &rb_rptr, rec_data->global_eop,
1239 false);
1240 if (status)
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001241 goto done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001243 if (context) {
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001244 adreno_context = context->devctxt;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001245
1246 if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
1247 if (rec_data->ib1) {
1248 status = _find_hanging_ib_sequence(rb, &rb_rptr,
1249 rec_data->ib1);
1250 if (status)
1251 goto copy_rb_contents;
1252 }
1253 _turn_preamble_on_for_ib_seq(rb, rb_rptr);
1254 }
1255 }
1256
1257copy_rb_contents:
Shubhraprakash Das1d577fe2012-05-31 18:28:22 -06001258 _copy_valid_rb_content(rb, rb_rptr, rec_data->rb_buffer,
1259 &rec_data->rb_size,
1260 rec_data->bad_rb_buffer,
1261 &rec_data->bad_rb_size,
1262 &rec_data->last_valid_ctx_id);
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001263 /* If we failed to get the hanging IB sequence then we cannot execute
1264 * commands from the bad context */
1265 if (status) {
1266 rec_data->bad_rb_size = 0;
1267 status = 0;
1268 }
1269done:
1270 return status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271}
1272
1273void
1274adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
1275 int num_rb_contents)
1276{
1277 int i;
1278 unsigned int *ringcmds;
1279 unsigned int rcmd_gpu;
1280
1281 if (!num_rb_contents)
1282 return;
1283
1284 if (num_rb_contents > (rb->buffer_desc.size - rb->wptr)) {
1285 adreno_regwrite(rb->device, REG_CP_RB_RPTR, 0);
1286 rb->rptr = 0;
1287 BUG_ON(num_rb_contents > rb->buffer_desc.size);
1288 }
1289 ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
1290 rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
1291 for (i = 0; i < num_rb_contents; i++)
1292 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb_buff[i]);
1293 rb->wptr += num_rb_contents;
1294 adreno_ringbuffer_submit(rb);
1295}