由前篇文章《海思Hi3559AV100平台韦根接收程序 》引出了一个问题,本应该写在那篇文章中,但由于内容较多,且属于相对独立的一块,所以专门开一篇文章详细说明。
之前发现在海思平台上运行韦根接收程序时,会产生丢中断的现象,当时分析是由于海思芯片中运行了很多MPP模块,这些模块影响了韦根接收程序中用到的GPIO外部中断。
进一步分析印证了当时的判断,根据运行cat /proc/interrupts命令得到的结果发现(见下面),绝大多数中断都在CPU0上,韦根所用的中断也分配到了CPU0上,这就会产生上述问题。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CPU0 CPU1 CPU2 CPU3
1: 0 0 0 0 GIC-0 29 Level arch_timer
2: 9156822 9156735 9156532 9156650 GIC-0 30 Level arch_timer
3: 0 0 0 0 GIC-0 243 Level ipcm
9: 157 0 0 0 GIC-0 38 Level uart-pl011
14: 0 0 0 0 GIC-0 63 Level pl022
15: 0 0 0 0 GIC-0 64 Level pl022
16: 0 0 0 0 GIC-0 65 Level pl022
17: 0 0 0 0 GIC-0 66 Level pl022
18: 0 0 0 0 GIC-0 67 Level pl022
19: 0 0 0 0 GIC-0 192 Level 12140000.gpio_chip
20: 0 0 0 0 GIC-0 193 Level 12141000.gpio_chip
21: 0 0 0 0 GIC-0 194 Level 12142000.gpio_chip
22: 0 0 0 0 GIC-0 195 Level 12143000.gpio_chip
23: 0 0 0 0 GIC-0 196 Level 12144000.gpio_chip
24: 0 0 0 0 GIC-0 197 Level 12145000.gpio_chip
25: 0 0 0 0 GIC-0 198 Level 12146000.gpio_chip
26: 0 0 0 0 GIC-0 199 Level 12147000.gpio_chip
27: 0 0 0 0 GIC-0 200 Level 12148000.gpio_chip
28: 0 0 0 0 GIC-0 201 Level 12149000.gpio_chip
29: 0 0 0 0 GIC-0 202 Level 1214a000.gpio_chip
30: 0 0 0 0 GIC-0 203 Level 1214b000.gpio_chip
31: 2 0 0 0 GIC-0 204 Level 1214c000.gpio_chip
32: 0 0 0 0 GIC-0 205 Level 1214d000.gpio_chip
33: 0 0 0 0 GIC-0 206 Level 1214e000.gpio_chip
34: 0 0 0 0 GIC-0 207 Level 1214f000.gpio_chip
35: 0 0 0 0 GIC-0 208 Level 12150000.gpio_chip
36: 0 0 0 0 GIC-0 209 Level 12151000.gpio_chip
37: 0 0 0 0 GIC-0 210 Level 12152000.gpio_chip
38: 0 0 0 0 GIC-0 215 Level 180d3000.shub_gpio
39: 0 0 0 0 GIC-0 43 Level 180b0000.rtc
40: 5588734 0 0 0 GIC-0 68 Level 101c0000.ethernet
42: 212 0 0 0 GIC-0 116 Level xhci-hcd:usb1
43: 0 0 0 0 GIC-0 117 Level xhci-hcd:usb3
44: 2314 0 0 0 GIC-0 58 Level mmc0
45: 0 0 0 0 GIC-0 106 Level mmc1
46: 0 0 0 0 GIC-0 107 Level mmc2
53: 0 0 0 0 GIC-0 113 Level hiedmacv310
55: 0 0 0 0 GIC-0 92 Level VI_CAP0
56: 0 0 0 0 GIC-0 93 Level VI_PROC0
57: 0 0 0 0 GIC-0 94 Level VI_PROC1
58: 0 0 0 0 GIC-0 118 Level SLVS_EC0
59: 0 0 0 0 GIC-0 120 Level MIPI0
60: 796266 0 0 0 GIC-0 77 Level VPSS0
61: 43022 0 0 0 GIC-0 78 Level VPSS1
62: 690722 0 0 0 GIC-0 75 Level VGS0
63: 222459 0 0 0 GIC-0 76 Level VGS1
64: 0 0 0 0 GIC-0 79 Level GDC0
65: 0 0 0 0 GIC-0 80 Level GDC1
66: 0 0 0 0 GIC-0 83 Level DIS
67: 0 0 0 0 GIC-0 184 Level AVS
68: 0 0 0 0 GIC-0 99 Level VO Int
69: 0 0 0 0 GIC-0 100 Level HIFB Int
70: 0 0 0 0 GIC-0 95 Level MIPI_TX
72: 0 0 0 0 GIC-0 71 Level VEDU_0
73: 0 0 0 0 GIC-0 72 Level VEDU_1
74: 0 0 0 0 GIC-0 73 Level VEDU_2
75: 652 0 0 0 GIC-0 81 Level JPGE_0
76: 0 0 0 0 GIC-0 123 Level vdh_bd
77: 912964 0 0 0 GIC-0 124 Level vdh_pd
78: 861008 0 0 0 GIC-0 126 Level vdh_scd
79: 0 0 0 0 GIC-0 84 Level JPEGD_0
80: 484599 0 0 0 GIC-0 90 Level nnie0
81: 484821 0 0 0 GIC-0 91 Level nnie1
82: 0 0 0 0 GIC-0 240 Level DPU RECT
83: 0 0 0 0 GIC-0 241 Level DPU MATCH
84: 326 0 0 0 GIC-0 88 Level IVE
86: 0 0 0 0 GIC-0 101 Level AIO Interrupt
87: 1 0 0 0 GIC-0 134 Level 11c00000.gpu
88: 3 0 0 0 GIC-0 85 Level tde_osr_isr
89: 1 0 0 0 GIC-0 135 Level 11c00000.gpu
90: 1 0 0 0 GIC-0 133 Level 11c00000.gpu
97: 0 0 0 0 pl061 2 Edge rst
193: 1 0 0 0 pl061 2 Edge wiegand_data1
195: 1 0 0 0 pl061 4 Edge wiegand_data0
IPI0: 1297810 2253123 4008151 9711865 Rescheduling interrupts
IPI1: 21 10 25 10 Function call interrupts
IPI2: 0 0 0 0 CPU stop interrupts
IPI3: 0 0 0 0 Timer broadcast interrupts
IPI4: 0 0 0 0 IRQ work interrupts
IPI5: 0 0 0 0 CPU wake-up interrupts
Err: 0
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
如何能解决上述问题?在网上找解决方法。
1. 利用echo命令将cpu掩码写入/proc/irq/中断ID/smp_affinity文件中,即可实现修改某一中断的CPU亲和性。
按照这个方法运行 echo 4 > /proc/irq/193/smp_affinity,结果提示如下错误:
echo: write error: Input/output error
再照这个问题的解决方法,答案令人失望,这是由硬件或操作系统决定的,无解!
方法1失败。
2. 不从应用层解决,着眼于内核层来寻求解决方法。内核中有这样一个函数:irq_set_affinity(clock_event_device->irq, cpumask);将irq 与 cpu 相关联,指出哪一个或几个 cpu 服务于该irq。
按照这个方法修改模块代码,加入以下语句:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct cpumask cpumask;
cpumask.bits[0] = (unsigned long)0x02;
irq_set_affinity_hint(wiegand_in_devp->d0_irq, &cpumask);
irq_set_affinity_hint(wiegand_in_devp->d1_irq, &cpumask);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
irq_set_affinity_hint函数位于kernel/irq/manage.c中,其调用了__irq_set_affinity函数,进而调用了irq_set_affinity函数。
这个方法貌似根本解决了问题,但实际上编译模块并运行后,观察韦根的2个GPIO中断,还是分配到了CPU0上,cat /proc/irq/193/smp_affinity的结果依旧是f,没有任何改变。这是为什么?继续在内核代码中加入打印进行调试,发现问题出现在了这里(见下述红色粗体显示):
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
bool force)
{
struct irq_chip *chip = irq_data_get_irq_chip(data);
struct irq_desc *desc = irq_data_to_desc(data);
int ret = 0;
printk("111\n");
if (!chip || !chip->irq_set_affinity)
return -EINVAL;
printk("222\n");
if (irq_can_move_pcntxt(data)) {
ret = irq_do_set_affinity(data, mask, force);
} else {
irqd_set_move_pending(data);
irq_copy_pending(desc, mask);
}
if (desc->affinity_notify) {
kref_get(&desc->affinity_notify->kref);
schedule_work(&desc->affinity_notify->work);
}
irqd_set(data, IRQD_AFFINITY_SET);
return ret;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
实际上并没有往下运行,这应该是由于chip->irq_set_affinity为空导致的,但具体为何为空,应在哪里设置,怎样设置就需要进一步研究了……