blob: 49786ba6aa0b33765aa5153ef18c6555482adad1 [file] [log] [blame]
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -07001/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/firmware.h>
14#include <linux/slab.h>
15#include <linux/sched.h>
16#include <linux/log2.h>
17
18#include "kgsl.h"
19#include "kgsl_sharedmem.h"
20#include "kgsl_cffdump.h"
21
22#include "adreno.h"
23#include "adreno_pm4types.h"
24#include "adreno_ringbuffer.h"
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -060025#include "adreno_debugfs.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026
Jeremy Gebbeneebc4612011-08-31 10:15:21 -070027#include "a2xx_reg.h"
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070028#include "a3xx_reg.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030#define GSL_RB_NOP_SIZEDWORDS 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070032void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033{
34 BUG_ON(rb->wptr == 0);
35
Lucille Sylvester958dc942011-09-06 18:19:49 -060036 /* Let the pwrscale policy know that new commands have
37 been submitted. */
38 kgsl_pwrscale_busy(rb->device);
39
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040 /*synchronize memory before informing the hardware of the
41 *new commands.
42 */
43 mb();
44
45 adreno_regwrite(rb->device, REG_CP_RB_WPTR, rb->wptr);
46}
47
Carter Cooper6dd94c82011-10-13 14:43:53 -060048static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, unsigned int numcmds,
50 int wptr_ahead)
51{
52 int nopcount;
53 unsigned int freecmds;
54 unsigned int *cmds;
55 uint cmds_gpu;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060056 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
57 unsigned long wait_timeout = msecs_to_jiffies(adreno_dev->wait_timeout);
58 unsigned long wait_time;
Tarun Karra3335f142012-06-19 14:11:48 -070059 unsigned long wait_time_part;
60 unsigned int msecs_part = KGSL_TIMEOUT_PART;
61 unsigned int prev_reg_val[hang_detect_regs_count];
62
63 memset(prev_reg_val, 0, sizeof(prev_reg_val));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064
65 /* if wptr ahead, fill the remaining with NOPs */
66 if (wptr_ahead) {
67 /* -1 for header */
68 nopcount = rb->sizedwords - rb->wptr - 1;
69
70 cmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
71 cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*rb->wptr;
72
Jordan Crouse084427d2011-07-28 08:37:58 -060073 GSL_RB_WRITE(cmds, cmds_gpu, cp_nop_packet(nopcount));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074
75 /* Make sure that rptr is not 0 before submitting
76 * commands at the end of ringbuffer. We do not
77 * want the rptr and wptr to become equal when
78 * the ringbuffer is not empty */
79 do {
80 GSL_RB_GET_READPTR(rb, &rb->rptr);
81 } while (!rb->rptr);
82
83 rb->wptr++;
84
85 adreno_ringbuffer_submit(rb);
86
87 rb->wptr = 0;
88 }
89
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060090 wait_time = jiffies + wait_timeout;
Tarun Karra3335f142012-06-19 14:11:48 -070091 wait_time_part = jiffies + msecs_to_jiffies(msecs_part);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092 /* wait for space in ringbuffer */
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060093 while (1) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 GSL_RB_GET_READPTR(rb, &rb->rptr);
95
96 freecmds = rb->rptr - rb->wptr;
97
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -060098 if (freecmds == 0 || freecmds > numcmds)
99 break;
100
Tarun Karra3335f142012-06-19 14:11:48 -0700101 /* Dont wait for timeout, detect hang faster.
102 */
103 if (time_after(jiffies, wait_time_part)) {
104 wait_time_part = jiffies +
105 msecs_to_jiffies(msecs_part);
106 if ((adreno_hang_detect(rb->device,
107 prev_reg_val))){
108 KGSL_DRV_ERR(rb->device,
109 "Hang detected while waiting for freespace in"
110 "ringbuffer rptr: 0x%x, wptr: 0x%x\n",
111 rb->rptr, rb->wptr);
112 goto err;
113 }
114 }
115
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600116 if (time_after(jiffies, wait_time)) {
117 KGSL_DRV_ERR(rb->device,
118 "Timed out while waiting for freespace in ringbuffer "
119 "rptr: 0x%x, wptr: 0x%x\n", rb->rptr, rb->wptr);
Tarun Karra3335f142012-06-19 14:11:48 -0700120 goto err;
121 }
122
Wei Zou50ec3372012-07-17 15:46:52 -0700123 continue;
124
Tarun Karra3335f142012-06-19 14:11:48 -0700125err:
126 if (!adreno_dump_and_recover(rb->device))
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600127 wait_time = jiffies + wait_timeout;
128 else
129 /* GPU is hung and we cannot recover */
130 BUG();
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600131 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132}
133
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700134unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135 unsigned int numcmds)
136{
137 unsigned int *ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138
139 BUG_ON(numcmds >= rb->sizedwords);
140
141 GSL_RB_GET_READPTR(rb, &rb->rptr);
142 /* check for available space */
143 if (rb->wptr >= rb->rptr) {
144 /* wptr ahead or equal to rptr */
145 /* reserve dwords for nop packet */
146 if ((rb->wptr + numcmds) > (rb->sizedwords -
147 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600148 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 } else {
150 /* wptr behind rptr */
151 if ((rb->wptr + numcmds) >= rb->rptr)
Carter Cooper6dd94c82011-10-13 14:43:53 -0600152 adreno_ringbuffer_waitspace(rb, numcmds, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 /* check for remaining space */
154 /* reserve dwords for nop packet */
155 if ((rb->wptr + numcmds) > (rb->sizedwords -
156 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600157 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158 }
159
Carter Cooper6dd94c82011-10-13 14:43:53 -0600160 ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
161 rb->wptr += numcmds;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162
163 return ptr;
164}
165
166static int _load_firmware(struct kgsl_device *device, const char *fwfile,
167 void **data, int *len)
168{
169 const struct firmware *fw = NULL;
170 int ret;
171
172 ret = request_firmware(&fw, fwfile, device->dev);
173
174 if (ret) {
175 KGSL_DRV_ERR(device, "request_firmware(%s) failed: %d\n",
176 fwfile, ret);
177 return ret;
178 }
179
180 *data = kmalloc(fw->size, GFP_KERNEL);
181
182 if (*data) {
183 memcpy(*data, fw->data, fw->size);
184 *len = fw->size;
185 } else
186 KGSL_MEM_ERR(device, "kmalloc(%d) failed\n", fw->size);
187
188 release_firmware(fw);
189 return (*data != NULL) ? 0 : -ENOMEM;
190}
191
192static int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
193{
194 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195 int i, ret = 0;
196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 if (adreno_dev->pm4_fw == NULL) {
198 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600199 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200
Jordan Crouse505df9c2011-07-28 08:37:59 -0600201 ret = _load_firmware(device, adreno_dev->pm4_fwfile,
202 &ptr, &len);
203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 if (ret)
205 goto err;
206
207 /* PM4 size is 3 dword aligned plus 1 dword of version */
208 if (len % ((sizeof(uint32_t) * 3)) != sizeof(uint32_t)) {
209 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
210 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600211 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212 goto err;
213 }
214
215 adreno_dev->pm4_fw_size = len / sizeof(uint32_t);
216 adreno_dev->pm4_fw = ptr;
217 }
218
219 KGSL_DRV_INFO(device, "loading pm4 ucode version: %d\n",
220 adreno_dev->pm4_fw[0]);
221
222 adreno_regwrite(device, REG_CP_DEBUG, 0x02000000);
223 adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
224 for (i = 1; i < adreno_dev->pm4_fw_size; i++)
225 adreno_regwrite(device, REG_CP_ME_RAM_DATA,
226 adreno_dev->pm4_fw[i]);
227err:
228 return ret;
229}
230
231static int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
232{
233 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 int i, ret = 0;
235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236 if (adreno_dev->pfp_fw == NULL) {
237 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600238 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239
Jordan Crouse505df9c2011-07-28 08:37:59 -0600240 ret = _load_firmware(device, adreno_dev->pfp_fwfile,
241 &ptr, &len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700242 if (ret)
243 goto err;
244
245 /* PFP size shold be dword aligned */
246 if (len % sizeof(uint32_t) != 0) {
247 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
248 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600249 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 goto err;
251 }
252
253 adreno_dev->pfp_fw_size = len / sizeof(uint32_t);
254 adreno_dev->pfp_fw = ptr;
255 }
256
257 KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
258 adreno_dev->pfp_fw[0]);
259
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700260 adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 for (i = 1; i < adreno_dev->pfp_fw_size; i++)
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700262 adreno_regwrite(device,
263 adreno_dev->gpudev->reg_cp_pfp_ucode_data,
264 adreno_dev->pfp_fw[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265err:
266 return ret;
267}
268
269int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
270{
271 int status;
272 /*cp_rb_cntl_u cp_rb_cntl; */
273 union reg_cp_rb_cntl cp_rb_cntl;
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700274 unsigned int rb_cntl;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 struct kgsl_device *device = rb->device;
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700276 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277
278 if (rb->flags & KGSL_FLAGS_STARTED)
279 return 0;
280
Carter Coopercb3e8eb2012-04-11 09:39:40 -0600281 if (init_ram)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700282 rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283
284 kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
285 sizeof(struct kgsl_rbmemptrs));
286
287 kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
288 (rb->sizedwords << 2));
289
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700290 if (adreno_is_a2xx(adreno_dev)) {
291 adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
292 (rb->memptrs_desc.gpuaddr
293 + GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700295 /* setup WPTR delay */
296 adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
297 0 /*0x70000010 */);
298 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299
300 /*setup REG_CP_RB_CNTL */
301 adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
302 cp_rb_cntl.val = rb_cntl;
303
304 /*
305 * The size of the ringbuffer in the hardware is the log2
306 * representation of the size in quadwords (sizedwords / 2)
307 */
308 cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);
309
310 /*
311 * Specify the quadwords to read before updating mem RPTR.
312 * Like above, pass the log2 representation of the blocksize
313 * in quadwords.
314 */
315 cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);
316
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700317 if (adreno_is_a2xx(adreno_dev)) {
318 /* WPTR polling */
319 cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
320 }
321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 /* mem RPTR writebacks */
323 cp_rb_cntl.f.rb_no_update = GSL_RB_CNTL_NO_UPDATE;
324
325 adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);
326
327 adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);
328
329 adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
330 rb->memptrs_desc.gpuaddr +
331 GSL_RB_MEMPTRS_RPTR_OFFSET);
332
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700333 if (adreno_is_a3xx(adreno_dev)) {
334 /* enable access protection to privileged registers */
335 adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);
336
337 /* RBBM registers */
338 adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
339 adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
340 adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
341 adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
342 adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
343 adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);
344
345 /* CP registers */
346 adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
347 adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
348 adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
349 adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
350 adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);
351
352 /* RB registers */
353 adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
354
355 /* VBIF registers */
356 adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
357 }
358
359 if (adreno_is_a2xx(adreno_dev)) {
360 /* explicitly clear all cp interrupts */
361 adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
362 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363
364 /* setup scratch/timestamp */
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700365 adreno_regwrite(device, REG_SCRATCH_ADDR, device->memstore.gpuaddr +
366 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
367 soptimestamp));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700368
369 adreno_regwrite(device, REG_SCRATCH_UMSK,
370 GSL_RB_MEMPTRS_SCRATCH_MASK);
371
372 /* load the CP ucode */
373
374 status = adreno_ringbuffer_load_pm4_ucode(device);
375 if (status != 0)
376 return status;
377
378 /* load the prefetch parser ucode */
379 status = adreno_ringbuffer_load_pfp_ucode(device);
380 if (status != 0)
381 return status;
382
Kevin Matlageff806df2012-05-07 18:13:21 -0600383 /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
Kevin Matlagee8d35862012-04-26 12:58:15 -0600384 if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
Kevin Matlageff806df2012-05-07 18:13:21 -0600385 adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386
387 rb->rptr = 0;
388 rb->wptr = 0;
389
390 /* clear ME_HALT to start micro engine */
391 adreno_regwrite(device, REG_CP_ME_CNTL, 0);
392
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700393 /* ME init is GPU specific, so jump into the sub-function */
394 adreno_dev->gpudev->rb_init(adreno_dev, rb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395
396 /* idle device to validate ME INIT */
397 status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
398
399 if (status == 0)
400 rb->flags |= KGSL_FLAGS_STARTED;
401
402 return status;
403}
404
Carter Cooper6dd94c82011-10-13 14:43:53 -0600405void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406{
Lucille Sylvester51feb4e2012-07-26 18:58:33 -0600407 if (rb->flags & KGSL_FLAGS_STARTED)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 rb->flags &= ~KGSL_FLAGS_STARTED;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409}
410
411int adreno_ringbuffer_init(struct kgsl_device *device)
412{
413 int status;
414 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
415 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
416
417 rb->device = device;
418 /*
419 * It is silly to convert this to words and then back to bytes
420 * immediately below, but most of the rest of the code deals
421 * in words, so we might as well only do the math once
422 */
423 rb->sizedwords = KGSL_RB_SIZE >> 2;
424
425 /* allocate memory for ringbuffer */
426 status = kgsl_allocate_contiguous(&rb->buffer_desc,
427 (rb->sizedwords << 2));
428
429 if (status != 0) {
430 adreno_ringbuffer_close(rb);
431 return status;
432 }
433
434 /* allocate memory for polling and timestamps */
435 /* This really can be at 4 byte alignment boundry but for using MMU
436 * we need to make it at page boundary */
437 status = kgsl_allocate_contiguous(&rb->memptrs_desc,
438 sizeof(struct kgsl_rbmemptrs));
439
440 if (status != 0) {
441 adreno_ringbuffer_close(rb);
442 return status;
443 }
444
445 /* overlay structure on memptrs memory */
446 rb->memptrs = (struct kgsl_rbmemptrs *) rb->memptrs_desc.hostptr;
447
448 return 0;
449}
450
Carter Cooper6dd94c82011-10-13 14:43:53 -0600451void adreno_ringbuffer_close(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700452{
453 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
454
455 kgsl_sharedmem_free(&rb->buffer_desc);
456 kgsl_sharedmem_free(&rb->memptrs_desc);
457
458 kfree(adreno_dev->pfp_fw);
459 kfree(adreno_dev->pm4_fw);
460
461 adreno_dev->pfp_fw = NULL;
462 adreno_dev->pm4_fw = NULL;
463
464 memset(rb, 0, sizeof(struct adreno_ringbuffer));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465}
466
467static uint32_t
468adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700469 struct adreno_context *context,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 unsigned int flags, unsigned int *cmds,
471 int sizedwords)
472{
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700473 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474 unsigned int *ringcmds;
475 unsigned int timestamp;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700476 unsigned int total_sizedwords = sizedwords;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 unsigned int i;
478 unsigned int rcmd_gpu;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700479 unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
480 unsigned int gpuaddr = rb->device->memstore.gpuaddr;
481
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600482 /*
483 * if the context was not created with per context timestamp
484 * support, we must use the global timestamp since issueibcmds
485 * will be returning that one.
486 */
487 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
488 context_id = context->id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489
490 /* reserve space to temporarily turn off protected mode
491 * error checking if needed
492 */
493 total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600494 /* 2 dwords to store the start of command sequence */
495 total_sizedwords += 2;
Carter Cooper7ffaba62012-05-24 13:59:53 -0600496 total_sizedwords += context ? 7 : 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700498 if (adreno_is_a3xx(adreno_dev))
499 total_sizedwords += 7;
500
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700501 total_sizedwords += 2; /* scratchpad ts for recovery */
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600502 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700503 total_sizedwords += 3; /* sop timestamp */
504 total_sizedwords += 4; /* eop timestamp */
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530505 total_sizedwords += 3; /* global timestamp without cache
506 * flush for non-zero context */
507 } else {
508 total_sizedwords += 4; /* global timestamp for recovery*/
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700509 }
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511 ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600512 /* GPU may hang during space allocation, if thats the case the current
513 * context may have hung the GPU */
514 if (context->flags & CTXT_FLAGS_GPU_HANG) {
515 KGSL_CTXT_WARN(rb->device,
516 "Context %p caused a gpu hang. Will not accept commands for context %d\n",
517 context, context->id);
518 return rb->timestamp[context_id];
519 }
520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521 rcmd_gpu = rb->buffer_desc.gpuaddr
522 + sizeof(uint)*(rb->wptr-total_sizedwords);
523
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600524 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
525 GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527 if (flags & KGSL_CMD_FLAGS_PMODE) {
528 /* disable protected mode error checking */
529 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600530 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
532 }
533
534 for (i = 0; i < sizedwords; i++) {
535 GSL_RB_WRITE(ringcmds, rcmd_gpu, *cmds);
536 cmds++;
537 }
538
539 if (flags & KGSL_CMD_FLAGS_PMODE) {
540 /* re-enable protected mode error checking */
541 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600542 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543 GSL_RB_WRITE(ringcmds, rcmd_gpu, 1);
544 }
545
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700546 /* always increment the global timestamp. once. */
547 rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
Carter Cooper7ffaba62012-05-24 13:59:53 -0600548
549 if (context && !(flags & KGSL_CMD_FLAGS_DUMMY_INTR_CMD)) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700550 if (context_id == KGSL_MEMSTORE_GLOBAL)
Carter Cooper7ffaba62012-05-24 13:59:53 -0600551 rb->timestamp[context->id] =
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700552 rb->timestamp[KGSL_MEMSTORE_GLOBAL];
553 else
554 rb->timestamp[context_id]++;
555 }
556 timestamp = rb->timestamp[context_id];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700557
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700558 /* scratchpad ts for recovery */
Jordan Crouse084427d2011-07-28 08:37:58 -0600559 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700560 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700561
562 if (adreno_is_a3xx(adreno_dev)) {
563 /*
564 * FLush HLSQ lazy updates to make sure there are no
565 * rsources pending for indirect loads after the timestamp
566 */
567
568 GSL_RB_WRITE(ringcmds, rcmd_gpu,
569 cp_type3_packet(CP_EVENT_WRITE, 1));
570 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x07); /* HLSQ_FLUSH */
571 GSL_RB_WRITE(ringcmds, rcmd_gpu,
572 cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
573 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
574 }
575
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600576 if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700577 /* start-of-pipeline timestamp */
578 GSL_RB_WRITE(ringcmds, rcmd_gpu,
579 cp_type3_packet(CP_MEM_WRITE, 2));
580 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600581 KGSL_MEMSTORE_OFFSET(context_id, soptimestamp)));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700582 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
583
584 /* end-of-pipeline timestamp */
585 GSL_RB_WRITE(ringcmds, rcmd_gpu,
586 cp_type3_packet(CP_EVENT_WRITE, 3));
587 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
588 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600589 KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700590 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700591
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530592 GSL_RB_WRITE(ringcmds, rcmd_gpu,
593 cp_type3_packet(CP_MEM_WRITE, 2));
594 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600595 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
596 eoptimestamp)));
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530597 GSL_RB_WRITE(ringcmds, rcmd_gpu,
598 rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
599 } else {
600 GSL_RB_WRITE(ringcmds, rcmd_gpu,
601 cp_type3_packet(CP_EVENT_WRITE, 3));
602 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
603 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
Carter Cooper7ffaba62012-05-24 13:59:53 -0600604 KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
605 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[context_id]);
Rajesh Kemisettic5699302012-04-21 21:09:05 +0530606 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607
Carter Cooper7ffaba62012-05-24 13:59:53 -0600608 if (context) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 /* Conditional execution based on memory values */
610 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600611 cp_type3_packet(CP_COND_EXEC, 4));
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700612 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
613 KGSL_MEMSTORE_OFFSET(
614 context_id, ts_cmp_enable)) >> 2);
615 GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
616 KGSL_MEMSTORE_OFFSET(
617 context_id, ref_wait_ts)) >> 2);
618 GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 /* # of conditional command DWORDs */
620 GSL_RB_WRITE(ringcmds, rcmd_gpu, 2);
621 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600622 cp_type3_packet(CP_INTERRUPT, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623 GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
624 }
625
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700626 if (adreno_is_a3xx(adreno_dev)) {
627 /* Dummy set-constant to trigger context rollover */
628 GSL_RB_WRITE(ringcmds, rcmd_gpu,
629 cp_type3_packet(CP_SET_CONSTANT, 2));
630 GSL_RB_WRITE(ringcmds, rcmd_gpu,
631 (0x4<<16)|(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG - 0x2000));
632 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
633 }
634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635 adreno_ringbuffer_submit(rb);
636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 return timestamp;
638}
639
Carter Cooper7ffaba62012-05-24 13:59:53 -0600640void
641adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
642 struct kgsl_context *k_ctxt,
643 unsigned int *cmds,
644 int sizedwords)
645{
646 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
647 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
648 struct adreno_context *a_ctxt = NULL;
649
650 if (!k_ctxt)
651 return;
652
653 a_ctxt = k_ctxt->devctxt;
654
655 if (k_ctxt->id == KGSL_CONTEXT_INVALID ||
656 a_ctxt == NULL ||
657 device->state & KGSL_STATE_HUNG)
658 return;
659
660 adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_DUMMY_INTR_CMD,
661 cmds, sizedwords);
662}
663
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600664unsigned int
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665adreno_ringbuffer_issuecmds(struct kgsl_device *device,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600666 struct adreno_context *drawctxt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700667 unsigned int flags,
668 unsigned int *cmds,
669 int sizedwords)
670{
671 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
672 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
673
674 if (device->state & KGSL_STATE_HUNG)
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600675 return kgsl_readtimestamp(device, KGSL_MEMSTORE_GLOBAL,
676 KGSL_TIMESTAMP_RETIRED);
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600677 return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds, sizedwords);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678}
679
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -0600680static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
681 int sizedwords);
682
683static bool
684_handle_type3(struct kgsl_device_private *dev_priv, uint *hostaddr)
685{
686 unsigned int opcode = cp_type3_opcode(*hostaddr);
687 switch (opcode) {
688 case CP_INDIRECT_BUFFER_PFD:
689 case CP_INDIRECT_BUFFER_PFE:
690 case CP_COND_INDIRECT_BUFFER_PFE:
691 case CP_COND_INDIRECT_BUFFER_PFD:
692 return _parse_ibs(dev_priv, hostaddr[1], hostaddr[2]);
693 case CP_NOP:
694 case CP_WAIT_FOR_IDLE:
695 case CP_WAIT_REG_MEM:
696 case CP_WAIT_REG_EQ:
697 case CP_WAT_REG_GTE:
698 case CP_WAIT_UNTIL_READ:
699 case CP_WAIT_IB_PFD_COMPLETE:
700 case CP_REG_RMW:
701 case CP_REG_TO_MEM:
702 case CP_MEM_WRITE:
703 case CP_MEM_WRITE_CNTR:
704 case CP_COND_EXEC:
705 case CP_COND_WRITE:
706 case CP_EVENT_WRITE:
707 case CP_EVENT_WRITE_SHD:
708 case CP_EVENT_WRITE_CFL:
709 case CP_EVENT_WRITE_ZPD:
710 case CP_DRAW_INDX:
711 case CP_DRAW_INDX_2:
712 case CP_DRAW_INDX_BIN:
713 case CP_DRAW_INDX_2_BIN:
714 case CP_VIZ_QUERY:
715 case CP_SET_STATE:
716 case CP_SET_CONSTANT:
717 case CP_IM_LOAD:
718 case CP_IM_LOAD_IMMEDIATE:
719 case CP_LOAD_CONSTANT_CONTEXT:
720 case CP_INVALIDATE_STATE:
721 case CP_SET_SHADER_BASES:
722 case CP_SET_BIN_MASK:
723 case CP_SET_BIN_SELECT:
724 case CP_SET_BIN_BASE_OFFSET:
725 case CP_SET_BIN_DATA:
726 case CP_CONTEXT_UPDATE:
727 case CP_INTERRUPT:
728 case CP_IM_STORE:
729 case CP_LOAD_STATE:
730 break;
731 /* these shouldn't come from userspace */
732 case CP_ME_INIT:
733 case CP_SET_PROTECTED_MODE:
734 default:
735 KGSL_CMD_ERR(dev_priv->device, "bad CP opcode %0x\n", opcode);
736 return false;
737 break;
738 }
739
740 return true;
741}
742
743static bool
744_handle_type0(struct kgsl_device_private *dev_priv, uint *hostaddr)
745{
746 unsigned int reg = type0_pkt_offset(*hostaddr);
747 unsigned int cnt = type0_pkt_size(*hostaddr);
748 if (reg < 0x0192 || (reg + cnt) >= 0x8000) {
749 KGSL_CMD_ERR(dev_priv->device, "bad type0 reg: 0x%0x cnt: %d\n",
750 reg, cnt);
751 return false;
752 }
753 return true;
754}
755
756/*
757 * Traverse IBs and dump them to test vector. Detect swap by inspecting
758 * register writes, keeping note of the current state, and dump
759 * framebuffer config to test vector
760 */
761static bool _parse_ibs(struct kgsl_device_private *dev_priv,
762 uint gpuaddr, int sizedwords)
763{
764 static uint level; /* recursion level */
765 bool ret = false;
766 uint *hostaddr, *hoststart;
767 int dwords_left = sizedwords; /* dwords left in the current command
768 buffer */
769 struct kgsl_mem_entry *entry;
770
771 spin_lock(&dev_priv->process_priv->mem_lock);
772 entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
773 gpuaddr, sizedwords * sizeof(uint));
774 spin_unlock(&dev_priv->process_priv->mem_lock);
775 if (entry == NULL) {
776 KGSL_CMD_ERR(dev_priv->device,
777 "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
778 return false;
779 }
780
781 hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(&entry->memdesc, gpuaddr);
782 if (hostaddr == NULL) {
783 KGSL_CMD_ERR(dev_priv->device,
784 "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
785 return false;
786 }
787
788 hoststart = hostaddr;
789
790 level++;
791
792 KGSL_CMD_INFO(dev_priv->device, "ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
793 gpuaddr, sizedwords, hostaddr);
794
795 mb();
796 while (dwords_left > 0) {
797 bool cur_ret = true;
798 int count = 0; /* dword count including packet header */
799
800 switch (*hostaddr >> 30) {
801 case 0x0: /* type-0 */
802 count = (*hostaddr >> 16)+2;
803 cur_ret = _handle_type0(dev_priv, hostaddr);
804 break;
805 case 0x1: /* type-1 */
806 count = 2;
807 break;
808 case 0x3: /* type-3 */
809 count = ((*hostaddr >> 16) & 0x3fff) + 2;
810 cur_ret = _handle_type3(dev_priv, hostaddr);
811 break;
812 default:
813 KGSL_CMD_ERR(dev_priv->device, "unexpected type: "
814 "type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
815 *hostaddr >> 30, *hostaddr, hostaddr,
816 gpuaddr+4*(sizedwords-dwords_left));
817 cur_ret = false;
818 count = dwords_left;
819 break;
820 }
821
822 if (!cur_ret) {
823 KGSL_CMD_ERR(dev_priv->device,
824 "bad sub-type: #:%d/%d, v:0x%08x"
825 " @ 0x%p[gb:0x%08x], level:%d\n",
826 sizedwords-dwords_left, sizedwords, *hostaddr,
827 hostaddr, gpuaddr+4*(sizedwords-dwords_left),
828 level);
829
830 if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
831 >= 2)
832 print_hex_dump(KERN_ERR,
833 level == 1 ? "IB1:" : "IB2:",
834 DUMP_PREFIX_OFFSET, 32, 4, hoststart,
835 sizedwords*4, 0);
836 goto done;
837 }
838
839 /* jump to next packet */
840 dwords_left -= count;
841 hostaddr += count;
842 if (dwords_left < 0) {
843 KGSL_CMD_ERR(dev_priv->device,
844 "bad count: c:%d, #:%d/%d, "
845 "v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
846 count, sizedwords-(dwords_left+count),
847 sizedwords, *(hostaddr-count), hostaddr-count,
848 gpuaddr+4*(sizedwords-(dwords_left+count)),
849 level);
850 if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
851 >= 2)
852 print_hex_dump(KERN_ERR,
853 level == 1 ? "IB1:" : "IB2:",
854 DUMP_PREFIX_OFFSET, 32, 4, hoststart,
855 sizedwords*4, 0);
856 goto done;
857 }
858 }
859
860 ret = true;
861done:
862 if (!ret)
863 KGSL_DRV_ERR(dev_priv->device,
864 "parsing failed: gpuaddr:0x%08x, "
865 "host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
866
867 level--;
868
869 return ret;
870}
871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700872int
873adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
874 struct kgsl_context *context,
875 struct kgsl_ibdesc *ibdesc,
876 unsigned int numibs,
877 uint32_t *timestamp,
878 unsigned int flags)
879{
880 struct kgsl_device *device = dev_priv->device;
881 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
882 unsigned int *link;
883 unsigned int *cmds;
884 unsigned int i;
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600885 struct adreno_context *drawctxt;
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700886 unsigned int start_index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887
888 if (device->state & KGSL_STATE_HUNG)
889 return -EBUSY;
890 if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) ||
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600891 context == NULL || ibdesc == 0 || numibs == 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 return -EINVAL;
893
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600894 drawctxt = context->devctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700895
896 if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
897 KGSL_CTXT_WARN(device, "Context %p caused a gpu hang.."
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700898 " will not accept commands for context %d\n",
899 drawctxt, drawctxt->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 return -EDEADLK;
901 }
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600902
903 cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
904 GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905 if (!link) {
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600906 KGSL_CORE_ERR("kzalloc(%d) failed\n",
907 sizeof(unsigned int) * (numibs * 3 + 4));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908 return -ENOMEM;
909 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700910
911 /*When preamble is enabled, the preamble buffer with state restoration
912 commands are stored in the first node of the IB chain. We can skip that
913 if a context switch hasn't occured */
914
915 if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
916 adreno_dev->drawctxt_active == drawctxt)
917 start_index = 1;
918
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600919 if (!start_index) {
920 *cmds++ = cp_nop_packet(1);
921 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
922 } else {
923 *cmds++ = cp_nop_packet(4);
924 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
925 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
926 *cmds++ = ibdesc[0].gpuaddr;
927 *cmds++ = ibdesc[0].sizedwords;
928 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700929 for (i = start_index; i < numibs; i++) {
Jeremy Gebbend0ab6ad2012-04-06 11:13:35 -0600930 if (unlikely(adreno_dev->ib_check_level >= 1 &&
931 !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
932 ibdesc[i].sizedwords))) {
933 kfree(link);
934 return -EINVAL;
935 }
Jordan Crouse084427d2011-07-28 08:37:58 -0600936 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700937 *cmds++ = ibdesc[i].gpuaddr;
938 *cmds++ = ibdesc[i].sizedwords;
939 }
940
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600941 *cmds++ = cp_nop_packet(1);
942 *cmds++ = KGSL_END_OF_IB_IDENTIFIER;
943
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600944 kgsl_setstate(&device->mmu, context->id,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600945 kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700946 device->id));
947
948 adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
949
950 *timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
Shubhraprakash Dasc3ad5802012-05-30 18:10:06 -0600951 drawctxt, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700952 &link[0], (cmds - link));
953
954 KGSL_CMD_INFO(device, "ctxt %d g %08x numibs %d ts %d\n",
955 context->id, (unsigned int)ibdesc, numibs, *timestamp);
956
957 kfree(link);
958
959#ifdef CONFIG_MSM_KGSL_CFF_DUMP
960 /*
961 * insert wait for idle after every IB1
962 * this is conservative but works reliably and is ok
963 * even for performance simulations
964 */
965 adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
966#endif
Shubhraprakash Das32240ef2012-06-06 20:27:46 -0600967 /* If context hung and recovered then return error so that the
968 * application may handle it */
969 if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_RECOVERED)
970 return -EDEADLK;
971 else
972 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700974}
975
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -0600976static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
977 unsigned int *ptr,
978 bool inc)
979{
980 int status = -EINVAL;
981 unsigned int val1;
982 unsigned int size = rb->buffer_desc.size;
983 unsigned int start_ptr = *ptr;
984
985 while ((start_ptr / sizeof(unsigned int)) != rb->wptr) {
986 if (inc)
987 start_ptr = adreno_ringbuffer_inc_wrapped(start_ptr,
988 size);
989 else
990 start_ptr = adreno_ringbuffer_dec_wrapped(start_ptr,
991 size);
992 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, start_ptr);
993 if (KGSL_CMD_IDENTIFIER == val1) {
994 if ((start_ptr / sizeof(unsigned int)) != rb->wptr)
995 start_ptr = adreno_ringbuffer_dec_wrapped(
996 start_ptr, size);
997 *ptr = start_ptr;
998 status = 0;
999 break;
1000 }
1001 }
1002 return status;
1003}
1004
1005static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb,
1006 unsigned int *rb_rptr,
1007 unsigned int global_eop,
1008 bool inc)
1009{
1010 int status = -EINVAL;
1011 unsigned int temp_rb_rptr = *rb_rptr;
1012 unsigned int size = rb->buffer_desc.size;
1013 unsigned int val[3];
1014 int i = 0;
1015 bool check = false;
1016
1017 if (inc && temp_rb_rptr / sizeof(unsigned int) != rb->wptr)
1018 return status;
1019
1020 do {
1021 /* when decrementing we need to decrement first and
1022 * then read make sure we cover all the data */
1023 if (!inc)
1024 temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
1025 temp_rb_rptr, size);
1026 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i],
1027 temp_rb_rptr);
1028
1029 if (check && ((inc && val[i] == global_eop) ||
1030 (!inc && (val[i] ==
1031 cp_type3_packet(CP_MEM_WRITE, 2) ||
1032 val[i] == CACHE_FLUSH_TS)))) {
1033 /* decrement i, i.e i = (i - 1 + 3) % 3 if
1034 * we are going forward, else increment i */
1035 i = (i + 2) % 3;
1036 if (val[i] == rb->device->memstore.gpuaddr +
1037 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
1038 eoptimestamp)) {
1039 int j = ((i + 2) % 3);
1040 if ((inc && (val[j] == CACHE_FLUSH_TS ||
1041 val[j] == cp_type3_packet(
1042 CP_MEM_WRITE, 2))) ||
1043 (!inc && val[j] == global_eop)) {
1044 /* Found the global eop */
1045 status = 0;
1046 break;
1047 }
1048 }
1049 /* if no match found then increment i again
1050 * since we decremented before matching */
1051 i = (i + 1) % 3;
1052 }
1053 if (inc)
1054 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(
1055 temp_rb_rptr, size);
1056
1057 i = (i + 1) % 3;
1058 if (2 == i)
1059 check = true;
1060 } while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr);
Shubhraprakash Das6f6ecb32012-06-13 12:17:11 -06001061 /* temp_rb_rptr points to the command stream after global eop,
1062 * move backward till the start of command sequence */
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001063 if (!status) {
Shubhraprakash Das6f6ecb32012-06-13 12:17:11 -06001064 status = _find_start_of_cmd_seq(rb, &temp_rb_rptr, false);
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001065 if (!status) {
1066 *rb_rptr = temp_rb_rptr;
1067 KGSL_DRV_ERR(rb->device,
1068 "Offset of cmd sequence after eop timestamp: 0x%x\n",
1069 temp_rb_rptr / sizeof(unsigned int));
1070 }
1071 }
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001072 if (status)
1073 KGSL_DRV_ERR(rb->device,
1074 "Failed to find the command sequence after eop timestamp\n");
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001075 return status;
1076}
1077
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001078static int _find_hanging_ib_sequence(struct adreno_ringbuffer *rb,
1079 unsigned int *rb_rptr,
1080 unsigned int ib1)
1081{
1082 int status = -EINVAL;
1083 unsigned int temp_rb_rptr = *rb_rptr;
1084 unsigned int size = rb->buffer_desc.size;
1085 unsigned int val[2];
1086 int i = 0;
1087 bool check = false;
1088 bool ctx_switch = false;
1089
1090 while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
1091 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
1092
1093 if (check && val[i] == ib1) {
1094 /* decrement i, i.e i = (i - 1 + 2) % 2 */
1095 i = (i + 1) % 2;
1096 if (adreno_cmd_is_ib(val[i])) {
1097 /* go till start of command sequence */
1098 status = _find_start_of_cmd_seq(rb,
1099 &temp_rb_rptr, false);
1100 KGSL_DRV_ERR(rb->device,
1101 "Found the hanging IB at offset 0x%x\n",
1102 temp_rb_rptr / sizeof(unsigned int));
1103 break;
1104 }
1105 /* if no match the increment i since we decremented
1106 * before checking */
1107 i = (i + 1) % 2;
1108 }
1109 /* Make sure you do not encounter a context switch twice, we can
1110 * encounter it once for the bad context as the start of search
1111 * can point to the context switch */
1112 if (val[i] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
1113 if (ctx_switch) {
1114 KGSL_DRV_ERR(rb->device,
1115 "Context switch encountered before bad "
1116 "IB found\n");
1117 break;
1118 }
1119 ctx_switch = true;
1120 }
1121 i = (i + 1) % 2;
1122 if (1 == i)
1123 check = true;
1124 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
1125 size);
1126 }
1127 if (!status)
1128 *rb_rptr = temp_rb_rptr;
1129 return status;
1130}
1131
1132static void _turn_preamble_on_for_ib_seq(struct adreno_ringbuffer *rb,
1133 unsigned int rb_rptr)
1134{
1135 unsigned int temp_rb_rptr = rb_rptr;
1136 unsigned int size = rb->buffer_desc.size;
1137 unsigned int val[2];
1138 int i = 0;
1139 bool check = false;
1140 bool cmd_start = false;
1141
1142 /* Go till the start of the ib sequence and turn on preamble */
1143 while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
1144 kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
1145 if (check && KGSL_START_OF_IB_IDENTIFIER == val[i]) {
1146 /* decrement i */
1147 i = (i + 1) % 2;
1148 if (val[i] == cp_nop_packet(4)) {
1149 temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
1150 temp_rb_rptr, size);
1151 kgsl_sharedmem_writel(&rb->buffer_desc,
1152 temp_rb_rptr, cp_nop_packet(1));
1153 }
1154 KGSL_DRV_ERR(rb->device,
1155 "Turned preamble on at offset 0x%x\n",
1156 temp_rb_rptr / 4);
1157 break;
1158 }
1159 /* If you reach beginning of next command sequence then exit
1160 * First command encountered is the current one so don't break
1161 * on that. */
1162 if (KGSL_CMD_IDENTIFIER == val[i]) {
1163 if (cmd_start)
1164 break;
1165 cmd_start = true;
1166 }
1167
1168 i = (i + 1) % 2;
1169 if (1 == i)
1170 check = true;
1171 temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
1172 size);
1173 }
1174}
1175
Shubhraprakash Das1d577fe2012-05-31 18:28:22 -06001176static void _copy_valid_rb_content(struct adreno_ringbuffer *rb,
1177 unsigned int rb_rptr, unsigned int *temp_rb_buffer,
1178 int *rb_size, unsigned int *bad_rb_buffer,
1179 int *bad_rb_size,
1180 int *last_valid_ctx_id)
1181{
1182 unsigned int good_rb_idx = 0, cmd_start_idx = 0;
1183 unsigned int val1 = 0;
1184 struct kgsl_context *k_ctxt;
1185 struct adreno_context *a_ctxt;
1186 unsigned int bad_rb_idx = 0;
1187 int copy_rb_contents = 0;
1188 unsigned int temp_rb_rptr;
1189 unsigned int size = rb->buffer_desc.size;
1190 unsigned int good_cmd_start_idx = 0;
1191
1192 /* Walk the rb from the context switch. Omit any commands
1193 * for an invalid context. */
1194 while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
1195 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
1196
1197 if (KGSL_CMD_IDENTIFIER == val1) {
1198 /* Start is the NOP dword that comes before
1199 * KGSL_CMD_IDENTIFIER */
1200 cmd_start_idx = bad_rb_idx - 1;
1201 if (copy_rb_contents)
1202 good_cmd_start_idx = good_rb_idx - 1;
1203 }
1204
1205 /* check for context switch indicator */
1206 if (val1 == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
1207 unsigned int temp_idx, val2;
1208 /* increment by 3 to get to the context_id */
1209 temp_rb_rptr = rb_rptr + (3 * sizeof(unsigned int)) %
1210 size;
1211 kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
1212 temp_rb_rptr);
1213
1214 /* if context switches to a context that did not cause
1215 * hang then start saving the rb contents as those
1216 * commands can be executed */
1217 k_ctxt = idr_find(&rb->device->context_idr, val2);
1218 if (k_ctxt) {
1219 a_ctxt = k_ctxt->devctxt;
1220
1221 /* If we are changing to a good context and were not
1222 * copying commands then copy over commands to the good
1223 * context */
1224 if (!copy_rb_contents && ((k_ctxt &&
1225 !(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
1226 !k_ctxt)) {
1227 for (temp_idx = cmd_start_idx;
1228 temp_idx < bad_rb_idx;
1229 temp_idx++)
1230 temp_rb_buffer[good_rb_idx++] =
1231 bad_rb_buffer[temp_idx];
1232 *last_valid_ctx_id = val2;
1233 copy_rb_contents = 1;
1234 } else if (copy_rb_contents && k_ctxt &&
1235 (a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
1236 /* If we are changing to bad context then remove
1237 * the dwords we copied for this sequence from
1238 * the good buffer */
1239 good_rb_idx = good_cmd_start_idx;
1240 copy_rb_contents = 0;
1241 }
1242 }
1243 }
1244
1245 if (copy_rb_contents)
1246 temp_rb_buffer[good_rb_idx++] = val1;
1247 /* Copy both good and bad commands for replay to the bad
1248 * buffer */
1249 bad_rb_buffer[bad_rb_idx++] = val1;
1250
1251 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
1252 }
1253 *rb_size = good_rb_idx;
1254 *bad_rb_size = bad_rb_idx;
1255}
1256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
Shubhraprakash Dasba6c70b2012-05-31 02:53:06 -06001258 struct adreno_recovery_data *rec_data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259{
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001260 int status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 struct kgsl_device *device = rb->device;
Shubhraprakash Dasadb16022012-05-31 16:19:37 -06001262 unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001263 struct kgsl_context *context;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001264 struct adreno_context *adreno_context;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265
Shubhraprakash Dasadb16022012-05-31 16:19:37 -06001266 context = idr_find(&device->context_idr, rec_data->context_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267
Shubhraprakash Das6f6ecb32012-06-13 12:17:11 -06001268 /* Look for the command stream that is right after the global eop */
1269 status = _find_cmd_seq_after_eop_ts(rb, &rb_rptr,
1270 rec_data->global_eop + 1, false);
Shubhraprakash Dasbb7b32a2012-06-04 15:36:39 -06001271 if (status)
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001272 goto done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001274 if (context) {
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001275 adreno_context = context->devctxt;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001276
1277 if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
1278 if (rec_data->ib1) {
1279 status = _find_hanging_ib_sequence(rb, &rb_rptr,
1280 rec_data->ib1);
1281 if (status)
1282 goto copy_rb_contents;
1283 }
1284 _turn_preamble_on_for_ib_seq(rb, rb_rptr);
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001285 } else {
1286 status = -EINVAL;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001287 }
1288 }
1289
1290copy_rb_contents:
Shubhraprakash Das1d577fe2012-05-31 18:28:22 -06001291 _copy_valid_rb_content(rb, rb_rptr, rec_data->rb_buffer,
1292 &rec_data->rb_size,
1293 rec_data->bad_rb_buffer,
1294 &rec_data->bad_rb_size,
1295 &rec_data->last_valid_ctx_id);
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001296 /* If we failed to get the hanging IB sequence then we cannot execute
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001297 * commands from the bad context or preambles not supported */
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001298 if (status) {
1299 rec_data->bad_rb_size = 0;
1300 status = 0;
1301 }
Shubhraprakash Das32240ef2012-06-06 20:27:46 -06001302 /* If there is no context then that means there are no commands for
1303 * good case */
1304 if (!context)
1305 rec_data->rb_size = 0;
Shubhraprakash Das2a85f1f2012-06-04 17:01:39 -06001306done:
1307 return status;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308}
1309
1310void
1311adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
1312 int num_rb_contents)
1313{
1314 int i;
1315 unsigned int *ringcmds;
1316 unsigned int rcmd_gpu;
1317
1318 if (!num_rb_contents)
1319 return;
1320
1321 if (num_rb_contents > (rb->buffer_desc.size - rb->wptr)) {
1322 adreno_regwrite(rb->device, REG_CP_RB_RPTR, 0);
1323 rb->rptr = 0;
1324 BUG_ON(num_rb_contents > rb->buffer_desc.size);
1325 }
1326 ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
1327 rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
1328 for (i = 0; i < num_rb_contents; i++)
1329 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb_buff[i]);
1330 rb->wptr += num_rb_contents;
1331 adreno_ringbuffer_submit(rb);
1332}