Duy Truong | e833aca | 2013-02-12 13:35:08 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2012, The Linux Foundation. All rights reserved. |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -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 | #ifndef _KGSL_SNAPSHOT_H_ |
| 15 | #define _KGSL_SNAPSHOT_H_ |
| 16 | |
| 17 | #include <linux/types.h> |
| 18 | |
| 19 | /* Snapshot header */ |
| 20 | |
Jordan Crouse | 70829d3 | 2012-06-20 08:22:17 -0600 | [diff] [blame] | 21 | /* High word is static, low word is snapshot version ID */ |
| 22 | #define SNAPSHOT_MAGIC 0x504D0002 |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 23 | |
| 24 | /* GPU ID scheme: |
| 25 | * [16:31] - core identifer (0x0002 for 2D or 0x0003 for 3D) |
| 26 | * [00:16] - GPU specific identifier |
| 27 | */ |
| 28 | |
| 29 | struct kgsl_snapshot_header { |
| 30 | __u32 magic; /* Magic identifier */ |
| 31 | __u32 gpuid; /* GPU ID - see above */ |
Jordan Crouse | 70829d3 | 2012-06-20 08:22:17 -0600 | [diff] [blame] | 32 | /* Added in snapshot version 2 */ |
| 33 | __u32 chipid; /* Chip ID from the GPU */ |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 34 | } __packed; |
| 35 | |
| 36 | /* Section header */ |
| 37 | #define SNAPSHOT_SECTION_MAGIC 0xABCD |
| 38 | |
| 39 | struct kgsl_snapshot_section_header { |
| 40 | __u16 magic; /* Magic identifier */ |
| 41 | __u16 id; /* Type of section */ |
| 42 | __u32 size; /* Size of the section including this header */ |
| 43 | } __packed; |
| 44 | |
| 45 | /* Section identifiers */ |
| 46 | #define KGSL_SNAPSHOT_SECTION_OS 0x0101 |
| 47 | #define KGSL_SNAPSHOT_SECTION_REGS 0x0201 |
| 48 | #define KGSL_SNAPSHOT_SECTION_RB 0x0301 |
| 49 | #define KGSL_SNAPSHOT_SECTION_IB 0x0401 |
| 50 | #define KGSL_SNAPSHOT_SECTION_INDEXED_REGS 0x0501 |
| 51 | #define KGSL_SNAPSHOT_SECTION_ISTORE 0x0801 |
| 52 | #define KGSL_SNAPSHOT_SECTION_DEBUG 0x0901 |
Jordan Crouse | 0c2761a | 2012-02-01 22:11:12 -0700 | [diff] [blame] | 53 | #define KGSL_SNAPSHOT_SECTION_DEBUGBUS 0x0A01 |
Jordan Crouse | 9610b6b | 2012-03-16 14:53:42 -0600 | [diff] [blame] | 54 | #define KGSL_SNAPSHOT_SECTION_GPU_OBJECT 0x0B01 |
| 55 | |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 56 | #define KGSL_SNAPSHOT_SECTION_END 0xFFFF |
| 57 | |
| 58 | /* OS sub-section header */ |
| 59 | #define KGSL_SNAPSHOT_OS_LINUX 0x0001 |
| 60 | |
| 61 | /* Linux OS specific information */ |
| 62 | |
| 63 | #define SNAPSHOT_STATE_HUNG 0 |
| 64 | #define SNAPSHOT_STATE_RUNNING 1 |
| 65 | |
| 66 | struct kgsl_snapshot_linux { |
| 67 | int osid; /* subsection OS identifier */ |
| 68 | int state; /* 1 if the thread is running, 0 for hung */ |
| 69 | __u32 seconds; /* Unix timestamp for the snapshot */ |
| 70 | __u32 power_flags; /* Current power flags */ |
| 71 | __u32 power_level; /* Current power level */ |
| 72 | __u32 power_interval_timeout; /* Power interval timeout */ |
| 73 | __u32 grpclk; /* Current GP clock value */ |
| 74 | __u32 busclk; /* Current busclk value */ |
| 75 | __u32 ptbase; /* Current ptbase */ |
| 76 | __u32 pid; /* PID of the process that owns the PT */ |
| 77 | __u32 current_context; /* ID of the current context */ |
| 78 | __u32 ctxtcount; /* Number of contexts appended to section */ |
| 79 | unsigned char release[32]; /* kernel release */ |
| 80 | unsigned char version[32]; /* kernel version */ |
| 81 | unsigned char comm[16]; /* Name of the process that owns the PT */ |
| 82 | } __packed; |
| 83 | |
| 84 | /* |
| 85 | * This structure contains a record of an active context. |
| 86 | * These are appended one after another in the OS section below |
| 87 | * the header above |
| 88 | */ |
| 89 | |
| 90 | struct kgsl_snapshot_linux_context { |
| 91 | __u32 id; /* The context ID */ |
| 92 | __u32 timestamp_queued; /* The last queued timestamp */ |
| 93 | __u32 timestamp_retired; /* The last timestamp retired by HW */ |
| 94 | }; |
| 95 | |
| 96 | /* Ringbuffer sub-section header */ |
| 97 | struct kgsl_snapshot_rb { |
| 98 | int start; /* dword at the start of the dump */ |
| 99 | int end; /* dword at the end of the dump */ |
| 100 | int rbsize; /* Size (in dwords) of the ringbuffer */ |
| 101 | int wptr; /* Current index of the CPU write pointer */ |
| 102 | int rptr; /* Current index of the GPU read pointer */ |
| 103 | int count; /* Number of dwords in the dump */ |
| 104 | } __packed; |
| 105 | |
| 106 | /* Indirect buffer sub-section header */ |
| 107 | struct kgsl_snapshot_ib { |
| 108 | __u32 gpuaddr; /* GPU address of the the IB */ |
| 109 | __u32 ptbase; /* Base for the pagetable the GPU address is valid in */ |
| 110 | int size; /* Size of the IB */ |
| 111 | } __packed; |
| 112 | |
| 113 | /* Register sub-section header */ |
| 114 | struct kgsl_snapshot_regs { |
| 115 | __u32 count; /* Number of register pairs in the section */ |
| 116 | } __packed; |
| 117 | |
| 118 | /* Indexed register sub-section header */ |
| 119 | struct kgsl_snapshot_indexed_regs { |
| 120 | __u32 index_reg; /* Offset of the index register for this section */ |
| 121 | __u32 data_reg; /* Offset of the data register for this section */ |
| 122 | int start; /* Starting index */ |
| 123 | int count; /* Number of dwords in the data */ |
| 124 | } __packed; |
| 125 | |
| 126 | /* Istore sub-section header */ |
| 127 | struct kgsl_snapshot_istore { |
| 128 | int count; /* Number of instructions in the istore */ |
| 129 | } __packed; |
| 130 | |
| 131 | /* Debug data sub-section header */ |
| 132 | |
Jordan Crouse | 0c2761a | 2012-02-01 22:11:12 -0700 | [diff] [blame] | 133 | /* A2XX debug sections */ |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 134 | #define SNAPSHOT_DEBUG_SX 1 |
| 135 | #define SNAPSHOT_DEBUG_CP 2 |
| 136 | #define SNAPSHOT_DEBUG_SQ 3 |
| 137 | #define SNAPSHOT_DEBUG_SQTHREAD 4 |
| 138 | #define SNAPSHOT_DEBUG_MIU 5 |
| 139 | |
Jordan Crouse | 0c2761a | 2012-02-01 22:11:12 -0700 | [diff] [blame] | 140 | /* A3XX debug sections */ |
| 141 | #define SNAPSHOT_DEBUG_VPC_MEMORY 6 |
| 142 | #define SNAPSHOT_DEBUG_CP_MEQ 7 |
| 143 | #define SNAPSHOT_DEBUG_CP_PM4_RAM 8 |
| 144 | #define SNAPSHOT_DEBUG_CP_PFP_RAM 9 |
| 145 | #define SNAPSHOT_DEBUG_CP_ROQ 10 |
Jordan Crouse | 013c731 | 2012-06-20 08:22:17 -0600 | [diff] [blame] | 146 | #define SNAPSHOT_DEBUG_SHADER_MEMORY 11 |
Jordan Crouse | 8256893 | 2012-08-14 12:40:07 -0600 | [diff] [blame] | 147 | #define SNAPSHOT_DEBUG_CP_MERCIU 12 |
Jordan Crouse | 0c2761a | 2012-02-01 22:11:12 -0700 | [diff] [blame] | 148 | |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 149 | struct kgsl_snapshot_debug { |
| 150 | int type; /* Type identifier for the attached tata */ |
Jordan Crouse | 0c2761a | 2012-02-01 22:11:12 -0700 | [diff] [blame] | 151 | int size; /* Size of the section in dwords */ |
| 152 | } __packed; |
| 153 | |
| 154 | struct kgsl_snapshot_debugbus { |
| 155 | int id; /* Debug bus ID */ |
| 156 | int count; /* Number of dwords in the dump */ |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 157 | } __packed; |
| 158 | |
Jordan Crouse | e0879b1 | 2012-03-16 14:53:43 -0600 | [diff] [blame] | 159 | #define SNAPSHOT_GPU_OBJECT_SHADER 1 |
| 160 | #define SNAPSHOT_GPU_OBJECT_IB 2 |
| 161 | #define SNAPSHOT_GPU_OBJECT_GENERIC 3 |
Jordan Crouse | ea2c638 | 2012-03-16 14:53:42 -0600 | [diff] [blame] | 162 | |
Jordan Crouse | 9610b6b | 2012-03-16 14:53:42 -0600 | [diff] [blame] | 163 | struct kgsl_snapshot_gpu_object { |
| 164 | int type; /* Type of GPU object */ |
| 165 | __u32 gpuaddr; /* GPU address of the the object */ |
| 166 | __u32 ptbase; /* Base for the pagetable the GPU address is valid in */ |
| 167 | int size; /* Size of the object (in dwords) */ |
| 168 | }; |
| 169 | |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 170 | #ifdef __KERNEL__ |
| 171 | |
| 172 | /* Allocate 512K for each device snapshot */ |
| 173 | #define KGSL_SNAPSHOT_MEMSIZE (512 * 1024) |
| 174 | |
| 175 | struct kgsl_device; |
| 176 | /* |
| 177 | * A helper macro to print out "not enough memory functions" - this |
| 178 | * makes it easy to standardize the messages as well as cut down on |
| 179 | * the number of strings in the binary |
| 180 | */ |
| 181 | |
| 182 | #define SNAPSHOT_ERR_NOMEM(_d, _s) \ |
| 183 | KGSL_DRV_ERR((_d), \ |
| 184 | "snapshot: not enough snapshot memory for section %s\n", (_s)) |
| 185 | |
| 186 | /* |
| 187 | * kgsl_snapshot_add_section - Add a new section to the GPU snapshot |
| 188 | * @device - the KGSL device being snapshotted |
| 189 | * @id - the section id |
| 190 | * @snapshot - pointer to the memory for the snapshot |
| 191 | * @remain - pointer to the number of bytes left in the snapshot region |
| 192 | * @func - Function pointer to fill the section |
| 193 | * @priv - Priv pointer to pass to the function |
| 194 | * |
| 195 | * Set up a KGSL snapshot header by filling the memory with the callback |
| 196 | * function and adding the standard section header |
| 197 | */ |
| 198 | |
| 199 | static inline void *kgsl_snapshot_add_section(struct kgsl_device *device, |
| 200 | u16 id, void *snapshot, int *remain, |
| 201 | int (*func)(struct kgsl_device *, void *, int, void *), void *priv) |
| 202 | { |
| 203 | struct kgsl_snapshot_section_header *header = snapshot; |
| 204 | void *data = snapshot + sizeof(*header); |
| 205 | int ret = 0; |
| 206 | |
| 207 | /* |
| 208 | * Sanity check to make sure there is enough for the header. The |
| 209 | * callback will check to make sure there is enough for the rest |
| 210 | * of the data. If there isn't enough room then don't advance the |
| 211 | * pointer. |
| 212 | */ |
| 213 | |
| 214 | if (*remain < sizeof(*header)) |
| 215 | return snapshot; |
| 216 | |
| 217 | /* It is legal to have no function (i.e. - make an empty section) */ |
| 218 | |
| 219 | if (func) { |
| 220 | ret = func(device, data, *remain, priv); |
| 221 | |
| 222 | /* |
| 223 | * If there wasn't enough room for the data then don't bother |
| 224 | * setting up the header. |
| 225 | */ |
| 226 | |
| 227 | if (ret == 0) |
| 228 | return snapshot; |
| 229 | } |
| 230 | |
| 231 | header->magic = SNAPSHOT_SECTION_MAGIC; |
| 232 | header->id = id; |
| 233 | header->size = ret + sizeof(*header); |
| 234 | |
| 235 | /* Decrement the room left in the snapshot region */ |
| 236 | *remain -= header->size; |
| 237 | /* Advance the pointer to the end of the next function */ |
| 238 | return snapshot + header->size; |
| 239 | } |
| 240 | |
| 241 | /* A common helper function to dump a range of registers. This will be used in |
| 242 | * the GPU specific devices like this: |
| 243 | * |
Jordan Crouse | ea4f8b8 | 2012-08-14 14:38:46 -0600 | [diff] [blame] | 244 | * struct kgsl_snapshot_registers_list list; |
| 245 | * struct kgsl_snapshot_registers priv[2]; |
| 246 | * |
| 247 | * priv[0].regs = registers_array;; |
| 248 | * priv[o].count = num_registers; |
| 249 | * priv[1].regs = registers_array_new;; |
| 250 | * priv[1].count = num_registers_new; |
| 251 | * |
| 252 | * list.registers = priv; |
| 253 | * list.count = 2; |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 254 | * |
| 255 | * kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, |
Jordan Crouse | ea4f8b8 | 2012-08-14 14:38:46 -0600 | [diff] [blame] | 256 | * remain, kgsl_snapshot_dump_regs, &list). |
| 257 | * |
| 258 | * Pass in a struct pointing to a list of register definitions as described |
| 259 | * below: |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 260 | * |
| 261 | * Pass in an array of register range pairs in the form of: |
| 262 | * start reg, stop reg |
| 263 | * All the registers between start and stop inclusive will be dumped |
| 264 | */ |
| 265 | |
| 266 | struct kgsl_snapshot_registers { |
| 267 | unsigned int *regs; /* Pointer to the array of register ranges */ |
| 268 | int count; /* Number of entries in the array */ |
| 269 | }; |
| 270 | |
Jordan Crouse | ea4f8b8 | 2012-08-14 14:38:46 -0600 | [diff] [blame] | 271 | struct kgsl_snapshot_registers_list { |
| 272 | /* Pointer to an array of register lists */ |
| 273 | struct kgsl_snapshot_registers *registers; |
| 274 | /* Number of registers lists in the array */ |
| 275 | int count; |
| 276 | }; |
| 277 | |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 278 | int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot, |
| 279 | int remain, void *priv); |
| 280 | |
| 281 | /* |
| 282 | * A common helper function to dump a set of indexed registers. Use it |
| 283 | * like this: |
| 284 | * |
| 285 | * struct kgsl_snapshot_indexed_registers priv; |
| 286 | * priv.index = REG_INDEX; |
| 287 | * priv.data = REG_DATA; |
| 288 | * priv.count = num_registers |
| 289 | * |
| 290 | * kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_INDEXED_REGS, |
| 291 | * snapshot, remain, kgsl_snapshot_dump_indexed_regs, &priv). |
| 292 | * |
| 293 | * The callback function will write an index from 0 to priv.count to |
| 294 | * the index register and read the data from the data register. |
| 295 | */ |
| 296 | |
| 297 | struct kgsl_snapshot_indexed_registers { |
| 298 | unsigned int index; /* Offset of the index register */ |
| 299 | unsigned int data; /* Offset of the data register */ |
| 300 | unsigned int start; /* Index to start with */ |
| 301 | unsigned int count; /* Number of values to read from the pair */ |
| 302 | }; |
| 303 | |
Jordan Crouse | 0c2761a | 2012-02-01 22:11:12 -0700 | [diff] [blame] | 304 | /* Helper function to snapshot a section of indexed registers */ |
| 305 | |
| 306 | void *kgsl_snapshot_indexed_registers(struct kgsl_device *device, |
| 307 | void *snapshot, int *remain, unsigned int index, |
| 308 | unsigned int data, unsigned int start, unsigned int count); |
| 309 | |
Jordan Crouse | 9610b6b | 2012-03-16 14:53:42 -0600 | [diff] [blame] | 310 | /* Freeze a GPU buffer so it can be dumped in the snapshot */ |
| 311 | int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase, |
| 312 | unsigned int gpuaddr, unsigned int size, unsigned int type); |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 313 | |
Jordan Crouse | 21aaadf | 2012-09-11 16:38:15 -0600 | [diff] [blame] | 314 | int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase, |
| 315 | unsigned int gpuaddr, unsigned int size); |
| 316 | |
Jordan Crouse | 156cfbc | 2012-01-24 09:32:04 -0700 | [diff] [blame] | 317 | #endif |
| 318 | #endif |