blob: 8293c2c2f3cef13b7c8501efd73ea96a56489ea8 [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;
55
56 /* if wptr ahead, fill the remaining with NOPs */
57 if (wptr_ahead) {
58 /* -1 for header */
59 nopcount = rb->sizedwords - rb->wptr - 1;
60
61 cmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
62 cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*rb->wptr;
63
Jordan Crouse084427d2011-07-28 08:37:58 -060064 GSL_RB_WRITE(cmds, cmds_gpu, cp_nop_packet(nopcount));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065
66 /* Make sure that rptr is not 0 before submitting
67 * commands at the end of ringbuffer. We do not
68 * want the rptr and wptr to become equal when
69 * the ringbuffer is not empty */
70 do {
71 GSL_RB_GET_READPTR(rb, &rb->rptr);
72 } while (!rb->rptr);
73
74 rb->wptr++;
75
76 adreno_ringbuffer_submit(rb);
77
78 rb->wptr = 0;
79 }
80
81 /* wait for space in ringbuffer */
82 do {
83 GSL_RB_GET_READPTR(rb, &rb->rptr);
84
85 freecmds = rb->rptr - rb->wptr;
86
87 } while ((freecmds != 0) && (freecmds <= numcmds));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088}
89
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070090unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 unsigned int numcmds)
92{
93 unsigned int *ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094
95 BUG_ON(numcmds >= rb->sizedwords);
96
97 GSL_RB_GET_READPTR(rb, &rb->rptr);
98 /* check for available space */
99 if (rb->wptr >= rb->rptr) {
100 /* wptr ahead or equal to rptr */
101 /* reserve dwords for nop packet */
102 if ((rb->wptr + numcmds) > (rb->sizedwords -
103 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600104 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105 } else {
106 /* wptr behind rptr */
107 if ((rb->wptr + numcmds) >= rb->rptr)
Carter Cooper6dd94c82011-10-13 14:43:53 -0600108 adreno_ringbuffer_waitspace(rb, numcmds, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 /* check for remaining space */
110 /* reserve dwords for nop packet */
111 if ((rb->wptr + numcmds) > (rb->sizedwords -
112 GSL_RB_NOP_SIZEDWORDS))
Carter Cooper6dd94c82011-10-13 14:43:53 -0600113 adreno_ringbuffer_waitspace(rb, numcmds, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700114 }
115
Carter Cooper6dd94c82011-10-13 14:43:53 -0600116 ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
117 rb->wptr += numcmds;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700118
119 return ptr;
120}
121
122static int _load_firmware(struct kgsl_device *device, const char *fwfile,
123 void **data, int *len)
124{
125 const struct firmware *fw = NULL;
126 int ret;
127
128 ret = request_firmware(&fw, fwfile, device->dev);
129
130 if (ret) {
131 KGSL_DRV_ERR(device, "request_firmware(%s) failed: %d\n",
132 fwfile, ret);
133 return ret;
134 }
135
136 *data = kmalloc(fw->size, GFP_KERNEL);
137
138 if (*data) {
139 memcpy(*data, fw->data, fw->size);
140 *len = fw->size;
141 } else
142 KGSL_MEM_ERR(device, "kmalloc(%d) failed\n", fw->size);
143
144 release_firmware(fw);
145 return (*data != NULL) ? 0 : -ENOMEM;
146}
147
148static int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
149{
150 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151 int i, ret = 0;
152
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 if (adreno_dev->pm4_fw == NULL) {
154 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600155 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156
Jordan Crouse505df9c2011-07-28 08:37:59 -0600157 ret = _load_firmware(device, adreno_dev->pm4_fwfile,
158 &ptr, &len);
159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 if (ret)
161 goto err;
162
163 /* PM4 size is 3 dword aligned plus 1 dword of version */
164 if (len % ((sizeof(uint32_t) * 3)) != sizeof(uint32_t)) {
165 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
166 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600167 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168 goto err;
169 }
170
171 adreno_dev->pm4_fw_size = len / sizeof(uint32_t);
172 adreno_dev->pm4_fw = ptr;
173 }
174
175 KGSL_DRV_INFO(device, "loading pm4 ucode version: %d\n",
176 adreno_dev->pm4_fw[0]);
177
178 adreno_regwrite(device, REG_CP_DEBUG, 0x02000000);
179 adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
180 for (i = 1; i < adreno_dev->pm4_fw_size; i++)
181 adreno_regwrite(device, REG_CP_ME_RAM_DATA,
182 adreno_dev->pm4_fw[i]);
183err:
184 return ret;
185}
186
187static int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
188{
189 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 int i, ret = 0;
191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192 if (adreno_dev->pfp_fw == NULL) {
193 int len;
Jordan Crouse505df9c2011-07-28 08:37:59 -0600194 void *ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195
Jordan Crouse505df9c2011-07-28 08:37:59 -0600196 ret = _load_firmware(device, adreno_dev->pfp_fwfile,
197 &ptr, &len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198 if (ret)
199 goto err;
200
201 /* PFP size shold be dword aligned */
202 if (len % sizeof(uint32_t) != 0) {
203 KGSL_DRV_ERR(device, "Bad firmware size: %d\n", len);
204 ret = -EINVAL;
Jeremy Gebben79acee62011-08-08 16:44:07 -0600205 kfree(ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206 goto err;
207 }
208
209 adreno_dev->pfp_fw_size = len / sizeof(uint32_t);
210 adreno_dev->pfp_fw = ptr;
211 }
212
213 KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
214 adreno_dev->pfp_fw[0]);
215
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700216 adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700217 for (i = 1; i < adreno_dev->pfp_fw_size; i++)
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700218 adreno_regwrite(device,
219 adreno_dev->gpudev->reg_cp_pfp_ucode_data,
220 adreno_dev->pfp_fw[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221err:
222 return ret;
223}
224
225int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
226{
227 int status;
228 /*cp_rb_cntl_u cp_rb_cntl; */
229 union reg_cp_rb_cntl cp_rb_cntl;
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700230 unsigned int rb_cntl;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 struct kgsl_device *device = rb->device;
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700232 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233
234 if (rb->flags & KGSL_FLAGS_STARTED)
235 return 0;
236
237 if (init_ram) {
238 rb->timestamp = 0;
239 GSL_RB_INIT_TIMESTAMP(rb);
240 }
241
242 kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
243 sizeof(struct kgsl_rbmemptrs));
244
245 kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
246 (rb->sizedwords << 2));
247
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700248 if (adreno_is_a2xx(adreno_dev)) {
249 adreno_regwrite(device, REG_CP_RB_WPTR_BASE,
250 (rb->memptrs_desc.gpuaddr
251 + GSL_RB_MEMPTRS_WPTRPOLL_OFFSET));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700253 /* setup WPTR delay */
254 adreno_regwrite(device, REG_CP_RB_WPTR_DELAY,
255 0 /*0x70000010 */);
256 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257
258 /*setup REG_CP_RB_CNTL */
259 adreno_regread(device, REG_CP_RB_CNTL, &rb_cntl);
260 cp_rb_cntl.val = rb_cntl;
261
262 /*
263 * The size of the ringbuffer in the hardware is the log2
264 * representation of the size in quadwords (sizedwords / 2)
265 */
266 cp_rb_cntl.f.rb_bufsz = ilog2(rb->sizedwords >> 1);
267
268 /*
269 * Specify the quadwords to read before updating mem RPTR.
270 * Like above, pass the log2 representation of the blocksize
271 * in quadwords.
272 */
273 cp_rb_cntl.f.rb_blksz = ilog2(KGSL_RB_BLKSIZE >> 3);
274
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700275 if (adreno_is_a2xx(adreno_dev)) {
276 /* WPTR polling */
277 cp_rb_cntl.f.rb_poll_en = GSL_RB_CNTL_POLL_EN;
278 }
279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280 /* mem RPTR writebacks */
281 cp_rb_cntl.f.rb_no_update = GSL_RB_CNTL_NO_UPDATE;
282
283 adreno_regwrite(device, REG_CP_RB_CNTL, cp_rb_cntl.val);
284
285 adreno_regwrite(device, REG_CP_RB_BASE, rb->buffer_desc.gpuaddr);
286
287 adreno_regwrite(device, REG_CP_RB_RPTR_ADDR,
288 rb->memptrs_desc.gpuaddr +
289 GSL_RB_MEMPTRS_RPTR_OFFSET);
290
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700291 if (adreno_is_a3xx(adreno_dev)) {
292 /* enable access protection to privileged registers */
293 adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);
294
295 /* RBBM registers */
296 adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
297 adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
298 adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
299 adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
300 adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
301 adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);
302
303 /* CP registers */
304 adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
305 adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
306 adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
307 adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
308 adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);
309
310 /* RB registers */
311 adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
312
313 /* VBIF registers */
314 adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
315 }
316
317 if (adreno_is_a2xx(adreno_dev)) {
318 /* explicitly clear all cp interrupts */
319 adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF);
320 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321
322 /* setup scratch/timestamp */
323 adreno_regwrite(device, REG_SCRATCH_ADDR,
324 device->memstore.gpuaddr +
325 KGSL_DEVICE_MEMSTORE_OFFSET(soptimestamp));
326
327 adreno_regwrite(device, REG_SCRATCH_UMSK,
328 GSL_RB_MEMPTRS_SCRATCH_MASK);
329
330 /* load the CP ucode */
331
332 status = adreno_ringbuffer_load_pm4_ucode(device);
333 if (status != 0)
334 return status;
335
336 /* load the prefetch parser ucode */
337 status = adreno_ringbuffer_load_pfp_ucode(device);
338 if (status != 0)
339 return status;
340
341 adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000C0804);
342
343 rb->rptr = 0;
344 rb->wptr = 0;
345
346 /* clear ME_HALT to start micro engine */
347 adreno_regwrite(device, REG_CP_ME_CNTL, 0);
348
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700349 /* ME init is GPU specific, so jump into the sub-function */
350 adreno_dev->gpudev->rb_init(adreno_dev, rb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351
352 /* idle device to validate ME INIT */
353 status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
354
355 if (status == 0)
356 rb->flags |= KGSL_FLAGS_STARTED;
357
358 return status;
359}
360
Carter Cooper6dd94c82011-10-13 14:43:53 -0600361void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362{
363 if (rb->flags & KGSL_FLAGS_STARTED) {
364 /* ME_HALT */
365 adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366 rb->flags &= ~KGSL_FLAGS_STARTED;
367 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700368}
369
370int adreno_ringbuffer_init(struct kgsl_device *device)
371{
372 int status;
373 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
374 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
375
376 rb->device = device;
377 /*
378 * It is silly to convert this to words and then back to bytes
379 * immediately below, but most of the rest of the code deals
380 * in words, so we might as well only do the math once
381 */
382 rb->sizedwords = KGSL_RB_SIZE >> 2;
383
384 /* allocate memory for ringbuffer */
385 status = kgsl_allocate_contiguous(&rb->buffer_desc,
386 (rb->sizedwords << 2));
387
388 if (status != 0) {
389 adreno_ringbuffer_close(rb);
390 return status;
391 }
392
393 /* allocate memory for polling and timestamps */
394 /* This really can be at 4 byte alignment boundry but for using MMU
395 * we need to make it at page boundary */
396 status = kgsl_allocate_contiguous(&rb->memptrs_desc,
397 sizeof(struct kgsl_rbmemptrs));
398
399 if (status != 0) {
400 adreno_ringbuffer_close(rb);
401 return status;
402 }
403
404 /* overlay structure on memptrs memory */
405 rb->memptrs = (struct kgsl_rbmemptrs *) rb->memptrs_desc.hostptr;
406
407 return 0;
408}
409
Carter Cooper6dd94c82011-10-13 14:43:53 -0600410void adreno_ringbuffer_close(struct adreno_ringbuffer *rb)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411{
412 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
413
414 kgsl_sharedmem_free(&rb->buffer_desc);
415 kgsl_sharedmem_free(&rb->memptrs_desc);
416
417 kfree(adreno_dev->pfp_fw);
418 kfree(adreno_dev->pm4_fw);
419
420 adreno_dev->pfp_fw = NULL;
421 adreno_dev->pm4_fw = NULL;
422
423 memset(rb, 0, sizeof(struct adreno_ringbuffer));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424}
425
426static uint32_t
427adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
428 unsigned int flags, unsigned int *cmds,
429 int sizedwords)
430{
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700431 struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 unsigned int *ringcmds;
433 unsigned int timestamp;
434 unsigned int total_sizedwords = sizedwords + 6;
435 unsigned int i;
436 unsigned int rcmd_gpu;
437
438 /* reserve space to temporarily turn off protected mode
439 * error checking if needed
440 */
441 total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
442 total_sizedwords += !(flags & KGSL_CMD_FLAGS_NO_TS_CMP) ? 7 : 0;
443 total_sizedwords += !(flags & KGSL_CMD_FLAGS_NOT_KERNEL_CMD) ? 2 : 0;
444
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700445 if (adreno_is_a3xx(adreno_dev))
446 total_sizedwords += 7;
447
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448 ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
449 rcmd_gpu = rb->buffer_desc.gpuaddr
450 + sizeof(uint)*(rb->wptr-total_sizedwords);
451
452 if (!(flags & KGSL_CMD_FLAGS_NOT_KERNEL_CMD)) {
Jordan Crouse084427d2011-07-28 08:37:58 -0600453 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
455 }
456 if (flags & KGSL_CMD_FLAGS_PMODE) {
457 /* disable protected mode error checking */
458 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600459 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
461 }
462
463 for (i = 0; i < sizedwords; i++) {
464 GSL_RB_WRITE(ringcmds, rcmd_gpu, *cmds);
465 cmds++;
466 }
467
468 if (flags & KGSL_CMD_FLAGS_PMODE) {
469 /* re-enable protected mode error checking */
470 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600471 cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472 GSL_RB_WRITE(ringcmds, rcmd_gpu, 1);
473 }
474
475 rb->timestamp++;
476 timestamp = rb->timestamp;
477
478 /* start-of-pipeline and end-of-pipeline timestamps */
Jordan Crouse084427d2011-07-28 08:37:58 -0600479 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp);
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700481
482 if (adreno_is_a3xx(adreno_dev)) {
483 /*
484 * FLush HLSQ lazy updates to make sure there are no
485 * rsources pending for indirect loads after the timestamp
486 */
487
488 GSL_RB_WRITE(ringcmds, rcmd_gpu,
489 cp_type3_packet(CP_EVENT_WRITE, 1));
490 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x07); /* HLSQ_FLUSH */
491 GSL_RB_WRITE(ringcmds, rcmd_gpu,
492 cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
493 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
494 }
495
Jordan Crouse084427d2011-07-28 08:37:58 -0600496 GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_EVENT_WRITE, 3));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
498 GSL_RB_WRITE(ringcmds, rcmd_gpu,
499 (rb->device->memstore.gpuaddr +
500 KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp)));
501 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp);
502
503 if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) {
504 /* Conditional execution based on memory values */
505 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600506 cp_type3_packet(CP_COND_EXEC, 4));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 GSL_RB_WRITE(ringcmds, rcmd_gpu, (rb->device->memstore.gpuaddr +
508 KGSL_DEVICE_MEMSTORE_OFFSET(ts_cmp_enable)) >> 2);
509 GSL_RB_WRITE(ringcmds, rcmd_gpu, (rb->device->memstore.gpuaddr +
510 KGSL_DEVICE_MEMSTORE_OFFSET(ref_wait_ts)) >> 2);
511 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp);
512 /* # of conditional command DWORDs */
513 GSL_RB_WRITE(ringcmds, rcmd_gpu, 2);
514 GSL_RB_WRITE(ringcmds, rcmd_gpu,
Jordan Crouse084427d2011-07-28 08:37:58 -0600515 cp_type3_packet(CP_INTERRUPT, 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700516 GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
517 }
518
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700519 if (adreno_is_a3xx(adreno_dev)) {
520 /* Dummy set-constant to trigger context rollover */
521 GSL_RB_WRITE(ringcmds, rcmd_gpu,
522 cp_type3_packet(CP_SET_CONSTANT, 2));
523 GSL_RB_WRITE(ringcmds, rcmd_gpu,
524 (0x4<<16)|(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG - 0x2000));
525 GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
526 }
527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528 adreno_ringbuffer_submit(rb);
529
530 /* return timestamp of issued coREG_ands */
531 return timestamp;
532}
533
534void
535adreno_ringbuffer_issuecmds(struct kgsl_device *device,
536 unsigned int flags,
537 unsigned int *cmds,
538 int sizedwords)
539{
540 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
541 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
542
543 if (device->state & KGSL_STATE_HUNG)
544 return;
545 adreno_ringbuffer_addcmds(rb, flags, cmds, sizedwords);
546}
547
548int
549adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
550 struct kgsl_context *context,
551 struct kgsl_ibdesc *ibdesc,
552 unsigned int numibs,
553 uint32_t *timestamp,
554 unsigned int flags)
555{
556 struct kgsl_device *device = dev_priv->device;
557 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
558 unsigned int *link;
559 unsigned int *cmds;
560 unsigned int i;
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600561 struct adreno_context *drawctxt;
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700562 unsigned int start_index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563
564 if (device->state & KGSL_STATE_HUNG)
565 return -EBUSY;
566 if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) ||
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600567 context == NULL || ibdesc == 0 || numibs == 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700568 return -EINVAL;
569
Jeremy Gebben3c127f52011-08-08 17:04:11 -0600570 drawctxt = context->devctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571
572 if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
573 KGSL_CTXT_WARN(device, "Context %p caused a gpu hang.."
574 " will not accept commands for this context\n",
575 drawctxt);
576 return -EDEADLK;
577 }
578 link = kzalloc(sizeof(unsigned int) * numibs * 3, GFP_KERNEL);
579 cmds = link;
580 if (!link) {
581 KGSL_MEM_ERR(device, "Failed to allocate memory for for command"
582 " submission, size %x\n", numibs * 3);
583 return -ENOMEM;
584 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700585
586 /*When preamble is enabled, the preamble buffer with state restoration
587 commands are stored in the first node of the IB chain. We can skip that
588 if a context switch hasn't occured */
589
590 if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
591 adreno_dev->drawctxt_active == drawctxt)
592 start_index = 1;
593
594 for (i = start_index; i < numibs; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700595 (void)kgsl_cffdump_parse_ibs(dev_priv, NULL,
596 ibdesc[i].gpuaddr, ibdesc[i].sizedwords, false);
597
Jordan Crouse084427d2011-07-28 08:37:58 -0600598 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 *cmds++ = ibdesc[i].gpuaddr;
600 *cmds++ = ibdesc[i].sizedwords;
601 }
602
603 kgsl_setstate(device,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600604 kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605 device->id));
606
607 adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
608
609 *timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
610 KGSL_CMD_FLAGS_NOT_KERNEL_CMD,
611 &link[0], (cmds - link));
612
613 KGSL_CMD_INFO(device, "ctxt %d g %08x numibs %d ts %d\n",
614 context->id, (unsigned int)ibdesc, numibs, *timestamp);
615
616 kfree(link);
617
618#ifdef CONFIG_MSM_KGSL_CFF_DUMP
619 /*
620 * insert wait for idle after every IB1
621 * this is conservative but works reliably and is ok
622 * even for performance simulations
623 */
624 adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
625#endif
626
627 return 0;
628}
629
630int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
631 unsigned int *temp_rb_buffer,
632 int *rb_size)
633{
634 struct kgsl_device *device = rb->device;
635 unsigned int rb_rptr;
636 unsigned int retired_timestamp;
637 unsigned int temp_idx = 0;
638 unsigned int value;
639 unsigned int val1;
640 unsigned int val2;
641 unsigned int val3;
642 unsigned int copy_rb_contents = 0;
643 unsigned int cur_context;
644 unsigned int j;
645
646 GSL_RB_GET_READPTR(rb, &rb->rptr);
647
648 retired_timestamp = device->ftbl->readtimestamp(device,
649 KGSL_TIMESTAMP_RETIRED);
650 KGSL_DRV_ERR(device, "GPU successfully executed till ts: %x\n",
651 retired_timestamp);
652 /*
653 * We need to go back in history by 4 dwords from the current location
654 * of read pointer as 4 dwords are read to match the end of a command.
655 * Also, take care of wrap around when moving back
656 */
657 if (rb->rptr >= 4)
658 rb_rptr = (rb->rptr - 4) * sizeof(unsigned int);
659 else
660 rb_rptr = rb->buffer_desc.size -
661 ((4 - rb->rptr) * sizeof(unsigned int));
662 /* Read the rb contents going backwards to locate end of last
663 * sucessfully executed command */
664 while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
665 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
666 if (value == retired_timestamp) {
667 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
668 rb->buffer_desc.size);
669 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
670 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
671 rb->buffer_desc.size);
672 kgsl_sharedmem_readl(&rb->buffer_desc, &val2, rb_rptr);
673 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
674 rb->buffer_desc.size);
675 kgsl_sharedmem_readl(&rb->buffer_desc, &val3, rb_rptr);
676 /* match the pattern found at the end of a command */
677 if ((val1 == 2 &&
Jordan Crouse084427d2011-07-28 08:37:58 -0600678 val2 == cp_type3_packet(CP_INTERRUPT, 1)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679 && val3 == CP_INT_CNTL__RB_INT_MASK) ||
Jordan Crouse084427d2011-07-28 08:37:58 -0600680 (val1 == cp_type3_packet(CP_EVENT_WRITE, 3)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681 && val2 == CACHE_FLUSH_TS &&
682 val3 == (rb->device->memstore.gpuaddr +
683 KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp)))) {
684 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
685 rb->buffer_desc.size);
686 KGSL_DRV_ERR(device,
687 "Found end of last executed "
688 "command at offset: %x\n",
689 rb_rptr / sizeof(unsigned int));
690 break;
691 } else {
692 if (rb_rptr < (3 * sizeof(unsigned int)))
693 rb_rptr = rb->buffer_desc.size -
694 (3 * sizeof(unsigned int))
695 + rb_rptr;
696 else
697 rb_rptr -= (3 * sizeof(unsigned int));
698 }
699 }
700
701 if (rb_rptr == 0)
702 rb_rptr = rb->buffer_desc.size - sizeof(unsigned int);
703 else
704 rb_rptr -= sizeof(unsigned int);
705 }
706
707 if ((rb_rptr / sizeof(unsigned int)) == rb->wptr) {
708 KGSL_DRV_ERR(device,
709 "GPU recovery from hang not possible because last"
710 " successful timestamp is overwritten\n");
711 return -EINVAL;
712 }
713 /* rb_rptr is now pointing to the first dword of the command following
714 * the last sucessfully executed command sequence. Assumption is that
715 * GPU is hung in the command sequence pointed by rb_rptr */
716 /* make sure the GPU is not hung in a command submitted by kgsl
717 * itself */
718 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
719 kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
720 adreno_ringbuffer_inc_wrapped(rb_rptr,
721 rb->buffer_desc.size));
Jordan Crouse084427d2011-07-28 08:37:58 -0600722 if (val1 == cp_nop_packet(1) && val2 == KGSL_CMD_IDENTIFIER) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 KGSL_DRV_ERR(device,
724 "GPU recovery from hang not possible because "
725 "of hang in kgsl command\n");
726 return -EINVAL;
727 }
728
729 /* current_context is the context that is presently active in the
730 * GPU, i.e the context in which the hang is caused */
731 kgsl_sharedmem_readl(&device->memstore, &cur_context,
732 KGSL_DEVICE_MEMSTORE_OFFSET(current_context));
733 while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
734 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
735 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
736 rb->buffer_desc.size);
737 /* check for context switch indicator */
738 if (value == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
739 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
740 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
741 rb->buffer_desc.size);
Jordan Crouse084427d2011-07-28 08:37:58 -0600742 BUG_ON(value != cp_type3_packet(CP_MEM_WRITE, 2));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
744 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
745 rb->buffer_desc.size);
746 BUG_ON(val1 != (device->memstore.gpuaddr +
747 KGSL_DEVICE_MEMSTORE_OFFSET(current_context)));
748 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
749 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
750 rb->buffer_desc.size);
Jordan Crousea400d8d2012-03-16 14:53:39 -0600751
752 /*
753 * If other context switches were already lost and
754 * and the current context is the one that is hanging,
755 * then we cannot recover. Print an error message
756 * and leave.
757 */
758
759 if ((copy_rb_contents == 0) && (value == cur_context)) {
760 KGSL_DRV_ERR(device, "GPU recovery could not "
761 "find the previous context\n");
762 return -EINVAL;
763 }
764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765 /*
766 * If we were copying the commands and got to this point
767 * then we need to remove the 3 commands that appear
768 * before KGSL_CONTEXT_TO_MEM_IDENTIFIER
769 */
770 if (temp_idx)
771 temp_idx -= 3;
772 /* if context switches to a context that did not cause
773 * hang then start saving the rb contents as those
774 * commands can be executed */
775 if (value != cur_context) {
776 copy_rb_contents = 1;
Jordan Crouse084427d2011-07-28 08:37:58 -0600777 temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778 temp_rb_buffer[temp_idx++] =
779 KGSL_CMD_IDENTIFIER;
Jordan Crouse084427d2011-07-28 08:37:58 -0600780 temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 temp_rb_buffer[temp_idx++] =
782 KGSL_CONTEXT_TO_MEM_IDENTIFIER;
783 temp_rb_buffer[temp_idx++] =
Jordan Crouse084427d2011-07-28 08:37:58 -0600784 cp_type3_packet(CP_MEM_WRITE, 2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700785 temp_rb_buffer[temp_idx++] = val1;
786 temp_rb_buffer[temp_idx++] = value;
787 } else {
788 copy_rb_contents = 0;
789 }
790 } else if (copy_rb_contents)
791 temp_rb_buffer[temp_idx++] = value;
792 }
793
794 *rb_size = temp_idx;
795 KGSL_DRV_ERR(device, "Extracted rb contents, size: %x\n", *rb_size);
796 for (temp_idx = 0; temp_idx < *rb_size;) {
797 char str[80];
798 int idx = 0;
799 if ((temp_idx + 8) <= *rb_size)
800 j = 8;
801 else
802 j = *rb_size - temp_idx;
803 for (; j != 0; j--)
804 idx += scnprintf(str + idx, 80 - idx,
805 "%8.8X ", temp_rb_buffer[temp_idx++]);
806 printk(KERN_ALERT "%s", str);
807 }
808 return 0;
809}
810
811void
812adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
813 int num_rb_contents)
814{
815 int i;
816 unsigned int *ringcmds;
817 unsigned int rcmd_gpu;
818
819 if (!num_rb_contents)
820 return;
821
822 if (num_rb_contents > (rb->buffer_desc.size - rb->wptr)) {
823 adreno_regwrite(rb->device, REG_CP_RB_RPTR, 0);
824 rb->rptr = 0;
825 BUG_ON(num_rb_contents > rb->buffer_desc.size);
826 }
827 ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
828 rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
829 for (i = 0; i < num_rb_contents; i++)
830 GSL_RB_WRITE(ringcmds, rcmd_gpu, rb_buff[i]);
831 rb->wptr += num_rb_contents;
832 adreno_ringbuffer_submit(rb);
833}