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