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

2019-03-10 13:53

34 * should now contain the SVC stack for this core 35 */

36 b secondary_startup 37

38 .align 391: .long .

40 .long pen_release

41ENDPROC(versatile_secondary_startup)

第1段高亮的部分实际上是等待pen_release成为CPU0设置的cpu_logical_map(cpu),一般直接就成立了。第2段高亮的部分则调用到内核通用的secondary_startup()函数,经过一系列的初始化如MMU等,最终新的被唤醒的CPU将调用到smp_operations的smp_secondary_init()成员函数,对于本例为versatile_secondary_init(): 37void __cpuinitversatile_secondary_init(unsigned int cpu) 38{ 39 /*

40 * if any interrupts are already enabled for the primary 41 * core (e.g. timer irq), then they will not have been enabled 42 * for us: do so 43 */

44 gic_secondary_init(0); 45 46 /*

47 * let the primary processor know we're out of the 48 * pen, then head off into the C entry point 49 */

50 write_pen_release(-1); 51 52 /*

53 * Synchronise with the boot thread. 54 */

55 spin_lock(&boot_lock); 56 spin_unlock(&boot_lock); 57}

上述代码中高亮的那1行会将pen_release写为-1,于是CPU0还在执行的versatile_boot_secondary()函数中的如下循环就退出了:

85 while (time_before(jiffies, timeout)) { 86 smp_rmb();

87 if (pen_release == -1) 88 break;

89

90 udelay(10); 91 }

此后CPU0和新唤醒的其他CPU各自狂奔。整个系统在运行过程中会进行实时进程和正常进程的动态负载均衡。 CPU hotplug的实现也是芯片相关的,对于VEXPRESS而言,实现了smp_operations的cpu_die()成员函数即vexpress_cpu_die()。它会在进行CPUn的拔除操作时将CPUn投入低功耗的WFI状态,相关代码位于arch/arm/mach-vexpress/hotplug.c:

90void __ref vexpress_cpu_die(unsigned intcpu) 91{

92 int spurious = 0; 93 94 /*

95 * we're ready for shutdown now, so do it 96 */

97 cpu_enter_lowpower();

98 platform_do_lowpower(cpu, &spurious); 99 100 /*

101 * bring this CPU back into the world of cache 102 * coherency, and then restore interrupts 103 */

104 cpu_leave_lowpower(); 105

106 if (spurious)

107 pr_warn(\108}

57static inline void platform_do_lowpower(unsignedint cpu, int *spurious) 58{ 59 /*

60 * there is no power-control hardware on this platform, so all 61 * we can do is put the core into WFI; this is safe as the calling 62 * code will have already disabled interrupts 63 */ 64 for (;;) { 65 wfi(); 66

67 if (pen_release ==cpu_logical_map(cpu)) { 68 /*

69 * OK, proper wakeup,we're done 70 */ 71 break; 72 } 73

74 /*

75 * Getting here, means that wehave come out of WFI without 76 * having been woken up - thisshouldn't happen 77 *

78 * Just note it happening -when we're woken, we can report 79 * its occurrence. 80 */

81 (*spurious)++; 82 } 83}

CPUn睡眠于wfi(),之后再次online的时候,又会因为CPU0给它发出的IPI而从wfi()函数返回继续执行,醒来时CPUn也判决了是否pen_release == cpu_logical_map(cpu)成立,以确定该次醒来确确实实是由CPU0唤醒的一次正常醒来。

5. DEBUG_LL和EARLY_PRINTK

在Linux启动的早期,console驱动还没有投入运行。当我们把Linux移植到一个新的SoC的时候,工程师一般非常需要早期就可以执行printk()功能以跟踪调试启动过程。内核的DEBUG_LL和EARLY_PRINTK选项为我们提供了这样的支持。而在Bootloader引导内核执行的bootargs中,则需要使能earlyprintk选项。

为了让DEBUG_LL和EARLY_PRINTK可以运行,Linux内核中需实现早期解压过程打印需要的putc()和后续的addruart、senduart和waituart等宏。以CSR SiRFprimaII为例,putc()的实现位于arch/arm/mach-prima2/include/mach/uncompress.h: 22static __inline__ void putc(char c) 23{ 24 /*

25 * during kernel decompression, all mappings are flat: 26 * virt_addr == phys_addr 27 */

28 while (__raw_readl((void __iomem *)SIRFSOC_UART1_PA_BASE +SIRFSOC_UART_TXFIFO_STATUS) 29 &SIRFSOC_UART1_TXFIFO_FULL) 30 barrier(); 31

32 __raw_writel(c, (void __iomem *)SIRFSOC_UART1_PA_BASE +SIRFSOC_UART_TXFIFO_DATA); 33}

由于解压过程中,MMU还没有初始化,所以这个时候的打印是直接往UART端口FIFO对应的物理地址丢打印字符。 addruart、senduart和waituart等宏的实现位于每个SoC对应的MACHINE代码目录的

include/mach/debug-macro.S,SiRFprimaII的实现mach-prima2/include/mach/debug-macro.S如下: 12 .macro addruart, rp, rv, tmp

13 ldr \\rp,=SIRFSOC_UART1_PA_BASE @physical 14 ldr \\rv,=SIRFSOC_UART1_VA_BASE @ virtual 15 .endm 16

17 .macro senduart,rd,rx

18 str \\rd, [\\rx,#SIRFSOC_UART_TXFIFO_DATA] 19 .endm 20

21 .macro busyuart,rd,rx 22 .endm 23

24 .macro waituart,rd,rx

251001: ldr \\rd, [\\rx,#SIRFSOC_UART_TXFIFO_STATUS] 26 tst \\rd,#SIRFSOC_UART1_TXFIFO_EMPTY 27 beq 1001b 28 .endm

其中的senduart完成了往UART的FIFO丢打印字符的过程。waituart则相当于一个流量握手,等待FIFO为空。这些宏最终会被内核的arch/arm/kernel/debug.S引用。

6. GPIO驱动

在drivers/gpio下实现了通用的基于gpiolib的GPIO驱动,其中定义了一个通用的用于描述底层GPIO控制器的gpio_chip结构体,并要求具体的SoC实现gpio_chip结构体的成员函数,最后透过gpiochip_add()注册gpio_chip。 gpio_chip结构体封装了底层的硬件的GPIO enable/disable等操作,它定义为: 94struct gpio_chip {

95 const char *label; 96 struct device *dev; 97 struct module *owner; 98

99 int (*request)(struct gpio_chip *chip, 100 unsigned offset); 101 void (*free)(struct gpio_chip *chip, 102 unsigned offset); 103

104 int (*direction_input)(struct gpio_chip *chip, 105 unsigned offset); 106 int (*get)(struct gpio_chip *chip, 107 unsigned offset);

108 int (*direction_output)(structgpio_chip *chip, 109 unsigned offset, int value); 110 int (*set_debounce)(struct gpio_chip *chip, 111 unsigned offset, unsigned debounce); 112

113 void (*set)(struct gpio_chip *chip, 114 unsigned offset, int value); 115

116 int (*to_irq)(struct gpio_chip *chip, 117 unsigned offset); 118

119 void (*dbg_show)(struct seq_file *s, 120 struct gpio_chip *chip); 121 int base; 122 u16 ngpio;

123 const char *const*names; 124 unsigned can_sleep:1; 125 unsigned exported:1; 126

127#if defined(CONFIG_OF_GPIO) 128 /*

129 * If CONFIG_OF is enabled, then all GPIOcontrollers described in the 130 * device tree automatically may have an OF translation 131 */

132 struct device_node *of_node; 133 int of_gpio_n_cells;

134 int (*of_xlate)(struct gpio_chip *gc,

135 const structof_phandle_args *gpiospec, u32 *flags); 136#endif 137};

透过这层封装,每个具体的要用到GPIO的设备驱动都使用通用的GPIO API来操作GPIO,这些API主要用于GPIO的申请、释放和设置:

intgpio_request(unsigned gpio, const char *label);


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

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

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

马上注册会员

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