| Jordan Crouse | 6d76c4d | 2012-03-26 09:50:43 -0600 | [diff] [blame] | 1 | /* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 2 |  * | 
 | 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 |  | 
 | 14 | /* #define DEBUG */ | 
 | 15 | #define ALIGN_CPU | 
 | 16 |  | 
 | 17 | #include <linux/spinlock.h> | 
 | 18 | #include <linux/debugfs.h> | 
 | 19 | #include <linux/relay.h> | 
 | 20 | #include <linux/slab.h> | 
 | 21 | #include <linux/time.h> | 
 | 22 | #include <linux/sched.h> | 
| Jeremy Gebben | 6061bc7 | 2011-04-18 15:23:16 -0600 | [diff] [blame] | 23 | #include <mach/socinfo.h> | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 24 |  | 
 | 25 | #include "kgsl.h" | 
 | 26 | #include "kgsl_cffdump.h" | 
 | 27 | #include "kgsl_debugfs.h" | 
| Sushmita Susheelendra | 22d8717 | 2011-05-09 16:40:02 -0600 | [diff] [blame] | 28 | #include "kgsl_log.h" | 
 | 29 | #include "kgsl_sharedmem.h" | 
 | 30 | #include "adreno_pm4types.h" | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 31 |  | 
 | 32 | static struct rchan	*chan; | 
 | 33 | static struct dentry	*dir; | 
 | 34 | static int		suspended; | 
 | 35 | static size_t		dropped; | 
 | 36 | static size_t		subbuf_size = 256*1024; | 
 | 37 | static size_t		n_subbufs = 64; | 
 | 38 |  | 
 | 39 | /* forward declarations */ | 
 | 40 | static void destroy_channel(void); | 
 | 41 | static struct rchan *create_channel(unsigned subbuf_size, unsigned n_subbufs); | 
 | 42 |  | 
 | 43 | static spinlock_t cffdump_lock; | 
 | 44 | static ulong serial_nr; | 
 | 45 | static ulong total_bytes; | 
 | 46 | static ulong total_syncmem; | 
 | 47 | static long last_sec; | 
 | 48 |  | 
 | 49 | #define MEMBUF_SIZE	64 | 
 | 50 |  | 
 | 51 | #define CFF_OP_WRITE_REG        0x00000002 | 
 | 52 | struct cff_op_write_reg { | 
 | 53 | 	unsigned char op; | 
 | 54 | 	uint addr; | 
 | 55 | 	uint value; | 
| Sushmita Susheelendra | 22d8717 | 2011-05-09 16:40:02 -0600 | [diff] [blame] | 56 | } __packed; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 57 |  | 
 | 58 | #define CFF_OP_POLL_REG         0x00000004 | 
 | 59 | struct cff_op_poll_reg { | 
 | 60 | 	unsigned char op; | 
 | 61 | 	uint addr; | 
 | 62 | 	uint value; | 
 | 63 | 	uint mask; | 
| Sushmita Susheelendra | 22d8717 | 2011-05-09 16:40:02 -0600 | [diff] [blame] | 64 | } __packed; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 65 |  | 
 | 66 | #define CFF_OP_WAIT_IRQ         0x00000005 | 
 | 67 | struct cff_op_wait_irq { | 
 | 68 | 	unsigned char op; | 
| Sushmita Susheelendra | 22d8717 | 2011-05-09 16:40:02 -0600 | [diff] [blame] | 69 | } __packed; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 70 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 71 | #define CFF_OP_RMW              0x0000000a | 
 | 72 |  | 
 | 73 | #define CFF_OP_WRITE_MEM        0x0000000b | 
 | 74 | struct cff_op_write_mem { | 
 | 75 | 	unsigned char op; | 
 | 76 | 	uint addr; | 
 | 77 | 	uint value; | 
| Sushmita Susheelendra | 22d8717 | 2011-05-09 16:40:02 -0600 | [diff] [blame] | 78 | } __packed; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 79 |  | 
 | 80 | #define CFF_OP_WRITE_MEMBUF     0x0000000c | 
 | 81 | struct cff_op_write_membuf { | 
 | 82 | 	unsigned char op; | 
 | 83 | 	uint addr; | 
 | 84 | 	ushort count; | 
 | 85 | 	uint buffer[MEMBUF_SIZE]; | 
| Sushmita Susheelendra | 22d8717 | 2011-05-09 16:40:02 -0600 | [diff] [blame] | 86 | } __packed; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 87 |  | 
| Jeremy Gebben | 6061bc7 | 2011-04-18 15:23:16 -0600 | [diff] [blame] | 88 | #define CFF_OP_MEMORY_BASE	0x0000000d | 
 | 89 | struct cff_op_memory_base { | 
 | 90 | 	unsigned char op; | 
 | 91 | 	uint base; | 
 | 92 | 	uint size; | 
 | 93 | 	uint gmemsize; | 
 | 94 | } __packed; | 
 | 95 |  | 
 | 96 | #define CFF_OP_HANG		0x0000000e | 
 | 97 | struct cff_op_hang { | 
 | 98 | 	unsigned char op; | 
 | 99 | } __packed; | 
 | 100 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 101 | #define CFF_OP_EOF              0xffffffff | 
 | 102 | struct cff_op_eof { | 
 | 103 | 	unsigned char op; | 
| Sushmita Susheelendra | 22d8717 | 2011-05-09 16:40:02 -0600 | [diff] [blame] | 104 | } __packed; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 105 |  | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 106 | #define CFF_OP_VERIFY_MEM_FILE  0x00000007 | 
 | 107 | #define CFF_OP_WRITE_SURFACE_PARAMS 0x00000011 | 
 | 108 | struct cff_op_user_event { | 
 | 109 | 	unsigned char op; | 
 | 110 | 	unsigned int op1; | 
 | 111 | 	unsigned int op2; | 
 | 112 | 	unsigned int op3; | 
 | 113 | 	unsigned int op4; | 
 | 114 | 	unsigned int op5; | 
 | 115 | } __packed; | 
 | 116 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 117 |  | 
 | 118 | static void b64_encodeblock(unsigned char in[3], unsigned char out[4], int len) | 
 | 119 | { | 
 | 120 | 	static const char tob64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmno" | 
 | 121 | 		"pqrstuvwxyz0123456789+/"; | 
 | 122 |  | 
 | 123 | 	out[0] = tob64[in[0] >> 2]; | 
 | 124 | 	out[1] = tob64[((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)]; | 
 | 125 | 	out[2] = (unsigned char) (len > 1 ? tob64[((in[1] & 0x0f) << 2) | 
 | 126 | 		| ((in[2] & 0xc0) >> 6)] : '='); | 
 | 127 | 	out[3] = (unsigned char) (len > 2 ? tob64[in[2] & 0x3f] : '='); | 
 | 128 | } | 
 | 129 |  | 
 | 130 | static void b64_encode(const unsigned char *in_buf, int in_size, | 
 | 131 | 	unsigned char *out_buf, int out_bufsize, int *out_size) | 
 | 132 | { | 
 | 133 | 	unsigned char in[3], out[4]; | 
 | 134 | 	int i, len; | 
 | 135 |  | 
 | 136 | 	*out_size = 0; | 
 | 137 | 	while (in_size > 0) { | 
 | 138 | 		len = 0; | 
 | 139 | 		for (i = 0; i < 3; ++i) { | 
 | 140 | 			if (in_size-- > 0) { | 
 | 141 | 				in[i] = *in_buf++; | 
 | 142 | 				++len; | 
 | 143 | 			} else | 
 | 144 | 				in[i] = 0; | 
 | 145 | 		} | 
 | 146 | 		if (len) { | 
 | 147 | 			b64_encodeblock(in, out, len); | 
 | 148 | 			if (out_bufsize < 4) { | 
 | 149 | 				pr_warn("kgsl: cffdump: %s: out of buffer\n", | 
 | 150 | 					__func__); | 
 | 151 | 				return; | 
 | 152 | 			} | 
 | 153 | 			for (i = 0; i < 4; ++i) | 
 | 154 | 				*out_buf++ = out[i]; | 
 | 155 | 			*out_size += 4; | 
 | 156 | 			out_bufsize -= 4; | 
 | 157 | 		} | 
 | 158 | 	} | 
 | 159 | } | 
 | 160 |  | 
 | 161 | #define KLOG_TMPBUF_SIZE (1024) | 
 | 162 | static void klog_printk(const char *fmt, ...) | 
 | 163 | { | 
 | 164 | 	/* per-cpu klog formatting temporary buffer */ | 
 | 165 | 	static char klog_buf[NR_CPUS][KLOG_TMPBUF_SIZE]; | 
 | 166 |  | 
 | 167 | 	va_list args; | 
 | 168 | 	int len; | 
 | 169 | 	char *cbuf; | 
 | 170 | 	unsigned long flags; | 
 | 171 |  | 
 | 172 | 	local_irq_save(flags); | 
 | 173 | 	cbuf = klog_buf[smp_processor_id()]; | 
 | 174 | 	va_start(args, fmt); | 
 | 175 | 	len = vsnprintf(cbuf, KLOG_TMPBUF_SIZE, fmt, args); | 
 | 176 | 	total_bytes += len; | 
 | 177 | 	va_end(args); | 
 | 178 | 	relay_write(chan, cbuf, len); | 
 | 179 | 	local_irq_restore(flags); | 
 | 180 | } | 
 | 181 |  | 
 | 182 | static struct cff_op_write_membuf cff_op_write_membuf; | 
 | 183 | static void cffdump_membuf(int id, unsigned char *out_buf, int out_bufsize) | 
 | 184 | { | 
 | 185 | 	void *data; | 
 | 186 | 	int len, out_size; | 
 | 187 | 	struct cff_op_write_mem cff_op_write_mem; | 
 | 188 |  | 
 | 189 | 	uint addr = cff_op_write_membuf.addr | 
 | 190 | 		- sizeof(uint)*cff_op_write_membuf.count; | 
 | 191 |  | 
 | 192 | 	if (!cff_op_write_membuf.count) { | 
 | 193 | 		pr_warn("kgsl: cffdump: membuf: count == 0, skipping"); | 
 | 194 | 		return; | 
 | 195 | 	} | 
 | 196 |  | 
 | 197 | 	if (cff_op_write_membuf.count != 1) { | 
 | 198 | 		cff_op_write_membuf.op = CFF_OP_WRITE_MEMBUF; | 
 | 199 | 		cff_op_write_membuf.addr = addr; | 
 | 200 | 		len = sizeof(cff_op_write_membuf) - | 
 | 201 | 			sizeof(uint)*(MEMBUF_SIZE - cff_op_write_membuf.count); | 
 | 202 | 		data = &cff_op_write_membuf; | 
 | 203 | 	} else { | 
 | 204 | 		cff_op_write_mem.op = CFF_OP_WRITE_MEM; | 
 | 205 | 		cff_op_write_mem.addr = addr; | 
 | 206 | 		cff_op_write_mem.value = cff_op_write_membuf.buffer[0]; | 
 | 207 | 		data = &cff_op_write_mem; | 
 | 208 | 		len = sizeof(cff_op_write_mem); | 
 | 209 | 	} | 
 | 210 | 	b64_encode(data, len, out_buf, out_bufsize, &out_size); | 
 | 211 | 	out_buf[out_size] = 0; | 
 | 212 | 	klog_printk("%ld:%d;%s\n", ++serial_nr, id, out_buf); | 
 | 213 | 	cff_op_write_membuf.count = 0; | 
 | 214 | 	cff_op_write_membuf.addr = 0; | 
 | 215 | } | 
 | 216 |  | 
 | 217 | static void cffdump_printline(int id, uint opcode, uint op1, uint op2, | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 218 | 	uint op3, uint op4, uint op5) | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 219 | { | 
 | 220 | 	struct cff_op_write_reg cff_op_write_reg; | 
 | 221 | 	struct cff_op_poll_reg cff_op_poll_reg; | 
 | 222 | 	struct cff_op_wait_irq cff_op_wait_irq; | 
| Jeremy Gebben | 6061bc7 | 2011-04-18 15:23:16 -0600 | [diff] [blame] | 223 | 	struct cff_op_memory_base cff_op_memory_base; | 
 | 224 | 	struct cff_op_hang cff_op_hang; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 225 | 	struct cff_op_eof cff_op_eof; | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 226 | 	struct cff_op_user_event cff_op_user_event; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 227 | 	unsigned char out_buf[sizeof(cff_op_write_membuf)/3*4 + 16]; | 
 | 228 | 	void *data; | 
 | 229 | 	int len = 0, out_size; | 
 | 230 | 	long cur_secs; | 
 | 231 |  | 
 | 232 | 	spin_lock(&cffdump_lock); | 
 | 233 | 	if (opcode == CFF_OP_WRITE_MEM) { | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 234 | 		if ((cff_op_write_membuf.addr != op1 && | 
 | 235 | 			cff_op_write_membuf.count) | 
 | 236 | 			|| (cff_op_write_membuf.count == MEMBUF_SIZE)) | 
 | 237 | 			cffdump_membuf(id, out_buf, sizeof(out_buf)); | 
 | 238 |  | 
 | 239 | 		cff_op_write_membuf.buffer[cff_op_write_membuf.count++] = op2; | 
 | 240 | 		cff_op_write_membuf.addr = op1 + sizeof(uint); | 
 | 241 | 		spin_unlock(&cffdump_lock); | 
 | 242 | 		return; | 
 | 243 | 	} else if (cff_op_write_membuf.count) | 
 | 244 | 		cffdump_membuf(id, out_buf, sizeof(out_buf)); | 
 | 245 | 	spin_unlock(&cffdump_lock); | 
 | 246 |  | 
 | 247 | 	switch (opcode) { | 
 | 248 | 	case CFF_OP_WRITE_REG: | 
 | 249 | 		cff_op_write_reg.op = opcode; | 
 | 250 | 		cff_op_write_reg.addr = op1; | 
 | 251 | 		cff_op_write_reg.value = op2; | 
 | 252 | 		data = &cff_op_write_reg; | 
 | 253 | 		len = sizeof(cff_op_write_reg); | 
 | 254 | 		break; | 
 | 255 |  | 
 | 256 | 	case CFF_OP_POLL_REG: | 
 | 257 | 		cff_op_poll_reg.op = opcode; | 
 | 258 | 		cff_op_poll_reg.addr = op1; | 
 | 259 | 		cff_op_poll_reg.value = op2; | 
 | 260 | 		cff_op_poll_reg.mask = op3; | 
 | 261 | 		data = &cff_op_poll_reg; | 
 | 262 | 		len = sizeof(cff_op_poll_reg); | 
 | 263 | 		break; | 
 | 264 |  | 
 | 265 | 	case CFF_OP_WAIT_IRQ: | 
 | 266 | 		cff_op_wait_irq.op = opcode; | 
 | 267 | 		data = &cff_op_wait_irq; | 
 | 268 | 		len = sizeof(cff_op_wait_irq); | 
 | 269 | 		break; | 
 | 270 |  | 
| Jeremy Gebben | 6061bc7 | 2011-04-18 15:23:16 -0600 | [diff] [blame] | 271 | 	case CFF_OP_MEMORY_BASE: | 
 | 272 | 		cff_op_memory_base.op = opcode; | 
 | 273 | 		cff_op_memory_base.base = op1; | 
 | 274 | 		cff_op_memory_base.size = op2; | 
 | 275 | 		cff_op_memory_base.gmemsize = op3; | 
 | 276 | 		data = &cff_op_memory_base; | 
 | 277 | 		len = sizeof(cff_op_memory_base); | 
 | 278 | 		break; | 
 | 279 |  | 
 | 280 | 	case CFF_OP_HANG: | 
 | 281 | 		cff_op_hang.op = opcode; | 
 | 282 | 		data = &cff_op_hang; | 
 | 283 | 		len = sizeof(cff_op_hang); | 
 | 284 | 		break; | 
 | 285 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 286 | 	case CFF_OP_EOF: | 
 | 287 | 		cff_op_eof.op = opcode; | 
 | 288 | 		data = &cff_op_eof; | 
 | 289 | 		len = sizeof(cff_op_eof); | 
 | 290 | 		break; | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 291 |  | 
 | 292 | 	case CFF_OP_WRITE_SURFACE_PARAMS: | 
 | 293 | 	case CFF_OP_VERIFY_MEM_FILE: | 
 | 294 | 		cff_op_user_event.op = opcode; | 
 | 295 | 		cff_op_user_event.op1 = op1; | 
 | 296 | 		cff_op_user_event.op2 = op2; | 
 | 297 | 		cff_op_user_event.op3 = op3; | 
 | 298 | 		cff_op_user_event.op4 = op4; | 
 | 299 | 		cff_op_user_event.op5 = op5; | 
 | 300 | 		data = &cff_op_user_event; | 
 | 301 | 		len = sizeof(cff_op_user_event); | 
 | 302 | 		break; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 303 | 	} | 
 | 304 |  | 
 | 305 | 	if (len) { | 
 | 306 | 		b64_encode(data, len, out_buf, sizeof(out_buf), &out_size); | 
 | 307 | 		out_buf[out_size] = 0; | 
 | 308 | 		klog_printk("%ld:%d;%s\n", ++serial_nr, id, out_buf); | 
 | 309 | 	} else | 
 | 310 | 		pr_warn("kgsl: cffdump: unhandled opcode: %d\n", opcode); | 
 | 311 |  | 
 | 312 | 	cur_secs = get_seconds(); | 
 | 313 | 	if ((cur_secs - last_sec) > 10 || (last_sec - cur_secs) > 10) { | 
 | 314 | 		pr_info("kgsl: cffdump: total [bytes:%lu kB, syncmem:%lu kB], " | 
 | 315 | 			"seq#: %lu\n", total_bytes/1024, total_syncmem/1024, | 
 | 316 | 			serial_nr); | 
 | 317 | 		last_sec = cur_secs; | 
 | 318 | 	} | 
 | 319 | } | 
 | 320 |  | 
 | 321 | void kgsl_cffdump_init() | 
 | 322 | { | 
 | 323 | 	struct dentry *debugfs_dir = kgsl_get_debugfs_dir(); | 
 | 324 |  | 
 | 325 | #ifdef ALIGN_CPU | 
 | 326 | 	cpumask_t mask; | 
 | 327 |  | 
 | 328 | 	cpumask_clear(&mask); | 
| Lucille Sylvester | 57996e3 | 2011-05-26 19:12:22 -0600 | [diff] [blame] | 329 | 	cpumask_set_cpu(0, &mask); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 330 | 	sched_setaffinity(0, &mask); | 
 | 331 | #endif | 
 | 332 | 	if (!debugfs_dir || IS_ERR(debugfs_dir)) { | 
 | 333 | 		KGSL_CORE_ERR("Debugfs directory is bad\n"); | 
 | 334 | 		return; | 
 | 335 | 	} | 
 | 336 |  | 
 | 337 | 	kgsl_cff_dump_enable = 1; | 
 | 338 |  | 
 | 339 | 	spin_lock_init(&cffdump_lock); | 
 | 340 |  | 
 | 341 | 	dir = debugfs_create_dir("cff", debugfs_dir); | 
 | 342 | 	if (!dir) { | 
 | 343 | 		KGSL_CORE_ERR("debugfs_create_dir failed\n"); | 
 | 344 | 		return; | 
 | 345 | 	} | 
 | 346 |  | 
 | 347 | 	chan = create_channel(subbuf_size, n_subbufs); | 
 | 348 | } | 
 | 349 |  | 
 | 350 | void kgsl_cffdump_destroy() | 
 | 351 | { | 
 | 352 | 	if (chan) | 
 | 353 | 		relay_flush(chan); | 
 | 354 | 	destroy_channel(); | 
 | 355 | 	if (dir) | 
 | 356 | 		debugfs_remove(dir); | 
 | 357 | } | 
 | 358 |  | 
 | 359 | void kgsl_cffdump_open(enum kgsl_deviceid device_id) | 
 | 360 | { | 
| Jeremy Gebben | a3d07a4 | 2011-10-17 12:08:16 -0600 | [diff] [blame] | 361 | 	kgsl_cffdump_memory_base(device_id, KGSL_PAGETABLE_BASE, | 
| Jordan Crouse | 6d76c4d | 2012-03-26 09:50:43 -0600 | [diff] [blame] | 362 | 			kgsl_mmu_get_ptsize(), SZ_256K); | 
| Jeremy Gebben | 6061bc7 | 2011-04-18 15:23:16 -0600 | [diff] [blame] | 363 | } | 
 | 364 |  | 
 | 365 | void kgsl_cffdump_memory_base(enum kgsl_deviceid device_id, unsigned int base, | 
 | 366 | 			      unsigned int range, unsigned gmemsize) | 
 | 367 | { | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 368 | 	cffdump_printline(device_id, CFF_OP_MEMORY_BASE, base, | 
 | 369 | 			range, gmemsize, 0, 0); | 
| Jeremy Gebben | 6061bc7 | 2011-04-18 15:23:16 -0600 | [diff] [blame] | 370 | } | 
 | 371 |  | 
 | 372 | void kgsl_cffdump_hang(enum kgsl_deviceid device_id) | 
 | 373 | { | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 374 | 	cffdump_printline(device_id, CFF_OP_HANG, 0, 0, 0, 0, 0); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 375 | } | 
 | 376 |  | 
 | 377 | void kgsl_cffdump_close(enum kgsl_deviceid device_id) | 
 | 378 | { | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 379 | 	cffdump_printline(device_id, CFF_OP_EOF, 0, 0, 0, 0, 0); | 
 | 380 | } | 
 | 381 |  | 
 | 382 | void kgsl_cffdump_user_event(unsigned int cff_opcode, unsigned int op1, | 
 | 383 | 		unsigned int op2, unsigned int op3, | 
 | 384 | 		unsigned int op4, unsigned int op5) | 
 | 385 | { | 
 | 386 | 	cffdump_printline(-1, cff_opcode, op1, op2, op3, op4, op5); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 387 | } | 
 | 388 |  | 
 | 389 | void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv, | 
 | 390 | 	const struct kgsl_memdesc *memdesc, uint gpuaddr, uint sizebytes, | 
 | 391 | 	bool clean_cache) | 
 | 392 | { | 
 | 393 | 	const void *src; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 394 |  | 
 | 395 | 	if (!kgsl_cff_dump_enable) | 
 | 396 | 		return; | 
 | 397 |  | 
 | 398 | 	total_syncmem += sizebytes; | 
 | 399 |  | 
 | 400 | 	if (memdesc == NULL) { | 
 | 401 | 		struct kgsl_mem_entry *entry; | 
 | 402 | 		spin_lock(&dev_priv->process_priv->mem_lock); | 
 | 403 | 		entry = kgsl_sharedmem_find_region(dev_priv->process_priv, | 
 | 404 | 			gpuaddr, sizebytes); | 
 | 405 | 		spin_unlock(&dev_priv->process_priv->mem_lock); | 
 | 406 | 		if (entry == NULL) { | 
 | 407 | 			KGSL_CORE_ERR("did not find mapping " | 
 | 408 | 				"for gpuaddr: 0x%08x\n", gpuaddr); | 
 | 409 | 			return; | 
 | 410 | 		} | 
 | 411 | 		memdesc = &entry->memdesc; | 
 | 412 | 	} | 
| Jeremy Gebben | 16e80fa | 2011-11-30 15:56:29 -0700 | [diff] [blame] | 413 | 	src = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr); | 
 | 414 | 	if (memdesc->hostptr == NULL) { | 
 | 415 | 		KGSL_CORE_ERR("no kernel mapping for " | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 416 | 			"gpuaddr: 0x%08x, m->host: 0x%p, phys: 0x%08x\n", | 
 | 417 | 			gpuaddr, memdesc->hostptr, memdesc->physaddr); | 
 | 418 | 		return; | 
 | 419 | 	} | 
 | 420 |  | 
 | 421 | 	if (clean_cache) { | 
 | 422 | 		/* Ensure that this memory region is not read from the | 
 | 423 | 		 * cache but fetched fresh */ | 
 | 424 |  | 
 | 425 | 		mb(); | 
 | 426 |  | 
| Sushmita Susheelendra | 22d8717 | 2011-05-09 16:40:02 -0600 | [diff] [blame] | 427 | 		kgsl_cache_range_op((struct kgsl_memdesc *)memdesc, | 
 | 428 | 				KGSL_CACHE_OP_INV); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 429 | 	} | 
 | 430 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 431 | 	while (sizebytes > 3) { | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 432 | 		cffdump_printline(-1, CFF_OP_WRITE_MEM, gpuaddr, *(uint *)src, | 
 | 433 | 			0, 0, 0); | 
 | 434 | 		gpuaddr += 4; | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 435 | 		src += 4; | 
 | 436 | 		sizebytes -= 4; | 
 | 437 | 	} | 
 | 438 | 	if (sizebytes > 0) | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 439 | 		cffdump_printline(-1, CFF_OP_WRITE_MEM, gpuaddr, *(uint *)src, | 
 | 440 | 			0, 0, 0); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 441 | } | 
 | 442 |  | 
 | 443 | void kgsl_cffdump_setmem(uint addr, uint value, uint sizebytes) | 
 | 444 | { | 
 | 445 | 	if (!kgsl_cff_dump_enable) | 
 | 446 | 		return; | 
 | 447 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 448 | 	while (sizebytes > 3) { | 
 | 449 | 		/* Use 32bit memory writes as long as there's at least | 
 | 450 | 		 * 4 bytes left */ | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 451 | 		cffdump_printline(-1, CFF_OP_WRITE_MEM, addr, value, | 
 | 452 | 				0, 0, 0); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 453 | 		addr += 4; | 
 | 454 | 		sizebytes -= 4; | 
 | 455 | 	} | 
 | 456 | 	if (sizebytes > 0) | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 457 | 		cffdump_printline(-1, CFF_OP_WRITE_MEM, addr, value, | 
 | 458 | 				0, 0, 0); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 459 | } | 
 | 460 |  | 
 | 461 | void kgsl_cffdump_regwrite(enum kgsl_deviceid device_id, uint addr, | 
 | 462 | 	uint value) | 
 | 463 | { | 
 | 464 | 	if (!kgsl_cff_dump_enable) | 
 | 465 | 		return; | 
 | 466 |  | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 467 | 	cffdump_printline(device_id, CFF_OP_WRITE_REG, addr, value, | 
 | 468 | 			0, 0, 0); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 469 | } | 
 | 470 |  | 
 | 471 | void kgsl_cffdump_regpoll(enum kgsl_deviceid device_id, uint addr, | 
 | 472 | 	uint value, uint mask) | 
 | 473 | { | 
 | 474 | 	if (!kgsl_cff_dump_enable) | 
 | 475 | 		return; | 
 | 476 |  | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 477 | 	cffdump_printline(device_id, CFF_OP_POLL_REG, addr, value, | 
 | 478 | 			mask, 0, 0); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 479 | } | 
 | 480 |  | 
 | 481 | void kgsl_cffdump_slavewrite(uint addr, uint value) | 
 | 482 | { | 
 | 483 | 	if (!kgsl_cff_dump_enable) | 
 | 484 | 		return; | 
 | 485 |  | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 486 | 	cffdump_printline(-1, CFF_OP_WRITE_REG, addr, value, 0, 0, 0); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 487 | } | 
 | 488 |  | 
 | 489 | int kgsl_cffdump_waitirq(void) | 
 | 490 | { | 
 | 491 | 	if (!kgsl_cff_dump_enable) | 
 | 492 | 		return 0; | 
 | 493 |  | 
| Sushmita Susheelendra | 41f8fa3 | 2011-05-11 17:15:58 -0600 | [diff] [blame] | 494 | 	cffdump_printline(-1, CFF_OP_WAIT_IRQ, 0, 0, 0, 0, 0); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 495 |  | 
 | 496 | 	return 1; | 
 | 497 | } | 
 | 498 | EXPORT_SYMBOL(kgsl_cffdump_waitirq); | 
 | 499 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 500 | static int subbuf_start_handler(struct rchan_buf *buf, | 
 | 501 | 	void *subbuf, void *prev_subbuf, uint prev_padding) | 
 | 502 | { | 
 | 503 | 	pr_debug("kgsl: cffdump: subbuf_start_handler(subbuf=%p, prev_subbuf" | 
 | 504 | 		"=%p, prev_padding=%08x)\n", subbuf, prev_subbuf, prev_padding); | 
 | 505 |  | 
 | 506 | 	if (relay_buf_full(buf)) { | 
 | 507 | 		if (!suspended) { | 
 | 508 | 			suspended = 1; | 
 | 509 | 			pr_warn("kgsl: cffdump: relay: cpu %d buffer full!!!\n", | 
 | 510 | 				smp_processor_id()); | 
 | 511 | 		} | 
 | 512 | 		dropped++; | 
 | 513 | 		return 0; | 
 | 514 | 	} else if (suspended) { | 
 | 515 | 		suspended = 0; | 
 | 516 | 		pr_warn("kgsl: cffdump: relay: cpu %d buffer no longer full.\n", | 
 | 517 | 			smp_processor_id()); | 
 | 518 | 	} | 
 | 519 |  | 
 | 520 | 	subbuf_start_reserve(buf, 0); | 
 | 521 | 	return 1; | 
 | 522 | } | 
 | 523 |  | 
 | 524 | static struct dentry *create_buf_file_handler(const char *filename, | 
 | 525 | 	struct dentry *parent, int mode, struct rchan_buf *buf, | 
 | 526 | 	int *is_global) | 
 | 527 | { | 
 | 528 | 	return debugfs_create_file(filename, mode, parent, buf, | 
 | 529 | 				       &relay_file_operations); | 
 | 530 | } | 
 | 531 |  | 
 | 532 | /* | 
 | 533 |  * file_remove() default callback.  Removes relay file in debugfs. | 
 | 534 |  */ | 
 | 535 | static int remove_buf_file_handler(struct dentry *dentry) | 
 | 536 | { | 
 | 537 | 	pr_info("kgsl: cffdump: %s()\n", __func__); | 
 | 538 | 	debugfs_remove(dentry); | 
 | 539 | 	return 0; | 
 | 540 | } | 
 | 541 |  | 
 | 542 | /* | 
 | 543 |  * relay callbacks | 
 | 544 |  */ | 
 | 545 | static struct rchan_callbacks relay_callbacks = { | 
 | 546 | 	.subbuf_start = subbuf_start_handler, | 
 | 547 | 	.create_buf_file = create_buf_file_handler, | 
 | 548 | 	.remove_buf_file = remove_buf_file_handler, | 
 | 549 | }; | 
 | 550 |  | 
 | 551 | /** | 
 | 552 |  *	create_channel - creates channel /debug/klog/cpuXXX | 
 | 553 |  * | 
 | 554 |  *	Creates channel along with associated produced/consumed control files | 
 | 555 |  * | 
 | 556 |  *	Returns channel on success, NULL otherwise | 
 | 557 |  */ | 
 | 558 | static struct rchan *create_channel(unsigned subbuf_size, unsigned n_subbufs) | 
 | 559 | { | 
 | 560 | 	struct rchan *chan; | 
 | 561 |  | 
 | 562 | 	pr_info("kgsl: cffdump: relay: create_channel: subbuf_size %u, " | 
 | 563 | 		"n_subbufs %u, dir 0x%p\n", subbuf_size, n_subbufs, dir); | 
 | 564 |  | 
 | 565 | 	chan = relay_open("cpu", dir, subbuf_size, | 
 | 566 | 			  n_subbufs, &relay_callbacks, NULL); | 
 | 567 | 	if (!chan) { | 
 | 568 | 		KGSL_CORE_ERR("relay_open failed\n"); | 
 | 569 | 		return NULL; | 
 | 570 | 	} | 
 | 571 |  | 
 | 572 | 	suspended = 0; | 
 | 573 | 	dropped = 0; | 
 | 574 |  | 
 | 575 | 	return chan; | 
 | 576 | } | 
 | 577 |  | 
 | 578 | /** | 
 | 579 |  *	destroy_channel - destroys channel /debug/kgsl/cff/cpuXXX | 
 | 580 |  * | 
 | 581 |  *	Destroys channel along with associated produced/consumed control files | 
 | 582 |  */ | 
 | 583 | static void destroy_channel(void) | 
 | 584 | { | 
 | 585 | 	pr_info("kgsl: cffdump: relay: destroy_channel\n"); | 
 | 586 | 	if (chan) { | 
 | 587 | 		relay_close(chan); | 
 | 588 | 		chan = NULL; | 
 | 589 | 	} | 
 | 590 | } | 
 | 591 |  |