Linux芯片级移植与底层驱动(基于3.7.4内核)(3)

2019-03-10 13:53

5. 305 unsigned int (*irq_startup)(structirq_data *data); 6.

7. 306 void (*irq_shutdown)(struct irq_data *data); 8.

9. 307 void (*irq_enable)(struct irq_data *data); 10.

11. 308 void (*irq_disable)(struct irq_data *data); 12. 13. 309 14.

15. 310 void (*irq_ack)(struct irq_data *data); 16.

17. 311 void (*irq_mask)(structirq_data *data); 18.

19. 312 void (*irq_mask_ack)(struct irq_data *data); 20.

21. 313 void (*irq_unmask)(struct irq_data *data); 22.

23. 314 void (*irq_eoi)(struct irq_data *data); 24. 25. 315 26.

27. 316 int (*irq_set_affinity)(struct irq_data *data, conststruct cpumask *dest,bool force); 28.

29. 317 int (*irq_retrigger)(struct irq_data *data); 30.

31. 318 int (*irq_set_type)(struct irq_data *data,unsigned int flow_type); 32.

33. 319 int (*irq_set_wake)(struct irq_data *data, unsigned int on); 34.

35. 334};

各个芯片公司会将芯片内部的中断控制器实现为irq_chip驱动的形式。受限于中断控制器硬件的能力,这些成员函数并不一定需要全部实现,有时候只需要实现其中的部分函数即可。譬如drivers/pinctrl/pinctrl-sirf.c驱动中的

[cpp]view plaincopy

1. 2. 3. 4. 5. 6. 7. 8.

1438staticstruct irq_chip sirfsoc_irq_chip = {

1439 .name = \

1440 .irq_ack = sirfsoc_gpio_irq_ack,

1441 .irq_mask = sirfsoc_gpio_irq_mask,

9. 1442 .irq_unmask = sirfsoc_gpio_irq_unmask, 10.

11. 1443 .irq_set_type = sirfsoc_gpio_irq_type, 12.

13. 1444};

我们只实现了其中的ack、mask、unmask和set_type成员函数,ack函数用于清中断,mask、unmask用于中断屏蔽和取消中断屏蔽、set_type则用于配置中断的触发方式,如高电平、低电平、上升沿、下降沿等。至于enable_irq()的时候,虽然没有实现irq_enable成员函数,但是内核会间接调用到irq_unmask成员函数,这点从kernel/irq/chip.c可以看出:

[cpp]view plaincopy

1. 192voidirq_enable(struct irq_desc *desc) 2. 3. 193{ 4.

5. 194 irq_state_clr_disabled(desc); 6.

7. 195 if (desc-

9. 196 desc-

11. 197 else 12.

13. 198 desc-

15. 199 irq_state_clr_masked(desc); 16. 17. 200}

在芯片内部,中断控制器可能不止1个,多个中断控制器之间还很可能是级联的。举个例子,假设芯片内部有一个中断控制器,支持32个中断源,其中有4个来源于GPIO控制器外围的4组GPIO,每组GPIO上又有32个中断(许多芯片的GPIO控制器也同时是一个中断控制器),其关系如下图:

那么,一般来讲,在实际操作中,gpio0_0——gpio0_31这些引脚本身在第1级会使用中断号28,而这些引脚本身的中断号在实现GPIO控制器对应的irq_chip驱动时,我们又会把它映射到Linux系统的32——63号中断。同理,gpio1_0——gpio1_31这些引脚本身在第1级会使用中断号29,而这些引脚本身的中断号在实现GPIO控制器对应的irq_chip驱动时,我们又会把它映射到Linux系统的64——95号中断,以此类推。对于中断号的使用者而言,无需看到这种2级映射关系。如果某设备想申请gpio1_0这个引脚对应的中断,它只需要申请64号中断即可。这个关系图看起来如下:

还是以drivers/pinctrl/pinctrl-sirf.c的irq_chip部分为例,我们对于每组GPIO都透过irq_domain_add_legacy()添加了相应的irq_domain,每组GPIO的中断号开始于SIRFSOC_GPIO_IRQ_START + i *SIRFSOC_GPIO_BANK_SIZE,而每组GPIO本身占用的第1级中断控制器的中断号则为bank-

1689 bank-

1693 if (!bank-

1694 pr_err(\1695 err = -ENOSYS; 1696 goto out; 1697 } 1698

1699 irq_set_chained_handler(bank-

而在sirfsoc_gpio_handle_irq()函数的入口出调用chained_irq_enter()暗示自身进入链式IRQ处理,在函数体内判决具体的GPIO中断,并透过generic_handle_irq()调用到最终的外设驱动中的中断服务程序,最后调用chained_irq_exit()暗示自身退出链式IRQ处理:

1446staticvoid sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) 1447{ 1448 …

1454 chained_irq_enter(chip, desc); 1456 …

1477 generic_handle_irq(first_irq + idx); 1478 …

1484 chained_irq_exit(chip, desc); 1485}

很多中断控制器的寄存器定义呈现出简单的规律,如有一个mask寄存器,其中每1位可屏蔽1个中断等,这种情况下,我们无需实现1个完整的irq_chip驱动,可以使用内核提供的通用irq_chip驱动架构irq_chip_generic,这样只需要实现极少量的代码,如arch/arm/mach-prima2/irq.c中,注册CSRSiRFprimaII内部中断控制器的代码仅为: 26static __init void

27sirfsoc_alloc_gc(void __iomem *base,unsigned int irq_start, unsigned int num) 28{

29 struct irq_chip_generic *gc; 30 struct irq_chip_type *ct; 31

32 gc = irq_alloc_generic_chip(\

33 ct = gc-

35 ct-

39 irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,IRQ_NOREQUEST, 0); 40}

特别值得一提的是,目前多数主流ARM芯片,内部的一级中断控制器都使用了ARM公司的GIC,我们几乎不需要实现任何代码,只需要在Device Tree中添加相关的结点并将gic_handle_irq()填入MACHINE的handle_irq成员。 如在arch/arm/boot/dts/exynos5250.dtsi即含有: 36 gic:interrupt-controller@10481000 { 37 compatible = \38 #interrupt-cells = <3>; 39 interrupt-controller;

40 reg = <0x104810000x1000>, <0x10482000 x>; 41 };

而在arch/arm/mach-exynos/mach-exynos5-dt.c中即含有:

95DT_MACHINE_START(EXYNOS5_DT, \96 /* Maintainer: Kukjin Kim */ 97 .init_irq =exynos5_init_irq,

98 .smp =smp_ops(exynos_smp_ops), 99 .map_io = exynos5250_dt_map_io, 100 .handle_irq = gic_handle_irq,

101 .init_machine =exynos5250_dt_machine_init, 102 .init_late =exynos_init_late, 103 .timer =&exynos4_timer,

104 .dt_compat =exynos5250_dt_compat, 105 .restart = exynos5_restart, 106MACHINE_END

4. SMP多核启动以及CPU热插拔驱动

在Linux系统中,对于多核的ARM芯片而言,Bootrom代码中,CPU0会率先起来,引导Bootloader和Linux内核执行,而其他的核则在上电时Bootrom一般将自身置于WFI或者WFE状态,并等待CPU0给其发CPU核间中断(IPI)或事件(一般透过SEV指令)唤醒之。一个典型的启动过程如下图:


Linux芯片级移植与底层驱动(基于3.7.4内核)(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:…生僻字相对大全…

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: