現在、Raspberry Pi 5の汎用タイマータイマーの1つにカスタムハンドラーを登録しようとしていますが、残念ながら機能しません。
これまでに私がしたことは、デバイスツリーのタイマーエントリを見ることだけであり、上記の4つの割り込み、PPI 10、11、13、および14があります。
timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
IRQ_TYPE_LEVEL_LOW)>;
/* This only applies to the ARMv7 stub */
arm,cpu-registers-not-fw-configured;
};
これらの割り込みを見ると、/proc/interrupts
10にはハンドラがインストールされていないようです。
CPU0 CPU1 CPU2 CPU3
9: 0 0 0 0 GICv2 25 Level vgic
11: 0 0 0 0 GICv2 30 Level kvm guest ptimer
12: 0 0 0 0 GICv2 27 Level kvm guest vtimer
13: 4018 9245 1668 9893 GICv2 26 Level arch_timer
14: 1147 0 0 0 GICv2 65 Level 107c013880.mailbox
15: 5 0 0 0 GICv2 153 Level uart-pl011
...
(また、デバイスツリーに記載されていない場合は、「kvm guest vtimer」がどこから来るのかを知りたいのですが、知っていますか?)
この知識に基づいて、次の簡単なカーネルモジュールを接続します。
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
MODULE_LICENSE("GPL");
DEFINE_PER_CPU(int, dev_id);
irqreturn_t test_handler(int irq, void *dev_id)
{
int this_cpu = smp_processor_id();
printk("CPU %i received interrupt!\n", this_cpu);
return IRQ_HANDLED;
}
int test_init(void)
{
u64 ctl = 0, cval = 0, tval = 0;
int err = 0, cpu = 0;
cpu = get_cpu();
printk("CPU: %i\n", cpu);
err = request_percpu_irq(10, test_handler, "test_module", &dev_id);
printk("request_percpu_irq() err: %i\n", err);
ctl = read_sysreg(CNTHP_CTL_EL2);
cval = read_sysreg(CNTHP_CVAL_EL2);
tval = read_sysreg(CNTHP_TVAL_EL2);
printk("CNTHP_CTL_EL2: %llu\n", ctl);
printk("CNTHP_CVAL_EL2: %llu\n", cval);
printk("CNTHP_TVAL_EL2: %llu\n", tval);
write_sysreg(1000, CNTHP_TVAL_EL2);
cval = read_sysreg(CNTHP_CVAL_EL2);
tval = read_sysreg(CNTHP_TVAL_EL2);
printk("CNTHP_CVAL_EL2: %llu\n", cval);
printk("CNTHP_TVAL_EL2: %llu\n", tval);
put_cpu();
return 0;
}
void test_exit(void)
{
free_percpu_irq(10, &dev_id);
}
module_init(test_init);
module_exit(test_exit);
もう一度見ると、/proc/interrupts
私のハンドラが正しく登録されているようです。
CPU0 CPU1 CPU2 CPU3
9: 0 0 0 0 GICv2 25 Level vgic
10: 0 0 0 0 GICv2 29 Level test_module
11: 0 0 0 0 GICv2 30 Level kvm guest ptimer
12: 0 0 0 0 GICv2 27 Level kvm guest vtimer
13: 2597 1798 3172 1910 GICv2 26 Level arch_timer
14: 249 0 0 0 GICv2 65 Level 107c013880.mailbox
15: 5 0 0 0 GICv2 153 Level uart-pl011
...
しかし、コードで私がやろうとしているのは、割り込みを生成して新しいハンドラをトリガーすることですが、残念ながらこの方法は機能しません。一般的なタイマリファレンスによれば、割り込み番号10(PPIオフセット16を追加する場合26)は、プレフィックスとサフィックスを持つNon-secure EL2 Physical Timer
関連システムレジスタに関連付ける必要があります。CNTHP
EL2
以下は、システム・レジスタを介してタイマー構成が作動したことを示す関連するdmesg項目です。次の条件に基づいて割り込み発生も有効にする必要がありますCNTHP_CTL_EL2
。
[ 26.007926] test: loading out-of-tree module taints kernel.
[ 26.008154] CPU: 3
[ 26.008167] request_percpu_irq() err: 0
[ 26.008169] CNTHP_CTL_EL2: 1
[ 26.008172] CNTHP_CVAL_EL2: 1409277728
[ 26.008174] CNTHP_TVAL_EL2: 185726
[ 26.008177] CNTHP_CVAL_EL2: 1409093405
[ 26.008179] CNTHP_TVAL_EL2: 998
しかし、内部の印刷物がtest_handler()
失われ、割り込みが私のハンドラに到達しないようです。残念ながら、私がしばらく閉じ込められていた場所がここです。
それでは、LinuxカーネルモジュールでARMユニバーサルタイマーの割り込みハンドラを登録する方法は? (なぜ私の思い通りにならないのか?)