1 // SPDX-License-Identifier: GPL-2.0-only OR MIT 2 /* Copyright (c) 2023 Imagination Technologies Ltd. */ 3 4 #include "pvr_device.h" 5 #include "pvr_gem.h" 6 #include "pvr_rogue_fwif.h" 7 #include "pvr_rogue_fwif_sf.h" 8 #include "pvr_fw_trace.h" 9 10 #include <drm/drm_drv.h> 11 #include <drm/drm_file.h> 12 13 #include <linux/build_bug.h> 14 #include <linux/dcache.h> 15 #include <linux/debugfs.h> 16 #include <linux/sysfs.h> 17 #include <linux/types.h> 18 19 static void 20 tracebuf_ctrl_init(void *cpu_ptr, void *priv) 21 { 22 struct rogue_fwif_tracebuf *tracebuf_ctrl = cpu_ptr; 23 struct pvr_fw_trace *fw_trace = priv; 24 25 tracebuf_ctrl->tracebuf_size_in_dwords = ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS; 26 tracebuf_ctrl->tracebuf_flags = 0; 27 28 if (fw_trace->group_mask) 29 tracebuf_ctrl->log_type = fw_trace->group_mask | ROGUE_FWIF_LOG_TYPE_TRACE; 30 else 31 tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_NONE; 32 33 for (u32 thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { 34 struct rogue_fwif_tracebuf_space *tracebuf_space = 35 &tracebuf_ctrl->tracebuf[thread_nr]; 36 struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; 37 38 pvr_fw_object_get_fw_addr(trace_buffer->buf_obj, 39 &tracebuf_space->trace_buffer_fw_addr); 40 41 tracebuf_space->trace_buffer = trace_buffer->buf; 42 tracebuf_space->trace_pointer = 0; 43 } 44 } 45 46 int pvr_fw_trace_init(struct pvr_device *pvr_dev) 47 { 48 struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; 49 struct drm_device *drm_dev = from_pvr_device(pvr_dev); 50 int err; 51 52 for (u32 thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { 53 struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; 54 55 trace_buffer->buf = 56 pvr_fw_object_create_and_map(pvr_dev, 57 ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS * 58 sizeof(*trace_buffer->buf), 59 PVR_BO_FW_FLAGS_DEVICE_UNCACHED | 60 PVR_BO_FW_NO_CLEAR_ON_RESET, 61 NULL, NULL, &trace_buffer->buf_obj); 62 if (IS_ERR(trace_buffer->buf)) { 63 drm_err(drm_dev, "Unable to allocate trace buffer\n"); 64 err = PTR_ERR(trace_buffer->buf); 65 trace_buffer->buf = NULL; 66 goto err_free_buf; 67 } 68 } 69 70 /* TODO: Provide control of group mask. */ 71 fw_trace->group_mask = 0; 72 73 fw_trace->tracebuf_ctrl = 74 pvr_fw_object_create_and_map(pvr_dev, 75 sizeof(*fw_trace->tracebuf_ctrl), 76 PVR_BO_FW_FLAGS_DEVICE_UNCACHED | 77 PVR_BO_FW_NO_CLEAR_ON_RESET, 78 tracebuf_ctrl_init, fw_trace, 79 &fw_trace->tracebuf_ctrl_obj); 80 if (IS_ERR(fw_trace->tracebuf_ctrl)) { 81 drm_err(drm_dev, "Unable to allocate trace buffer control structure\n"); 82 err = PTR_ERR(fw_trace->tracebuf_ctrl); 83 goto err_free_buf; 84 } 85 86 BUILD_BUG_ON(ARRAY_SIZE(fw_trace->tracebuf_ctrl->tracebuf) != 87 ARRAY_SIZE(fw_trace->buffers)); 88 89 for (u32 thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { 90 struct rogue_fwif_tracebuf_space *tracebuf_space = 91 &fw_trace->tracebuf_ctrl->tracebuf[thread_nr]; 92 struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; 93 94 trace_buffer->tracebuf_space = tracebuf_space; 95 } 96 97 return 0; 98 99 err_free_buf: 100 for (u32 thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { 101 struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; 102 103 if (trace_buffer->buf) 104 pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj); 105 } 106 107 return err; 108 } 109 110 void pvr_fw_trace_fini(struct pvr_device *pvr_dev) 111 { 112 struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; 113 114 for (u32 thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { 115 struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; 116 117 pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj); 118 } 119 pvr_fw_object_unmap_and_destroy(fw_trace->tracebuf_ctrl_obj); 120 } 121 122 /** 123 * update_logtype() - Send KCCB command to trigger FW to update logtype 124 * @pvr_dev: Target PowerVR device 125 * @group_mask: New log group mask. 126 * 127 * Returns: 128 * * 0 on success, 129 * * Any error returned by pvr_kccb_send_cmd(), or 130 * * -%EIO if the device is lost. 131 */ 132 static int 133 update_logtype(struct pvr_device *pvr_dev, u32 group_mask) 134 { 135 struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; 136 struct rogue_fwif_kccb_cmd cmd; 137 int idx; 138 int err; 139 140 if (group_mask) 141 fw_trace->tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_TRACE | group_mask; 142 else 143 fw_trace->tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_NONE; 144 145 fw_trace->group_mask = group_mask; 146 147 down_read(&pvr_dev->reset_sem); 148 if (!drm_dev_enter(from_pvr_device(pvr_dev), &idx)) { 149 err = -EIO; 150 goto err_up_read; 151 } 152 153 cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_LOGTYPE_UPDATE; 154 cmd.kccb_flags = 0; 155 156 err = pvr_kccb_send_cmd(pvr_dev, &cmd, NULL); 157 158 drm_dev_exit(idx); 159 160 err_up_read: 161 up_read(&pvr_dev->reset_sem); 162 163 return err; 164 } 165 166 struct pvr_fw_trace_seq_data { 167 /** @buffer: Pointer to copy of trace data. */ 168 u32 *buffer; 169 170 /** @start_offset: Starting offset in trace data, as reported by FW. */ 171 u32 start_offset; 172 173 /** @idx: Current index into trace data. */ 174 u32 idx; 175 176 /** @assert_buf: Trace assert buffer, as reported by FW. */ 177 struct rogue_fwif_file_info_buf assert_buf; 178 }; 179 180 static u32 find_sfid(u32 id) 181 { 182 for (u32 i = 0; i < ARRAY_SIZE(stid_fmts); i++) { 183 if (stid_fmts[i].id == id) 184 return i; 185 } 186 187 return ROGUE_FW_SF_LAST; 188 } 189 190 static u32 read_fw_trace(struct pvr_fw_trace_seq_data *trace_seq_data, u32 offset) 191 { 192 u32 idx; 193 194 idx = trace_seq_data->idx + offset; 195 if (idx >= ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) 196 return 0; 197 198 idx = (idx + trace_seq_data->start_offset) % ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS; 199 return trace_seq_data->buffer[idx]; 200 } 201 202 /** 203 * fw_trace_get_next() - Advance trace index to next entry 204 * @trace_seq_data: Trace sequence data. 205 * 206 * Returns: 207 * * %true if trace index is now pointing to a valid entry, or 208 * * %false if trace index is pointing to an invalid entry, or has hit the end 209 * of the trace. 210 */ 211 static bool fw_trace_get_next(struct pvr_fw_trace_seq_data *trace_seq_data) 212 { 213 u32 id, sf_id; 214 215 while (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) { 216 id = read_fw_trace(trace_seq_data, 0); 217 trace_seq_data->idx++; 218 if (!ROGUE_FW_LOG_VALIDID(id)) 219 continue; 220 if (id == ROGUE_FW_SF_MAIN_ASSERT_FAILED) { 221 /* Assertion failure marks the end of the trace. */ 222 return false; 223 } 224 225 sf_id = find_sfid(id); 226 if (sf_id == ROGUE_FW_SF_FIRST) 227 continue; 228 if (sf_id == ROGUE_FW_SF_LAST) { 229 /* 230 * Could not match with an ID in the SF table, trace is 231 * most likely corrupt from this point. 232 */ 233 return false; 234 } 235 236 /* Skip over the timestamp, and any parameters. */ 237 trace_seq_data->idx += 2 + ROGUE_FW_SF_PARAMNUM(id); 238 239 /* Ensure index is now pointing to a valid trace entry. */ 240 id = read_fw_trace(trace_seq_data, 0); 241 if (!ROGUE_FW_LOG_VALIDID(id)) 242 continue; 243 244 return true; 245 } 246 247 /* Hit end of trace data. */ 248 return false; 249 } 250 251 /** 252 * fw_trace_get_first() - Find first valid entry in trace 253 * @trace_seq_data: Trace sequence data. 254 * 255 * Skips over invalid (usually zero) and ROGUE_FW_SF_FIRST entries. 256 * 257 * If the trace has no valid entries, this function will exit with the trace 258 * index pointing to the end of the trace. trace_seq_show() will return an error 259 * in this state. 260 */ 261 static void fw_trace_get_first(struct pvr_fw_trace_seq_data *trace_seq_data) 262 { 263 trace_seq_data->idx = 0; 264 265 while (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) { 266 u32 id = read_fw_trace(trace_seq_data, 0); 267 268 if (ROGUE_FW_LOG_VALIDID(id)) { 269 u32 sf_id = find_sfid(id); 270 271 if (sf_id != ROGUE_FW_SF_FIRST) 272 break; 273 } 274 trace_seq_data->idx++; 275 } 276 } 277 278 static void *fw_trace_seq_start(struct seq_file *s, loff_t *pos) 279 { 280 struct pvr_fw_trace_seq_data *trace_seq_data = s->private; 281 282 /* Reset trace index, then advance to *pos. */ 283 fw_trace_get_first(trace_seq_data); 284 285 for (u32 i = 0; i < *pos; i++) { 286 if (!fw_trace_get_next(trace_seq_data)) 287 return NULL; 288 } 289 290 return (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) ? pos : NULL; 291 } 292 293 static void *fw_trace_seq_next(struct seq_file *s, void *v, loff_t *pos) 294 { 295 struct pvr_fw_trace_seq_data *trace_seq_data = s->private; 296 297 (*pos)++; 298 if (!fw_trace_get_next(trace_seq_data)) 299 return NULL; 300 301 return (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) ? pos : NULL; 302 } 303 304 static void fw_trace_seq_stop(struct seq_file *s, void *v) 305 { 306 } 307 308 static int fw_trace_seq_show(struct seq_file *s, void *v) 309 { 310 struct pvr_fw_trace_seq_data *trace_seq_data = s->private; 311 u64 timestamp; 312 u32 id; 313 u32 sf_id; 314 315 if (trace_seq_data->idx >= ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) 316 return -EINVAL; 317 318 id = read_fw_trace(trace_seq_data, 0); 319 /* Index is not pointing at a valid entry. */ 320 if (!ROGUE_FW_LOG_VALIDID(id)) 321 return -EINVAL; 322 323 sf_id = find_sfid(id); 324 /* Index is not pointing at a valid entry. */ 325 if (sf_id == ROGUE_FW_SF_LAST) 326 return -EINVAL; 327 328 timestamp = ((u64)read_fw_trace(trace_seq_data, 1) << 32) | 329 read_fw_trace(trace_seq_data, 2); 330 timestamp = (timestamp & ~ROGUE_FWT_TIMESTAMP_TIME_CLRMSK) >> 331 ROGUE_FWT_TIMESTAMP_TIME_SHIFT; 332 333 seq_printf(s, "[%llu] : ", timestamp); 334 if (id == ROGUE_FW_SF_MAIN_ASSERT_FAILED) { 335 seq_printf(s, "ASSERTION %s failed at %s:%u", 336 trace_seq_data->assert_buf.info, 337 trace_seq_data->assert_buf.path, 338 trace_seq_data->assert_buf.line_num); 339 } else { 340 seq_printf(s, stid_fmts[sf_id].name, 341 read_fw_trace(trace_seq_data, 3), 342 read_fw_trace(trace_seq_data, 4), 343 read_fw_trace(trace_seq_data, 5), 344 read_fw_trace(trace_seq_data, 6), 345 read_fw_trace(trace_seq_data, 7), 346 read_fw_trace(trace_seq_data, 8), 347 read_fw_trace(trace_seq_data, 9), 348 read_fw_trace(trace_seq_data, 10), 349 read_fw_trace(trace_seq_data, 11), 350 read_fw_trace(trace_seq_data, 12), 351 read_fw_trace(trace_seq_data, 13), 352 read_fw_trace(trace_seq_data, 14), 353 read_fw_trace(trace_seq_data, 15), 354 read_fw_trace(trace_seq_data, 16), 355 read_fw_trace(trace_seq_data, 17), 356 read_fw_trace(trace_seq_data, 18), 357 read_fw_trace(trace_seq_data, 19), 358 read_fw_trace(trace_seq_data, 20), 359 read_fw_trace(trace_seq_data, 21), 360 read_fw_trace(trace_seq_data, 22)); 361 } 362 seq_puts(s, "\n"); 363 return 0; 364 } 365 366 static const struct seq_operations pvr_fw_trace_seq_ops = { 367 .start = fw_trace_seq_start, 368 .next = fw_trace_seq_next, 369 .stop = fw_trace_seq_stop, 370 .show = fw_trace_seq_show 371 }; 372 373 static int fw_trace_open(struct inode *inode, struct file *file) 374 { 375 struct pvr_fw_trace_buffer *trace_buffer = inode->i_private; 376 struct rogue_fwif_tracebuf_space *tracebuf_space = 377 trace_buffer->tracebuf_space; 378 struct pvr_fw_trace_seq_data *trace_seq_data; 379 int err; 380 381 trace_seq_data = kzalloc(sizeof(*trace_seq_data), GFP_KERNEL); 382 if (!trace_seq_data) 383 return -ENOMEM; 384 385 trace_seq_data->buffer = kcalloc(ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS, 386 sizeof(*trace_seq_data->buffer), GFP_KERNEL); 387 if (!trace_seq_data->buffer) { 388 err = -ENOMEM; 389 goto err_free_data; 390 } 391 392 /* 393 * Take a local copy of the trace buffer, as firmware may still be 394 * writing to it. This will exist as long as this file is open. 395 */ 396 memcpy(trace_seq_data->buffer, trace_buffer->buf, 397 ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS * sizeof(u32)); 398 trace_seq_data->start_offset = READ_ONCE(tracebuf_space->trace_pointer); 399 trace_seq_data->assert_buf = tracebuf_space->assert_buf; 400 fw_trace_get_first(trace_seq_data); 401 402 err = seq_open(file, &pvr_fw_trace_seq_ops); 403 if (err) 404 goto err_free_buffer; 405 406 ((struct seq_file *)file->private_data)->private = trace_seq_data; 407 408 return 0; 409 410 err_free_buffer: 411 kfree(trace_seq_data->buffer); 412 413 err_free_data: 414 kfree(trace_seq_data); 415 416 return err; 417 } 418 419 static int fw_trace_release(struct inode *inode, struct file *file) 420 { 421 struct pvr_fw_trace_seq_data *trace_seq_data = 422 ((struct seq_file *)file->private_data)->private; 423 424 seq_release(inode, file); 425 kfree(trace_seq_data->buffer); 426 kfree(trace_seq_data); 427 428 return 0; 429 } 430 431 static const struct file_operations pvr_fw_trace_fops = { 432 .owner = THIS_MODULE, 433 .open = fw_trace_open, 434 .read = seq_read, 435 .llseek = seq_lseek, 436 .release = fw_trace_release, 437 }; 438 439 void 440 pvr_fw_trace_mask_update(struct pvr_device *pvr_dev, u32 old_mask, u32 new_mask) 441 { 442 if (IS_ENABLED(CONFIG_DEBUG_FS) && old_mask != new_mask) 443 update_logtype(pvr_dev, new_mask); 444 } 445 446 void 447 pvr_fw_trace_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir) 448 { 449 struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; 450 451 if (!IS_ENABLED(CONFIG_DEBUG_FS)) 452 return; 453 454 static_assert(ARRAY_SIZE(fw_trace->buffers) <= 10, 455 "The filename buffer is only large enough for a single-digit thread count"); 456 457 for (u32 thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); ++thread_nr) { 458 char filename[8]; 459 460 snprintf(filename, ARRAY_SIZE(filename), "trace_%u", thread_nr); 461 debugfs_create_file(filename, 0400, dir, 462 &fw_trace->buffers[thread_nr], 463 &pvr_fw_trace_fops); 464 } 465 } 466