blob: 73b45134278fbd0f2b133f71b849c031b9c297d6 [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;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059
60 /* if wptr ahead, fill the remaining with NOPs */
61 if (wptr_ahead) {
62 /* -1 for header */
63 nopcount = rb->sizedwords - rb->wptr - 1;
64
65 cmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
66 cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*rb->wptr;
67
Jordan Crouse084427d2011-07-28 08:37:58 -060068 GSL_RB_WRITE(cmds, cmds_gpu, cp_nop_packet(nopcount));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070069
70 /* Make sure that rptr is not 0 before submitting
71 * commands at the end of ringbuffer. We do not
72 * want the rptr and wptr to become equal when
73 * the ringbuffer is not empty */
74 do {
75 GSL_RB_GET_READPTR(rb, &rb->rptr);
76 } while (!rb->rptr);
77
78 rb->wptr++;
79
80 adreno_ringbuffer_submit(rb);
81
82 rb->wptr = 0;
83 }
84
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060085 wait_time = jiffies + wait_timeout;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086 /* wait for space in ringbuffer */
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060087 while (1) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088 GSL_RB_GET_READPTR(rb, &rb->rptr);
89
90 freecmds = rb->rptr - rb->wptr;
91
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060092 if (freecmds == 0 || freecmds > numcmds)
93 break;
94
95 if (time_after(jiffies, wait_time)) {
96 KGSL_DRV_ERR(rb->device,
97 "Timed out while waiting for freespace in ringbuffer "
98 "rptr: 0x%x, wptr: 0x%x\n", rb->rptr, rb->wptr);
99 if (!adreno_dump_and_recover(rb->device))
100 wait_time = jiffies + wait_timeout;
101 else
102 /* GPU is hung and we cannot recover */
103 BUG();
104 }
105 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106}
107
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700108unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 unsigned int numcmds)
110{
111 unsigned int *ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112
113 BUG_ON(numcmds >= rb->sizedwords);
114
115 GSL_RB_GET_READPTR(rb, &rb->rptr);
116 /* check for available space */
117 if (rb->wptr >= rb->rptr) {
118 /* wptr ahead or equal to rptr */
119 /* reserve dwords for nop packet */
120 if ((rb->wptr + numcmds) > (rb->sizedwords -
121 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600122 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123 } else {
124 /* wptr behind rptr */
125 if ((rb->wptr + numcmds) >= rb->rptr)
Carter Cooper6dd94c82011-10-13 14:43:53 -0600126 adreno_ringbuffer_waitspace(rb, numcmds, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 /* check for remaining space */
128 /* reserve dwords for nop packet */
129 if ((rb->wptr + numcmds) > (rb->sizedwords -
130 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600131 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 }
133
Carter Cooper6dd94c82011-10-13 14:43:53 -0600134 ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
135 rb->wptr += numcmds;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136
137 return ptr;
138}
139
140static int _load_firmware(struct kgsl_device *device, const char *fwfile,
141 void **data, int *len)
142{
143 const struct firmware *fw = NULL;
144 int ret;
145
146 ret = request_firmware(&fw, fwfile, device->dev);
147
148 if (ret) {
149 KGSL_DRV_ERR(device, "request_firmware(%s) failed: %d\n",
150 fwfile, ret);
151 return ret;
152 }
153
154 *data = kmalloc(fw->size, GFP_KERNEL);
155
156 if (*data) {
157 memcpy(*data, fw->data, fw->size);
158 *len = fw->size;
159 } else
160 KGSL_MEM_ERR(device, "kmalloc(%d) failed\n", fw->size);
161
162 release_firmware(fw);
163 return (*data != NULL) ? 0 : -ENOMEM;
164}
165
166static int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
167{
168 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700169 int i, ret = 0;
170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171 if (adreno_dev->pm4_fw == NULL) {
172 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600173 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174
Jordan Crouse505df9c2011-07-28 08:37:59 -0600175 ret = _load_firmware(device, adreno_dev->pm4_fwfile,
176 &ptr, &len);
177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178 if (ret)
179 goto err;
180
181 /* PM4 size is 3 dword aligned plus 1 dword of version */
182 if (len % ((sizeof(uint32_t) * 3)) != sizeof(uint32_t)) {
183 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
184 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600185 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186 goto err;
187 }
188
189 adreno_dev->pm4_fw_size = len / sizeof(uint32_t);
190 adreno_dev->pm4_fw = ptr;
191 }
192
193 KGSL_DRV_INFO(device, "loading pm4 ucode version: %d\n",
194 adreno_dev->pm4_fw[0]);
195
196 adreno_regwrite(device, REG_CP_DEBUG, 0x02000000);
197 adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
198 for (i = 1; i < adreno_dev->pm4_fw_size; i++)
199 adreno_regwrite(device, REG_CP_ME_RAM_DATA,
200 adreno_dev->pm4_fw[i]);
201err:
202 return ret;
203}
204
205static int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
206{
207 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 int i, ret = 0;
209
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210 if (adreno_dev->pfp_fw == NULL) {
211 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600212 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213
Jordan Crouse505df9c2011-07-28 08:37:59 -0600214 ret = _load_firmware(device, adreno_dev->pfp_fwfile,
215 &ptr, &len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216 if (ret)
217 goto err;
218
219 /* PFP size shold be dword aligned */
220 if (len % sizeof(uint32_t) != 0) {
221 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
222 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600223 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700224 goto err;
225 }
226
227 adreno_dev->pfp_fw_size = len / sizeof(uint32_t);
228 adreno_dev->pfp_fw = ptr;
229 }
230
231 KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
232 adreno_dev->pfp_fw[0]);
233
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700234 adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 for (i = 1; i < adreno_dev->pfp_fw_size; i++)
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700236 adreno_regwrite(device,
237 adreno_dev->gpudev->reg_cp_pfp_ucode_data,
238 adreno_dev->pfp_fw[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239err:
240 return ret;
241}
242
243int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
244{
245 int status;
246 /*cp_rb_cntl_u cp_rb_cntl; */
247 union reg_cp_rb_cntl cp_rb_cntl;
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700248 unsigned int rb_cntl;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 struct kgsl_device *device = rb->device;
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700250 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251
252 if (rb->flags & KGSL_FLAGS_STARTED)
253 return 0;
254
Carter Coopercb3e8eb2012-04-11 09:39:40 -0600255 if (init_ram)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700256 rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257
258 kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
259 sizeof(struct kgsl_rbmemptrs));
260
261 kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
262 (rb->sizedwords << 2));
263
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700264 if (adreno_is_a2xx(adreno_dev)) {
265 adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
266 (rb->memptrs_desc.gpuaddr
267 + GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700269 /* setup WPTR delay */
270 adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
271 0 /*0x70000010 */);
272 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273
274 /*setup REG_CP_RB_CNTL */
275 adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
276 cp_rb_cntl.val = rb_cntl;
277
278 /*
279 * The size of the ringbuffer in the hardware is the log2
280 * representation of the size in quadwords (sizedwords / 2)
281 */
282 cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);
283
284 /*
285 * Specify the quadwords to read before updating mem RPTR.
286 * Like above, pass the log2 representation of the blocksize
287 * in quadwords.
288 */
289 cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);
290
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700291 if (adreno_is_a2xx(adreno_dev)) {
292 /* WPTR polling */
293 cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
294 }
295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296 /* mem RPTR writebacks */
297 cp_rb_cntl.f.rb_no_update = GSL_RB_CNTL_NO_UPDATE;
298
299 adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);
300
301 adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);
302
303 adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
304 rb->memptrs_desc.gpuaddr +
305 GSL_RB_MEMPTRS_RPTR_OFFSET);
306
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700307 if (adreno_is_a3xx(adreno_dev)) {
308 /* enable access protection to privileged registers */
309 adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);
310
311 /* RBBM registers */
312 adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
313 adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
314 adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
315 adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
316 adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
317 adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);
318
319 /* CP registers */
320 adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
321 adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
322 adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
323 adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
324 adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);
325
326 /* RB registers */
327 adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
328
329 /* VBIF registers */
330 adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
331 }
332
333 if (adreno_is_a2xx(adreno_dev)) {
334 /* explicitly clear all cp interrupts */
335 adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
336 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337
338 /* setup scratch/timestamp */
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700339 adreno_regwrite(device, REG_SCRATCH_ADDR, device->memstore.gpuaddr +
340 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
341 soptimestamp));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342
343 adreno_regwrite(device, REG_SCRATCH_UMSK,
344 GSL_RB_MEMPTRS_SCRATCH_MASK);
345
346 /* load the CP ucode */
347
348 status = adreno_ringbuffer_load_pm4_ucode(device);
349 if (status != 0)
350 return status;
351
352 /* load the prefetch parser ucode */
353 status = adreno_ringbuffer_load_pfp_ucode(device);
354 if (status != 0)
355 return status;
356
Kevin Matlageff806df2012-05-07 18:13:21 -0600357 /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
Kevin Matlagee8d35862012-04-26 12:58:15 -0600358 if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
Kevin Matlageff806df2012-05-07 18:13:21 -0600359 adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360
361 rb->rptr = 0;
362 rb->wptr = 0;
363
364 /* clear ME_HALT to start micro engine */
365 adreno_regwrite(device, REG_CP_ME_CNTL, 0);
366
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700367 /* ME init is GPU specific, so jump into the sub-function */
368 adreno_dev->gpudev->rb_init(adreno_dev, rb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369
370 /* idle device to validate ME INIT */
371 status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
372
373 if (status == 0)
374 rb->flags |= KGSL_FLAGS_STARTED;
375
376 return status;
377}
378
Carter Cooper6dd94c82011-10-13 14:43:53 -0600379void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380{
381 if (rb->flags & KGSL_FLAGS_STARTED) {
382 /* ME_HALT */
383 adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 rb->flags &= ~KGSL_FLAGS_STARTED;
385 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386}
387
388int adreno_ringbuffer_init(struct kgsl_device *device)
389{
390 int status;
391 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
392 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
393
394 rb->device = device;
395 /*
396 * It is silly to convert this to words and then back to bytes
397 * immediately below, but most of the rest of the code deals
398 * in words, so we might as well only do the math once
399 */
400 rb->sizedwords = KGSL_RB_SIZE >> 2;
401
402 /* allocate memory for ringbuffer */
403 status = kgsl_allocate_contiguous(&rb->buffer_desc,
404 (rb->sizedwords << 2));
405
406 if (status != 0) {
407 adreno_ringbuffer_close(rb);
408 return status;
409 }
410
411 /* allocate memory for polling and timestamps */
412 /* This really can be at 4 byte alignment boundry but for using MMU
413 * we need to make it at page boundary */
414 status = kgsl_allocate_contiguous(&rb->memptrs_desc,
415 sizeof(struct kgsl_rbmemptrs));
416
417 if (status != 0) {
418 adreno_ringbuffer_close(rb);
419 return status;
420 }
421
422 /* overlay structure on memptrs memory */
423 rb->memptrs = (struct kgsl_rbmemptrs *) rb->memptrs_desc.hostptr;
424
425 return 0;
426}
427
Carter Cooper6dd94c82011-10-13 14:43:53 -0600428void adreno_ringbuffer_close(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429{
430 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
431
432 kgsl_sharedmem_free(&rb->buffer_desc);
433 kgsl_sharedmem_free(&rb->memptrs_desc);
434
435 kfree(adreno_dev->pfp_fw);
436 kfree(adreno_dev->pm4_fw);
437
438 adreno_dev->pfp_fw = NULL;
439 adreno_dev->pm4_fw = NULL;
440
441 memset(rb, 0, sizeof(struct adreno_ringbuffer));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442}
443
444static uint32_t
445adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700446 struct adreno_context *context,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 unsigned int flags, unsigned int *cmds,
448 int sizedwords)
449{
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700450 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451 unsigned int *ringcmds;
452 unsigned int timestamp;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700453 unsigned int total_sizedwords = sizedwords;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 unsigned int i;
455 unsigned int rcmd_gpu;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700456 unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
457 unsigned int gpuaddr = rb->device->memstore.gpuaddr;
458
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600459 /*
460 * if the context was not created with per context timestamp
461 * support, we must use the global timestamp since issueibcmds
462 * will be returning that one.
463 */
464 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
465 context_id = context->id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466
467 /* reserve space to temporarily turn off protected mode
468 * error checking if needed
469 */
470 total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
Zhoulu Luo552905e2012-06-21 15:21:52 -0700471 total_sizedwords += !(flags & KGSL_CMD_FLAGS_NO_TS_CMP) ? 7 : 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472 total_sizedwords += !(flags & KGSL_CMD_FLAGS_NOT_KERNEL_CMD) ? 2 : 0;
473
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700474 if (adreno_is_a3xx(adreno_dev))
475 total_sizedwords += 7;
476
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700477 total_sizedwords += 2; /* scratchpad ts for recovery */
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600478 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700479 total_sizedwords += 3; /* sop timestamp */
480 total_sizedwords += 4; /* eop timestamp */
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530481 total_sizedwords += 3; /* global timestamp without cache
482 * flush for non-zero context */
483 } else {
484 total_sizedwords += 4; /* global timestamp for recovery*/
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700485 }
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600488 /* GPU may hang during space allocation, if thats the case the current
489 * context may have hung the GPU */
490 if (context->flags & CTXT_FLAGS_GPU_HANG) {
491 KGSL_CTXT_WARN(rb->device,
492 "Context %p caused a gpu hang. Will not accept commands for context %d\n",
493 context, context->id);
494 return rb->timestamp[context_id];
495 }
496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 rcmd_gpu = rb->buffer_desc.gpuaddr
498 + sizeof(uint)*(rb->wptr-total_sizedwords);
499
500 if (!(flags & KGSL_CMD_FLAGS_NOT_KERNEL_CMD)) {
Jordan Crouse084427d2011-07-28 08:37:58 -0600501 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
503 }
504 if (flags & KGSL_CMD_FLAGS_PMODE) {
505 /* disable protected mode error checking */
506 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600507 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
509 }
510
511 for (i = 0; i < sizedwords; i++) {
512 GSL_RB_WRITE(ringcmds, rcmd_gpu, *cmds);
513 cmds++;
514 }
515
516 if (flags & KGSL_CMD_FLAGS_PMODE) {
517 /* re-enable protected mode error checking */
518 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600519 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700520 GSL_RB_WRITE(ringcmds, rcmd_gpu, 1);
521 }
522
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700523 /* always increment the global timestamp. once. */
524 rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
Zhoulu Luo552905e2012-06-21 15:21:52 -0700525 if (context) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700526 if (context_id == KGSL_MEMSTORE_GLOBAL)
Zhoulu Luo552905e2012-06-21 15:21:52 -0700527 rb->timestamp[context_id] =
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700528 rb->timestamp[KGSL_MEMSTORE_GLOBAL];
529 else
530 rb->timestamp[context_id]++;
531 }
532 timestamp = rb->timestamp[context_id];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700534 /* scratchpad ts for recovery */
Jordan Crouse084427d2011-07-28 08:37:58 -0600535 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700536 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700537
538 if (adreno_is_a3xx(adreno_dev)) {
539 /*
540 * FLush HLSQ lazy updates to make sure there are no
541 * rsources pending for indirect loads after the timestamp
542 */
543
544 GSL_RB_WRITE(ringcmds, rcmd_gpu,
545 cp_type3_packet(CP_EVENT_WRITE, 1));
546 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x07); /* HLSQ_FLUSH */
547 GSL_RB_WRITE(ringcmds, rcmd_gpu,
548 cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
549 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
550 }
551
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600552 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700553 /* start-of-pipeline timestamp */
554 GSL_RB_WRITE(ringcmds, rcmd_gpu,
555 cp_type3_packet(CP_MEM_WRITE, 2));
556 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Zhoulu Luo552905e2012-06-21 15:21:52 -0700557 KGSL_MEMSTORE_OFFSET(context->id, soptimestamp)));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700558 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
559
560 /* end-of-pipeline timestamp */
561 GSL_RB_WRITE(ringcmds, rcmd_gpu,
562 cp_type3_packet(CP_EVENT_WRITE, 3));
563 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
564 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Zhoulu Luo552905e2012-06-21 15:21:52 -0700565 KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp)));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700566 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700567
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530568 GSL_RB_WRITE(ringcmds, rcmd_gpu,
569 cp_type3_packet(CP_MEM_WRITE, 2));
570 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Zhoulu Luo552905e2012-06-21 15:21:52 -0700571 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
572 eoptimestamp)));
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530573 GSL_RB_WRITE(ringcmds, rcmd_gpu,
574 rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
575 } else {
576 GSL_RB_WRITE(ringcmds, rcmd_gpu,
577 cp_type3_packet(CP_EVENT_WRITE, 3));
578 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
579 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Zhoulu Luo552905e2012-06-21 15:21:52 -0700580 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
581 eoptimestamp)));
582 GSL_RB_WRITE(ringcmds, rcmd_gpu,
583 rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530584 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585
Zhoulu Luo552905e2012-06-21 15:21:52 -0700586 if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 /* Conditional execution based on memory values */
588 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600589 cp_type3_packet(CP_COND_EXEC, 4));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700590 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
591 KGSL_MEMSTORE_OFFSET(
592 context_id, ts_cmp_enable)) >> 2);
593 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
594 KGSL_MEMSTORE_OFFSET(
595 context_id, ref_wait_ts)) >> 2);
596 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597 /* # of conditional command DWORDs */
598 GSL_RB_WRITE(ringcmds, rcmd_gpu, 2);
599 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600600 cp_type3_packet(CP_INTERRUPT, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601 GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
602 }
603
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700604 if (adreno_is_a3xx(adreno_dev)) {
605 /* Dummy set-constant to trigger context rollover */
606 GSL_RB_WRITE(ringcmds, rcmd_gpu,
607 cp_type3_packet(CP_SET_CONSTANT, 2));
608 GSL_RB_WRITE(ringcmds, rcmd_gpu,
609 (0x4<<16)|(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG - 0x2000));
610 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
611 }
612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700613 adreno_ringbuffer_submit(rb);
614
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615 return timestamp;
616}
617
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600618unsigned int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619adreno_ringbuffer_issuecmds(struct kgsl_device *device,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600620 struct adreno_context *drawctxt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 unsigned int flags,
622 unsigned int *cmds,
623 int sizedwords)
624{
625 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
626 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
627
628 if (device->state & KGSL_STATE_HUNG)
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600629 return kgsl_readtimestamp(device, KGSL_MEMSTORE_GLOBAL,
630 KGSL_TIMESTAMP_RETIRED);
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600631 return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds, sizedwords);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632}
633
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -0600634static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
635 int sizedwords);
636
637static bool
638_handle_type3(struct kgsl_device_private *dev_priv, uint *hostaddr)
639{
640 unsigned int opcode = cp_type3_opcode(*hostaddr);
641 switch (opcode) {
642 case CP_INDIRECT_BUFFER_PFD:
643 case CP_INDIRECT_BUFFER_PFE:
644 case CP_COND_INDIRECT_BUFFER_PFE:
645 case CP_COND_INDIRECT_BUFFER_PFD:
646 return _parse_ibs(dev_priv, hostaddr[1], hostaddr[2]);
647 case CP_NOP:
648 case CP_WAIT_FOR_IDLE:
649 case CP_WAIT_REG_MEM:
650 case CP_WAIT_REG_EQ:
651 case CP_WAT_REG_GTE:
652 case CP_WAIT_UNTIL_READ:
653 case CP_WAIT_IB_PFD_COMPLETE:
654 case CP_REG_RMW:
655 case CP_REG_TO_MEM:
656 case CP_MEM_WRITE:
657 case CP_MEM_WRITE_CNTR:
658 case CP_COND_EXEC:
659 case CP_COND_WRITE:
660 case CP_EVENT_WRITE:
661 case CP_EVENT_WRITE_SHD:
662 case CP_EVENT_WRITE_CFL:
663 case CP_EVENT_WRITE_ZPD:
664 case CP_DRAW_INDX:
665 case CP_DRAW_INDX_2:
666 case CP_DRAW_INDX_BIN:
667 case CP_DRAW_INDX_2_BIN:
668 case CP_VIZ_QUERY:
669 case CP_SET_STATE:
670 case CP_SET_CONSTANT:
671 case CP_IM_LOAD:
672 case CP_IM_LOAD_IMMEDIATE:
673 case CP_LOAD_CONSTANT_CONTEXT:
674 case CP_INVALIDATE_STATE:
675 case CP_SET_SHADER_BASES:
676 case CP_SET_BIN_MASK:
677 case CP_SET_BIN_SELECT:
678 case CP_SET_BIN_BASE_OFFSET:
679 case CP_SET_BIN_DATA:
680 case CP_CONTEXT_UPDATE:
681 case CP_INTERRUPT:
682 case CP_IM_STORE:
683 case CP_LOAD_STATE:
684 break;
685 /* these shouldn't come from userspace */
686 case CP_ME_INIT:
687 case CP_SET_PROTECTED_MODE:
688 default:
689 KGSL_CMD_ERR(dev_priv->device, "bad CP opcode %0x\n", opcode);
690 return false;
691 break;
692 }
693
694 return true;
695}
696
697static bool
698_handle_type0(struct kgsl_device_private *dev_priv, uint *hostaddr)
699{
700 unsigned int reg = type0_pkt_offset(*hostaddr);
701 unsigned int cnt = type0_pkt_size(*hostaddr);
702 if (reg < 0x0192 || (reg + cnt) >= 0x8000) {
703 KGSL_CMD_ERR(dev_priv->device, "bad type0 reg: 0x%0x cnt: %d\n",
704 reg, cnt);
705 return false;
706 }
707 return true;
708}
709
710/*
711 * Traverse IBs and dump them to test vector. Detect swap by inspecting
712 * register writes, keeping note of the current state, and dump
713 * framebuffer config to test vector
714 */
715static bool _parse_ibs(struct kgsl_device_private *dev_priv,
716 uint gpuaddr, int sizedwords)
717{
718 static uint level; /* recursion level */
719 bool ret = false;
720 uint *hostaddr, *hoststart;
721 int dwords_left = sizedwords; /* dwords left in the current command
722 buffer */
723 struct kgsl_mem_entry *entry;
724
725 spin_lock(&dev_priv->process_priv->mem_lock);
726 entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
727 gpuaddr, sizedwords * sizeof(uint));
728 spin_unlock(&dev_priv->process_priv->mem_lock);
729 if (entry == NULL) {
730 KGSL_CMD_ERR(dev_priv->device,
731 "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
732 return false;
733 }
734
735 hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(&entry->memdesc, gpuaddr);
736 if (hostaddr == NULL) {
737 KGSL_CMD_ERR(dev_priv->device,
738 "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
739 return false;
740 }
741
742 hoststart = hostaddr;
743
744 level++;
745
746 KGSL_CMD_INFO(dev_priv->device, "ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
747 gpuaddr, sizedwords, hostaddr);
748
749 mb();
750 while (dwords_left > 0) {
751 bool cur_ret = true;
752 int count = 0; /* dword count including packet header */
753
754 switch (*hostaddr >> 30) {
755 case 0x0: /* type-0 */
756 count = (*hostaddr >> 16)+2;
757 cur_ret = _handle_type0(dev_priv, hostaddr);
758 break;
759 case 0x1: /* type-1 */
760 count = 2;
761 break;
762 case 0x3: /* type-3 */
763 count = ((*hostaddr >> 16) & 0x3fff) + 2;
764 cur_ret = _handle_type3(dev_priv, hostaddr);
765 break;
766 default:
767 KGSL_CMD_ERR(dev_priv->device, "unexpected type: "
768 "type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
769 *hostaddr >> 30, *hostaddr, hostaddr,
770 gpuaddr+4*(sizedwords-dwords_left));
771 cur_ret = false;
772 count = dwords_left;
773 break;
774 }
775
776 if (!cur_ret) {
777 KGSL_CMD_ERR(dev_priv->device,
778 "bad sub-type: #:%d/%d, v:0x%08x"
779 " @ 0x%p[gb:0x%08x], level:%d\n",
780 sizedwords-dwords_left, sizedwords, *hostaddr,
781 hostaddr, gpuaddr+4*(sizedwords-dwords_left),
782 level);
783
784 if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
785 >= 2)
786 print_hex_dump(KERN_ERR,
787 level == 1 ? "IB1:" : "IB2:",
788 DUMP_PREFIX_OFFSET, 32, 4, hoststart,
789 sizedwords*4, 0);
790 goto done;
791 }
792
793 /* jump to next packet */
794 dwords_left -= count;
795 hostaddr += count;
796 if (dwords_left < 0) {
797 KGSL_CMD_ERR(dev_priv->device,
798 "bad count: c:%d, #:%d/%d, "
799 "v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
800 count, sizedwords-(dwords_left+count),
801 sizedwords, *(hostaddr-count), hostaddr-count,
802 gpuaddr+4*(sizedwords-(dwords_left+count)),
803 level);
804 if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
805 >= 2)
806 print_hex_dump(KERN_ERR,
807 level == 1 ? "IB1:" : "IB2:",
808 DUMP_PREFIX_OFFSET, 32, 4, hoststart,
809 sizedwords*4, 0);
810 goto done;
811 }
812 }
813
814 ret = true;
815done:
816 if (!ret)
817 KGSL_DRV_ERR(dev_priv->device,
818 "parsing failed: gpuaddr:0x%08x, "
819 "host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
820
821 level--;
822
823 return ret;
824}
825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826int
827adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
828 struct kgsl_context *context,
829 struct kgsl_ibdesc *ibdesc,
830 unsigned int numibs,
831 uint32_t *timestamp,
832 unsigned int flags)
833{
834 struct kgsl_device *device = dev_priv->device;
835 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
836 unsigned int *link;
837 unsigned int *cmds;
838 unsigned int i;
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600839 struct adreno_context *drawctxt;
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700840 unsigned int start_index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700841
842 if (device->state & KGSL_STATE_HUNG)
843 return -EBUSY;
844 if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) ||
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600845 context == NULL || ibdesc == 0 || numibs == 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700846 return -EINVAL;
847
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600848 drawctxt = context->devctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700849
850 if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
851 KGSL_CTXT_WARN(device, "Context %p caused a gpu hang.."
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700852 " will not accept commands for context %d\n",
853 drawctxt, drawctxt->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700854 return -EDEADLK;
855 }
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600856
857 cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
858 GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700859 if (!link) {
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600860 KGSL_CORE_ERR("kzalloc(%d) failed\n",
861 sizeof(unsigned int) * (numibs * 3 + 4));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862 return -ENOMEM;
863 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700864
865 /*When preamble is enabled, the preamble buffer with state restoration
866 commands are stored in the first node of the IB chain. We can skip that
867 if a context switch hasn't occured */
868
869 if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
870 adreno_dev->drawctxt_active == drawctxt)
871 start_index = 1;
872
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600873 if (!start_index) {
874 *cmds++ = cp_nop_packet(1);
875 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
876 } else {
877 *cmds++ = cp_nop_packet(4);
878 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
879 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
880 *cmds++ = ibdesc[0].gpuaddr;
881 *cmds++ = ibdesc[0].sizedwords;
882 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700883 for (i = start_index; i < numibs; i++) {
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -0600884 if (unlikely(adreno_dev->ib_check_level >= 1 &&
885 !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
886 ibdesc[i].sizedwords))) {
887 kfree(link);
888 return -EINVAL;
889 }
Jordan Crouse084427d2011-07-28 08:37:58 -0600890 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891 *cmds++ = ibdesc[i].gpuaddr;
892 *cmds++ = ibdesc[i].sizedwords;
893 }
894
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600895 *cmds++ = cp_nop_packet(1);
896 *cmds++ = KGSL_END_OF_IB_IDENTIFIER;
897
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600898 kgsl_setstate(&device->mmu, context->id,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600899 kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 device->id));
901
902 adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
903
904 *timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700905 drawctxt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906 KGSL_CMD_FLAGS_NOT_KERNEL_CMD,
907 &link[0], (cmds - link));
908
909 KGSL_CMD_INFO(device, "ctxt %d g %08x numibs %d ts %d\n",
910 context->id, (unsigned int)ibdesc, numibs, *timestamp);
911
912 kfree(link);
913
914#ifdef CONFIG_MSM_KGSL_CFF_DUMP
915 /*
916 * insert wait for idle after every IB1
917 * this is conservative but works reliably and is ok
918 * even for performance simulations
919 */
920 adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
921#endif
922
923 return 0;
924}
925
926int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
927 unsigned int *temp_rb_buffer,
928 int *rb_size)
929{
930 struct kgsl_device *device = rb->device;
931 unsigned int rb_rptr;
932 unsigned int retired_timestamp;
933 unsigned int temp_idx = 0;
934 unsigned int value;
935 unsigned int val1;
936 unsigned int val2;
937 unsigned int val3;
938 unsigned int copy_rb_contents = 0;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700939 struct kgsl_context *context;
940 unsigned int context_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941
942 GSL_RB_GET_READPTR(rb, &rb->rptr);
943
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700944 /* current_context is the context that is presently active in the
945 * GPU, i.e the context in which the hang is caused */
946 kgsl_sharedmem_readl(&device->memstore, &context_id,
947 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
948 current_context));
949 KGSL_DRV_ERR(device, "Last context id: %d\n", context_id);
950 context = idr_find(&device->context_idr, context_id);
951 if (context == NULL) {
952 KGSL_DRV_ERR(device,
953 "GPU recovery from hang not possible because last"
954 " context id is invalid.\n");
955 return -EINVAL;
956 }
Jeremy Gebben731dac52012-05-10 11:13:42 -0600957 retired_timestamp = kgsl_readtimestamp(device, context,
958 KGSL_TIMESTAMP_RETIRED);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959 KGSL_DRV_ERR(device, "GPU successfully executed till ts: %x\n",
960 retired_timestamp);
961 /*
962 * We need to go back in history by 4 dwords from the current location
963 * of read pointer as 4 dwords are read to match the end of a command.
964 * Also, take care of wrap around when moving back
965 */
966 if (rb->rptr >= 4)
967 rb_rptr = (rb->rptr - 4) * sizeof(unsigned int);
968 else
969 rb_rptr = rb->buffer_desc.size -
970 ((4 - rb->rptr) * sizeof(unsigned int));
971 /* Read the rb contents going backwards to locate end of last
972 * sucessfully executed command */
973 while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
974 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
975 if (value == retired_timestamp) {
976 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
977 rb->buffer_desc.size);
978 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
979 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
980 rb->buffer_desc.size);
981 kgsl_sharedmem_readl(&rb->buffer_desc, &val2, rb_rptr);
982 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
983 rb->buffer_desc.size);
984 kgsl_sharedmem_readl(&rb->buffer_desc, &val3, rb_rptr);
985 /* match the pattern found at the end of a command */
986 if ((val1 == 2 &&
Jordan Crouse084427d2011-07-28 08:37:58 -0600987 val2 == cp_type3_packet(CP_INTERRUPT, 1)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 && val3 == CP_INT_CNTL__RB_INT_MASK) ||
Jordan Crouse084427d2011-07-28 08:37:58 -0600989 (val1 == cp_type3_packet(CP_EVENT_WRITE, 3)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990 && val2 == CACHE_FLUSH_TS &&
991 val3 == (rb->device->memstore.gpuaddr +
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700992 KGSL_MEMSTORE_OFFSET(context_id,
993 eoptimestamp)))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700994 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
995 rb->buffer_desc.size);
996 KGSL_DRV_ERR(device,
997 "Found end of last executed "
998 "command at offset: %x\n",
999 rb_rptr / sizeof(unsigned int));
1000 break;
1001 } else {
1002 if (rb_rptr < (3 * sizeof(unsigned int)))
1003 rb_rptr = rb->buffer_desc.size -
1004 (3 * sizeof(unsigned int))
1005 + rb_rptr;
1006 else
1007 rb_rptr -= (3 * sizeof(unsigned int));
1008 }
1009 }
1010
1011 if (rb_rptr == 0)
1012 rb_rptr = rb->buffer_desc.size - sizeof(unsigned int);
1013 else
1014 rb_rptr -= sizeof(unsigned int);
1015 }
1016
1017 if ((rb_rptr / sizeof(unsigned int)) == rb->wptr) {
1018 KGSL_DRV_ERR(device,
1019 "GPU recovery from hang not possible because last"
1020 " successful timestamp is overwritten\n");
1021 return -EINVAL;
1022 }
1023 /* rb_rptr is now pointing to the first dword of the command following
1024 * the last sucessfully executed command sequence. Assumption is that
1025 * GPU is hung in the command sequence pointed by rb_rptr */
1026 /* make sure the GPU is not hung in a command submitted by kgsl
1027 * itself */
1028 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
1029 kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
1030 adreno_ringbuffer_inc_wrapped(rb_rptr,
1031 rb->buffer_desc.size));
Jordan Crouse084427d2011-07-28 08:37:58 -06001032 if (val1 == cp_nop_packet(1) && val2 == KGSL_CMD_IDENTIFIER) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 KGSL_DRV_ERR(device,
1034 "GPU recovery from hang not possible because "
1035 "of hang in kgsl command\n");
1036 return -EINVAL;
1037 }
1038
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039 while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
1040 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
1041 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
1042 rb->buffer_desc.size);
1043 /* check for context switch indicator */
1044 if (value == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
1045 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
1046 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
1047 rb->buffer_desc.size);
Jordan Crouse084427d2011-07-28 08:37:58 -06001048 BUG_ON(value != cp_type3_packet(CP_MEM_WRITE, 2));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
1050 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
1051 rb->buffer_desc.size);
1052 BUG_ON(val1 != (device->memstore.gpuaddr +
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001053 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
1054 current_context)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
1056 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
1057 rb->buffer_desc.size);
Jordan Crousea400d8d2012-03-16 14:53:39 -06001058
1059 /*
1060 * If other context switches were already lost and
1061 * and the current context is the one that is hanging,
1062 * then we cannot recover. Print an error message
1063 * and leave.
1064 */
1065
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001066 if ((copy_rb_contents == 0) && (value == context_id)) {
Jordan Crousea400d8d2012-03-16 14:53:39 -06001067 KGSL_DRV_ERR(device, "GPU recovery could not "
1068 "find the previous context\n");
1069 return -EINVAL;
1070 }
1071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 /*
1073 * If we were copying the commands and got to this point
1074 * then we need to remove the 3 commands that appear
1075 * before KGSL_CONTEXT_TO_MEM_IDENTIFIER
1076 */
1077 if (temp_idx)
1078 temp_idx -= 3;
1079 /* if context switches to a context that did not cause
1080 * hang then start saving the rb contents as those
1081 * commands can be executed */
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001082 if (value != context_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001083 copy_rb_contents = 1;
Jordan Crouse084427d2011-07-28 08:37:58 -06001084 temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085 temp_rb_buffer[temp_idx++] =
1086 KGSL_CMD_IDENTIFIER;
Jordan Crouse084427d2011-07-28 08:37:58 -06001087 temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088 temp_rb_buffer[temp_idx++] =
1089 KGSL_CONTEXT_TO_MEM_IDENTIFIER;
1090 temp_rb_buffer[temp_idx++] =
Jordan Crouse084427d2011-07-28 08:37:58 -06001091 cp_type3_packet(CP_MEM_WRITE, 2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 temp_rb_buffer[temp_idx++] = val1;
1093 temp_rb_buffer[temp_idx++] = value;
1094 } else {
1095 copy_rb_contents = 0;
1096 }
1097 } else if (copy_rb_contents)
1098 temp_rb_buffer[temp_idx++] = value;
1099 }
1100
1101 *rb_size = temp_idx;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102 return 0;
1103}
1104
1105void
1106adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
1107 int num_rb_contents)
1108{
1109 int i;
1110 unsigned int *ringcmds;
1111 unsigned int rcmd_gpu;
1112
1113 if (!num_rb_contents)
1114 return;
1115
1116 if (num_rb_contents > (rb->buffer_desc.size - rb->wptr)) {
1117 adreno_regwrite(rb->device, REG_CP_RB_RPTR, 0);
1118 rb->rptr = 0;
1119 BUG_ON(num_rb_contents > rb->buffer_desc.size);
1120 }
1121 ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
1122 rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
1123 for (i = 0; i < num_rb_contents; i++)
1124 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb_buff[i]);
1125 rb->wptr += num_rb_contents;
1126 adreno_ringbuffer_submit(rb);
1127}