| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * |
|---|
| 4 | | - * (C) COPYRIGHT 2018-2021 ARM Limited. All rights reserved. |
|---|
| 4 | + * (C) COPYRIGHT 2018-2022 ARM Limited. All rights reserved. |
|---|
| 5 | 5 | * |
|---|
| 6 | 6 | * This program is free software and is provided to you under the terms of the |
|---|
| 7 | 7 | * GNU General Public License version 2 as published by the Free Software |
|---|
| .. | .. |
|---|
| 29 | 29 | #include <linux/list.h> |
|---|
| 30 | 30 | #include <linux/mman.h> |
|---|
| 31 | 31 | |
|---|
| 32 | | -#if IS_ENABLED(CONFIG_DEBUG_FS) |
|---|
| 33 | | -#if (KERNEL_VERSION(4, 7, 0) > LINUX_VERSION_CODE) |
|---|
| 34 | | -#define DEFINE_DEBUGFS_ATTRIBUTE DEFINE_SIMPLE_ATTRIBUTE |
|---|
| 35 | | -#endif |
|---|
| 36 | | -#endif |
|---|
| 37 | | - |
|---|
| 38 | 32 | /** |
|---|
| 39 | 33 | * struct firmware_trace_buffer - Trace Buffer within the MCU firmware |
|---|
| 40 | | - * |
|---|
| 41 | | - * The firmware relays information to the host by writing on memory buffers |
|---|
| 42 | | - * which are allocated and partially configured by the host. These buffers |
|---|
| 43 | | - * are called Trace Buffers: each of them has a specific purpose and is |
|---|
| 44 | | - * identified by a name and a set of memory addresses where the host can |
|---|
| 45 | | - * set pointers to host-allocated structures. |
|---|
| 46 | 34 | * |
|---|
| 47 | 35 | * @kbdev: Pointer to the Kbase device. |
|---|
| 48 | 36 | * @node: List head linking all trace buffers to |
|---|
| .. | .. |
|---|
| 73 | 61 | * @num_pages: Size of the data buffer, in pages. |
|---|
| 74 | 62 | * @trace_enable_init_mask: Initial value for the trace enable bit mask. |
|---|
| 75 | 63 | * @name: NULL terminated string which contains the name of the trace buffer. |
|---|
| 64 | + * |
|---|
| 65 | + * The firmware relays information to the host by writing on memory buffers |
|---|
| 66 | + * which are allocated and partially configured by the host. These buffers |
|---|
| 67 | + * are called Trace Buffers: each of them has a specific purpose and is |
|---|
| 68 | + * identified by a name and a set of memory addresses where the host can |
|---|
| 69 | + * set pointers to host-allocated structures. |
|---|
| 76 | 70 | */ |
|---|
| 77 | 71 | struct firmware_trace_buffer { |
|---|
| 78 | 72 | struct kbase_device *kbdev; |
|---|
| .. | .. |
|---|
| 100 | 94 | /** |
|---|
| 101 | 95 | * struct firmware_trace_buffer_data - Configuration data for trace buffers |
|---|
| 102 | 96 | * |
|---|
| 103 | | - * Describe how to set up a trace buffer interface. |
|---|
| 104 | | - * Trace buffers are identified by name and they require a data buffer and |
|---|
| 105 | | - * an initial mask of values for the trace enable bits. |
|---|
| 106 | | - * |
|---|
| 107 | 97 | * @name: Name identifier of the trace buffer |
|---|
| 108 | 98 | * @trace_enable_init_mask: Initial value to assign to the trace enable bits |
|---|
| 109 | 99 | * @size: Size of the data buffer to allocate for the trace buffer, in pages. |
|---|
| 110 | 100 | * The size of a data buffer must always be a power of 2. |
|---|
| 101 | + * |
|---|
| 102 | + * Describe how to set up a trace buffer interface. |
|---|
| 103 | + * Trace buffers are identified by name and they require a data buffer and |
|---|
| 104 | + * an initial mask of values for the trace enable bits. |
|---|
| 111 | 105 | */ |
|---|
| 112 | 106 | struct firmware_trace_buffer_data { |
|---|
| 113 | 107 | char name[64]; |
|---|
| .. | .. |
|---|
| 121 | 115 | * This table contains the configuration data for the trace buffers that are |
|---|
| 122 | 116 | * expected to be parsed from the firmware. |
|---|
| 123 | 117 | */ |
|---|
| 124 | | -static const struct firmware_trace_buffer_data |
|---|
| 125 | | -trace_buffer_data[] = { |
|---|
| 126 | | -#ifndef MALI_KBASE_BUILD |
|---|
| 127 | | - { "fwutf", {0}, 1 }, |
|---|
| 118 | +static const struct firmware_trace_buffer_data trace_buffer_data[] = { |
|---|
| 119 | +#if MALI_UNIT_TEST |
|---|
| 120 | + { "fwutf", { 0 }, 1 }, |
|---|
| 128 | 121 | #endif |
|---|
| 129 | | - { FW_TRACE_BUF_NAME, {0}, 4 }, |
|---|
| 130 | | - { "benchmark", {0}, 2 }, |
|---|
| 131 | | - { "timeline", {0}, KBASE_CSF_TL_BUFFER_NR_PAGES }, |
|---|
| 122 | + { FIRMWARE_LOG_BUF_NAME, { 0 }, 4 }, |
|---|
| 123 | + { "benchmark", { 0 }, 2 }, |
|---|
| 124 | + { "timeline", { 0 }, KBASE_CSF_TL_BUFFER_NR_PAGES }, |
|---|
| 132 | 125 | }; |
|---|
| 133 | 126 | |
|---|
| 134 | 127 | int kbase_csf_firmware_trace_buffers_init(struct kbase_device *kbdev) |
|---|
| .. | .. |
|---|
| 180 | 173 | extract_gpu_va = |
|---|
| 181 | 174 | (kbdev->csf.firmware_trace_buffers.mcu_rw.va_reg->start_pfn << PAGE_SHIFT) + |
|---|
| 182 | 175 | mcu_rw_offset; |
|---|
| 183 | | - extract_cpu_va = (u32*)( |
|---|
| 176 | + extract_cpu_va = (u32 *)( |
|---|
| 184 | 177 | kbdev->csf.firmware_trace_buffers.mcu_rw.cpu_addr + |
|---|
| 185 | 178 | mcu_rw_offset); |
|---|
| 186 | 179 | insert_gpu_va = |
|---|
| 187 | 180 | (kbdev->csf.firmware_trace_buffers.mcu_write.va_reg->start_pfn << PAGE_SHIFT) + |
|---|
| 188 | 181 | mcu_write_offset; |
|---|
| 189 | | - insert_cpu_va = (u32*)( |
|---|
| 182 | + insert_cpu_va = (u32 *)( |
|---|
| 190 | 183 | kbdev->csf.firmware_trace_buffers.mcu_write.cpu_addr + |
|---|
| 191 | 184 | mcu_write_offset); |
|---|
| 192 | 185 | data_buffer_gpu_va = |
|---|
| .. | .. |
|---|
| 324 | 317 | extract_gpu_va = |
|---|
| 325 | 318 | (kbdev->csf.firmware_trace_buffers.mcu_rw.va_reg->start_pfn << PAGE_SHIFT) + |
|---|
| 326 | 319 | mcu_rw_offset; |
|---|
| 327 | | - extract_cpu_va = (u32*)( |
|---|
| 320 | + extract_cpu_va = (u32 *)( |
|---|
| 328 | 321 | kbdev->csf.firmware_trace_buffers.mcu_rw.cpu_addr + |
|---|
| 329 | 322 | mcu_rw_offset); |
|---|
| 330 | 323 | insert_gpu_va = |
|---|
| 331 | 324 | (kbdev->csf.firmware_trace_buffers.mcu_write.va_reg->start_pfn << PAGE_SHIFT) + |
|---|
| 332 | 325 | mcu_write_offset; |
|---|
| 333 | | - insert_cpu_va = (u32*)( |
|---|
| 326 | + insert_cpu_va = (u32 *)( |
|---|
| 334 | 327 | kbdev->csf.firmware_trace_buffers.mcu_write.cpu_addr + |
|---|
| 335 | 328 | mcu_write_offset); |
|---|
| 336 | 329 | data_buffer_gpu_va = |
|---|
| .. | .. |
|---|
| 513 | 506 | } |
|---|
| 514 | 507 | EXPORT_SYMBOL(kbase_csf_firmware_trace_buffer_read_data); |
|---|
| 515 | 508 | |
|---|
| 516 | | -#if IS_ENABLED(CONFIG_DEBUG_FS) |
|---|
| 509 | +static void update_trace_buffer_active_mask64(struct firmware_trace_buffer *tb, u64 mask) |
|---|
| 510 | +{ |
|---|
| 511 | + unsigned int i; |
|---|
| 512 | + |
|---|
| 513 | + for (i = 0; i < tb->trace_enable_entry_count; i++) |
|---|
| 514 | + kbasep_csf_firmware_trace_buffer_update_trace_enable_bit(tb, i, (mask >> i) & 1); |
|---|
| 515 | +} |
|---|
| 517 | 516 | |
|---|
| 518 | 517 | #define U32_BITS 32 |
|---|
| 519 | | -static u64 get_trace_buffer_active_mask64(struct firmware_trace_buffer *tb) |
|---|
| 518 | +u64 kbase_csf_firmware_trace_buffer_get_active_mask64(struct firmware_trace_buffer *tb) |
|---|
| 520 | 519 | { |
|---|
| 521 | 520 | u64 active_mask = tb->trace_enable_init_mask[0]; |
|---|
| 522 | 521 | |
|---|
| .. | .. |
|---|
| 526 | 525 | return active_mask; |
|---|
| 527 | 526 | } |
|---|
| 528 | 527 | |
|---|
| 529 | | -static void update_trace_buffer_active_mask64(struct firmware_trace_buffer *tb, |
|---|
| 530 | | - u64 mask) |
|---|
| 531 | | -{ |
|---|
| 532 | | - unsigned int i; |
|---|
| 533 | | - |
|---|
| 534 | | - for (i = 0; i < tb->trace_enable_entry_count; i++) |
|---|
| 535 | | - kbasep_csf_firmware_trace_buffer_update_trace_enable_bit( |
|---|
| 536 | | - tb, i, (mask >> i) & 1); |
|---|
| 537 | | -} |
|---|
| 538 | | - |
|---|
| 539 | | -static int set_trace_buffer_active_mask64(struct firmware_trace_buffer *tb, |
|---|
| 540 | | - u64 mask) |
|---|
| 528 | +int kbase_csf_firmware_trace_buffer_set_active_mask64(struct firmware_trace_buffer *tb, u64 mask) |
|---|
| 541 | 529 | { |
|---|
| 542 | 530 | struct kbase_device *kbdev = tb->kbdev; |
|---|
| 543 | 531 | unsigned long flags; |
|---|
| .. | .. |
|---|
| 565 | 553 | |
|---|
| 566 | 554 | return err; |
|---|
| 567 | 555 | } |
|---|
| 568 | | - |
|---|
| 569 | | -static int kbase_csf_firmware_trace_enable_mask_read(void *data, u64 *val) |
|---|
| 570 | | -{ |
|---|
| 571 | | - struct kbase_device *kbdev = (struct kbase_device *)data; |
|---|
| 572 | | - struct firmware_trace_buffer *tb = |
|---|
| 573 | | - kbase_csf_firmware_get_trace_buffer(kbdev, FW_TRACE_BUF_NAME); |
|---|
| 574 | | - |
|---|
| 575 | | - if (tb == NULL) { |
|---|
| 576 | | - dev_err(kbdev->dev, "Couldn't get the firmware trace buffer"); |
|---|
| 577 | | - return -EIO; |
|---|
| 578 | | - } |
|---|
| 579 | | - /* The enabled traces limited to u64 here, regarded practical */ |
|---|
| 580 | | - *val = get_trace_buffer_active_mask64(tb); |
|---|
| 581 | | - return 0; |
|---|
| 582 | | -} |
|---|
| 583 | | - |
|---|
| 584 | | -static int kbase_csf_firmware_trace_enable_mask_write(void *data, u64 val) |
|---|
| 585 | | -{ |
|---|
| 586 | | - struct kbase_device *kbdev = (struct kbase_device *)data; |
|---|
| 587 | | - struct firmware_trace_buffer *tb = |
|---|
| 588 | | - kbase_csf_firmware_get_trace_buffer(kbdev, FW_TRACE_BUF_NAME); |
|---|
| 589 | | - u64 new_mask; |
|---|
| 590 | | - unsigned int enable_bits_count; |
|---|
| 591 | | - |
|---|
| 592 | | - if (tb == NULL) { |
|---|
| 593 | | - dev_err(kbdev->dev, "Couldn't get the firmware trace buffer"); |
|---|
| 594 | | - return -EIO; |
|---|
| 595 | | - } |
|---|
| 596 | | - |
|---|
| 597 | | - /* Ignore unsupported types */ |
|---|
| 598 | | - enable_bits_count = |
|---|
| 599 | | - kbase_csf_firmware_trace_buffer_get_trace_enable_bits_count(tb); |
|---|
| 600 | | - if (enable_bits_count > 64) { |
|---|
| 601 | | - dev_dbg(kbdev->dev, "Limit enabled bits count from %u to 64", |
|---|
| 602 | | - enable_bits_count); |
|---|
| 603 | | - enable_bits_count = 64; |
|---|
| 604 | | - } |
|---|
| 605 | | - new_mask = val & ((1 << enable_bits_count) - 1); |
|---|
| 606 | | - |
|---|
| 607 | | - if (new_mask != get_trace_buffer_active_mask64(tb)) |
|---|
| 608 | | - return set_trace_buffer_active_mask64(tb, new_mask); |
|---|
| 609 | | - else |
|---|
| 610 | | - return 0; |
|---|
| 611 | | -} |
|---|
| 612 | | - |
|---|
| 613 | | -static int kbasep_csf_firmware_trace_debugfs_open(struct inode *in, |
|---|
| 614 | | - struct file *file) |
|---|
| 615 | | -{ |
|---|
| 616 | | - struct kbase_device *kbdev = in->i_private; |
|---|
| 617 | | - |
|---|
| 618 | | - file->private_data = kbdev; |
|---|
| 619 | | - dev_dbg(kbdev->dev, "Opened firmware trace buffer dump debugfs file"); |
|---|
| 620 | | - |
|---|
| 621 | | - return 0; |
|---|
| 622 | | -} |
|---|
| 623 | | - |
|---|
| 624 | | -static ssize_t kbasep_csf_firmware_trace_debugfs_read(struct file *file, |
|---|
| 625 | | - char __user *buf, size_t size, loff_t *ppos) |
|---|
| 626 | | -{ |
|---|
| 627 | | - struct kbase_device *kbdev = file->private_data; |
|---|
| 628 | | - u8 *pbyte; |
|---|
| 629 | | - unsigned int n_read; |
|---|
| 630 | | - unsigned long not_copied; |
|---|
| 631 | | - /* Limit the kernel buffer to no more than two pages */ |
|---|
| 632 | | - size_t mem = MIN(size, 2 * PAGE_SIZE); |
|---|
| 633 | | - unsigned long flags; |
|---|
| 634 | | - |
|---|
| 635 | | - struct firmware_trace_buffer *tb = |
|---|
| 636 | | - kbase_csf_firmware_get_trace_buffer(kbdev, FW_TRACE_BUF_NAME); |
|---|
| 637 | | - |
|---|
| 638 | | - if (tb == NULL) { |
|---|
| 639 | | - dev_err(kbdev->dev, "Couldn't get the firmware trace buffer"); |
|---|
| 640 | | - return -EIO; |
|---|
| 641 | | - } |
|---|
| 642 | | - |
|---|
| 643 | | - pbyte = kmalloc(mem, GFP_KERNEL); |
|---|
| 644 | | - if (pbyte == NULL) { |
|---|
| 645 | | - dev_err(kbdev->dev, "Couldn't allocate memory for trace buffer dump"); |
|---|
| 646 | | - return -ENOMEM; |
|---|
| 647 | | - } |
|---|
| 648 | | - |
|---|
| 649 | | - spin_lock_irqsave(&kbdev->hwaccess_lock, flags); |
|---|
| 650 | | - n_read = kbase_csf_firmware_trace_buffer_read_data(tb, pbyte, mem); |
|---|
| 651 | | - spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); |
|---|
| 652 | | - |
|---|
| 653 | | - /* Do the copy, if we have obtained some trace data */ |
|---|
| 654 | | - not_copied = (n_read) ? copy_to_user(buf, pbyte, n_read) : 0; |
|---|
| 655 | | - kfree(pbyte); |
|---|
| 656 | | - |
|---|
| 657 | | - if (!not_copied) { |
|---|
| 658 | | - *ppos += n_read; |
|---|
| 659 | | - return n_read; |
|---|
| 660 | | - } |
|---|
| 661 | | - |
|---|
| 662 | | - dev_err(kbdev->dev, "Couldn't copy trace buffer data to user space buffer"); |
|---|
| 663 | | - return -EFAULT; |
|---|
| 664 | | -} |
|---|
| 665 | | - |
|---|
| 666 | | - |
|---|
| 667 | | -DEFINE_SIMPLE_ATTRIBUTE(kbase_csf_firmware_trace_enable_mask_fops, |
|---|
| 668 | | - kbase_csf_firmware_trace_enable_mask_read, |
|---|
| 669 | | - kbase_csf_firmware_trace_enable_mask_write, "%llx\n"); |
|---|
| 670 | | - |
|---|
| 671 | | -static const struct file_operations kbasep_csf_firmware_trace_debugfs_fops = { |
|---|
| 672 | | - .owner = THIS_MODULE, |
|---|
| 673 | | - .open = kbasep_csf_firmware_trace_debugfs_open, |
|---|
| 674 | | - .read = kbasep_csf_firmware_trace_debugfs_read, |
|---|
| 675 | | - .llseek = no_llseek, |
|---|
| 676 | | -}; |
|---|
| 677 | | - |
|---|
| 678 | | -void kbase_csf_firmware_trace_buffer_debugfs_init(struct kbase_device *kbdev) |
|---|
| 679 | | -{ |
|---|
| 680 | | - debugfs_create_file("fw_trace_enable_mask", 0644, |
|---|
| 681 | | - kbdev->mali_debugfs_directory, kbdev, |
|---|
| 682 | | - &kbase_csf_firmware_trace_enable_mask_fops); |
|---|
| 683 | | - |
|---|
| 684 | | - debugfs_create_file("fw_traces", 0444, |
|---|
| 685 | | - kbdev->mali_debugfs_directory, kbdev, |
|---|
| 686 | | - &kbasep_csf_firmware_trace_debugfs_fops); |
|---|
| 687 | | -} |
|---|
| 688 | | -#endif /* CONFIG_DEBUG_FS */ |
|---|