smp boot

kernel 提供了smp boot 实现的架构,要实现smp boot 先要实现smp_operations  这个结构体


http://lxr.free-electrons.com/source/arch/arm/mach-prima2/platsmp.c?v=3.18#L140
140 struct smp_operations sirfsoc_smp_ops __initdata = {
141         .smp_prepare_cpus       = sirfsoc_smp_prepare_cpus,
142         .smp_secondary_init     = sirfsoc_secondary_init,
143         .smp_boot_secondary     = sirfsoc_boot_secondary,
144 #ifdef CONFIG_HOTPLUG_CPU
145         .cpu_die                = sirfsoc_cpu_die,
146 #endif
147 };


这个结构体中的smp_prepare_cpus 和 smp_secondary_init 我们已经讲过了。在_cpu_up 中会调到sirfsoc_boot_secondary来boot其他cpu。
94 int __cpu_up(unsigned int cpu, struct task_struct *idle)
 95 {
 96         int ret;
 97 
 98         if (!smp_ops.smp_boot_secondary)
 99                 return -ENOSYS;
100 
101         /*
102          * We need to tell the secondary core where to find
103          * its stack and the page tables.
104          */
105         secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
106 #ifdef CONFIG_ARM_MPU
107         secondary_data.mpu_rgn_szr = mpu_rgn_info.rgns[MPU_RAM_REGION].drsr;
108 #endif
109 
110 #ifdef CONFIG_MMU
111         secondary_data.pgdir = get_arch_pgd(idmap_pgd);
112         secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
113 #endif
114         sync_cache_w(&secondary_data);
115 
116         /*
117          * Now bring the CPU into our world.
118          */
119         ret = smp_ops.smp_boot_secondary(cpu, idle);
120         if (ret == 0) {
121                 /*
122                  * CPU was successfully started, wait for it
123                  * to come online or time out.
124                  */
125                 wait_for_completion_timeout(&cpu_running,
126                                                  msecs_to_jiffies(1000));
127 
128                 if (!cpu_online(cpu)) {
129                         pr_crit("CPU%u: failed to come online\n", cpu);
130                         ret = -EIO;
131                 }
132         } else {
133                 pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
134         }
135 
136 
137         memset(&secondary_data, 0, sizeof(secondary_data));
138         return ret;
139 }
__cpu_up 中的119行smp_ops.smp_boot_secondary 会调用smp_boot_secondary 方法来boot 其他cpu,且在125行会new 一个完成量,其timeout是1s,也就是如果1s只能还不能释放完成量的话,就认为这个cpu boot failed了
那在哪里释放完成量呢?
答案是在secondary_start_kernel 函数中377行。secondary_start_kernel同时也是其他cpu的c code的入口函数,就想start_kernel是cpu 0的入口函数一样.
329 asmlinkage void secondary_start_kernel(void)
330 {
377         complete(&cpu_running);
378 
386 }
我们再来看看sirfsoc_boot_secondary的实现
这个函数的88行将sirfsoc_secondary_startup的地址写到rsc_base + SIRFSOC_CPU1_JUMPADDR_OFFSET,然后在92行写一个flag(0x3CAF5D62),最后在115行调用dsb_sev()send event后,一般情况下其他cpu都在wfi状态下.其他cpu就会跳到sirfsoc_secondary_startup 开始执行
http://lxr.free-electrons.com/source/arch/arm/mach-prima2/platsmp.c?v=3.18#L68
 68 static int sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle)
 69 {
 70         unsigned long timeout;
 71         struct device_node *np;
 72 
 73         np = of_find_matching_node(NULL, rsc_ids);
 74         if (!np)
 75                 return -ENODEV;
 76 
 77         rsc_base = of_iomap(np, 0);
 78         if (!rsc_base)
 79                 return -ENOMEM;
 80 
 81         /*
 82          * write the address of secondary startup into the sram register
 83          * at offset 0x2C, then write the magic number 0x3CAF5D62 to the
 84          * RSC register at offset 0x28, which is what boot rom code is
 85          * waiting for. This would wake up the secondary core from WFE
 86          */
 87 #define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x2C
 88         __raw_writel(virt_to_phys(sirfsoc_secondary_startup),
 89                 rsc_base + SIRFSOC_CPU1_JUMPADDR_OFFSET);
 90 
 91 #define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x28
 92         __raw_writel(0x3CAF5D62,
 93                 rsc_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET);
 94 
 95         /* make sure write buffer is drained */
 96         mb();
 97 
 98         spin_lock(&boot_lock);
 99 
100         /*
101          * The secondary processor is waiting to be released from
102          * the holding pen - release it, then wait for it to flag
103          * that it has been released by resetting pen_release.
104          *
105          * Note that "pen_release" is the hardware CPU ID, whereas
106          * "cpu" is Linux's internal ID.
107          */
108         pen_release = cpu_logical_map(cpu);
109         sync_cache_w(&pen_release);
110 
111         /*
112          * Send the secondary CPU SEV, thereby causing the boot monitor to read
113          * the JUMPADDR and WAKEMAGIC, and branch to the address found there.
114          */
115         dsb_sev();
116 
117         timeout = jiffies + (1 * HZ);
118         while (time_before(jiffies, timeout)) {
119                 smp_rmb();
120                 if (pen_release == -1)
121                         break;
122 
123                 udelay(10);
124         }
125 
126         /*
127          * now the secondary core is starting up let it run its
128          * calibrations, then wait for it to finish
129          */
130         spin_unlock(&boot_lock);
131 
132         return pen_release != -1 ? -ENOSYS : 0;
133 }
我们再来看sirfsoc_secondary_startup 的实现
http://lxr.free-electrons.com/source/arch/arm/mach-prima2/headsmp.S?v=3.18
 17 ENTRY(sirfsoc_secondary_startup)
 18         bl v7_invalidate_l1
 19         mrc     p15, 0, r0, c0, c0, 5
 20         and     r0, r0, #15
 21         adr     r4, 1f
 22         ldmia   r4, {r5, r6}
 23         sub     r4, r4, r5
 24         add     r6, r6, r4
 25 pen:    ldr     r7, [r6]
 26         cmp     r7, r0
 27         bne     pen
 28 
 29         /*
 30          * we've been released from the holding pen: secondary_stack
 31          * should now contain the SVC stack for this core
 32          */
 33         b       secondary_startup
 34 ENDPROC(sirfsoc_secondary_startup)
在第33行调用到secondary_startup 函数,也就是进入c code执行.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值