blob: e0ef1fd07f20c9c97beccbd218737286e9452005 [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 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
56 unsigned long wait_timeout = msecs_to_jiffies(adreno_dev->wait_timeout);
57 unsigned long wait_time;
Tarun Karra3335f142012-06-19 14:11:48 -070058 unsigned long wait_time_part;
59 unsigned int msecs_part = KGSL_TIMEOUT_PART;
60 unsigned int prev_reg_val[hang_detect_regs_count];
61
62 memset(prev_reg_val, 0, sizeof(prev_reg_val));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063
64 /* if wptr ahead, fill the remaining with NOPs */
65 if (wptr_ahead) {
66 /* -1 for header */
67 nopcount = rb->sizedwords - rb->wptr - 1;
68
69 cmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
70 cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*rb->wptr;
71
Jordan Crouse084427d2011-07-28 08:37:58 -060072 GSL_RB_WRITE(cmds, cmds_gpu, cp_nop_packet(nopcount));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073
74 /* Make sure that rptr is not 0 before submitting
75 * commands at the end of ringbuffer. We do not
76 * want the rptr and wptr to become equal when
77 * the ringbuffer is not empty */
78 do {
79 GSL_RB_GET_READPTR(rb, &rb->rptr);
80 } while (!rb->rptr);
81
82 rb->wptr++;
83
84 adreno_ringbuffer_submit(rb);
85
86 rb->wptr = 0;
87 }
88
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060089 wait_time = jiffies + wait_timeout;
Tarun Karra3335f142012-06-19 14:11:48 -070090 wait_time_part = jiffies + msecs_to_jiffies(msecs_part);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 /* wait for space in ringbuffer */
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060092 while (1) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093 GSL_RB_GET_READPTR(rb, &rb->rptr);
94
95 freecmds = rb->rptr - rb->wptr;
96
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060097 if (freecmds == 0 || freecmds > numcmds)
98 break;
99
Tarun Karra3335f142012-06-19 14:11:48 -0700100 /* Dont wait for timeout, detect hang faster.
101 */
102 if (time_after(jiffies, wait_time_part)) {
103 wait_time_part = jiffies +
104 msecs_to_jiffies(msecs_part);
105 if ((adreno_hang_detect(rb->device,
106 prev_reg_val))){
107 KGSL_DRV_ERR(rb->device,
108 "Hang detected while waiting for freespace in"
109 "ringbuffer rptr: 0x%x, wptr: 0x%x\n",
110 rb->rptr, rb->wptr);
111 goto err;
112 }
113 }
114
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600115 if (time_after(jiffies, wait_time)) {
116 KGSL_DRV_ERR(rb->device,
117 "Timed out while waiting for freespace in ringbuffer "
118 "rptr: 0x%x, wptr: 0x%x\n", rb->rptr, rb->wptr);
Tarun Karra3335f142012-06-19 14:11:48 -0700119 goto err;
120 }
121
Wei Zou50ec3372012-07-17 15:46:52 -0700122 continue;
123
Tarun Karra3335f142012-06-19 14:11:48 -0700124err:
125 if (!adreno_dump_and_recover(rb->device))
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600126 wait_time = jiffies + wait_timeout;
127 else
128 /* GPU is hung and we cannot recover */
129 BUG();
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600130 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131}
132
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700133unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134 unsigned int numcmds)
135{
136 unsigned int *ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137
138 BUG_ON(numcmds >= rb->sizedwords);
139
140 GSL_RB_GET_READPTR(rb, &rb->rptr);
141 /* check for available space */
142 if (rb->wptr >= rb->rptr) {
143 /* wptr ahead or equal to rptr */
144 /* reserve dwords for nop packet */
145 if ((rb->wptr + numcmds) > (rb->sizedwords -
146 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600147 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 } else {
149 /* wptr behind rptr */
150 if ((rb->wptr + numcmds) >= rb->rptr)
Carter Cooper6dd94c82011-10-13 14:43:53 -0600151 adreno_ringbuffer_waitspace(rb, numcmds, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 /* check for remaining space */
153 /* reserve dwords for nop packet */
154 if ((rb->wptr + numcmds) > (rb->sizedwords -
155 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600156 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157 }
158
Carter Cooper6dd94c82011-10-13 14:43:53 -0600159 ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
160 rb->wptr += numcmds;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161
162 return ptr;
163}
164
165static int _load_firmware(struct kgsl_device *device, const char *fwfile,
166 void **data, int *len)
167{
168 const struct firmware *fw = NULL;
169 int ret;
170
171 ret = request_firmware(&fw, fwfile, device->dev);
172
173 if (ret) {
174 KGSL_DRV_ERR(device, "request_firmware(%s) failed: %d\n",
175 fwfile, ret);
176 return ret;
177 }
178
179 *data = kmalloc(fw->size, GFP_KERNEL);
180
181 if (*data) {
182 memcpy(*data, fw->data, fw->size);
183 *len = fw->size;
184 } else
185 KGSL_MEM_ERR(device, "kmalloc(%d) failed\n", fw->size);
186
187 release_firmware(fw);
188 return (*data != NULL) ? 0 : -ENOMEM;
189}
190
191static int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
192{
193 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194 int i, ret = 0;
195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 if (adreno_dev->pm4_fw == NULL) {
197 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600198 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199
Jordan Crouse505df9c2011-07-28 08:37:59 -0600200 ret = _load_firmware(device, adreno_dev->pm4_fwfile,
201 &ptr, &len);
202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 if (ret)
204 goto err;
205
206 /* PM4 size is 3 dword aligned plus 1 dword of version */
207 if (len % ((sizeof(uint32_t) * 3)) != sizeof(uint32_t)) {
208 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
209 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600210 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 goto err;
212 }
213
214 adreno_dev->pm4_fw_size = len / sizeof(uint32_t);
215 adreno_dev->pm4_fw = ptr;
216 }
217
218 KGSL_DRV_INFO(device, "loading pm4 ucode version: %d\n",
219 adreno_dev->pm4_fw[0]);
220
221 adreno_regwrite(device, REG_CP_DEBUG, 0x02000000);
222 adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
223 for (i = 1; i < adreno_dev->pm4_fw_size; i++)
224 adreno_regwrite(device, REG_CP_ME_RAM_DATA,
225 adreno_dev->pm4_fw[i]);
226err:
227 return ret;
228}
229
230static int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
231{
232 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233 int i, ret = 0;
234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 if (adreno_dev->pfp_fw == NULL) {
236 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600237 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700238
Jordan Crouse505df9c2011-07-28 08:37:59 -0600239 ret = _load_firmware(device, adreno_dev->pfp_fwfile,
240 &ptr, &len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 if (ret)
242 goto err;
243
244 /* PFP size shold be dword aligned */
245 if (len % sizeof(uint32_t) != 0) {
246 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
247 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600248 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 goto err;
250 }
251
252 adreno_dev->pfp_fw_size = len / sizeof(uint32_t);
253 adreno_dev->pfp_fw = ptr;
254 }
255
256 KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
257 adreno_dev->pfp_fw[0]);
258
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700259 adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260 for (i = 1; i < adreno_dev->pfp_fw_size; i++)
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700261 adreno_regwrite(device,
262 adreno_dev->gpudev->reg_cp_pfp_ucode_data,
263 adreno_dev->pfp_fw[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264err:
265 return ret;
266}
267
268int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
269{
270 int status;
271 /*cp_rb_cntl_u cp_rb_cntl; */
272 union reg_cp_rb_cntl cp_rb_cntl;
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700273 unsigned int rb_cntl;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 struct kgsl_device *device = rb->device;
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700275 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276
277 if (rb->flags & KGSL_FLAGS_STARTED)
278 return 0;
279
Carter Coopercb3e8eb2012-04-11 09:39:40 -0600280 if (init_ram)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700281 rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282
283 kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
284 sizeof(struct kgsl_rbmemptrs));
285
286 kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
287 (rb->sizedwords << 2));
288
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700289 if (adreno_is_a2xx(adreno_dev)) {
290 adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
291 (rb->memptrs_desc.gpuaddr
292 + GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700294 /* setup WPTR delay */
295 adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
296 0 /*0x70000010 */);
297 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298
299 /*setup REG_CP_RB_CNTL */
300 adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
301 cp_rb_cntl.val = rb_cntl;
302
303 /*
304 * The size of the ringbuffer in the hardware is the log2
305 * representation of the size in quadwords (sizedwords / 2)
306 */
307 cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);
308
309 /*
310 * Specify the quadwords to read before updating mem RPTR.
311 * Like above, pass the log2 representation of the blocksize
312 * in quadwords.
313 */
314 cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);
315
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700316 if (adreno_is_a2xx(adreno_dev)) {
317 /* WPTR polling */
318 cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
319 }
320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321 /* mem RPTR writebacks */
322 cp_rb_cntl.f.rb_no_update = GSL_RB_CNTL_NO_UPDATE;
323
324 adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);
325
326 adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);
327
328 adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
329 rb->memptrs_desc.gpuaddr +
330 GSL_RB_MEMPTRS_RPTR_OFFSET);
331
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700332 if (adreno_is_a3xx(adreno_dev)) {
333 /* enable access protection to privileged registers */
334 adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);
335
336 /* RBBM registers */
337 adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
338 adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
339 adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
340 adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
341 adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
342 adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);
343
344 /* CP registers */
345 adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
346 adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
347 adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
348 adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
349 adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);
350
351 /* RB registers */
352 adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
353
354 /* VBIF registers */
355 adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
356 }
357
358 if (adreno_is_a2xx(adreno_dev)) {
359 /* explicitly clear all cp interrupts */
360 adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
361 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362
363 /* setup scratch/timestamp */
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700364 adreno_regwrite(device, REG_SCRATCH_ADDR, device->memstore.gpuaddr +
365 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
366 soptimestamp));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367
368 adreno_regwrite(device, REG_SCRATCH_UMSK,
369 GSL_RB_MEMPTRS_SCRATCH_MASK);
370
371 /* load the CP ucode */
372
373 status = adreno_ringbuffer_load_pm4_ucode(device);
374 if (status != 0)
375 return status;
376
377 /* load the prefetch parser ucode */
378 status = adreno_ringbuffer_load_pfp_ucode(device);
379 if (status != 0)
380 return status;
381
Kevin Matlageff806df2012-05-07 18:13:21 -0600382 /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
Kevin Matlagee8d35862012-04-26 12:58:15 -0600383 if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
Kevin Matlageff806df2012-05-07 18:13:21 -0600384 adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385
386 rb->rptr = 0;
387 rb->wptr = 0;
388
389 /* clear ME_HALT to start micro engine */
390 adreno_regwrite(device, REG_CP_ME_CNTL, 0);
391
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700392 /* ME init is GPU specific, so jump into the sub-function */
393 adreno_dev->gpudev->rb_init(adreno_dev, rb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394
395 /* idle device to validate ME INIT */
Jordan Crousea29a2e02012-08-14 09:09:23 -0600396 status = adreno_idle(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397
398 if (status == 0)
399 rb->flags |= KGSL_FLAGS_STARTED;
400
401 return status;
402}
403
Carter Cooper6dd94c82011-10-13 14:43:53 -0600404void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405{
Lucille Sylvester51feb4e2012-07-26 18:58:33 -0600406 if (rb->flags & KGSL_FLAGS_STARTED)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 rb->flags &= ~KGSL_FLAGS_STARTED;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408}
409
410int adreno_ringbuffer_init(struct kgsl_device *device)
411{
412 int status;
413 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
414 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
415
416 rb->device = device;
417 /*
418 * It is silly to convert this to words and then back to bytes
419 * immediately below, but most of the rest of the code deals
420 * in words, so we might as well only do the math once
421 */
422 rb->sizedwords = KGSL_RB_SIZE >> 2;
423
424 /* allocate memory for ringbuffer */
425 status = kgsl_allocate_contiguous(&rb->buffer_desc,
426 (rb->sizedwords << 2));
427
428 if (status != 0) {
429 adreno_ringbuffer_close(rb);
430 return status;
431 }
432
433 /* allocate memory for polling and timestamps */
434 /* This really can be at 4 byte alignment boundry but for using MMU
435 * we need to make it at page boundary */
436 status = kgsl_allocate_contiguous(&rb->memptrs_desc,
437 sizeof(struct kgsl_rbmemptrs));
438
439 if (status != 0) {
440 adreno_ringbuffer_close(rb);
441 return status;
442 }
443
444 /* overlay structure on memptrs memory */
445 rb->memptrs = (struct kgsl_rbmemptrs *) rb->memptrs_desc.hostptr;
446
447 return 0;
448}
449
Carter Cooper6dd94c82011-10-13 14:43:53 -0600450void adreno_ringbuffer_close(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451{
452 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
453
454 kgsl_sharedmem_free(&rb->buffer_desc);
455 kgsl_sharedmem_free(&rb->memptrs_desc);
456
457 kfree(adreno_dev->pfp_fw);
458 kfree(adreno_dev->pm4_fw);
459
460 adreno_dev->pfp_fw = NULL;
461 adreno_dev->pm4_fw = NULL;
462
463 memset(rb, 0, sizeof(struct adreno_ringbuffer));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700464}
465
466static uint32_t
467adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700468 struct adreno_context *context,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 unsigned int flags, unsigned int *cmds,
470 int sizedwords)
471{
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700472 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 unsigned int *ringcmds;
474 unsigned int timestamp;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700475 unsigned int total_sizedwords = sizedwords;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700476 unsigned int i;
477 unsigned int rcmd_gpu;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700478 unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
479 unsigned int gpuaddr = rb->device->memstore.gpuaddr;
480
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600481 /*
482 * if the context was not created with per context timestamp
483 * support, we must use the global timestamp since issueibcmds
484 * will be returning that one.
485 */
486 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
487 context_id = context->id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488
489 /* reserve space to temporarily turn off protected mode
490 * error checking if needed
491 */
492 total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600493 /* 2 dwords to store the start of command sequence */
494 total_sizedwords += 2;
Carter Cooper7ffaba62012-05-24 13:59:53 -0600495 total_sizedwords += context ? 7 : 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700497 if (adreno_is_a3xx(adreno_dev))
498 total_sizedwords += 7;
499
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700500 total_sizedwords += 2; /* scratchpad ts for recovery */
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600501 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700502 total_sizedwords += 3; /* sop timestamp */
503 total_sizedwords += 4; /* eop timestamp */
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530504 total_sizedwords += 3; /* global timestamp without cache
505 * flush for non-zero context */
506 } else {
507 total_sizedwords += 4; /* global timestamp for recovery*/
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700508 }
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700510 ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600511 /* GPU may hang during space allocation, if thats the case the current
512 * context may have hung the GPU */
513 if (context->flags & CTXT_FLAGS_GPU_HANG) {
514 KGSL_CTXT_WARN(rb->device,
515 "Context %p caused a gpu hang. Will not accept commands for context %d\n",
516 context, context->id);
517 return rb->timestamp[context_id];
518 }
519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700520 rcmd_gpu = rb->buffer_desc.gpuaddr
521 + sizeof(uint)*(rb->wptr-total_sizedwords);
522
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600523 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
524 GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
525
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526 if (flags & KGSL_CMD_FLAGS_PMODE) {
527 /* disable protected mode error checking */
528 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600529 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
531 }
532
533 for (i = 0; i < sizedwords; i++) {
534 GSL_RB_WRITE(ringcmds, rcmd_gpu, *cmds);
535 cmds++;
536 }
537
538 if (flags & KGSL_CMD_FLAGS_PMODE) {
539 /* re-enable protected mode error checking */
540 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600541 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542 GSL_RB_WRITE(ringcmds, rcmd_gpu, 1);
543 }
544
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700545 /* always increment the global timestamp. once. */
546 rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
Carter Cooper7ffaba62012-05-24 13:59:53 -0600547
548 if (context && !(flags & KGSL_CMD_FLAGS_DUMMY_INTR_CMD)) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700549 if (context_id == KGSL_MEMSTORE_GLOBAL)
Carter Cooper7ffaba62012-05-24 13:59:53 -0600550 rb->timestamp[context->id] =
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700551 rb->timestamp[KGSL_MEMSTORE_GLOBAL];
552 else
553 rb->timestamp[context_id]++;
554 }
555 timestamp = rb->timestamp[context_id];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700556
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700557 /* scratchpad ts for recovery */
Jordan Crouse084427d2011-07-28 08:37:58 -0600558 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700559 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700560
561 if (adreno_is_a3xx(adreno_dev)) {
562 /*
563 * FLush HLSQ lazy updates to make sure there are no
564 * rsources pending for indirect loads after the timestamp
565 */
566
567 GSL_RB_WRITE(ringcmds, rcmd_gpu,
568 cp_type3_packet(CP_EVENT_WRITE, 1));
569 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x07); /* HLSQ_FLUSH */
570 GSL_RB_WRITE(ringcmds, rcmd_gpu,
571 cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
572 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
573 }
574
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600575 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700576 /* start-of-pipeline timestamp */
577 GSL_RB_WRITE(ringcmds, rcmd_gpu,
578 cp_type3_packet(CP_MEM_WRITE, 2));
579 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600580 KGSL_MEMSTORE_OFFSET(context_id, soptimestamp)));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700581 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
582
583 /* end-of-pipeline timestamp */
584 GSL_RB_WRITE(ringcmds, rcmd_gpu,
585 cp_type3_packet(CP_EVENT_WRITE, 3));
586 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
587 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600588 KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700589 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700590
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530591 GSL_RB_WRITE(ringcmds, rcmd_gpu,
592 cp_type3_packet(CP_MEM_WRITE, 2));
593 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600594 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
595 eoptimestamp)));
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530596 GSL_RB_WRITE(ringcmds, rcmd_gpu,
597 rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
598 } else {
599 GSL_RB_WRITE(ringcmds, rcmd_gpu,
600 cp_type3_packet(CP_EVENT_WRITE, 3));
601 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
602 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600603 KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
604 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[context_id]);
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530605 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606
Carter Cooper7ffaba62012-05-24 13:59:53 -0600607 if (context) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 /* Conditional execution based on memory values */
609 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600610 cp_type3_packet(CP_COND_EXEC, 4));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700611 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
612 KGSL_MEMSTORE_OFFSET(
613 context_id, ts_cmp_enable)) >> 2);
614 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
615 KGSL_MEMSTORE_OFFSET(
616 context_id, ref_wait_ts)) >> 2);
617 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 /* # of conditional command DWORDs */
619 GSL_RB_WRITE(ringcmds, rcmd_gpu, 2);
620 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600621 cp_type3_packet(CP_INTERRUPT, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622 GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
623 }
624
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700625 if (adreno_is_a3xx(adreno_dev)) {
626 /* Dummy set-constant to trigger context rollover */
627 GSL_RB_WRITE(ringcmds, rcmd_gpu,
628 cp_type3_packet(CP_SET_CONSTANT, 2));
629 GSL_RB_WRITE(ringcmds, rcmd_gpu,
630 (0x4<<16)|(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG - 0x2000));
631 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
632 }
633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634 adreno_ringbuffer_submit(rb);
635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636 return timestamp;
637}
638
Carter Cooper7ffaba62012-05-24 13:59:53 -0600639void
640adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
641 struct kgsl_context *k_ctxt,
642 unsigned int *cmds,
643 int sizedwords)
644{
645 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
646 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
647 struct adreno_context *a_ctxt = NULL;
648
649 if (!k_ctxt)
650 return;
651
652 a_ctxt = k_ctxt->devctxt;
653
654 if (k_ctxt->id == KGSL_CONTEXT_INVALID ||
655 a_ctxt == NULL ||
656 device->state & KGSL_STATE_HUNG)
657 return;
658
659 adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_DUMMY_INTR_CMD,
660 cmds, sizedwords);
661}
662
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600663unsigned int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664adreno_ringbuffer_issuecmds(struct kgsl_device *device,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600665 struct adreno_context *drawctxt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 unsigned int flags,
667 unsigned int *cmds,
668 int sizedwords)
669{
670 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
671 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
672
673 if (device->state & KGSL_STATE_HUNG)
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600674 return kgsl_readtimestamp(device, KGSL_MEMSTORE_GLOBAL,
675 KGSL_TIMESTAMP_RETIRED);
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600676 return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds, sizedwords);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677}
678
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -0600679static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
680 int sizedwords);
681
682static bool
683_handle_type3(struct kgsl_device_private *dev_priv, uint *hostaddr)
684{
685 unsigned int opcode = cp_type3_opcode(*hostaddr);
686 switch (opcode) {
687 case CP_INDIRECT_BUFFER_PFD:
688 case CP_INDIRECT_BUFFER_PFE:
689 case CP_COND_INDIRECT_BUFFER_PFE:
690 case CP_COND_INDIRECT_BUFFER_PFD:
691 return _parse_ibs(dev_priv, hostaddr[1], hostaddr[2]);
692 case CP_NOP:
693 case CP_WAIT_FOR_IDLE:
694 case CP_WAIT_REG_MEM:
695 case CP_WAIT_REG_EQ:
696 case CP_WAT_REG_GTE:
697 case CP_WAIT_UNTIL_READ:
698 case CP_WAIT_IB_PFD_COMPLETE:
699 case CP_REG_RMW:
700 case CP_REG_TO_MEM:
701 case CP_MEM_WRITE:
702 case CP_MEM_WRITE_CNTR:
703 case CP_COND_EXEC:
704 case CP_COND_WRITE:
705 case CP_EVENT_WRITE:
706 case CP_EVENT_WRITE_SHD:
707 case CP_EVENT_WRITE_CFL:
708 case CP_EVENT_WRITE_ZPD:
709 case CP_DRAW_INDX:
710 case CP_DRAW_INDX_2:
711 case CP_DRAW_INDX_BIN:
712 case CP_DRAW_INDX_2_BIN:
713 case CP_VIZ_QUERY:
714 case CP_SET_STATE:
715 case CP_SET_CONSTANT:
716 case CP_IM_LOAD:
717 case CP_IM_LOAD_IMMEDIATE:
718 case CP_LOAD_CONSTANT_CONTEXT:
719 case CP_INVALIDATE_STATE:
720 case CP_SET_SHADER_BASES:
721 case CP_SET_BIN_MASK:
722 case CP_SET_BIN_SELECT:
723 case CP_SET_BIN_BASE_OFFSET:
724 case CP_SET_BIN_DATA:
725 case CP_CONTEXT_UPDATE:
726 case CP_INTERRUPT:
727 case CP_IM_STORE:
728 case CP_LOAD_STATE:
729 break;
730 /* these shouldn't come from userspace */
731 case CP_ME_INIT:
732 case CP_SET_PROTECTED_MODE:
733 default:
734 KGSL_CMD_ERR(dev_priv->device, "bad CP opcode %0x\n", opcode);
735 return false;
736 break;
737 }
738
739 return true;
740}
741
742static bool
743_handle_type0(struct kgsl_device_private *dev_priv, uint *hostaddr)
744{
745 unsigned int reg = type0_pkt_offset(*hostaddr);
746 unsigned int cnt = type0_pkt_size(*hostaddr);
747 if (reg < 0x0192 || (reg + cnt) >= 0x8000) {
748 KGSL_CMD_ERR(dev_priv->device, "bad type0 reg: 0x%0x cnt: %d\n",
749 reg, cnt);
750 return false;
751 }
752 return true;
753}
754
755/*
756 * Traverse IBs and dump them to test vector. Detect swap by inspecting
757 * register writes, keeping note of the current state, and dump
758 * framebuffer config to test vector
759 */
760static bool _parse_ibs(struct kgsl_device_private *dev_priv,
761 uint gpuaddr, int sizedwords)
762{
763 static uint level; /* recursion level */
764 bool ret = false;
765 uint *hostaddr, *hoststart;
766 int dwords_left = sizedwords; /* dwords left in the current command
767 buffer */
768 struct kgsl_mem_entry *entry;
769
770 spin_lock(&dev_priv->process_priv->mem_lock);
771 entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
772 gpuaddr, sizedwords * sizeof(uint));
773 spin_unlock(&dev_priv->process_priv->mem_lock);
774 if (entry == NULL) {
775 KGSL_CMD_ERR(dev_priv->device,
776 "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
777 return false;
778 }
779
780 hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(&entry->memdesc, gpuaddr);
781 if (hostaddr == NULL) {
782 KGSL_CMD_ERR(dev_priv->device,
783 "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
784 return false;
785 }
786
787 hoststart = hostaddr;
788
789 level++;
790
791 KGSL_CMD_INFO(dev_priv->device, "ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
792 gpuaddr, sizedwords, hostaddr);
793
794 mb();
795 while (dwords_left > 0) {
796 bool cur_ret = true;
797 int count = 0; /* dword count including packet header */
798
799 switch (*hostaddr >> 30) {
800 case 0x0: /* type-0 */
801 count = (*hostaddr >> 16)+2;
802 cur_ret = _handle_type0(dev_priv, hostaddr);
803 break;
804 case 0x1: /* type-1 */
805 count = 2;
806 break;
807 case 0x3: /* type-3 */
808 count = ((*hostaddr >> 16) & 0x3fff) + 2;
809 cur_ret = _handle_type3(dev_priv, hostaddr);
810 break;
811 default:
812 KGSL_CMD_ERR(dev_priv->device, "unexpected type: "
813 "type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
814 *hostaddr >> 30, *hostaddr, hostaddr,
815 gpuaddr+4*(sizedwords-dwords_left));
816 cur_ret = false;
817 count = dwords_left;
818 break;
819 }
820
821 if (!cur_ret) {
822 KGSL_CMD_ERR(dev_priv->device,
823 "bad sub-type: #:%d/%d, v:0x%08x"
824 " @ 0x%p[gb:0x%08x], level:%d\n",
825 sizedwords-dwords_left, sizedwords, *hostaddr,
826 hostaddr, gpuaddr+4*(sizedwords-dwords_left),
827 level);
828
829 if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
830 >= 2)
831 print_hex_dump(KERN_ERR,
832 level == 1 ? "IB1:" : "IB2:",
833 DUMP_PREFIX_OFFSET, 32, 4, hoststart,
834 sizedwords*4, 0);
835 goto done;
836 }
837
838 /* jump to next packet */
839 dwords_left -= count;
840 hostaddr += count;
841 if (dwords_left < 0) {
842 KGSL_CMD_ERR(dev_priv->device,
843 "bad count: c:%d, #:%d/%d, "
844 "v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
845 count, sizedwords-(dwords_left+count),
846 sizedwords, *(hostaddr-count), hostaddr-count,
847 gpuaddr+4*(sizedwords-(dwords_left+count)),
848 level);
849 if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
850 >= 2)
851 print_hex_dump(KERN_ERR,
852 level == 1 ? "IB1:" : "IB2:",
853 DUMP_PREFIX_OFFSET, 32, 4, hoststart,
854 sizedwords*4, 0);
855 goto done;
856 }
857 }
858
859 ret = true;
860done:
861 if (!ret)
862 KGSL_DRV_ERR(dev_priv->device,
863 "parsing failed: gpuaddr:0x%08x, "
864 "host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
865
866 level--;
867
868 return ret;
869}
870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871int
872adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
873 struct kgsl_context *context,
874 struct kgsl_ibdesc *ibdesc,
875 unsigned int numibs,
876 uint32_t *timestamp,
877 unsigned int flags)
878{
879 struct kgsl_device *device = dev_priv->device;
880 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
881 unsigned int *link;
882 unsigned int *cmds;
883 unsigned int i;
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600884 struct adreno_context *drawctxt;
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700885 unsigned int start_index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886
887 if (device->state & KGSL_STATE_HUNG)
888 return -EBUSY;
889 if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) ||
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600890 context == NULL || ibdesc == 0 || numibs == 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891 return -EINVAL;
892
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600893 drawctxt = context->devctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894
895 if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
896 KGSL_CTXT_WARN(device, "Context %p caused a gpu hang.."
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700897 " will not accept commands for context %d\n",
898 drawctxt, drawctxt->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899 return -EDEADLK;
900 }
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600901
902 cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
903 GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904 if (!link) {
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600905 KGSL_CORE_ERR("kzalloc(%d) failed\n",
906 sizeof(unsigned int) * (numibs * 3 + 4));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 return -ENOMEM;
908 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700909
910 /*When preamble is enabled, the preamble buffer with state restoration
911 commands are stored in the first node of the IB chain. We can skip that
912 if a context switch hasn't occured */
913
914 if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
915 adreno_dev->drawctxt_active == drawctxt)
916 start_index = 1;
917
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600918 if (!start_index) {
919 *cmds++ = cp_nop_packet(1);
920 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
921 } else {
922 *cmds++ = cp_nop_packet(4);
923 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
924 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
925 *cmds++ = ibdesc[0].gpuaddr;
926 *cmds++ = ibdesc[0].sizedwords;
927 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700928 for (i = start_index; i < numibs; i++) {
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -0600929 if (unlikely(adreno_dev->ib_check_level >= 1 &&
930 !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
931 ibdesc[i].sizedwords))) {
932 kfree(link);
933 return -EINVAL;
934 }
Jordan Crouse084427d2011-07-28 08:37:58 -0600935 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 *cmds++ = ibdesc[i].gpuaddr;
937 *cmds++ = ibdesc[i].sizedwords;
938 }
939
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600940 *cmds++ = cp_nop_packet(1);
941 *cmds++ = KGSL_END_OF_IB_IDENTIFIER;
942
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600943 kgsl_setstate(&device->mmu, context->id,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600944 kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700945 device->id));
946
947 adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
948
949 *timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600950 drawctxt, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951 &link[0], (cmds - link));
952
953 KGSL_CMD_INFO(device, "ctxt %d g %08x numibs %d ts %d\n",
954 context->id, (unsigned int)ibdesc, numibs, *timestamp);
955
956 kfree(link);
957
958#ifdef CONFIG_MSM_KGSL_CFF_DUMP
959 /*
960 * insert wait for idle after every IB1
961 * this is conservative but works reliably and is ok
962 * even for performance simulations
963 */
Jordan Crousea29a2e02012-08-14 09:09:23 -0600964 adreno_idle(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965#endif
Shubhraprakash Das32240ef2012-06-06 20:27:46 -0600966 /* If context hung and recovered then return error so that the
967 * application may handle it */
968 if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_RECOVERED)
969 return -EDEADLK;
970 else
971 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700972
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973}
974
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -0600975static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
976 unsigned int *ptr,
977 bool inc)
978{
979 int status = -EINVAL;
980 unsigned int val1;
981 unsigned int size = rb->buffer_desc.size;
982 unsigned int start_ptr = *ptr;
983
984 while ((start_ptr / sizeof(unsigned int)) != rb->wptr) {
985 if (inc)
986 start_ptr = adreno_ringbuffer_inc_wrapped(start_ptr,
987 size);
988 else
989 start_ptr = adreno_ringbuffer_dec_wrapped(start_ptr,
990 size);
991 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, start_ptr);
992 if (KGSL_CMD_IDENTIFIER == val1) {
993 if ((start_ptr / sizeof(unsigned int)) != rb->wptr)
994 start_ptr = adreno_ringbuffer_dec_wrapped(
995 start_ptr, size);
996 *ptr = start_ptr;
997 status = 0;
998 break;
999 }
1000 }
1001 return status;
1002}
1003
1004static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb,
1005 unsigned int *rb_rptr,
1006 unsigned int global_eop,
1007 bool inc)
1008{
1009 int status = -EINVAL;
1010 unsigned int temp_rb_rptr = *rb_rptr;
1011 unsigned int size = rb->buffer_desc.size;
1012 unsigned int val[3];
1013 int i = 0;
1014 bool check = false;
1015
1016 if (inc && temp_rb_rptr / sizeof(unsigned int) != rb->wptr)
1017 return status;
1018
1019 do {
1020 /* when decrementing we need to decrement first and
1021 * then read make sure we cover all the data */
1022 if (!inc)
1023 temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
1024 temp_rb_rptr, size);
1025 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i],
1026 temp_rb_rptr);
1027
1028 if (check && ((inc && val[i] == global_eop) ||
1029 (!inc && (val[i] ==
1030 cp_type3_packet(CP_MEM_WRITE, 2) ||
1031 val[i] == CACHE_FLUSH_TS)))) {
1032 /* decrement i, i.e i = (i - 1 + 3) % 3 if
1033 * we are going forward, else increment i */
1034 i = (i + 2) % 3;
1035 if (val[i] == rb->device->memstore.gpuaddr +
1036 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
1037 eoptimestamp)) {
1038 int j = ((i + 2) % 3);
1039 if ((inc && (val[j] == CACHE_FLUSH_TS ||
1040 val[j] == cp_type3_packet(
1041 CP_MEM_WRITE, 2))) ||
1042 (!inc && val[j] == global_eop)) {
1043 /* Found the global eop */
1044 status = 0;
1045 break;
1046 }
1047 }
1048 /* if no match found then increment i again
1049 * since we decremented before matching */
1050 i = (i + 1) % 3;
1051 }
1052 if (inc)
1053 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(
1054 temp_rb_rptr, size);
1055
1056 i = (i + 1) % 3;
1057 if (2 == i)
1058 check = true;
1059 } while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr);
Shubhraprakash Das6f6ecb32012-06-13 12:17:11 -06001060 /* temp_rb_rptr points to the command stream after global eop,
1061 * move backward till the start of command sequence */
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001062 if (!status) {
Shubhraprakash Das6f6ecb32012-06-13 12:17:11 -06001063 status = _find_start_of_cmd_seq(rb, &temp_rb_rptr, false);
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001064 if (!status) {
1065 *rb_rptr = temp_rb_rptr;
1066 KGSL_DRV_ERR(rb->device,
1067 "Offset of cmd sequence after eop timestamp: 0x%x\n",
1068 temp_rb_rptr / sizeof(unsigned int));
1069 }
1070 }
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001071 if (status)
1072 KGSL_DRV_ERR(rb->device,
1073 "Failed to find the command sequence after eop timestamp\n");
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001074 return status;
1075}
1076
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001077static int _find_hanging_ib_sequence(struct adreno_ringbuffer *rb,
1078 unsigned int *rb_rptr,
1079 unsigned int ib1)
1080{
1081 int status = -EINVAL;
1082 unsigned int temp_rb_rptr = *rb_rptr;
1083 unsigned int size = rb->buffer_desc.size;
1084 unsigned int val[2];
1085 int i = 0;
1086 bool check = false;
1087 bool ctx_switch = false;
1088
1089 while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
1090 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
1091
1092 if (check && val[i] == ib1) {
1093 /* decrement i, i.e i = (i - 1 + 2) % 2 */
1094 i = (i + 1) % 2;
1095 if (adreno_cmd_is_ib(val[i])) {
1096 /* go till start of command sequence */
1097 status = _find_start_of_cmd_seq(rb,
1098 &temp_rb_rptr, false);
1099 KGSL_DRV_ERR(rb->device,
1100 "Found the hanging IB at offset 0x%x\n",
1101 temp_rb_rptr / sizeof(unsigned int));
1102 break;
1103 }
1104 /* if no match the increment i since we decremented
1105 * before checking */
1106 i = (i + 1) % 2;
1107 }
1108 /* Make sure you do not encounter a context switch twice, we can
1109 * encounter it once for the bad context as the start of search
1110 * can point to the context switch */
1111 if (val[i] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
1112 if (ctx_switch) {
1113 KGSL_DRV_ERR(rb->device,
1114 "Context switch encountered before bad "
1115 "IB found\n");
1116 break;
1117 }
1118 ctx_switch = true;
1119 }
1120 i = (i + 1) % 2;
1121 if (1 == i)
1122 check = true;
1123 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
1124 size);
1125 }
1126 if (!status)
1127 *rb_rptr = temp_rb_rptr;
1128 return status;
1129}
1130
1131static void _turn_preamble_on_for_ib_seq(struct adreno_ringbuffer *rb,
1132 unsigned int rb_rptr)
1133{
1134 unsigned int temp_rb_rptr = rb_rptr;
1135 unsigned int size = rb->buffer_desc.size;
1136 unsigned int val[2];
1137 int i = 0;
1138 bool check = false;
1139 bool cmd_start = false;
1140
1141 /* Go till the start of the ib sequence and turn on preamble */
1142 while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
1143 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
1144 if (check && KGSL_START_OF_IB_IDENTIFIER == val[i]) {
1145 /* decrement i */
1146 i = (i + 1) % 2;
1147 if (val[i] == cp_nop_packet(4)) {
1148 temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
1149 temp_rb_rptr, size);
1150 kgsl_sharedmem_writel(&rb->buffer_desc,
1151 temp_rb_rptr, cp_nop_packet(1));
1152 }
1153 KGSL_DRV_ERR(rb->device,
1154 "Turned preamble on at offset 0x%x\n",
1155 temp_rb_rptr / 4);
1156 break;
1157 }
1158 /* If you reach beginning of next command sequence then exit
1159 * First command encountered is the current one so don't break
1160 * on that. */
1161 if (KGSL_CMD_IDENTIFIER == val[i]) {
1162 if (cmd_start)
1163 break;
1164 cmd_start = true;
1165 }
1166
1167 i = (i + 1) % 2;
1168 if (1 == i)
1169 check = true;
1170 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
1171 size);
1172 }
1173}
1174
Shubhraprakash Das1d577fe2012-05-31 18:28:22 -06001175static void _copy_valid_rb_content(struct adreno_ringbuffer *rb,
1176 unsigned int rb_rptr, unsigned int *temp_rb_buffer,
1177 int *rb_size, unsigned int *bad_rb_buffer,
1178 int *bad_rb_size,
1179 int *last_valid_ctx_id)
1180{
1181 unsigned int good_rb_idx = 0, cmd_start_idx = 0;
1182 unsigned int val1 = 0;
1183 struct kgsl_context *k_ctxt;
1184 struct adreno_context *a_ctxt;
1185 unsigned int bad_rb_idx = 0;
1186 int copy_rb_contents = 0;
1187 unsigned int temp_rb_rptr;
1188 unsigned int size = rb->buffer_desc.size;
1189 unsigned int good_cmd_start_idx = 0;
1190
1191 /* Walk the rb from the context switch. Omit any commands
1192 * for an invalid context. */
1193 while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
1194 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
1195
1196 if (KGSL_CMD_IDENTIFIER == val1) {
1197 /* Start is the NOP dword that comes before
1198 * KGSL_CMD_IDENTIFIER */
1199 cmd_start_idx = bad_rb_idx - 1;
1200 if (copy_rb_contents)
1201 good_cmd_start_idx = good_rb_idx - 1;
1202 }
1203
1204 /* check for context switch indicator */
1205 if (val1 == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
1206 unsigned int temp_idx, val2;
1207 /* increment by 3 to get to the context_id */
1208 temp_rb_rptr = rb_rptr + (3 * sizeof(unsigned int)) %
1209 size;
1210 kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
1211 temp_rb_rptr);
1212
1213 /* if context switches to a context that did not cause
1214 * hang then start saving the rb contents as those
1215 * commands can be executed */
1216 k_ctxt = idr_find(&rb->device->context_idr, val2);
1217 if (k_ctxt) {
1218 a_ctxt = k_ctxt->devctxt;
1219
1220 /* If we are changing to a good context and were not
1221 * copying commands then copy over commands to the good
1222 * context */
1223 if (!copy_rb_contents && ((k_ctxt &&
1224 !(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
1225 !k_ctxt)) {
1226 for (temp_idx = cmd_start_idx;
1227 temp_idx < bad_rb_idx;
1228 temp_idx++)
1229 temp_rb_buffer[good_rb_idx++] =
1230 bad_rb_buffer[temp_idx];
1231 *last_valid_ctx_id = val2;
1232 copy_rb_contents = 1;
1233 } else if (copy_rb_contents && k_ctxt &&
1234 (a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
1235 /* If we are changing to bad context then remove
1236 * the dwords we copied for this sequence from
1237 * the good buffer */
1238 good_rb_idx = good_cmd_start_idx;
1239 copy_rb_contents = 0;
1240 }
1241 }
1242 }
1243
1244 if (copy_rb_contents)
1245 temp_rb_buffer[good_rb_idx++] = val1;
1246 /* Copy both good and bad commands for replay to the bad
1247 * buffer */
1248 bad_rb_buffer[bad_rb_idx++] = val1;
1249
1250 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
1251 }
1252 *rb_size = good_rb_idx;
1253 *bad_rb_size = bad_rb_idx;
1254}
1255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
Shubhraprakash Dasba6c70b2012-05-31 02:53:06 -06001257 struct adreno_recovery_data *rec_data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258{
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001259 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 struct kgsl_device *device = rb->device;
Shubhraprakash Dasadb16022012-05-31 16:19:37 -06001261 unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001262 struct kgsl_context *context;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001263 struct adreno_context *adreno_context;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264
Shubhraprakash Dasadb16022012-05-31 16:19:37 -06001265 context = idr_find(&device->context_idr, rec_data->context_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266
Shubhraprakash Das6f6ecb32012-06-13 12:17:11 -06001267 /* Look for the command stream that is right after the global eop */
1268 status = _find_cmd_seq_after_eop_ts(rb, &rb_rptr,
1269 rec_data->global_eop + 1, false);
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001270 if (status)
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001271 goto done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001273 if (context) {
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001274 adreno_context = context->devctxt;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001275
1276 if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
1277 if (rec_data->ib1) {
1278 status = _find_hanging_ib_sequence(rb, &rb_rptr,
1279 rec_data->ib1);
1280 if (status)
1281 goto copy_rb_contents;
1282 }
1283 _turn_preamble_on_for_ib_seq(rb, rb_rptr);
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001284 } else {
1285 status = -EINVAL;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001286 }
1287 }
1288
1289copy_rb_contents:
Shubhraprakash Das1d577fe2012-05-31 18:28:22 -06001290 _copy_valid_rb_content(rb, rb_rptr, rec_data->rb_buffer,
1291 &rec_data->rb_size,
1292 rec_data->bad_rb_buffer,
1293 &rec_data->bad_rb_size,
1294 &rec_data->last_valid_ctx_id);
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001295 /* If we failed to get the hanging IB sequence then we cannot execute
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001296 * commands from the bad context or preambles not supported */
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001297 if (status) {
1298 rec_data->bad_rb_size = 0;
1299 status = 0;
1300 }
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001301 /* If there is no context then that means there are no commands for
1302 * good case */
1303 if (!context)
1304 rec_data->rb_size = 0;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001305done:
1306 return status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307}
1308
1309void
1310adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
1311 int num_rb_contents)
1312{
1313 int i;
1314 unsigned int *ringcmds;
1315 unsigned int rcmd_gpu;
1316
1317 if (!num_rb_contents)
1318 return;
1319
1320 if (num_rb_contents > (rb->buffer_desc.size - rb->wptr)) {
1321 adreno_regwrite(rb->device, REG_CP_RB_RPTR, 0);
1322 rb->rptr = 0;
1323 BUG_ON(num_rb_contents > rb->buffer_desc.size);
1324 }
1325 ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
1326 rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
1327 for (i = 0; i < num_rb_contents; i++)
1328 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb_buff[i]);
1329 rb->wptr += num_rb_contents;
1330 adreno_ringbuffer_submit(rb);
1331}