1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2022 Intel Corporation 4 5 #include <linux/debugfs.h> 6 #include <linux/sched/signal.h> 7 #include <linux/sched/clock.h> 8 #include <sound/sof/ipc4/header.h> 9 #include "sof-priv.h" 10 #include "ipc4-priv.h" 11 12 /* 13 * debug info window is organized in 16 (equal sized) pages: 14 * 15 * ------------------------ 16 * | Page0 - descriptors | 17 * ------------------------ 18 * | Page1 - slot0 | 19 * ------------------------ 20 * | Page2 - slot1 | 21 * ------------------------ 22 * | ... | 23 * ------------------------ 24 * | Page14 - slot13 | 25 * ------------------------ 26 * | Page15 - slot14 | 27 * ------------------------ 28 * 29 * The slot size == page size 30 * 31 * The first page contains descriptors for the remaining 15 cores 32 * The slot descriptor is: 33 * u32 res_id; 34 * u32 type; 35 * u32 vma; 36 * 37 * Log buffer slots have the following layout: 38 * u32 host_read_ptr; 39 * u32 dsp_write_ptr; 40 * u8 buffer[]; 41 * 42 * The two pointers are offsets within the buffer. 43 */ 44 45 #define FW_EPOCH_DELTA 11644473600LL 46 47 #define MAX_ALLOWED_LIBRARIES 16 48 49 #define SOF_IPC4_INVALID_SLOT_OFFSET 0xffffffff 50 51 /* for debug and critical types */ 52 #define SOF_MTRACE_SLOT_CORE_MASK GENMASK(7, 0) 53 #define SOF_MTRACE_SLOT_TYPE_MASK GENMASK(31, 8) 54 55 #define DEFAULT_AGING_TIMER_PERIOD_MS 0x100 56 #define DEFAULT_FIFO_FULL_TIMER_PERIOD_MS 0x1000 57 58 /* ipc4 log level and source definitions for logs_priorities_mask */ 59 #define SOF_MTRACE_LOG_LEVEL_CRITICAL BIT(0) 60 #define SOF_MTRACE_LOG_LEVEL_ERROR BIT(1) 61 #define SOF_MTRACE_LOG_LEVEL_WARNING BIT(2) 62 #define SOF_MTRACE_LOG_LEVEL_INFO BIT(3) 63 #define SOF_MTRACE_LOG_LEVEL_VERBOSE BIT(4) 64 #define SOF_MTRACE_LOG_SOURCE_INFRA BIT(5) /* log source 0 */ 65 #define SOF_MTRACE_LOG_SOURCE_HAL BIT(6) 66 #define SOF_MTRACE_LOG_SOURCE_MODULE BIT(7) 67 #define SOF_MTRACE_LOG_SOURCE_AUDIO BIT(8) 68 #define SOF_MTRACE_LOG_SOURCE_SCHEDULER BIT(9) 69 #define SOF_MTRACE_LOG_SOURCE_ULP_INFRA BIT(10) 70 #define SOF_MTRACE_LOG_SOURCE_ULP_MODULE BIT(11) 71 #define SOF_MTRACE_LOG_SOURCE_VISION BIT(12) /* log source 7 */ 72 #define DEFAULT_LOGS_PRIORITIES_MASK (SOF_MTRACE_LOG_LEVEL_CRITICAL | \ 73 SOF_MTRACE_LOG_LEVEL_ERROR | \ 74 SOF_MTRACE_LOG_LEVEL_WARNING | \ 75 SOF_MTRACE_LOG_LEVEL_INFO | \ 76 SOF_MTRACE_LOG_SOURCE_INFRA | \ 77 SOF_MTRACE_LOG_SOURCE_HAL | \ 78 SOF_MTRACE_LOG_SOURCE_MODULE | \ 79 SOF_MTRACE_LOG_SOURCE_AUDIO) 80 81 struct sof_log_state_info { 82 u32 aging_timer_period; 83 u32 fifo_full_timer_period; 84 u32 enable; 85 u32 logs_priorities_mask[MAX_ALLOWED_LIBRARIES]; 86 } __packed; 87 88 enum sof_mtrace_state { 89 SOF_MTRACE_DISABLED, 90 SOF_MTRACE_INITIALIZING, 91 SOF_MTRACE_ENABLED, 92 }; 93 94 struct sof_mtrace_core_data { 95 struct snd_sof_dev *sdev; 96 97 int id; 98 u32 slot_offset; 99 void *log_buffer; 100 struct mutex buffer_lock; /* for log_buffer alloc/free */ 101 u32 host_read_ptr; 102 u32 dsp_write_ptr; 103 /* pos update IPC arrived before the slot offset is known, queried */ 104 bool delayed_pos_update; 105 wait_queue_head_t trace_sleep; 106 }; 107 108 struct sof_mtrace_priv { 109 struct snd_sof_dev *sdev; 110 enum sof_mtrace_state mtrace_state; 111 struct sof_log_state_info state_info; 112 113 struct sof_mtrace_core_data cores[]; 114 }; 115 116 static int sof_ipc4_mtrace_dfs_open(struct inode *inode, struct file *file) 117 { 118 struct sof_mtrace_core_data *core_data = inode->i_private; 119 int ret; 120 121 guard(mutex)(&core_data->buffer_lock); 122 123 if (core_data->log_buffer) 124 return -EBUSY; 125 126 ret = debugfs_file_get(file->f_path.dentry); 127 if (unlikely(ret)) 128 return ret; 129 130 core_data->log_buffer = kmalloc(SOF_IPC4_DEBUG_SLOT_SIZE, GFP_KERNEL); 131 if (!core_data->log_buffer) { 132 debugfs_file_put(file->f_path.dentry); 133 return -ENOMEM; 134 } 135 136 ret = simple_open(inode, file); 137 if (ret) { 138 kfree(core_data->log_buffer); 139 debugfs_file_put(file->f_path.dentry); 140 } 141 142 return ret; 143 } 144 145 static bool sof_wait_mtrace_avail(struct sof_mtrace_core_data *core_data) 146 { 147 wait_queue_entry_t wait; 148 149 /* data immediately available */ 150 if (core_data->host_read_ptr != core_data->dsp_write_ptr) 151 return true; 152 153 /* wait for available trace data from FW */ 154 init_waitqueue_entry(&wait, current); 155 set_current_state(TASK_INTERRUPTIBLE); 156 add_wait_queue(&core_data->trace_sleep, &wait); 157 158 if (!signal_pending(current)) { 159 /* set timeout to max value, no error code */ 160 schedule_timeout(MAX_SCHEDULE_TIMEOUT); 161 } 162 remove_wait_queue(&core_data->trace_sleep, &wait); 163 164 if (core_data->host_read_ptr != core_data->dsp_write_ptr) 165 return true; 166 167 return false; 168 } 169 170 static ssize_t sof_ipc4_mtrace_dfs_read(struct file *file, char __user *buffer, 171 size_t count, loff_t *ppos) 172 { 173 struct sof_mtrace_core_data *core_data = file->private_data; 174 u32 log_buffer_offset, log_buffer_size, read_ptr, write_ptr; 175 struct snd_sof_dev *sdev = core_data->sdev; 176 struct sof_mtrace_priv *priv = sdev->fw_trace_data; 177 void *log_buffer = core_data->log_buffer; 178 loff_t lpos = *ppos; 179 u32 avail; 180 int ret; 181 182 /* check pos and count */ 183 if (lpos < 0) 184 return -EINVAL; 185 if (!count || count < sizeof(avail)) 186 return 0; 187 188 /* get available count based on current host offset */ 189 if (!sof_wait_mtrace_avail(core_data)) { 190 /* No data available */ 191 avail = 0; 192 if (copy_to_user(buffer, &avail, sizeof(avail))) 193 return -EFAULT; 194 195 return 0; 196 } 197 198 if (core_data->slot_offset == SOF_IPC4_INVALID_SLOT_OFFSET) 199 return 0; 200 201 /* The log data buffer starts after the two pointer in the slot */ 202 log_buffer_offset = core_data->slot_offset + (sizeof(u32) * 2); 203 /* The log data size excludes the pointers */ 204 log_buffer_size = SOF_IPC4_DEBUG_SLOT_SIZE - (sizeof(u32) * 2); 205 206 read_ptr = core_data->host_read_ptr; 207 write_ptr = core_data->dsp_write_ptr; 208 209 if (read_ptr < write_ptr) 210 avail = write_ptr - read_ptr; 211 else 212 avail = log_buffer_size - read_ptr + write_ptr; 213 214 if (!avail) 215 return 0; 216 217 if (avail > log_buffer_size) 218 avail = log_buffer_size; 219 220 /* Need space for the initial u32 of the avail */ 221 if (avail > count - sizeof(avail)) 222 avail = count - sizeof(avail); 223 224 if (sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS)) 225 dev_dbg(sdev->dev, 226 "core%d, host read: %#x, dsp write: %#x, avail: %#x\n", 227 core_data->id, read_ptr, write_ptr, avail); 228 229 if (read_ptr < write_ptr) { 230 /* Read data between read pointer and write pointer */ 231 sof_mailbox_read(sdev, log_buffer_offset + read_ptr, log_buffer, avail); 232 } else { 233 /* read from read pointer to end of the slot */ 234 sof_mailbox_read(sdev, log_buffer_offset + read_ptr, log_buffer, 235 avail - write_ptr); 236 /* read from slot start to write pointer */ 237 if (write_ptr) 238 sof_mailbox_read(sdev, log_buffer_offset, 239 (u8 *)(log_buffer) + avail - write_ptr, 240 write_ptr); 241 } 242 243 /* first write the number of bytes we have gathered */ 244 ret = copy_to_user(buffer, &avail, sizeof(avail)); 245 if (ret) 246 return -EFAULT; 247 248 /* Followed by the data itself */ 249 ret = copy_to_user(buffer + sizeof(avail), log_buffer, avail); 250 if (ret) 251 return -EFAULT; 252 253 /* Update the host_read_ptr in the slot for this core */ 254 read_ptr += avail; 255 if (read_ptr >= log_buffer_size) 256 read_ptr -= log_buffer_size; 257 sof_mailbox_write(sdev, core_data->slot_offset, &read_ptr, sizeof(read_ptr)); 258 259 /* Only update the host_read_ptr if mtrace is enabled */ 260 if (priv->mtrace_state != SOF_MTRACE_DISABLED) 261 core_data->host_read_ptr = read_ptr; 262 263 /* 264 * Ask for a new buffer from user space for the next chunk, not 265 * streaming due to the heading number of bytes value. 266 */ 267 *ppos += count; 268 269 return count; 270 } 271 272 static int sof_ipc4_mtrace_dfs_release(struct inode *inode, struct file *file) 273 { 274 struct sof_mtrace_core_data *core_data = inode->i_private; 275 276 debugfs_file_put(file->f_path.dentry); 277 278 scoped_guard(mutex, &core_data->buffer_lock) { 279 kfree(core_data->log_buffer); 280 core_data->log_buffer = NULL; 281 } 282 283 return 0; 284 } 285 286 static const struct file_operations sof_dfs_mtrace_fops = { 287 .open = sof_ipc4_mtrace_dfs_open, 288 .read = sof_ipc4_mtrace_dfs_read, 289 .llseek = default_llseek, 290 .release = sof_ipc4_mtrace_dfs_release, 291 292 .owner = THIS_MODULE, 293 }; 294 295 static ssize_t sof_ipc4_priority_mask_dfs_read(struct file *file, char __user *to, 296 size_t count, loff_t *ppos) 297 { 298 struct sof_mtrace_priv *priv = file->private_data; 299 int i, ret, offset, remaining; 300 char *buf; 301 302 /* 303 * one entry (14 char + new line = 15): 304 * " 0: 000001ef" 305 * 306 * 16 * 15 + 1 = 241 307 */ 308 buf = kzalloc(241, GFP_KERNEL); 309 if (!buf) 310 return -ENOMEM; 311 312 for (i = 0; i < MAX_ALLOWED_LIBRARIES; i++) { 313 offset = strlen(buf); 314 remaining = 241 - offset; 315 snprintf(buf + offset, remaining, "%2d: 0x%08x\n", i, 316 priv->state_info.logs_priorities_mask[i]); 317 } 318 319 ret = simple_read_from_buffer(to, count, ppos, buf, strlen(buf)); 320 321 kfree(buf); 322 return ret; 323 } 324 325 static ssize_t sof_ipc4_priority_mask_dfs_write(struct file *file, 326 const char __user *from, 327 size_t count, loff_t *ppos) 328 { 329 struct sof_mtrace_priv *priv = file->private_data; 330 unsigned int id; 331 char *buf; 332 u32 mask; 333 int ret; 334 335 /* 336 * To update Nth mask entry, write: 337 * "N,0x1234" or "N,1234" to the debugfs file 338 * The mask will be interpreted as hexadecimal number 339 */ 340 buf = memdup_user_nul(from, count); 341 if (IS_ERR(buf)) 342 return PTR_ERR(buf); 343 344 ret = sscanf(buf, "%u,0x%x", &id, &mask); 345 if (ret != 2) { 346 ret = sscanf(buf, "%u,%x", &id, &mask); 347 if (ret != 2) { 348 ret = -EINVAL; 349 goto out; 350 } 351 } 352 353 if (id >= MAX_ALLOWED_LIBRARIES) { 354 ret = -EINVAL; 355 goto out; 356 } 357 358 priv->state_info.logs_priorities_mask[id] = mask; 359 ret = count; 360 361 out: 362 kfree(buf); 363 return ret; 364 } 365 366 static const struct file_operations sof_dfs_priority_mask_fops = { 367 .open = simple_open, 368 .read = sof_ipc4_priority_mask_dfs_read, 369 .write = sof_ipc4_priority_mask_dfs_write, 370 .llseek = default_llseek, 371 372 .owner = THIS_MODULE, 373 }; 374 375 static int mtrace_debugfs_create(struct snd_sof_dev *sdev) 376 { 377 struct sof_mtrace_priv *priv = sdev->fw_trace_data; 378 struct dentry *dfs_root; 379 char dfs_name[100]; 380 int i; 381 382 dfs_root = debugfs_create_dir("mtrace", sdev->debugfs_root); 383 if (IS_ERR_OR_NULL(dfs_root)) 384 return 0; 385 386 /* Create files for the logging parameters */ 387 debugfs_create_u32("aging_timer_period", 0644, dfs_root, 388 &priv->state_info.aging_timer_period); 389 debugfs_create_u32("fifo_full_timer_period", 0644, dfs_root, 390 &priv->state_info.fifo_full_timer_period); 391 debugfs_create_file("logs_priorities_mask", 0644, dfs_root, priv, 392 &sof_dfs_priority_mask_fops); 393 394 /* Separate log files per core */ 395 for (i = 0; i < sdev->num_cores; i++) { 396 snprintf(dfs_name, sizeof(dfs_name), "core%d", i); 397 debugfs_create_file(dfs_name, 0444, dfs_root, &priv->cores[i], 398 &sof_dfs_mtrace_fops); 399 } 400 401 return 0; 402 } 403 404 static int ipc4_mtrace_enable(struct snd_sof_dev *sdev) 405 { 406 struct sof_mtrace_priv *priv = sdev->fw_trace_data; 407 const struct sof_ipc_ops *iops = sdev->ipc->ops; 408 struct sof_ipc4_msg msg; 409 u64 system_time; 410 int ret; 411 412 if (priv->mtrace_state != SOF_MTRACE_DISABLED) 413 return 0; 414 415 msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 416 msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 417 msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID); 418 msg.primary |= SOF_IPC4_MOD_INSTANCE(SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID); 419 msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_SYSTEM_TIME); 420 421 /* 422 * local_clock() is used to align with dmesg, so both kernel and firmware logs have 423 * the same base and a minor delta due to the IPC. system time is in us format but 424 * local_clock() returns the time in ns, so convert to ns. 425 */ 426 system_time = div64_u64(local_clock(), NSEC_PER_USEC); 427 msg.data_size = sizeof(system_time); 428 msg.data_ptr = &system_time; 429 ret = iops->set_get_data(sdev, &msg, msg.data_size, true); 430 if (ret) 431 return ret; 432 433 msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_ENABLE_LOGS); 434 435 priv->state_info.enable = 1; 436 437 msg.data_size = sizeof(priv->state_info); 438 msg.data_ptr = &priv->state_info; 439 440 priv->mtrace_state = SOF_MTRACE_INITIALIZING; 441 ret = iops->set_get_data(sdev, &msg, msg.data_size, true); 442 if (ret) { 443 priv->mtrace_state = SOF_MTRACE_DISABLED; 444 return ret; 445 } 446 447 priv->mtrace_state = SOF_MTRACE_ENABLED; 448 449 return 0; 450 } 451 452 static void ipc4_mtrace_disable(struct snd_sof_dev *sdev) 453 { 454 struct sof_mtrace_priv *priv = sdev->fw_trace_data; 455 const struct sof_ipc_ops *iops = sdev->ipc->ops; 456 struct sof_ipc4_msg msg; 457 int i; 458 459 if (priv->mtrace_state == SOF_MTRACE_DISABLED) 460 return; 461 462 msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 463 msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 464 msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID); 465 msg.primary |= SOF_IPC4_MOD_INSTANCE(SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID); 466 msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_ENABLE_LOGS); 467 468 priv->state_info.enable = 0; 469 470 msg.data_size = sizeof(priv->state_info); 471 msg.data_ptr = &priv->state_info; 472 iops->set_get_data(sdev, &msg, msg.data_size, true); 473 474 priv->mtrace_state = SOF_MTRACE_DISABLED; 475 476 for (i = 0; i < sdev->num_cores; i++) { 477 struct sof_mtrace_core_data *core_data = &priv->cores[i]; 478 479 core_data->host_read_ptr = 0; 480 core_data->dsp_write_ptr = 0; 481 wake_up(&core_data->trace_sleep); 482 } 483 } 484 485 /* 486 * Each DSP core logs to a dedicated slot. 487 * Parse the slot descriptors at debug_box offset to find the debug log slots 488 * and map them to cores. 489 * There are 15 slots and therefore 15 descriptors to check (MAX_MTRACE_SLOTS) 490 */ 491 static void sof_mtrace_find_core_slots(struct snd_sof_dev *sdev) 492 { 493 struct sof_mtrace_priv *priv = sdev->fw_trace_data; 494 struct sof_mtrace_core_data *core_data; 495 u32 slot_desc_type_offset, type, core; 496 int i; 497 498 for (i = 0; i < SOF_IPC4_MAX_DEBUG_SLOTS; i++) { 499 /* The type is the second u32 in the slot descriptor */ 500 slot_desc_type_offset = sdev->debug_box.offset; 501 slot_desc_type_offset += SOF_IPC4_DEBUG_DESCRIPTOR_SIZE * i + sizeof(u32); 502 sof_mailbox_read(sdev, slot_desc_type_offset, &type, sizeof(type)); 503 504 if ((type & SOF_MTRACE_SLOT_TYPE_MASK) == SOF_IPC4_DEBUG_SLOT_DEBUG_LOG) { 505 core = type & SOF_MTRACE_SLOT_CORE_MASK; 506 507 if (core >= sdev->num_cores) { 508 dev_dbg(sdev->dev, "core%u is invalid for slot%d\n", 509 core, i); 510 continue; 511 } 512 513 core_data = &priv->cores[core]; 514 /* 515 * The area reserved for descriptors have the same size 516 * as a slot. 517 * In other words: slot0 starts at 518 * debug_box + SOF_MTRACE_SLOT_SIZE offset 519 */ 520 core_data->slot_offset = sdev->debug_box.offset; 521 core_data->slot_offset += SOF_IPC4_DEBUG_SLOT_SIZE * (i + 1); 522 dev_dbg(sdev->dev, "slot%d is used for core%u\n", i, core); 523 if (core_data->delayed_pos_update) { 524 sof_ipc4_mtrace_update_pos(sdev, core); 525 core_data->delayed_pos_update = false; 526 } 527 } else if (type) { 528 dev_dbg(sdev->dev, "slot%d is not a log slot (%#x)\n", i, type); 529 } 530 } 531 } 532 533 static int ipc4_mtrace_init(struct snd_sof_dev *sdev) 534 { 535 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 536 struct sof_mtrace_priv *priv; 537 int i, ret; 538 539 if (sdev->fw_trace_data) { 540 dev_err(sdev->dev, "fw_trace_data has been already allocated\n"); 541 return -EBUSY; 542 } 543 544 if (!ipc4_data->mtrace_log_bytes || 545 ipc4_data->mtrace_type != SOF_IPC4_MTRACE_INTEL_CAVS_2) { 546 sdev->fw_trace_is_supported = false; 547 return 0; 548 } 549 550 priv = devm_kzalloc(sdev->dev, struct_size(priv, cores, sdev->num_cores), 551 GFP_KERNEL); 552 if (!priv) 553 return -ENOMEM; 554 555 sdev->fw_trace_data = priv; 556 557 /* Set initial values for mtrace parameters */ 558 priv->state_info.aging_timer_period = DEFAULT_AGING_TIMER_PERIOD_MS; 559 priv->state_info.fifo_full_timer_period = DEFAULT_FIFO_FULL_TIMER_PERIOD_MS; 560 /* Only enable basefw logs initially (index 0 is always basefw) */ 561 priv->state_info.logs_priorities_mask[0] = DEFAULT_LOGS_PRIORITIES_MASK; 562 563 for (i = 0; i < sdev->num_cores; i++) { 564 struct sof_mtrace_core_data *core_data = &priv->cores[i]; 565 566 init_waitqueue_head(&core_data->trace_sleep); 567 mutex_init(&core_data->buffer_lock); 568 core_data->sdev = sdev; 569 core_data->id = i; 570 } 571 572 ret = ipc4_mtrace_enable(sdev); 573 if (ret) { 574 /* 575 * Mark firmware tracing as not supported and return 0 to not 576 * block the whole audio stack 577 */ 578 sdev->fw_trace_is_supported = false; 579 dev_dbg(sdev->dev, "initialization failed, fw tracing is disabled\n"); 580 return 0; 581 } 582 583 sof_mtrace_find_core_slots(sdev); 584 585 ret = mtrace_debugfs_create(sdev); 586 if (ret) 587 ipc4_mtrace_disable(sdev); 588 589 return ret; 590 } 591 592 static void ipc4_mtrace_free(struct snd_sof_dev *sdev) 593 { 594 ipc4_mtrace_disable(sdev); 595 } 596 597 static int sof_ipc4_mtrace_update_pos_all_cores(struct snd_sof_dev *sdev) 598 { 599 int i; 600 601 for (i = 0; i < sdev->num_cores; i++) 602 sof_ipc4_mtrace_update_pos(sdev, i); 603 604 return 0; 605 } 606 607 int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core) 608 { 609 struct sof_mtrace_priv *priv = sdev->fw_trace_data; 610 struct sof_mtrace_core_data *core_data; 611 612 if (!sdev->fw_trace_is_supported || 613 priv->mtrace_state == SOF_MTRACE_DISABLED) 614 return 0; 615 616 if (core >= sdev->num_cores) 617 return -EINVAL; 618 619 core_data = &priv->cores[core]; 620 621 if (core_data->slot_offset == SOF_IPC4_INVALID_SLOT_OFFSET) { 622 core_data->delayed_pos_update = true; 623 return 0; 624 } 625 626 /* Read out the dsp_write_ptr from the slot for this core */ 627 sof_mailbox_read(sdev, core_data->slot_offset + sizeof(u32), 628 &core_data->dsp_write_ptr, 4); 629 core_data->dsp_write_ptr -= core_data->dsp_write_ptr % 4; 630 631 if (sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS)) 632 dev_dbg(sdev->dev, "core%d, host read: %#x, dsp write: %#x", 633 core, core_data->host_read_ptr, core_data->dsp_write_ptr); 634 635 wake_up(&core_data->trace_sleep); 636 637 return 0; 638 } 639 640 static void ipc4_mtrace_fw_crashed(struct snd_sof_dev *sdev) 641 { 642 /* 643 * The DSP might not be able to send SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS 644 * messages anymore, so check the log buffer status on all 645 * cores and process any pending messages. 646 */ 647 sof_ipc4_mtrace_update_pos_all_cores(sdev); 648 } 649 650 static int ipc4_mtrace_resume(struct snd_sof_dev *sdev) 651 { 652 return ipc4_mtrace_enable(sdev); 653 } 654 655 static void ipc4_mtrace_suspend(struct snd_sof_dev *sdev, pm_message_t pm_state) 656 { 657 ipc4_mtrace_disable(sdev); 658 } 659 660 const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops = { 661 .init = ipc4_mtrace_init, 662 .free = ipc4_mtrace_free, 663 .fw_crashed = ipc4_mtrace_fw_crashed, 664 .suspend = ipc4_mtrace_suspend, 665 .resume = ipc4_mtrace_resume, 666 }; 667