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