1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2018 Intel Corporation. All rights reserved. 7 // 8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 9 // 10 // Generic debug routines used to export DSP MMIO and memories to userspace 11 // for firmware debugging. 12 // 13 14 #include <linux/debugfs.h> 15 #include <linux/io.h> 16 #include <linux/pm_runtime.h> 17 #include <sound/sof/ext_manifest.h> 18 #include <sound/sof/debug.h> 19 #include "sof-priv.h" 20 #include "ops.h" 21 22 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) 23 #include "probe.h" 24 25 /** 26 * strsplit_u32 - Split string into sequence of u32 tokens 27 * @buf: String to split into tokens. 28 * @delim: String containing delimiter characters. 29 * @tkns: Returned u32 sequence pointer. 30 * @num_tkns: Returned number of tokens obtained. 31 */ 32 static int 33 strsplit_u32(char **buf, const char *delim, u32 **tkns, size_t *num_tkns) 34 { 35 char *s; 36 u32 *data, *tmp; 37 size_t count = 0; 38 size_t cap = 32; 39 int ret = 0; 40 41 *tkns = NULL; 42 *num_tkns = 0; 43 data = kcalloc(cap, sizeof(*data), GFP_KERNEL); 44 if (!data) 45 return -ENOMEM; 46 47 while ((s = strsep(buf, delim)) != NULL) { 48 ret = kstrtouint(s, 0, data + count); 49 if (ret) 50 goto exit; 51 if (++count >= cap) { 52 cap *= 2; 53 tmp = krealloc(data, cap * sizeof(*data), GFP_KERNEL); 54 if (!tmp) { 55 ret = -ENOMEM; 56 goto exit; 57 } 58 data = tmp; 59 } 60 } 61 62 if (!count) 63 goto exit; 64 *tkns = kmemdup(data, count * sizeof(*data), GFP_KERNEL); 65 if (*tkns == NULL) { 66 ret = -ENOMEM; 67 goto exit; 68 } 69 *num_tkns = count; 70 71 exit: 72 kfree(data); 73 return ret; 74 } 75 76 static int tokenize_input(const char __user *from, size_t count, 77 loff_t *ppos, u32 **tkns, size_t *num_tkns) 78 { 79 char *buf; 80 int ret; 81 82 buf = kmalloc(count + 1, GFP_KERNEL); 83 if (!buf) 84 return -ENOMEM; 85 86 ret = simple_write_to_buffer(buf, count, ppos, from, count); 87 if (ret != count) { 88 ret = ret >= 0 ? -EIO : ret; 89 goto exit; 90 } 91 92 buf[count] = '\0'; 93 ret = strsplit_u32((char **)&buf, ",", tkns, num_tkns); 94 exit: 95 kfree(buf); 96 return ret; 97 } 98 99 static ssize_t probe_points_read(struct file *file, 100 char __user *to, size_t count, loff_t *ppos) 101 { 102 struct snd_sof_dfsentry *dfse = file->private_data; 103 struct snd_sof_dev *sdev = dfse->sdev; 104 struct sof_probe_point_desc *desc; 105 size_t num_desc, len = 0; 106 char *buf; 107 int i, ret; 108 109 if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) { 110 dev_warn(sdev->dev, "no extractor stream running\n"); 111 return -ENOENT; 112 } 113 114 buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 115 if (!buf) 116 return -ENOMEM; 117 118 ret = sof_ipc_probe_points_info(sdev, &desc, &num_desc); 119 if (ret < 0) 120 goto exit; 121 122 for (i = 0; i < num_desc; i++) { 123 ret = snprintf(buf + len, PAGE_SIZE - len, 124 "Id: %#010x Purpose: %d Node id: %#x\n", 125 desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag); 126 if (ret < 0) 127 goto free_desc; 128 len += ret; 129 } 130 131 ret = simple_read_from_buffer(to, count, ppos, buf, len); 132 free_desc: 133 kfree(desc); 134 exit: 135 kfree(buf); 136 return ret; 137 } 138 139 static ssize_t probe_points_write(struct file *file, 140 const char __user *from, size_t count, loff_t *ppos) 141 { 142 struct snd_sof_dfsentry *dfse = file->private_data; 143 struct snd_sof_dev *sdev = dfse->sdev; 144 struct sof_probe_point_desc *desc; 145 size_t num_tkns, bytes; 146 u32 *tkns; 147 int ret; 148 149 if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) { 150 dev_warn(sdev->dev, "no extractor stream running\n"); 151 return -ENOENT; 152 } 153 154 ret = tokenize_input(from, count, ppos, &tkns, &num_tkns); 155 if (ret < 0) 156 return ret; 157 bytes = sizeof(*tkns) * num_tkns; 158 if (!num_tkns || (bytes % sizeof(*desc))) { 159 ret = -EINVAL; 160 goto exit; 161 } 162 163 desc = (struct sof_probe_point_desc *)tkns; 164 ret = sof_ipc_probe_points_add(sdev, 165 desc, bytes / sizeof(*desc)); 166 if (!ret) 167 ret = count; 168 exit: 169 kfree(tkns); 170 return ret; 171 } 172 173 static const struct file_operations probe_points_fops = { 174 .open = simple_open, 175 .read = probe_points_read, 176 .write = probe_points_write, 177 .llseek = default_llseek, 178 }; 179 180 static ssize_t probe_points_remove_write(struct file *file, 181 const char __user *from, size_t count, loff_t *ppos) 182 { 183 struct snd_sof_dfsentry *dfse = file->private_data; 184 struct snd_sof_dev *sdev = dfse->sdev; 185 size_t num_tkns; 186 u32 *tkns; 187 int ret; 188 189 if (sdev->extractor_stream_tag == SOF_PROBE_INVALID_NODE_ID) { 190 dev_warn(sdev->dev, "no extractor stream running\n"); 191 return -ENOENT; 192 } 193 194 ret = tokenize_input(from, count, ppos, &tkns, &num_tkns); 195 if (ret < 0) 196 return ret; 197 if (!num_tkns) { 198 ret = -EINVAL; 199 goto exit; 200 } 201 202 ret = sof_ipc_probe_points_remove(sdev, tkns, num_tkns); 203 if (!ret) 204 ret = count; 205 exit: 206 kfree(tkns); 207 return ret; 208 } 209 210 static const struct file_operations probe_points_remove_fops = { 211 .open = simple_open, 212 .write = probe_points_remove_write, 213 .llseek = default_llseek, 214 }; 215 216 static int snd_sof_debugfs_probe_item(struct snd_sof_dev *sdev, 217 const char *name, mode_t mode, 218 const struct file_operations *fops) 219 { 220 struct snd_sof_dfsentry *dfse; 221 222 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); 223 if (!dfse) 224 return -ENOMEM; 225 226 dfse->type = SOF_DFSENTRY_TYPE_BUF; 227 dfse->sdev = sdev; 228 229 debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops); 230 /* add to dfsentry list */ 231 list_add(&dfse->list, &sdev->dfsentry_list); 232 233 return 0; 234 } 235 #endif 236 237 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 238 #define MAX_IPC_FLOOD_DURATION_MS 1000 239 #define MAX_IPC_FLOOD_COUNT 10000 240 #define IPC_FLOOD_TEST_RESULT_LEN 512 241 242 static int sof_debug_ipc_flood_test(struct snd_sof_dev *sdev, 243 struct snd_sof_dfsentry *dfse, 244 bool flood_duration_test, 245 unsigned long ipc_duration_ms, 246 unsigned long ipc_count) 247 { 248 struct sof_ipc_cmd_hdr hdr; 249 struct sof_ipc_reply reply; 250 u64 min_response_time = U64_MAX; 251 ktime_t start, end, test_end; 252 u64 avg_response_time = 0; 253 u64 max_response_time = 0; 254 u64 ipc_response_time; 255 int i = 0; 256 int ret; 257 258 /* configure test IPC */ 259 hdr.cmd = SOF_IPC_GLB_TEST_MSG | SOF_IPC_TEST_IPC_FLOOD; 260 hdr.size = sizeof(hdr); 261 262 /* set test end time for duration flood test */ 263 if (flood_duration_test) 264 test_end = ktime_get_ns() + ipc_duration_ms * NSEC_PER_MSEC; 265 266 /* send test IPC's */ 267 while (1) { 268 start = ktime_get(); 269 ret = sof_ipc_tx_message(sdev->ipc, hdr.cmd, &hdr, hdr.size, 270 &reply, sizeof(reply)); 271 end = ktime_get(); 272 273 if (ret < 0) 274 break; 275 276 /* compute min and max response times */ 277 ipc_response_time = ktime_to_ns(ktime_sub(end, start)); 278 min_response_time = min(min_response_time, ipc_response_time); 279 max_response_time = max(max_response_time, ipc_response_time); 280 281 /* sum up response times */ 282 avg_response_time += ipc_response_time; 283 i++; 284 285 /* test complete? */ 286 if (flood_duration_test) { 287 if (ktime_to_ns(end) >= test_end) 288 break; 289 } else { 290 if (i == ipc_count) 291 break; 292 } 293 } 294 295 if (ret < 0) 296 dev_err(sdev->dev, 297 "error: ipc flood test failed at %d iterations\n", i); 298 299 /* return if the first IPC fails */ 300 if (!i) 301 return ret; 302 303 /* compute average response time */ 304 do_div(avg_response_time, i); 305 306 /* clear previous test output */ 307 memset(dfse->cache_buf, 0, IPC_FLOOD_TEST_RESULT_LEN); 308 309 if (flood_duration_test) { 310 dev_dbg(sdev->dev, "IPC Flood test duration: %lums\n", 311 ipc_duration_ms); 312 snprintf(dfse->cache_buf, IPC_FLOOD_TEST_RESULT_LEN, 313 "IPC Flood test duration: %lums\n", ipc_duration_ms); 314 } 315 316 dev_dbg(sdev->dev, 317 "IPC Flood count: %d, Avg response time: %lluns\n", 318 i, avg_response_time); 319 dev_dbg(sdev->dev, "Max response time: %lluns\n", 320 max_response_time); 321 dev_dbg(sdev->dev, "Min response time: %lluns\n", 322 min_response_time); 323 324 /* format output string */ 325 snprintf(dfse->cache_buf + strlen(dfse->cache_buf), 326 IPC_FLOOD_TEST_RESULT_LEN - strlen(dfse->cache_buf), 327 "IPC Flood count: %d\nAvg response time: %lluns\n", 328 i, avg_response_time); 329 330 snprintf(dfse->cache_buf + strlen(dfse->cache_buf), 331 IPC_FLOOD_TEST_RESULT_LEN - strlen(dfse->cache_buf), 332 "Max response time: %lluns\nMin response time: %lluns\n", 333 max_response_time, min_response_time); 334 335 return ret; 336 } 337 #endif 338 339 static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, 340 size_t count, loff_t *ppos) 341 { 342 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 343 struct snd_sof_dfsentry *dfse = file->private_data; 344 struct snd_sof_dev *sdev = dfse->sdev; 345 unsigned long ipc_duration_ms = 0; 346 bool flood_duration_test = false; 347 unsigned long ipc_count = 0; 348 struct dentry *dentry; 349 int err; 350 #endif 351 size_t size; 352 char *string; 353 int ret; 354 355 string = kzalloc(count+1, GFP_KERNEL); 356 if (!string) 357 return -ENOMEM; 358 359 size = simple_write_to_buffer(string, count, ppos, buffer, count); 360 ret = size; 361 362 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 363 /* 364 * write op is only supported for ipc_flood_count or 365 * ipc_flood_duration_ms debugfs entries atm. 366 * ipc_flood_count floods the DSP with the number of IPC's specified. 367 * ipc_duration_ms test floods the DSP for the time specified 368 * in the debugfs entry. 369 */ 370 dentry = file->f_path.dentry; 371 if (strcmp(dentry->d_name.name, "ipc_flood_count") && 372 strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) { 373 ret = -EINVAL; 374 goto out; 375 } 376 377 if (!strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) 378 flood_duration_test = true; 379 380 /* test completion criterion */ 381 if (flood_duration_test) 382 ret = kstrtoul(string, 0, &ipc_duration_ms); 383 else 384 ret = kstrtoul(string, 0, &ipc_count); 385 if (ret < 0) 386 goto out; 387 388 /* limit max duration/ipc count for flood test */ 389 if (flood_duration_test) { 390 if (!ipc_duration_ms) { 391 ret = size; 392 goto out; 393 } 394 395 /* find the minimum. min() is not used to avoid warnings */ 396 if (ipc_duration_ms > MAX_IPC_FLOOD_DURATION_MS) 397 ipc_duration_ms = MAX_IPC_FLOOD_DURATION_MS; 398 } else { 399 if (!ipc_count) { 400 ret = size; 401 goto out; 402 } 403 404 /* find the minimum. min() is not used to avoid warnings */ 405 if (ipc_count > MAX_IPC_FLOOD_COUNT) 406 ipc_count = MAX_IPC_FLOOD_COUNT; 407 } 408 409 ret = pm_runtime_get_sync(sdev->dev); 410 if (ret < 0 && ret != -EACCES) { 411 dev_err_ratelimited(sdev->dev, 412 "error: debugfs write failed to resume %d\n", 413 ret); 414 pm_runtime_put_noidle(sdev->dev); 415 goto out; 416 } 417 418 /* flood test */ 419 ret = sof_debug_ipc_flood_test(sdev, dfse, flood_duration_test, 420 ipc_duration_ms, ipc_count); 421 422 pm_runtime_mark_last_busy(sdev->dev); 423 err = pm_runtime_put_autosuspend(sdev->dev); 424 if (err < 0) 425 dev_err_ratelimited(sdev->dev, 426 "error: debugfs write failed to idle %d\n", 427 err); 428 429 /* return size if test is successful */ 430 if (ret >= 0) 431 ret = size; 432 out: 433 #endif 434 kfree(string); 435 return ret; 436 } 437 438 static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, 439 size_t count, loff_t *ppos) 440 { 441 struct snd_sof_dfsentry *dfse = file->private_data; 442 struct snd_sof_dev *sdev = dfse->sdev; 443 loff_t pos = *ppos; 444 size_t size_ret; 445 int skip = 0; 446 int size; 447 u8 *buf; 448 449 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 450 struct dentry *dentry; 451 452 dentry = file->f_path.dentry; 453 if ((!strcmp(dentry->d_name.name, "ipc_flood_count") || 454 !strcmp(dentry->d_name.name, "ipc_flood_duration_ms"))) { 455 if (*ppos) 456 return 0; 457 458 count = strlen(dfse->cache_buf); 459 size_ret = copy_to_user(buffer, dfse->cache_buf, count); 460 if (size_ret) 461 return -EFAULT; 462 463 *ppos += count; 464 return count; 465 } 466 #endif 467 size = dfse->size; 468 469 /* validate position & count */ 470 if (pos < 0) 471 return -EINVAL; 472 if (pos >= size || !count) 473 return 0; 474 /* find the minimum. min() is not used since it adds sparse warnings */ 475 if (count > size - pos) 476 count = size - pos; 477 478 /* align io read start to u32 multiple */ 479 pos = ALIGN_DOWN(pos, 4); 480 481 /* intermediate buffer size must be u32 multiple */ 482 size = ALIGN(count, 4); 483 484 /* if start position is unaligned, read extra u32 */ 485 if (unlikely(pos != *ppos)) { 486 skip = *ppos - pos; 487 if (pos + size + 4 < dfse->size) 488 size += 4; 489 } 490 491 buf = kzalloc(size, GFP_KERNEL); 492 if (!buf) 493 return -ENOMEM; 494 495 if (dfse->type == SOF_DFSENTRY_TYPE_IOMEM) { 496 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) 497 /* 498 * If the DSP is active: copy from IO. 499 * If the DSP is suspended: 500 * - Copy from IO if the memory is always accessible. 501 * - Otherwise, copy from cached buffer. 502 */ 503 if (pm_runtime_active(sdev->dev) || 504 dfse->access_type == SOF_DEBUGFS_ACCESS_ALWAYS) { 505 memcpy_fromio(buf, dfse->io_mem + pos, size); 506 } else { 507 dev_info(sdev->dev, 508 "Copying cached debugfs data\n"); 509 memcpy(buf, dfse->cache_buf + pos, size); 510 } 511 #else 512 /* if the DSP is in D3 */ 513 if (!pm_runtime_active(sdev->dev) && 514 dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { 515 dev_err(sdev->dev, 516 "error: debugfs entry cannot be read in DSP D3\n"); 517 kfree(buf); 518 return -EINVAL; 519 } 520 521 memcpy_fromio(buf, dfse->io_mem + pos, size); 522 #endif 523 } else { 524 memcpy(buf, ((u8 *)(dfse->buf) + pos), size); 525 } 526 527 /* copy to userspace */ 528 size_ret = copy_to_user(buffer, buf + skip, count); 529 530 kfree(buf); 531 532 /* update count & position if copy succeeded */ 533 if (size_ret) 534 return -EFAULT; 535 536 *ppos = pos + count; 537 538 return count; 539 } 540 541 static const struct file_operations sof_dfs_fops = { 542 .open = simple_open, 543 .read = sof_dfsentry_read, 544 .llseek = default_llseek, 545 .write = sof_dfsentry_write, 546 }; 547 548 /* create FS entry for debug files that can expose DSP memories, registers */ 549 int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, 550 void __iomem *base, size_t size, 551 const char *name, 552 enum sof_debugfs_access_type access_type) 553 { 554 struct snd_sof_dfsentry *dfse; 555 556 if (!sdev) 557 return -EINVAL; 558 559 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); 560 if (!dfse) 561 return -ENOMEM; 562 563 dfse->type = SOF_DFSENTRY_TYPE_IOMEM; 564 dfse->io_mem = base; 565 dfse->size = size; 566 dfse->sdev = sdev; 567 dfse->access_type = access_type; 568 569 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) 570 /* 571 * allocate cache buffer that will be used to save the mem window 572 * contents prior to suspend 573 */ 574 if (access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { 575 dfse->cache_buf = devm_kzalloc(sdev->dev, size, GFP_KERNEL); 576 if (!dfse->cache_buf) 577 return -ENOMEM; 578 } 579 #endif 580 581 debugfs_create_file(name, 0444, sdev->debugfs_root, dfse, 582 &sof_dfs_fops); 583 584 /* add to dfsentry list */ 585 list_add(&dfse->list, &sdev->dfsentry_list); 586 587 return 0; 588 } 589 EXPORT_SYMBOL_GPL(snd_sof_debugfs_io_item); 590 591 /* create FS entry for debug files to expose kernel memory */ 592 int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, 593 void *base, size_t size, 594 const char *name, mode_t mode) 595 { 596 struct snd_sof_dfsentry *dfse; 597 598 if (!sdev) 599 return -EINVAL; 600 601 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); 602 if (!dfse) 603 return -ENOMEM; 604 605 dfse->type = SOF_DFSENTRY_TYPE_BUF; 606 dfse->buf = base; 607 dfse->size = size; 608 dfse->sdev = sdev; 609 610 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 611 if (!strncmp(name, "ipc_flood", strlen("ipc_flood"))) { 612 /* 613 * cache_buf is unused for SOF_DFSENTRY_TYPE_BUF debugfs entries. 614 * So, use it to save the results of the last IPC flood test. 615 */ 616 dfse->cache_buf = devm_kzalloc(sdev->dev, IPC_FLOOD_TEST_RESULT_LEN, 617 GFP_KERNEL); 618 if (!dfse->cache_buf) 619 return -ENOMEM; 620 } 621 #endif 622 623 debugfs_create_file(name, mode, sdev->debugfs_root, dfse, 624 &sof_dfs_fops); 625 /* add to dfsentry list */ 626 list_add(&dfse->list, &sdev->dfsentry_list); 627 628 return 0; 629 } 630 EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item); 631 632 static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_size) 633 { 634 struct sof_ipc_cmd_hdr msg = { 635 .size = sizeof(struct sof_ipc_cmd_hdr), 636 .cmd = SOF_IPC_GLB_DEBUG | SOF_IPC_DEBUG_MEM_USAGE, 637 }; 638 struct sof_ipc_dbg_mem_usage *reply; 639 int len; 640 int ret; 641 int i; 642 643 reply = kmalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); 644 if (!reply) 645 return -ENOMEM; 646 647 ret = pm_runtime_get_sync(sdev->dev); 648 if (ret < 0 && ret != -EACCES) { 649 pm_runtime_put_noidle(sdev->dev); 650 dev_err(sdev->dev, "error: enabling device failed: %d\n", ret); 651 goto error; 652 } 653 654 ret = sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE); 655 pm_runtime_mark_last_busy(sdev->dev); 656 pm_runtime_put_autosuspend(sdev->dev); 657 if (ret < 0 || reply->rhdr.error < 0) { 658 ret = min(ret, reply->rhdr.error); 659 dev_err(sdev->dev, "error: reading memory info failed, %d\n", ret); 660 goto error; 661 } 662 663 if (struct_size(reply, elems, reply->num_elems) != reply->rhdr.hdr.size) { 664 dev_err(sdev->dev, "error: invalid memory info ipc struct size, %d\n", 665 reply->rhdr.hdr.size); 666 ret = -EINVAL; 667 goto error; 668 } 669 670 for (i = 0, len = 0; i < reply->num_elems; i++) { 671 ret = snprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n", 672 reply->elems[i].zone, reply->elems[i].id, 673 reply->elems[i].used, reply->elems[i].free); 674 if (ret < 0) 675 goto error; 676 len += ret; 677 } 678 679 ret = len; 680 error: 681 kfree(reply); 682 return ret; 683 } 684 685 static ssize_t memory_info_read(struct file *file, char __user *to, size_t count, loff_t *ppos) 686 { 687 struct snd_sof_dfsentry *dfse = file->private_data; 688 struct snd_sof_dev *sdev = dfse->sdev; 689 int data_length; 690 691 /* read memory info from FW only once for each file read */ 692 if (!*ppos) { 693 dfse->buf_data_size = 0; 694 data_length = memory_info_update(sdev, dfse->buf, dfse->size); 695 if (data_length < 0) 696 return data_length; 697 dfse->buf_data_size = data_length; 698 } 699 700 return simple_read_from_buffer(to, count, ppos, dfse->buf, dfse->buf_data_size); 701 } 702 703 static int memory_info_open(struct inode *inode, struct file *file) 704 { 705 struct snd_sof_dfsentry *dfse = inode->i_private; 706 struct snd_sof_dev *sdev = dfse->sdev; 707 708 file->private_data = dfse; 709 710 /* allocate buffer memory only in first open run, to save memory when unused */ 711 if (!dfse->buf) { 712 dfse->buf = devm_kmalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); 713 if (!dfse->buf) 714 return -ENOMEM; 715 dfse->size = PAGE_SIZE; 716 } 717 718 return 0; 719 } 720 721 static const struct file_operations memory_info_fops = { 722 .open = memory_info_open, 723 .read = memory_info_read, 724 .llseek = default_llseek, 725 }; 726 727 int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev) 728 { 729 struct snd_sof_dfsentry *dfse; 730 731 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); 732 if (!dfse) 733 return -ENOMEM; 734 735 /* don't allocate buffer before first usage, to save memory when unused */ 736 dfse->type = SOF_DFSENTRY_TYPE_BUF; 737 dfse->sdev = sdev; 738 739 debugfs_create_file("memory_info", 0444, sdev->debugfs_root, dfse, &memory_info_fops); 740 741 /* add to dfsentry list */ 742 list_add(&dfse->list, &sdev->dfsentry_list); 743 return 0; 744 } 745 EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init); 746 747 int snd_sof_dbg_init(struct snd_sof_dev *sdev) 748 { 749 const struct snd_sof_dsp_ops *ops = sof_ops(sdev); 750 const struct snd_sof_debugfs_map *map; 751 int i; 752 int err; 753 754 /* use "sof" as top level debugFS dir */ 755 sdev->debugfs_root = debugfs_create_dir("sof", NULL); 756 757 /* init dfsentry list */ 758 INIT_LIST_HEAD(&sdev->dfsentry_list); 759 760 /* create debugFS files for platform specific MMIO/DSP memories */ 761 for (i = 0; i < ops->debug_map_count; i++) { 762 map = &ops->debug_map[i]; 763 764 err = snd_sof_debugfs_io_item(sdev, sdev->bar[map->bar] + 765 map->offset, map->size, 766 map->name, map->access_type); 767 /* errors are only due to memory allocation, not debugfs */ 768 if (err < 0) 769 return err; 770 } 771 772 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) 773 err = snd_sof_debugfs_probe_item(sdev, "probe_points", 774 0644, &probe_points_fops); 775 if (err < 0) 776 return err; 777 err = snd_sof_debugfs_probe_item(sdev, "probe_points_remove", 778 0200, &probe_points_remove_fops); 779 if (err < 0) 780 return err; 781 #endif 782 783 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 784 /* create read-write ipc_flood_count debugfs entry */ 785 err = snd_sof_debugfs_buf_item(sdev, NULL, 0, 786 "ipc_flood_count", 0666); 787 788 /* errors are only due to memory allocation, not debugfs */ 789 if (err < 0) 790 return err; 791 792 /* create read-write ipc_flood_duration_ms debugfs entry */ 793 err = snd_sof_debugfs_buf_item(sdev, NULL, 0, 794 "ipc_flood_duration_ms", 0666); 795 796 /* errors are only due to memory allocation, not debugfs */ 797 if (err < 0) 798 return err; 799 #endif 800 801 return 0; 802 } 803 EXPORT_SYMBOL_GPL(snd_sof_dbg_init); 804 805 void snd_sof_free_debug(struct snd_sof_dev *sdev) 806 { 807 debugfs_remove_recursive(sdev->debugfs_root); 808 } 809 EXPORT_SYMBOL_GPL(snd_sof_free_debug); 810 811 void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev) 812 { 813 if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) || 814 (sof_core_debug & SOF_DBG_RETAIN_CTX)) { 815 /* should we prevent DSP entering D3 ? */ 816 dev_info(sdev->dev, "info: preventing DSP entering D3 state to preserve context\n"); 817 pm_runtime_get_noresume(sdev->dev); 818 } 819 820 /* dump vital information to the logs */ 821 snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); 822 snd_sof_ipc_dump(sdev); 823 snd_sof_trace_notify_for_error(sdev); 824 } 825 EXPORT_SYMBOL(snd_sof_handle_fw_exception); 826