刚入了台天选Air 14寸 H350 + 5060 (FA401KM)点名吐槽云南国补,装上Arch Linux 发现启动时间超长,需要50秒才能进桌面。。。刷了目前最新的303 BIOS也没有提升😑
省流:直接看解决方法
分析了一下,内核启动就话了40多秒肯定不正常:
$ systemd-analyze
Startup finished in 5.721s (firmware) + 7.782s (loader) + 44.140s (kernel) + 2.460s (userspace) = 1min 105ms
graphical.target reached after 1.705s in userspace. 看dmesg的话,发现USB枚举完以后貌似等待了36秒:
# dmesg
...
[ 2.165573] usb 3-5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2.166127] usb 3-5: Product: Bluetooth Radio
[ 2.166671] usb 3-5: Manufacturer: Realtek
[ 2.167208] usb 3-5: SerialNumber: 00e04c000001
[ 38.188085] clk: Disabling unused clocks
[ 38.188644] PM: genpd: Disabling unused power domains
[ 38.191606] Freeing unused decrypted memory: 2028K
[ 38.192520] Freeing unused kernel image (initmem) memory: 4644K
直接trace了下initcall,大部分时间都花在了acpi_gpio_handle_deferred_request_irqs上面,和上面的36秒对应:
[ 1.750332] calling acpi_gpio_handle_deferred_request_irqs+0x0/0x40 @ 1
...
[ 38.126886] initcall acpi_gpio_handle_deferred_request_irqs+0x0/0x40 returned 0 after 36376321 usecs
为了看的更清楚使用ftrace跟踪了该函数,具体结果见连接,居然跑出了28万行的log😑
https://gist.github.com/HiFiPhile/324c330b204ef038ef8b3ff2aff7bb6c
从结果可以发现大部分时间花在了acpi_ex_system_do_sleep上,结合内核源码可以定位到BIOS ACPI DSDT表的解析过程,是DSDT代码要求的sleep😓
好家伙,藏的还挺深,DSDT我可从来每搞过,硬着头皮上吧。。。把DSDT dump出来并反编译,查找Sleep发现了如下可疑函数:
Method (NOD2, 1, Serialized)
{
If ((IVGA == Zero))
{
If ((Arg0 != RDNT))
{
Local0 = Zero
Local1 = DNOT /* \_SB_.PCI0.SBRG.DNOT */
DNOT = Arg0
RDNT = Zero
While ((Arg0 != RDNT))
{
If ((Local0 >= 0x0f))
{
DNOT = Local1
Break
}
Notify (^^GPP9.PEGP, Arg0)
Local0++
Local2 = (Local0 * 0x64)
Sleep (Local2)
}
}
}
}
也不清楚是在干啥,第一次循环等待100ms,退出条件不成立则每次递增直到1500ms,完全对应log中的执行时间。
光脚不怕穿鞋的,把这个函数干掉试试:
Method (NOD2, 1, Serialized)
{
If ((IVGA == Zero))
{
If ((Arg0 != RDNT))
{
Local1 = DNOT /* \_SB_.PCI0.SBRG.DNOT */
DNOT = Arg0
RDNT = Zero
Notify (^^GPP9.PEGP, Arg0)
Sleep (0x64)
DNOT = Local1
}
}
}
重新编译DSDT并用mkinitcpio的acpi_override hook把文件加入initramfs,问题解决,使用了一天目前还未冒烟🙄
$ systemd-analyze
Startup finished in 5.734s (firmware) + 2.246s (loader) + 5.370s (kernel) + 2.481s (userspace) = 15.832s
graphical.target reached after 2.468s in userspace.
声明:ACPI DSDT涉及硬件,错误的DSDT修改可能导致硬件损坏,本人不对此负责!
最稳妥的方法当然是等华硕发布修复版BIOS或是Linux添加对应补丁,该方法只是临时解决方案。
从https://gist.github.com/HiFiPhile/324c330b204ef038ef8b3ff2aff7bb6c 下载修改好的DSDT文件dsdt.aml
wget https://gist.github.com/HiFiPhile/324c330b204ef038ef8b3ff2aff7bb6c/raw/791afbad504a61e28738a6ad147f08471d1a583a/dsdt.aml 复制到 /etc/initcpio/acpi_override/
mkdir /etc/initcpio/acpi_override/
cp dsdt.aml /etc/initcpio/acpi_override/ 启用acpi_override
echo "HOOKS+=(acpi_override )" > /etc/mkinitcpio.conf.d/acpi.conf 重建initramfs
kernel-install add-all