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 "sof-probes.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 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) 340 static ssize_t msg_inject_read(struct file *file, char __user *buffer, 341 size_t count, loff_t *ppos) 342 { 343 struct snd_sof_dfsentry *dfse = file->private_data; 344 struct sof_ipc_reply *rhdr = dfse->msg_inject_rx; 345 346 if (!rhdr->hdr.size || !count || *ppos) 347 return 0; 348 349 if (count > rhdr->hdr.size) 350 count = rhdr->hdr.size; 351 352 if (copy_to_user(buffer, dfse->msg_inject_rx, count)) 353 return -EFAULT; 354 355 *ppos += count; 356 return count; 357 } 358 359 static ssize_t msg_inject_write(struct file *file, const char __user *buffer, 360 size_t count, loff_t *ppos) 361 { 362 struct snd_sof_dfsentry *dfse = file->private_data; 363 struct snd_sof_dev *sdev = dfse->sdev; 364 struct sof_ipc_cmd_hdr *hdr = dfse->msg_inject_tx; 365 size_t size; 366 int ret, err; 367 368 if (*ppos) 369 return 0; 370 371 size = simple_write_to_buffer(dfse->msg_inject_tx, SOF_IPC_MSG_MAX_SIZE, 372 ppos, buffer, count); 373 if (size != count) 374 return size > 0 ? -EFAULT : size; 375 376 ret = pm_runtime_get_sync(sdev->dev); 377 if (ret < 0 && ret != -EACCES) { 378 dev_err_ratelimited(sdev->dev, "%s: DSP resume failed: %d\n", 379 __func__, ret); 380 pm_runtime_put_noidle(sdev->dev); 381 goto out; 382 } 383 384 /* send the message */ 385 memset(dfse->msg_inject_rx, 0, SOF_IPC_MSG_MAX_SIZE); 386 ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, dfse->msg_inject_tx, count, 387 dfse->msg_inject_rx, SOF_IPC_MSG_MAX_SIZE); 388 389 pm_runtime_mark_last_busy(sdev->dev); 390 err = pm_runtime_put_autosuspend(sdev->dev); 391 if (err < 0) 392 dev_err_ratelimited(sdev->dev, "%s: DSP idle failed: %d\n", 393 __func__, err); 394 395 /* return size if test is successful */ 396 if (ret >= 0) 397 ret = size; 398 399 out: 400 return ret; 401 } 402 403 static const struct file_operations msg_inject_fops = { 404 .open = simple_open, 405 .read = msg_inject_read, 406 .write = msg_inject_write, 407 .llseek = default_llseek, 408 }; 409 410 static int snd_sof_debugfs_msg_inject_item(struct snd_sof_dev *sdev, 411 const char *name, mode_t mode, 412 const struct file_operations *fops) 413 { 414 struct snd_sof_dfsentry *dfse; 415 416 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); 417 if (!dfse) 418 return -ENOMEM; 419 420 /* pre allocate the tx and rx buffers */ 421 dfse->msg_inject_tx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); 422 dfse->msg_inject_rx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); 423 if (!dfse->msg_inject_tx || !dfse->msg_inject_rx) 424 return -ENOMEM; 425 426 dfse->type = SOF_DFSENTRY_TYPE_BUF; 427 dfse->sdev = sdev; 428 429 debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops); 430 /* add to dfsentry list */ 431 list_add(&dfse->list, &sdev->dfsentry_list); 432 433 return 0; 434 } 435 #endif 436 437 static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, 438 size_t count, loff_t *ppos) 439 { 440 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 441 struct snd_sof_dfsentry *dfse = file->private_data; 442 struct snd_sof_dev *sdev = dfse->sdev; 443 unsigned long ipc_duration_ms = 0; 444 bool flood_duration_test = false; 445 unsigned long ipc_count = 0; 446 struct dentry *dentry; 447 int err; 448 #endif 449 size_t size; 450 char *string; 451 int ret; 452 453 string = kzalloc(count+1, GFP_KERNEL); 454 if (!string) 455 return -ENOMEM; 456 457 size = simple_write_to_buffer(string, count, ppos, buffer, count); 458 ret = size; 459 460 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 461 /* 462 * write op is only supported for ipc_flood_count or 463 * ipc_flood_duration_ms debugfs entries atm. 464 * ipc_flood_count floods the DSP with the number of IPC's specified. 465 * ipc_duration_ms test floods the DSP for the time specified 466 * in the debugfs entry. 467 */ 468 dentry = file->f_path.dentry; 469 if (strcmp(dentry->d_name.name, "ipc_flood_count") && 470 strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) { 471 ret = -EINVAL; 472 goto out; 473 } 474 475 if (!strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) 476 flood_duration_test = true; 477 478 /* test completion criterion */ 479 if (flood_duration_test) 480 ret = kstrtoul(string, 0, &ipc_duration_ms); 481 else 482 ret = kstrtoul(string, 0, &ipc_count); 483 if (ret < 0) 484 goto out; 485 486 /* limit max duration/ipc count for flood test */ 487 if (flood_duration_test) { 488 if (!ipc_duration_ms) { 489 ret = size; 490 goto out; 491 } 492 493 /* find the minimum. min() is not used to avoid warnings */ 494 if (ipc_duration_ms > MAX_IPC_FLOOD_DURATION_MS) 495 ipc_duration_ms = MAX_IPC_FLOOD_DURATION_MS; 496 } else { 497 if (!ipc_count) { 498 ret = size; 499 goto out; 500 } 501 502 /* find the minimum. min() is not used to avoid warnings */ 503 if (ipc_count > MAX_IPC_FLOOD_COUNT) 504 ipc_count = MAX_IPC_FLOOD_COUNT; 505 } 506 507 ret = pm_runtime_get_sync(sdev->dev); 508 if (ret < 0 && ret != -EACCES) { 509 dev_err_ratelimited(sdev->dev, 510 "error: debugfs write failed to resume %d\n", 511 ret); 512 pm_runtime_put_noidle(sdev->dev); 513 goto out; 514 } 515 516 /* flood test */ 517 ret = sof_debug_ipc_flood_test(sdev, dfse, flood_duration_test, 518 ipc_duration_ms, ipc_count); 519 520 pm_runtime_mark_last_busy(sdev->dev); 521 err = pm_runtime_put_autosuspend(sdev->dev); 522 if (err < 0) 523 dev_err_ratelimited(sdev->dev, 524 "error: debugfs write failed to idle %d\n", 525 err); 526 527 /* return size if test is successful */ 528 if (ret >= 0) 529 ret = size; 530 out: 531 #endif 532 kfree(string); 533 return ret; 534 } 535 536 static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, 537 size_t count, loff_t *ppos) 538 { 539 struct snd_sof_dfsentry *dfse = file->private_data; 540 struct snd_sof_dev *sdev = dfse->sdev; 541 loff_t pos = *ppos; 542 size_t size_ret; 543 int skip = 0; 544 int size; 545 u8 *buf; 546 547 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 548 struct dentry *dentry; 549 550 dentry = file->f_path.dentry; 551 if ((!strcmp(dentry->d_name.name, "ipc_flood_count") || 552 !strcmp(dentry->d_name.name, "ipc_flood_duration_ms"))) { 553 if (*ppos) 554 return 0; 555 556 count = strlen(dfse->cache_buf); 557 size_ret = copy_to_user(buffer, dfse->cache_buf, count); 558 if (size_ret) 559 return -EFAULT; 560 561 *ppos += count; 562 return count; 563 } 564 #endif 565 size = dfse->size; 566 567 /* validate position & count */ 568 if (pos < 0) 569 return -EINVAL; 570 if (pos >= size || !count) 571 return 0; 572 /* find the minimum. min() is not used since it adds sparse warnings */ 573 if (count > size - pos) 574 count = size - pos; 575 576 /* align io read start to u32 multiple */ 577 pos = ALIGN_DOWN(pos, 4); 578 579 /* intermediate buffer size must be u32 multiple */ 580 size = ALIGN(count, 4); 581 582 /* if start position is unaligned, read extra u32 */ 583 if (unlikely(pos != *ppos)) { 584 skip = *ppos - pos; 585 if (pos + size + 4 < dfse->size) 586 size += 4; 587 } 588 589 buf = kzalloc(size, GFP_KERNEL); 590 if (!buf) 591 return -ENOMEM; 592 593 if (dfse->type == SOF_DFSENTRY_TYPE_IOMEM) { 594 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) 595 /* 596 * If the DSP is active: copy from IO. 597 * If the DSP is suspended: 598 * - Copy from IO if the memory is always accessible. 599 * - Otherwise, copy from cached buffer. 600 */ 601 if (pm_runtime_active(sdev->dev) || 602 dfse->access_type == SOF_DEBUGFS_ACCESS_ALWAYS) { 603 memcpy_fromio(buf, dfse->io_mem + pos, size); 604 } else { 605 dev_info(sdev->dev, 606 "Copying cached debugfs data\n"); 607 memcpy(buf, dfse->cache_buf + pos, size); 608 } 609 #else 610 /* if the DSP is in D3 */ 611 if (!pm_runtime_active(sdev->dev) && 612 dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { 613 dev_err(sdev->dev, 614 "error: debugfs entry cannot be read in DSP D3\n"); 615 kfree(buf); 616 return -EINVAL; 617 } 618 619 memcpy_fromio(buf, dfse->io_mem + pos, size); 620 #endif 621 } else { 622 memcpy(buf, ((u8 *)(dfse->buf) + pos), size); 623 } 624 625 /* copy to userspace */ 626 size_ret = copy_to_user(buffer, buf + skip, count); 627 628 kfree(buf); 629 630 /* update count & position if copy succeeded */ 631 if (size_ret) 632 return -EFAULT; 633 634 *ppos = pos + count; 635 636 return count; 637 } 638 639 static const struct file_operations sof_dfs_fops = { 640 .open = simple_open, 641 .read = sof_dfsentry_read, 642 .llseek = default_llseek, 643 .write = sof_dfsentry_write, 644 }; 645 646 /* create FS entry for debug files that can expose DSP memories, registers */ 647 static int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, 648 void __iomem *base, size_t size, 649 const char *name, 650 enum sof_debugfs_access_type access_type) 651 { 652 struct snd_sof_dfsentry *dfse; 653 654 if (!sdev) 655 return -EINVAL; 656 657 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); 658 if (!dfse) 659 return -ENOMEM; 660 661 dfse->type = SOF_DFSENTRY_TYPE_IOMEM; 662 dfse->io_mem = base; 663 dfse->size = size; 664 dfse->sdev = sdev; 665 dfse->access_type = access_type; 666 667 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) 668 /* 669 * allocate cache buffer that will be used to save the mem window 670 * contents prior to suspend 671 */ 672 if (access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { 673 dfse->cache_buf = devm_kzalloc(sdev->dev, size, GFP_KERNEL); 674 if (!dfse->cache_buf) 675 return -ENOMEM; 676 } 677 #endif 678 679 debugfs_create_file(name, 0444, sdev->debugfs_root, dfse, 680 &sof_dfs_fops); 681 682 /* add to dfsentry list */ 683 list_add(&dfse->list, &sdev->dfsentry_list); 684 685 return 0; 686 } 687 688 int snd_sof_debugfs_add_region_item_iomem(struct snd_sof_dev *sdev, 689 enum snd_sof_fw_blk_type blk_type, u32 offset, 690 size_t size, const char *name, 691 enum sof_debugfs_access_type access_type) 692 { 693 int bar = snd_sof_dsp_get_bar_index(sdev, blk_type); 694 695 if (bar < 0) 696 return bar; 697 698 return snd_sof_debugfs_io_item(sdev, sdev->bar[bar] + offset, size, name, 699 access_type); 700 } 701 EXPORT_SYMBOL_GPL(snd_sof_debugfs_add_region_item_iomem); 702 703 /* create FS entry for debug files to expose kernel memory */ 704 int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, 705 void *base, size_t size, 706 const char *name, mode_t mode) 707 { 708 struct snd_sof_dfsentry *dfse; 709 710 if (!sdev) 711 return -EINVAL; 712 713 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); 714 if (!dfse) 715 return -ENOMEM; 716 717 dfse->type = SOF_DFSENTRY_TYPE_BUF; 718 dfse->buf = base; 719 dfse->size = size; 720 dfse->sdev = sdev; 721 722 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 723 if (!strncmp(name, "ipc_flood", strlen("ipc_flood"))) { 724 /* 725 * cache_buf is unused for SOF_DFSENTRY_TYPE_BUF debugfs entries. 726 * So, use it to save the results of the last IPC flood test. 727 */ 728 dfse->cache_buf = devm_kzalloc(sdev->dev, IPC_FLOOD_TEST_RESULT_LEN, 729 GFP_KERNEL); 730 if (!dfse->cache_buf) 731 return -ENOMEM; 732 } 733 #endif 734 735 debugfs_create_file(name, mode, sdev->debugfs_root, dfse, 736 &sof_dfs_fops); 737 /* add to dfsentry list */ 738 list_add(&dfse->list, &sdev->dfsentry_list); 739 740 return 0; 741 } 742 EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item); 743 744 static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_size) 745 { 746 struct sof_ipc_cmd_hdr msg = { 747 .size = sizeof(struct sof_ipc_cmd_hdr), 748 .cmd = SOF_IPC_GLB_DEBUG | SOF_IPC_DEBUG_MEM_USAGE, 749 }; 750 struct sof_ipc_dbg_mem_usage *reply; 751 int len; 752 int ret; 753 int i; 754 755 reply = kmalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); 756 if (!reply) 757 return -ENOMEM; 758 759 ret = pm_runtime_get_sync(sdev->dev); 760 if (ret < 0 && ret != -EACCES) { 761 pm_runtime_put_noidle(sdev->dev); 762 dev_err(sdev->dev, "error: enabling device failed: %d\n", ret); 763 goto error; 764 } 765 766 ret = sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE); 767 pm_runtime_mark_last_busy(sdev->dev); 768 pm_runtime_put_autosuspend(sdev->dev); 769 if (ret < 0 || reply->rhdr.error < 0) { 770 ret = min(ret, reply->rhdr.error); 771 dev_err(sdev->dev, "error: reading memory info failed, %d\n", ret); 772 goto error; 773 } 774 775 if (struct_size(reply, elems, reply->num_elems) != reply->rhdr.hdr.size) { 776 dev_err(sdev->dev, "error: invalid memory info ipc struct size, %d\n", 777 reply->rhdr.hdr.size); 778 ret = -EINVAL; 779 goto error; 780 } 781 782 for (i = 0, len = 0; i < reply->num_elems; i++) { 783 ret = snprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n", 784 reply->elems[i].zone, reply->elems[i].id, 785 reply->elems[i].used, reply->elems[i].free); 786 if (ret < 0) 787 goto error; 788 len += ret; 789 } 790 791 ret = len; 792 error: 793 kfree(reply); 794 return ret; 795 } 796 797 static ssize_t memory_info_read(struct file *file, char __user *to, size_t count, loff_t *ppos) 798 { 799 struct snd_sof_dfsentry *dfse = file->private_data; 800 struct snd_sof_dev *sdev = dfse->sdev; 801 int data_length; 802 803 /* read memory info from FW only once for each file read */ 804 if (!*ppos) { 805 dfse->buf_data_size = 0; 806 data_length = memory_info_update(sdev, dfse->buf, dfse->size); 807 if (data_length < 0) 808 return data_length; 809 dfse->buf_data_size = data_length; 810 } 811 812 return simple_read_from_buffer(to, count, ppos, dfse->buf, dfse->buf_data_size); 813 } 814 815 static int memory_info_open(struct inode *inode, struct file *file) 816 { 817 struct snd_sof_dfsentry *dfse = inode->i_private; 818 struct snd_sof_dev *sdev = dfse->sdev; 819 820 file->private_data = dfse; 821 822 /* allocate buffer memory only in first open run, to save memory when unused */ 823 if (!dfse->buf) { 824 dfse->buf = devm_kmalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); 825 if (!dfse->buf) 826 return -ENOMEM; 827 dfse->size = PAGE_SIZE; 828 } 829 830 return 0; 831 } 832 833 static const struct file_operations memory_info_fops = { 834 .open = memory_info_open, 835 .read = memory_info_read, 836 .llseek = default_llseek, 837 }; 838 839 int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev) 840 { 841 struct snd_sof_dfsentry *dfse; 842 843 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); 844 if (!dfse) 845 return -ENOMEM; 846 847 /* don't allocate buffer before first usage, to save memory when unused */ 848 dfse->type = SOF_DFSENTRY_TYPE_BUF; 849 dfse->sdev = sdev; 850 851 debugfs_create_file("memory_info", 0444, sdev->debugfs_root, dfse, &memory_info_fops); 852 853 /* add to dfsentry list */ 854 list_add(&dfse->list, &sdev->dfsentry_list); 855 return 0; 856 } 857 EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init); 858 859 int snd_sof_dbg_init(struct snd_sof_dev *sdev) 860 { 861 const struct snd_sof_dsp_ops *ops = sof_ops(sdev); 862 const struct snd_sof_debugfs_map *map; 863 int i; 864 int err; 865 866 /* use "sof" as top level debugFS dir */ 867 sdev->debugfs_root = debugfs_create_dir("sof", NULL); 868 869 /* init dfsentry list */ 870 INIT_LIST_HEAD(&sdev->dfsentry_list); 871 872 /* create debugFS files for platform specific MMIO/DSP memories */ 873 for (i = 0; i < ops->debug_map_count; i++) { 874 map = &ops->debug_map[i]; 875 876 err = snd_sof_debugfs_io_item(sdev, sdev->bar[map->bar] + 877 map->offset, map->size, 878 map->name, map->access_type); 879 /* errors are only due to memory allocation, not debugfs */ 880 if (err < 0) 881 return err; 882 } 883 884 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) 885 err = snd_sof_debugfs_probe_item(sdev, "probe_points", 886 0644, &probe_points_fops); 887 if (err < 0) 888 return err; 889 err = snd_sof_debugfs_probe_item(sdev, "probe_points_remove", 890 0200, &probe_points_remove_fops); 891 if (err < 0) 892 return err; 893 #endif 894 895 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) 896 /* create read-write ipc_flood_count debugfs entry */ 897 err = snd_sof_debugfs_buf_item(sdev, NULL, 0, 898 "ipc_flood_count", 0666); 899 900 /* errors are only due to memory allocation, not debugfs */ 901 if (err < 0) 902 return err; 903 904 /* create read-write ipc_flood_duration_ms debugfs entry */ 905 err = snd_sof_debugfs_buf_item(sdev, NULL, 0, 906 "ipc_flood_duration_ms", 0666); 907 908 /* errors are only due to memory allocation, not debugfs */ 909 if (err < 0) 910 return err; 911 #endif 912 913 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) 914 err = snd_sof_debugfs_msg_inject_item(sdev, "ipc_msg_inject", 0644, 915 &msg_inject_fops); 916 917 /* errors are only due to memory allocation, not debugfs */ 918 if (err < 0) 919 return err; 920 #endif 921 922 return 0; 923 } 924 EXPORT_SYMBOL_GPL(snd_sof_dbg_init); 925 926 void snd_sof_free_debug(struct snd_sof_dev *sdev) 927 { 928 debugfs_remove_recursive(sdev->debugfs_root); 929 } 930 EXPORT_SYMBOL_GPL(snd_sof_free_debug); 931 932 static const struct soc_fw_state_info { 933 enum sof_fw_state state; 934 const char *name; 935 } fw_state_dbg[] = { 936 {SOF_FW_BOOT_NOT_STARTED, "SOF_FW_BOOT_NOT_STARTED"}, 937 {SOF_FW_BOOT_PREPARE, "SOF_FW_BOOT_PREPARE"}, 938 {SOF_FW_BOOT_IN_PROGRESS, "SOF_FW_BOOT_IN_PROGRESS"}, 939 {SOF_FW_BOOT_FAILED, "SOF_FW_BOOT_FAILED"}, 940 {SOF_FW_BOOT_READY_FAILED, "SOF_FW_BOOT_READY_FAILED"}, 941 {SOF_FW_BOOT_READY_OK, "SOF_FW_BOOT_READY_OK"}, 942 {SOF_FW_BOOT_COMPLETE, "SOF_FW_BOOT_COMPLETE"}, 943 {SOF_FW_CRASHED, "SOF_FW_CRASHED"}, 944 }; 945 946 static void snd_sof_dbg_print_fw_state(struct snd_sof_dev *sdev, const char *level) 947 { 948 int i; 949 950 for (i = 0; i < ARRAY_SIZE(fw_state_dbg); i++) { 951 if (sdev->fw_state == fw_state_dbg[i].state) { 952 dev_printk(level, sdev->dev, "fw_state: %s (%d)\n", 953 fw_state_dbg[i].name, i); 954 return; 955 } 956 } 957 958 dev_printk(level, sdev->dev, "fw_state: UNKNOWN (%d)\n", sdev->fw_state); 959 } 960 961 void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, const char *msg, u32 flags) 962 { 963 char *level = flags & SOF_DBG_DUMP_OPTIONAL ? KERN_DEBUG : KERN_ERR; 964 bool print_all = sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS); 965 966 if (flags & SOF_DBG_DUMP_OPTIONAL && !print_all) 967 return; 968 969 if (sof_ops(sdev)->dbg_dump && !sdev->dbg_dump_printed) { 970 dev_printk(level, sdev->dev, 971 "------------[ DSP dump start ]------------\n"); 972 if (msg) 973 dev_printk(level, sdev->dev, "%s\n", msg); 974 snd_sof_dbg_print_fw_state(sdev, level); 975 sof_ops(sdev)->dbg_dump(sdev, flags); 976 dev_printk(level, sdev->dev, 977 "------------[ DSP dump end ]------------\n"); 978 if (!print_all) 979 sdev->dbg_dump_printed = true; 980 } else if (msg) { 981 dev_printk(level, sdev->dev, "%s\n", msg); 982 } 983 } 984 EXPORT_SYMBOL(snd_sof_dsp_dbg_dump); 985 986 static void snd_sof_ipc_dump(struct snd_sof_dev *sdev) 987 { 988 if (sof_ops(sdev)->ipc_dump && !sdev->ipc_dump_printed) { 989 dev_err(sdev->dev, "------------[ IPC dump start ]------------\n"); 990 sof_ops(sdev)->ipc_dump(sdev); 991 dev_err(sdev->dev, "------------[ IPC dump end ]------------\n"); 992 if (!sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS)) 993 sdev->ipc_dump_printed = true; 994 } 995 } 996 997 void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev) 998 { 999 if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) || 1000 sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) { 1001 /* should we prevent DSP entering D3 ? */ 1002 if (!sdev->ipc_dump_printed) 1003 dev_info(sdev->dev, 1004 "preventing DSP entering D3 state to preserve context\n"); 1005 pm_runtime_get_noresume(sdev->dev); 1006 } 1007 1008 /* dump vital information to the logs */ 1009 snd_sof_ipc_dump(sdev); 1010 snd_sof_dsp_dbg_dump(sdev, "Firmware exception", 1011 SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); 1012 snd_sof_trace_notify_for_error(sdev); 1013 } 1014 EXPORT_SYMBOL(snd_sof_handle_fw_exception); 1015