tracepoint是驱动编程必学的小技巧,它依附于ftrace系统,本文介绍一个最简单的tracepoint,方便大家在编写subsystem/driver时,为自己的程序安插tracepoint,后面同样会介绍linux中预置的trace event的使用方法。
我们之前聊过blk_update_request
是块设备层的经典函数,在文件系统中,如果读取一个文件,它会先submit_bio
来提交到block层,此后,blk_update_request
用于更新block的request信息后续直接处理IO。
我们以blk_update_request为例,测试一下其本身的tracepoint,如下:
vim block/blk-core.c
先查看头文件
#define CREATE_TRACE_POINTS #include <trace/events/block.h>
此时找到这个h文件,查看如下:
#undef TRACE_SYSTEM #define TRACE_SYSTEM block
然后查看具体函数代码:
bool blk_update_request(struct request *req, blk_status_t error, unsigned int nr_bytes) { int total_bytes; trace_block_rq_complete(req, blk_status_to_errno(error), nr_bytes); if (!req->bio) return false;
我们留意trace_block_rq_complete(req, blk_status_to_errno(error), nr_bytes);
此时我们知道tracepoint是block下的block_rq_complete
根据上面的信息我们找一下路径如下,我们直接进入:
cd /sys/kernel/tracing/events/block/block_rq_complete/
此时我们正常enable即可,
echo 1 > enable
此时我们监听ftrace的日志即可
cat /sys/kernel/debug/tracing/trace_pipe
我们可以看到日志如下:
# cat /sys/kernel/debug/tracing/trace_pipe <idle>-0 [000] ..s. 104.385029: block_rq_complete: 179,0 WS () 13430392 + 96 [0] kworker/3:2H-610 [003] .... 104.385386: block_rq_complete: 179,0 FF () 18446744073709551615 + 0 [0] sshd-3368 [000] ..s. 104.385710: block_rq_complete: 179,0 WFS () 13430488 + 8 [0] sshd-3368 [000] d.s. 104.385733: block_rq_complete: 179,0 WFS () 13430488 + 0 [0] <idle>-0 [000] ..s. 105.877799: block_rq_complete: 179,0 W () 17460720 + 8 [0]
至此tracepoint的演示完成了。其他文章会更详细的演示linux已有的tracepoint
为了在自己的驱动写tracepoint,我们需要注意如下几点:
不清楚的可以参考如下:
https://www.kernel.org/doc/html/latest/trace/tracepoints.html
我们可以编写一个最简单的驱动,使用kthread拉起函数,如下:
#include <linux/init.h> #include <linux/module.h> #include <linux/kthread.h> #include <linux/delay.h> #define CREATE_TRACE_POINTS #include "trace/events/kylin.h" static struct task_struct *thread1; static void test_tracepoint(void) { pr_info("%s starting...\n", __func__); trace_test_kylin("test"); } static int thread_1(void *arg) { while(!kthread_should_stop()){ schedule_timeout_interruptible(msecs_to_jiffies(1000)); test_tracepoint(); } return 0; } static void start_test(void) { thread1 = kthread_run(thread_1, "Thread", "tracepoint-test"); return ; } static int __init test_init(void) { start_test(); return 0; } static void __exit test_exit(void) { kthread_stop(thread1); return; } module_init(test_init); module_exit(test_exit); MODULE_AUTHOR("tangfeng <tangfeng@kylinos.cn>"); MODULE_DESCRIPTION("Test tracepoint"); MODULE_LICENSE("GPL");
这里细节后面可以介绍,先简单看看即可。
vim include/trace/events/kylin.h
#undef TRACE_SYSTEM #define TRACE_SYSTEM kylin #if !defined(_TRACE_KYLIN_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_KYLIN_H #include <linux/tracepoint.h> TRACE_EVENT(test_kylin, TP_PROTO(const char *name), TP_ARGS(name), TP_STRUCT__entry( __field(const char *, name) ), TP_fast_assign( __entry->name = name ), TP_printk("kylin: %s", __entry->name) ); #endif #include <trace/define_trace.h>
我们需要注意以下几点:
关于TRACE_EVENT的编写,参考如下:
https://lwn.net/Articles/379903/ https://lwn.net/Articles/381064/ https://lwn.net/Articles/383362/
我们只需要关注TRACE_EVENT五要素:
对于我们的代码,如下定义:
TRACE_EVENT(test_kylin, TP_PROTO(const char *name), TP_ARGS(name), TP_STRUCT__entry( __field(const char *, name) ), TP_fast_assign( __entry->name = name ), TP_printk("kylin: %s", __entry->name) );
对于prototype:我们使用TP_PROTO的宏定义,传入需要跟踪的函数声明即可,我们打算跟踪的是带字符串的trace如下:
trace_test_kylin("test");
所以我们只需要一个const char* 即可
对于args:我们使用TP_ARGS的宏定义,这里传入参数name
对于struct:我们需要新增一个const char*的成员,故通过TP_STRUCT__entry 定义一个__field即可。
对于assign:我们使用TP_fast_assign来将参数赋值给结构体成员变量
对于print:我们使用TP_printk直接按照printk的方式打印结构体的成员变量
为了使得头文件能够生效,我们定义了TRACE_SYSTEM 为kylin
#undef TRACE_SYSTEM #define TRACE_SYSTEM kylin
这里就要求了头文件的存放位置为include/trace/events
,且名字是kylin
include/trace/events/kylin.h
为了在驱动中使用tracepoint,我们需要在include kylin.h之前添加CREATE_TRACE_POINTS的定义,如下:
#define CREATE_TRACE_POINTS #include "trace/events/kylin.h"
接下来我们就直接使用tracepoint即可,在函数直接安插:
static void test_tracepoint(void) { trace_test_kylin("test"); }
我们写了一个tracepoint,接下来是测试这个tracepoint,当ko加载时,我们可以发现ftrace的events下存在如下文件
# find /sys/kernel/debug/tracing/events/kylin/ /sys/kernel/debug/tracing/events/kylin/ /sys/kernel/debug/tracing/events/kylin/test_kylin /sys/kernel/debug/tracing/events/kylin/test_kylin/format /sys/kernel/debug/tracing/events/kylin/test_kylin/trigger /sys/kernel/debug/tracing/events/kylin/test_kylin/filter /sys/kernel/debug/tracing/events/kylin/test_kylin/id /sys/kernel/debug/tracing/events/kylin/test_kylin/enable /sys/kernel/debug/tracing/events/kylin/enable /sys/kernel/debug/tracing/events/kylin/filter
然后我们准备获取trace的内容,如下:
cat /sys/kernel/debug/tracing/trace_pipe
我们使得我们自己的tracepoint如下:
echo 1 > /sys/kernel/debug/tracing/events/kylin/enable
这样我们trace_pipe可以看到如下日志
# cat /sys/kernel/debug/tracing/trace_pipe | grep test_ thread-141765 [002] .... 9598.458509: test_kylin: kylin: test thread-141765 [002] .... 9599.471840: test_kylin: kylin: test
至此,一个tracepoint的演示完全完成。想必能够有效的帮助大家去编写driver
系统中存在很多linux内核默认预设的trace events,其目的是方便大家查相同问题时能够复用他们的tracepoint,基于此,本文章根据linux内核现成的trace event做分享,主要聊聊如何使用人家定义好的event,从而方便大家调试问题
trace events的目录如下:
# ls /sys/kernel/debug/tracing/events/ alarmtimer fib6 namei sched android_fs filelock napi scmi asoc filemap neigh signal avc ftrace net skb binder gadget nfs smbus block gpio nfs4 sock bpf_test_run header_event nfsd spi bpf_trace header_page nvme sunrpc bridge hwmon oom swiotlb btrfs i2c pagefault sync_trace cfg80211 initcall page_isolation task cgroup iomap pagemap tcp cifs iommu page_pool thermal clk io_uring percpu thermal_ipa_power cma ipi power thermal_power_allocator compaction irq printk timer cpufreq_interactive jbd2 pwm udp cpuhp kmem qdisc v4l2 devfreq kvm ras vb2 dma_fence kyber raw_syscalls virtio_gpu drm mac80211 rcu vmscan dwc3 mali regmap workqueue emulation mdio regulator writeback enable migrate rpcgss xdp error_report mmap rpm xfs ext4 mmc rseq xhci-hcd fib module rtc
我们可以看到linux提供了107个trace system,我们在查问题的时候可以先考虑这些trace system
这里还是以经典函数block_rq_complete为例,可以看到其内容如下:
# find /sys/kernel/debug/tracing/events/block/block_rq_complete/ /sys/kernel/debug/tracing/events/block/block_rq_complete/ /sys/kernel/debug/tracing/events/block/block_rq_complete/format /sys/kernel/debug/tracing/events/block/block_rq_complete/trigger /sys/kernel/debug/tracing/events/block/block_rq_complete/filter /sys/kernel/debug/tracing/events/block/block_rq_complete/id /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
关于trace evemt的文章,可以查看内核官方文档如下,这里就不按照文档重复讨论了:
https://www.kernel.org/doc/html/latest/trace/events.html
本章主要聚焦在下面这几个文件的使用上:
enable filter format id trigger
顾名思义,这个就是打开此event的事件,方法如下:
echo 1 > enable
这里和tracepoint基础编程介绍有点重复,就无需展开了。
这里能够查看这个event的格式,我们在tracepoint基础编程介绍可以知道定义一个TRACE_EVENT需要包含五要素:name/prototype/args/struct/assign/print
,这里是具体展现。如下示例:
# cat format name: block_rq_complete ID: 1350 format: field:unsigned short common_type; offset:0; size:2; signed:0; field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1; signed:0; field:int common_pid; offset:4; size:4; signed:1; field:dev_t dev; offset:8; size:4; signed:0; field:sector_t sector; offset:16; size:8; signed:0; field:unsigned int nr_sector; offset:24; size:4; signed:0; field:int error; offset:28; size:4; signed:1; field:char rwbs[8]; offset:32; size:8; signed:0; field:__data_loc char[] cmd; offset:40; size:4; signed:0; print fmt: "%d,%d %s (%s) %llu + %u [%d]", ((unsigned int) ((REC->dev) >> 20)), ((unsigned int) ((REC->dev) & ((1U << 20) - 1))), REC->rwbs, __get_str(cmd), (unsigned long long)REC->sector, REC->nr_sector, REC->error
这里我们知道如下信息:
这个trace里面,结构体提供了从common_type到cmd的所有字段域 提供了这个struct的offset,也就是具体位置 提供了打印格式
这里提供了id,这个id代表这个trace的id,我们可以从format上看到,如下:
ID: 1350
这个id是只读的,所以我们只能读到这个id,用作filter过滤
# cat id 1350
这个用作过滤,我们可以知道,如果直接enable,我们没办法进行过滤,所以可以在这里添加多个过滤条件,如下:
假设我们只想看idle进程的信息,则如下:
echo "common_pid==0" > filter
如果想要关闭filter,直接echo 0即可
echo 0 > filter
注意,这里的filter只能是struct的成员,如果不是,就会失效,所以提前需要cat format看一下struct哪些成员可以过滤
trigger是trace默认提供的触发类型,我们可以通过cat获取可以使用的trigger类型,如下:
# cat trigger # Available triggers: # traceon traceoff stacktrace enable_event disable_event
这里提供了6个trigger,我们如果想要echo trigger,这里需要指定的语法格式,如下:
echo 'command[:count] [if filter]' > trigger
这里可以看到,我们需要填入command: trigger类型,count
次数 if filter 过滤条件。这里是检测过滤条件满足的时候,一定次数下直接打开此trace,如下示例
echo 'traceon:5 if common_pid==0' > trigger
这里意思是如果pid为idle下触发blk_update_request达到5次,则主动打开此trace event
echo 'traceoff:5 if common_pid==0' > trigger
这里意思是如果pid为idle下触发blk_update_request达到5次,则主动关闭此trace event
这里是打印此函数的堆栈,可以示例如下:
echo "stacktrace:1 if common_pid==0" > trigger
这里是当pid是idle的时候,打印一次堆栈,这样日志如下:
<idle>-0 [000] .Ns. 3780.543922: <stack trace> => trace_event_buffer_commit => trace_event_raw_event_block_rq_complete => blk_update_request => mmc_blk_cqe_complete_rq => mmc_blk_mq_complete => blk_done_softirq => __do_softirq => irq_exit => __handle_domain_irq => gic_handle_irq => el1_irq => cpuidle_enter_state => cpuidle_enter => call_cpuidle => do_idle => cpu_startup_entry => rest_init => arch_call_rest_init => start_kernel
这是打开对于的event的trigger,如下:
echo "enable_event:block:block_rq_complete:2" > trigger
当block_rq_complete被触发两次时,打开event
对于我们有关闭event的trigger,如下:
echo 'disable_event:block:block_rq_complete:2' > trigger
当block_rq_complete被触发两次时,关闭event
至此,我们简单了解了trace event的使用。
自己经常使用windows平台,通过工具putty和mtputty已经能够做到很好的切屏和操作,最近为了在调试openharmony的时候,经常需要编译,而putty放在后台的编译需要自己手拖,这不是很方便,最近同事分享了tmux,原来虽然自己了解过tmux,但是鉴于第一次学习时觉得比较复杂,就没有使用下来,最近恰巧网上系统的学习了tmux的技巧,编写了适用于自己的tmux配置,目前感觉tmux还是有一定的优势的,故分享自己的tmux配置和用途。
安装tmux比较简单,如下
apt install tmux
为了让tmux在我的环境良好的工作,我自己按照自己习惯设计了如下配置,将其填入
~/.tmux.conf
即可
# 参考:https://louiszhai.github.io/2017/09/30/tmux/ # ctrl+b alt+方向键 调整切屏大小 # 设置第二个prefix为` set-option -g prefix2 ` # 重载配置文件 unbind r bind r source-file ~/.tmux.conf \; display "Configuration Reloaded!" # 开启256 colors set -g default-terminal "screen-256color" # 按竖分割 unbind % bind | split-window -h # 按行分割 unbind '"' bind - split-window -v # 按竖分割,这里默认左边只有40 bind v split-window -v -l 40 # 按行分割,这里默认上面只有120 bind h split-window -h -l 120 # 状态栏左对齐 set -g status-justify left # 非当前窗口有内容更新时在状态栏通知 setw -g monitor-activity on # 关闭rename机制,提高性能 setw -g automatic-rename off setw -g allow-rename off # 绑定C为清空缓冲区 bind C send-keys -R \; send-keys C-l \; clear-history \; send-keys
tmux默认使用ctrl+b作为命令前缀,可以设置第二个命令前缀为`,这样敲快捷键的时候,就不用一直敲ctrl+b那么麻烦了
set-option -g prefix2 `
原始配置重新加载需要
ctrl+b : source-file ~/.tmux.conf
比较麻烦,这里使用r键作为快捷键,只需要
`+r
即可,如下是配置详情
unbind r bind r source-file ~/.tmux.conf \; display "Configuration Reloaded!"
通常来说,我们的terminal带点颜色好看的
为了快捷按键按竖分割,这里设置了|,所以我们可以如下
`+|
实现按竖分割
效果如下
如果我们是看代码,可以按照代码行数分割,如下
此时命令是
`+h
为了快捷按键按行分割,这里设置了-,所以我们可以如下
`+-
效果如下
如果我们是在运行编译命令,则可以将编译命令放上面,如下
`+v
效果如下
这样上面编译代码,下面看代码就行了
当我们开了多窗口下,我们还是需要切换窗口,可以使用如下命令
`+alt+(上下左右)
如果我们开了多个tmux,我们可以使用n来切换,如下
`+n
通过C命令可以清空缓冲区,如下
`+C
如果我们需要检索缓冲区的内容,可以通过如下
`+[ # 进入查看模式 `+s # 开始搜索
在调试内核时,我们有时候需要更详细的内容展示,这时候crash工具就上场了,crash工具在RK平台默认是不可用的,本文主要说明在rk平台上麒麟系统开启crash工具的基本方法
我们直接安装一个依赖空包即可
apt install linux-crashdump crash
这个包会主动安装
apt install kdump-tools kexec-tools makedumpfile crash
此时我们查看如下工具正常运行即可:
# crash --version crash 7.2.8 Copyright (C) 2002-2020 Red Hat, Inc. Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation Copyright (C) 1999-2006 Hewlett-Packard Co Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited Copyright (C) 2006, 2007 VA Linux Systems Japan K.K. Copyright (C) 2005, 2011 NEC Corporation Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc. Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. This program is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Enter "help copying" to see the conditions. This program has absolutely no warranty. Enter "help warranty" for details. GNU gdb (GDB) 7.6 Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "aarch64-unknown-linux-gnu".
# kexec --version kexec-tools 2.0.29
# kdump-config --help Usage: kdump-config {help|test|show|status|load|unload|savecore|propagate|symlinks kernel-version}" help - print this page test - Do a dry-run of kdump kernel load command by showing the kernels and parameters that will be used and echo'ing the kexec command. The kexec command will not be executed. If using fadump, check if required sysfs directories exist. show - Show dump mode, status, any current parameters. Show kexec command for kdump. status - evaluate /sys/kernel/{kexec_crash_loaded,fadump_registered} depending on dump mode. Print appropriate message load - Locate the kdump kernel, debug kernel, and establish links for makedumpfile. Then load the kdump kernel using kexec If using fadump, register. unload - unload the kdump kernel using kexec If using fadump, unregister. savecore - use previously made links to save /proc/vmcore propagate - Send public ssh key to remote host for passwordless connection symlinks - Verify and create vmlinuz and initrd.img links in /var/lib/kdump according to the provided kernel version. If the target initrd.img file is absent, it will create it.
接下来我们会用到crash工具
为了使得crash工具正常,我们需要打开内核的配置,如下:
CONFIG_KEXEC=y CONFIG_SYSFS=y CONFIG_DEBUG_INFO=y CONFIG_CRASH_DUMP=y CONFIG_PROC_VMCORE=y
为了vmcore,我们可以在bootargs添加crashkernel=256M,用作core的收集
重新编译内核即可。 我们需要boot.img和vmlinux两个文件
上述准备好了之后,我们还需要vmlinux用来加载crash,如下:
crash ./vmlinux /proc/kcore
稍等一会儿,我们加载好所有符号即可开始crash调试
crash 7.2.8 Copyright (C) 2002-2020 Red Hat, Inc. Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation Copyright (C) 1999-2006 Hewlett-Packard Co Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited Copyright (C) 2006, 2007 VA Linux Systems Japan K.K. Copyright (C) 2005, 2011 NEC Corporation Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc. Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. This program is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Enter "help copying" to see the conditions. This program has absolutely no warranty. Enter "help warranty" for details. GNU gdb (GDB) 7.6 Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "aarch64-unknown-linux-gnu"... please wait... (patching 189292 gdb minimal_symbol values) SYSTEM MAP: /boot/System.map DEBUG KERNEL: /root/vmlinux (5.10.198) DUMPFILE: /proc/kcore CPUS: 8 DATE: Mon Nov 25 17:36:10 2024 UPTIME: 00:12:52 LOAD AVERAGE: 0.73, 0.35, 0.21 TASKS: 659 NODENAME: kylin RELEASE: 5.10.198 VERSION: #4 SMP Tue Nov 26 00:17:27 CST 2024 MACHINE: aarch64 (unknown Mhz) MEMORY: 4 GB PID: 15712 COMMAND: "crash" TASK: ffffff8062f84880 [THREAD_INFO: ffffff8062f84880] CPU: 6 STATE: TASK_RUNNING (ACTIVE) crash>
为了简单演示crash,我随便介绍几个示例,有兴趣了解crash的,可以私下咨询,或查看官方文档如下:
https://crash-utility.github.io/crash_whitepaper.html
crash> p saved_command_line saved_command_line = $1 = 0xffffff81feee7dc0 "storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal dsi-0=2 storagenode=/mmc@fe2e0000 androidboot.verifiedbootstate=orange androidboot.serialno=cc45dde649cc1b19 ro rootwait earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.g"...
crash> dis blk_update_request 0xffffffc0087d2fb8 <blk_update_request>: mov x9, x30 0xffffffc0087d2fbc <blk_update_request+4>: nop 0xffffffc0087d2fc0 <blk_update_request+8>: sub sp, sp, #0x60 0xffffffc0087d2fc4 <blk_update_request+12>: stp x29, x30, [sp,#16] 0xffffffc0087d2fc8 <blk_update_request+16>: add x29, sp, #0x10 0xffffffc0087d2fcc <blk_update_request+20>: stp x19, x20, [sp,#32] ....................
crash> struct task_struct ffffff8026600000 struct task_struct { thread_info = { flags = 0, addr_limit = 549755813887, { preempt_count = 4294967296, preempt = { count = 0, need_resched = 1 } } }, state = 264, stack = 0xffffffc00f248000, .......................
假设我们有驱动如下操作:
test = kmalloc(128, GFP_KERNEL);; memcpy(test, "helloworld", 128);
此时我们加载ko,获取test 的虚拟地址0xffffff806f63eb00,crash内直接打印即可
crash> rd -8 0xffffff806f63eb00 10 ffffff806f63eb00: 68 65 6c 6c 6f 77 6f 72 6c 64 helloworld
至此,我们可以发现crash对于调试内核来说还是挺方便的。
RK3588的gpu是mali g610,这个驱动已经默认合入主线mesa了,对于社区,知名开源机构Collabora开源了基于mali的panthor方案,mesa这边使用主线版本,内核更新基于linux6.8的panthor驱动即可。文章详情如下:
https://www.collabora.com/news-and-blog/news-and-events/release-the-panthor.html
对于mesa,我们需要更新到这笔commit之后即可:
https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26358
我们切一下mesa的仓库,我们可以直接针对mali显卡编译即可,如下:
meson . build/ -Dvulkan-drivers= -Dgallium-drivers=panfrost -Dllvm=disabled
对应文档如下:
https://docs.mesa3d.org/drivers/panfrost.html
对于内核,默认mesa对于的panthor版本在6.8上,我们需要更新如下仓库:
https://gitlab.freedesktop.org/panfrost/linux/-/tree/panthor-next+rk3588?ref_type=heads
其主要代码在:driver/gpu/drm/panthor
我们需要移植这里的代码到自己的版本上,例如linux6.1(已验证)/linux5.10(未验证)
我们知道mali显卡支持csf固件加载,这里的固件也提交在社区上了,可以从如下仓库获取:
https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
我们需要一个名字为mali_csffw.bin的文件放在系统环境下,或合并在内核中,通过firmware_request加载
对于mesa,我们需要切到24.1.0分支上构建,如果我们需要二进制,可以从ubuntu社区上找oibaf的每日构建,如下:
https://launchpad.net/~oibaf/+archive/ubuntu/graphics-drivers
对于指定版本的,根据下载链接修改版本号,可以下载到指定版本上。
当然,如果我们不需要mesa的deb系列包,仍然可以通过meson直接构建如下:
meson . build/ -Dvulkan-drivers= -Dgallium-drivers=panfrost -Dllvm=disabled
使能defconfig,如下:
CONFIG_DRM=y CONFIG_DRM_GPUVM=y CONFIG_DRM_EXEC=y CONFIG_DRM_SCHED=y CONFIG_IOMMU_SUPPORT=y CONFIG_IOMMU_IO_PGTABLE_LPAE=y CONFIG_DRM_GEM_SHMEM_HELPER=y CONFIG_PM_DEVFREQ=y CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_DRM_PANTHOR=y CONFIG_ROCKCHIP_REGULATOR_COUPLER=y CONFIG_DRM_GPUVM=y
合入panthor驱动如下:
0041-panthor-v6.txt
设备树需要关闭原来的mali gpu节点,并新增基于panthor的节点如下:
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@collabora.com> Date: Mon, 7 Aug 2023 17:30:58 +0200 Subject: arm64: dts: rockchip: rk3588: Add GPU nodes Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> --- arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 119 ++++++++++ 1 file changed, 119 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index 762a095648b1..f43f10340d5d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -962,6 +962,120 @@ usb_host2_xhci: usb@fcd00000 { snps,dis-del-phy-power-chg-quirk; snps,dis-tx-ipgap-linecheck-quirk; snps,dis_rxdet_inp3_quirk; + }; + + gpu_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + nvmem-cells = <&gpu_leakage>; + nvmem-cell-names = "leakage"; + + rockchip,pvtm-voltage-sel = < + 0 815 0 + 816 835 1 + 836 860 2 + 861 885 3 + 886 910 4 + 911 9999 5 + >; + rockchip,pvtm-pvtpll; + rockchip,pvtm-offset = <0x1c>; + rockchip,pvtm-sample-time = <1100>; + rockchip,pvtm-freq = <800000>; + rockchip,pvtm-volt = <750000>; + rockchip,pvtm-ref-temp = <25>; + rockchip,pvtm-temp-prop = <(-135) (-135)>; + rockchip,pvtm-thermal-zone = "gpu-thermal"; + + clocks = <&cru CLK_GPU>; + clock-names = "clk"; + rockchip,grf = <&gpu_grf>; + volt-mem-read-margin = < + 855000 1 + 765000 2 + 675000 3 + 495000 4 + >; + low-volt-mem-read-margin = <4>; + intermediate-threshold-freq = <400000>; /* KHz */ + rockchip,temp-hysteresis = <5000>; + rockchip,low-temp = <10000>; + rockchip,low-temp-min-volt = <750000>; + rockchip,high-temp = <85000>; + rockchip,high-temp-max-freq = <800000>; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <675000 675000 850000>; + }; + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <675000 675000 850000>; + }; + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <675000 675000 850000>; + }; + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <675000 675000 850000>; + }; + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = <700000 700000 850000>; + opp-microvolt-L2 = <687500 687500 850000>; + opp-microvolt-L3 = <675000 675000 850000>; + opp-microvolt-L4 = <675000 675000 850000>; + opp-microvolt-L5 = <675000 675000 850000>; + }; + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <750000 750000 850000>; + opp-microvolt-L1 = <737500 737500 850000>; + opp-microvolt-L2 = <725000 725000 850000>; + opp-microvolt-L3 = <712500 712500 850000>; + opp-microvolt-L4 = <700000 700000 850000>; + opp-microvolt-L5 = <700000 700000 850000>; + }; + opp-900000000 { + opp-hz = /bits/ 64 <900000000>; + opp-microvolt = <800000 800000 850000>; + opp-microvolt-L1 = <787500 787500 850000>; + opp-microvolt-L2 = <775000 775000 850000>; + opp-microvolt-L3 = <762500 762500 850000>; + opp-microvolt-L4 = <750000 750000 850000>; + opp-microvolt-L5 = <737500 737500 850000>; + }; + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <850000 850000 850000>; + opp-microvolt-L1 = <837500 837500 850000>; + opp-microvolt-L2 = <825000 825000 850000>; + opp-microvolt-L3 = <812500 812500 850000>; + opp-microvolt-L4 = <800000 800000 850000>; + opp-microvolt-L5 = <787500 787500 850000>; + }; + }; + + gpu: gpu@fb000000 { + compatible = "rockchip,rk3588-mali", "arm,mali-valhall-csf"; + reg = <0x0 0xfb000000 0x0 0x200000>; + interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH 0>; + interrupt-names = "job", "mmu", "gpu"; + + clock-names = "core", "coregroup", "stacks"; + clocks = <&cru CLK_GPU>, <&cru CLK_GPU_COREGROUP>, + <&cru CLK_GPU_STACKS>; + assigned-clocks = <&scmi_clk SCMI_CLK_GPU>; + assigned-clock-rates = <200000000>; + power-domains = <&power RK3588_PD_GPU>; + operating-points-v2 = <&gpu_opp_table>; + #cooling-cells = <2>; + dynamic-power-coefficient = <2982>; + status = "disabled"; }; @@ -3124,6 +3238,11 @@ gpio4: gpio@fec50000 { }; }; + gpu_grf: syscon@fd5a0000 { + compatible = "rockchip,rk3588-gpu-grf", "syscon"; + reg = <0x0 0xfd5a0000 0x0 0x100>; + }; + av1d: video-codec@fdc70000 { compatible = "rockchip,rk3588-av1-vpu"; reg = <0x0 0xfdc70000 0x0 0x800>; --
对于firmware加载部分,如果我们有initrd,则firmware可以放在inird中加载,如果没有,我们可以将其放在内核中自包含,则如下修改:
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index ef232c0c2049..de85e30241f6 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -705,7 +705,7 @@ static int panthor_fw_load(struct panthor_device *ptdev) (u32)GPU_ARCH_MINOR(ptdev->gpu_info.gpu_id), CSF_FW_NAME); - ret = request_firmware(&fw, fw_path, ptdev->base.dev); + ret = request_firmware(&fw, CSF_FW_NAME, ptdev->base.dev); if (ret) { drm_err(&ptdev->base, "Failed to load firmware image '%s'\n", CSF_FW_NAME); @@ -1367,4 +1367,4 @@ int panthor_fw_init(struct panthor_device *ptdev) return ret;
defconfig设置如下:
CONFIG_FW_LOADER=y CONFIG_EXTRA_FIRMWARE="mali_csffw.bin" CONFIG_EXTRA_FIRMWARE_DIR="firmware"
此时固件应该放在内核目录如下:
firmware/ └── mali_csffw.bin
至此,panthor的移植已完全完成,如果内核panthor启动成功,则出现如下日志:
[ 10.187485] panthor fb000000.gpu-panthor: [drm] clock rate = 198000000 [ 10.188422] panthor fb000000.gpu-panthor: EM: OPP:400000 is inefficient [ 10.188429] panthor fb000000.gpu-panthor: EM: OPP:300000 is inefficient [ 10.188525] panthor fb000000.gpu-panthor: EM: created perf domain [ 10.188854] panthor fb000000.gpu-panthor: [drm] mali-g610 id 0xa867 major 0x0 minor 0x0 status 0x5 [ 10.188866] panthor fb000000.gpu-panthor: [drm] Features: L2:0x7120306 Tiler:0x809 Mem:0x301 MMU:0x2830 AS:0xff [ 10.188875] panthor fb000000.gpu-panthor: [drm] shader_present=0x50005 l2_present=0x1 tiler_present=0x1 [ 10.190340] panthor fb000000.gpu-panthor: [drm] Firmware protected mode entry not be supported, ignoring [ 10.190563] panthor fb000000.gpu-panthor: [drm] CSF FW v1.1.0, Features 0x0 Instrumentation features 0x71 [ 10.190996] [drm] Initialized panthor 1.0.0 20230801 for fb000000.gpu-panthor on minor 1
此时我们glmark2测试如下,则代表系统启动正常
root@kylin:~# glmark2 ======================================================= glmark2 2021.02 ======================================================= OpenGL Information GL_VENDOR: Mesa GL_RENDERER: Mali-G610 (Panfrost) GL_VERSION: 3.1 Mesa 24.1.0-devel-panthor (git-1c769cb2b0) ======================================================= [build] use-vbo=false: FPS: 1859 FrameTime: 0.538 ms