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