blob: 9542dfce91bc830f4b3948fd7aa647ef75310308 [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) {
Wei Zouc8c01632012-03-24 17:27:26 -0700238 rb->timestamp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239 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 */
Wei Zouc8c01632012-03-24 17:27:26 -0700323 adreno_regwrite(device, REG_SCRATCH_ADDR,
324 device->memstore.gpuaddr +
325 KGSL_DEVICE_MEMSTORE_OFFSET(soptimestamp));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326
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;
Wei Zouc8c01632012-03-24 17:27:26 -0700434 unsigned int total_sizedwords = sizedwords + 6;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 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
Wei Zouc8c01632012-03-24 17:27:26 -0700475 rb->timestamp++;
476 timestamp = rb->timestamp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477
Wei Zouc8c01632012-03-24 17:27:26 -0700478 /* 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));
Wei Zouc8c01632012-03-24 17:27:26 -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);
Wei Zouc8c01632012-03-24 17:27:26 -0700498 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);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502
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));
Wei Zouc8c01632012-03-24 17:27:26 -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);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512 /* # 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
Wei Zouc8c01632012-03-24 17:27:26 -0700530 /* return timestamp of issued coREG_ands */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531 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;
Wei Zouc8c01632012-03-24 17:27:26 -0700545 adreno_ringbuffer_addcmds(rb, flags, cmds, sizedwords);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546}
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 }
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600578
579 cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
580 GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 if (!link) {
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600582 KGSL_CORE_ERR("kzalloc(%d) failed\n",
583 sizeof(unsigned int) * (numibs * 3 + 4));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584 return -ENOMEM;
585 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700586
587 /*When preamble is enabled, the preamble buffer with state restoration
588 commands are stored in the first node of the IB chain. We can skip that
589 if a context switch hasn't occured */
590
591 if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
592 adreno_dev->drawctxt_active == drawctxt)
593 start_index = 1;
594
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600595 if (!start_index) {
596 *cmds++ = cp_nop_packet(1);
597 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
598 } else {
599 *cmds++ = cp_nop_packet(4);
600 *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
601 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
602 *cmds++ = ibdesc[0].gpuaddr;
603 *cmds++ = ibdesc[0].sizedwords;
604 }
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700605 for (i = start_index; i < numibs; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606 (void)kgsl_cffdump_parse_ibs(dev_priv, NULL,
607 ibdesc[i].gpuaddr, ibdesc[i].sizedwords, false);
608
Jordan Crouse084427d2011-07-28 08:37:58 -0600609 *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610 *cmds++ = ibdesc[i].gpuaddr;
611 *cmds++ = ibdesc[i].sizedwords;
612 }
613
Shubhraprakash Dasd23ff4b2012-04-05 16:55:54 -0600614 *cmds++ = cp_nop_packet(1);
615 *cmds++ = KGSL_END_OF_IB_IDENTIFIER;
616
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 kgsl_setstate(device,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600618 kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 device->id));
620
621 adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
622
623 *timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
624 KGSL_CMD_FLAGS_NOT_KERNEL_CMD,
625 &link[0], (cmds - link));
626
627 KGSL_CMD_INFO(device, "ctxt %d g %08x numibs %d ts %d\n",
628 context->id, (unsigned int)ibdesc, numibs, *timestamp);
629
630 kfree(link);
631
632#ifdef CONFIG_MSM_KGSL_CFF_DUMP
633 /*
634 * insert wait for idle after every IB1
635 * this is conservative but works reliably and is ok
636 * even for performance simulations
637 */
638 adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
639#endif
640
641 return 0;
642}
643
644int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
645 unsigned int *temp_rb_buffer,
646 int *rb_size)
647{
648 struct kgsl_device *device = rb->device;
649 unsigned int rb_rptr;
650 unsigned int retired_timestamp;
651 unsigned int temp_idx = 0;
652 unsigned int value;
653 unsigned int val1;
654 unsigned int val2;
655 unsigned int val3;
656 unsigned int copy_rb_contents = 0;
Wei Zouc8c01632012-03-24 17:27:26 -0700657 unsigned int cur_context;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658
659 GSL_RB_GET_READPTR(rb, &rb->rptr);
660
Wei Zouc8c01632012-03-24 17:27:26 -0700661 retired_timestamp = device->ftbl->readtimestamp(device,
662 KGSL_TIMESTAMP_RETIRED);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 KGSL_DRV_ERR(device, "GPU successfully executed till ts: %x\n",
664 retired_timestamp);
665 /*
666 * We need to go back in history by 4 dwords from the current location
667 * of read pointer as 4 dwords are read to match the end of a command.
668 * Also, take care of wrap around when moving back
669 */
670 if (rb->rptr >= 4)
671 rb_rptr = (rb->rptr - 4) * sizeof(unsigned int);
672 else
673 rb_rptr = rb->buffer_desc.size -
674 ((4 - rb->rptr) * sizeof(unsigned int));
675 /* Read the rb contents going backwards to locate end of last
676 * sucessfully executed command */
677 while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
678 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
679 if (value == retired_timestamp) {
680 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
681 rb->buffer_desc.size);
682 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
683 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
684 rb->buffer_desc.size);
685 kgsl_sharedmem_readl(&rb->buffer_desc, &val2, rb_rptr);
686 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
687 rb->buffer_desc.size);
688 kgsl_sharedmem_readl(&rb->buffer_desc, &val3, rb_rptr);
689 /* match the pattern found at the end of a command */
690 if ((val1 == 2 &&
Jordan Crouse084427d2011-07-28 08:37:58 -0600691 val2 == cp_type3_packet(CP_INTERRUPT, 1)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692 && val3 == CP_INT_CNTL__RB_INT_MASK) ||
Jordan Crouse084427d2011-07-28 08:37:58 -0600693 (val1 == cp_type3_packet(CP_EVENT_WRITE, 3)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694 && val2 == CACHE_FLUSH_TS &&
695 val3 == (rb->device->memstore.gpuaddr +
Wei Zouc8c01632012-03-24 17:27:26 -0700696 KGSL_DEVICE_MEMSTORE_OFFSET(eoptimestamp)))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700697 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
698 rb->buffer_desc.size);
699 KGSL_DRV_ERR(device,
700 "Found end of last executed "
701 "command at offset: %x\n",
702 rb_rptr / sizeof(unsigned int));
703 break;
704 } else {
705 if (rb_rptr < (3 * sizeof(unsigned int)))
706 rb_rptr = rb->buffer_desc.size -
707 (3 * sizeof(unsigned int))
708 + rb_rptr;
709 else
710 rb_rptr -= (3 * sizeof(unsigned int));
711 }
712 }
713
714 if (rb_rptr == 0)
715 rb_rptr = rb->buffer_desc.size - sizeof(unsigned int);
716 else
717 rb_rptr -= sizeof(unsigned int);
718 }
719
720 if ((rb_rptr / sizeof(unsigned int)) == rb->wptr) {
721 KGSL_DRV_ERR(device,
722 "GPU recovery from hang not possible because last"
723 " successful timestamp is overwritten\n");
724 return -EINVAL;
725 }
726 /* rb_rptr is now pointing to the first dword of the command following
727 * the last sucessfully executed command sequence. Assumption is that
728 * GPU is hung in the command sequence pointed by rb_rptr */
729 /* make sure the GPU is not hung in a command submitted by kgsl
730 * itself */
731 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
732 kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
733 adreno_ringbuffer_inc_wrapped(rb_rptr,
734 rb->buffer_desc.size));
Jordan Crouse084427d2011-07-28 08:37:58 -0600735 if (val1 == cp_nop_packet(1) && val2 == KGSL_CMD_IDENTIFIER) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700736 KGSL_DRV_ERR(device,
737 "GPU recovery from hang not possible because "
738 "of hang in kgsl command\n");
739 return -EINVAL;
740 }
741
Wei Zouc8c01632012-03-24 17:27:26 -0700742 /* current_context is the context that is presently active in the
743 * GPU, i.e the context in which the hang is caused */
744 kgsl_sharedmem_readl(&device->memstore, &cur_context,
745 KGSL_DEVICE_MEMSTORE_OFFSET(current_context));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
747 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
748 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
749 rb->buffer_desc.size);
750 /* check for context switch indicator */
751 if (value == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
752 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
753 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
754 rb->buffer_desc.size);
Jordan Crouse084427d2011-07-28 08:37:58 -0600755 BUG_ON(value != cp_type3_packet(CP_MEM_WRITE, 2));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700756 kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
757 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
758 rb->buffer_desc.size);
759 BUG_ON(val1 != (device->memstore.gpuaddr +
Wei Zouc8c01632012-03-24 17:27:26 -0700760 KGSL_DEVICE_MEMSTORE_OFFSET(current_context)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700761 kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
762 rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
763 rb->buffer_desc.size);
Jordan Crousea400d8d2012-03-16 14:53:39 -0600764
765 /*
766 * If other context switches were already lost and
767 * and the current context is the one that is hanging,
768 * then we cannot recover. Print an error message
769 * and leave.
770 */
771
Wei Zouc8c01632012-03-24 17:27:26 -0700772 if ((copy_rb_contents == 0) && (value == cur_context)) {
Jordan Crousea400d8d2012-03-16 14:53:39 -0600773 KGSL_DRV_ERR(device, "GPU recovery could not "
774 "find the previous context\n");
775 return -EINVAL;
776 }
777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778 /*
779 * If we were copying the commands and got to this point
780 * then we need to remove the 3 commands that appear
781 * before KGSL_CONTEXT_TO_MEM_IDENTIFIER
782 */
783 if (temp_idx)
784 temp_idx -= 3;
785 /* if context switches to a context that did not cause
786 * hang then start saving the rb contents as those
787 * commands can be executed */
Wei Zouc8c01632012-03-24 17:27:26 -0700788 if (value != cur_context) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789 copy_rb_contents = 1;
Jordan Crouse084427d2011-07-28 08:37:58 -0600790 temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791 temp_rb_buffer[temp_idx++] =
792 KGSL_CMD_IDENTIFIER;
Jordan Crouse084427d2011-07-28 08:37:58 -0600793 temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700794 temp_rb_buffer[temp_idx++] =
795 KGSL_CONTEXT_TO_MEM_IDENTIFIER;
796 temp_rb_buffer[temp_idx++] =
Jordan Crouse084427d2011-07-28 08:37:58 -0600797 cp_type3_packet(CP_MEM_WRITE, 2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700798 temp_rb_buffer[temp_idx++] = val1;
799 temp_rb_buffer[temp_idx++] = value;
800 } else {
801 copy_rb_contents = 0;
802 }
803 } else if (copy_rb_contents)
804 temp_rb_buffer[temp_idx++] = value;
805 }
806
807 *rb_size = temp_idx;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808 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}