late_initcall
所有的__init函数在区段.initcall.init中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数指针,并在整个初始化完成后,释放整个init区段(包括.init.text,.initcall.init等)。
注意,这些函数在内核初始化过程中的调用顺序只和这里的函数指针的顺序有关,和1)中所述的这些函数本身在.init.text区段中的顺序无关。initcall.init区段分成7个子区段,分别是
.initcall1.init
.initcall2.init
.initcall3.init
.initcall4.init
.initcall5.init
.initcall6.init
.initcall7.init
当需要把函数fn放到.initcall1.init区段时,只要声明
core_initcall(fn);
即可。
其他的各个区段的定义方法分别是:
core_initcall(fn) --->.initcall1.init
postcore_initcall(fn) --->.initcall2.init
arch_initcall(fn) --->.initcall3.init
subsys_initcall(fn) --->.initcall4.init
fs_initcall(fn) --->.initcall5.init
device_initcall(fn) --->.initcall6.init
late_initcall(fn) --->.initcall7.init
在内核中,不同的init函数被放在不同的子区段中,因此也就决定了它们的调用顺序。这样也就解决了一些init函数之间必须保证一定的调用顺序的问题。按照include/linux/init.h文件所写的,我在驱动里偿试了这样两种方式:
__define_initcall("7", fn);
late_initcall(fn);
都可以把我的驱动调整到最后调用。实际上上面两个是一回事:
#define late_initcall(fn)__define_initcall("7", fn)
linux中把initcall分成了若干种类,主要用来区别不同的initcall的调用次序,由于initcall中的调用次序是随机的,所以不能保证某些重要的初始化先运行。分成了以下几个initcall,按执行顺序先后排列:
pure_initcall:最先运行的,不依赖于任何其他初始化函数。
core_initcall
core_initcall_sync
postcore_initcall
postcore_initcall_sync
arch_initcall
arch_initcall_sync
subsys_initcall
subsys_initcall_sync
fs_initcall
fs_initcall_sync
rootfs_initcall
device_initcall
device_initcall_sync
late_initcall
late_initcall_sync。
如:
Kernel/include/linux/init.h
178 #define __define_initcall(level,fn,id)\
179 static initcall_t __initcall_##fn##id __used \
180 __attribute__((__section__(".initcall" level".init"))) = fn
181
182 /*
183 * Early initcalls run before initializing SMP.
184 *
185 * Only for built-in code, not modules.
186 */
187 #define early_initcall(fn) __define_initcall("early",fn,early)
188
189 /*
190 * A "pure" initcall has no dependencies on anything else, andpurely
191 * initializes variables that couldn't be statically initialized.
192 *
193 * This only exists for built-in code, not for modules.
194 */
195 #define pure_initcall(fn) __define_initcall("0",fn,0)
196
197 #define core_initcall(fn) __define_initcall("1",fn,1)
198 #define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
199 #define postcore_initcall(fn) __define_initcall("2",fn,2)
200 #define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
201 #define arch_initcall(fn) __define_initcall("3",fn,3)
202 #define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
203 #define subsys_initcall(fn) __define_initcall("4",fn,4)
204 #define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
205 #define fs_initcall(fn) __define_initcall("5",fn,5)
206 #define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
207 #define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
208 #define device_initcall(fn) __define_initcall("6",fn,6)
209 #define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
210 #define late_initcall(fn) __define_initcall("7",fn,7)
211 #define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
Meditek kernel启动:
platform/mt6592/kernel/core/board.c
board_init()调mt_board_init();
./platform/mt6592/kernel/core/core.c
111 #ifdef MTK_TABLET_PLATFORM
112 MACHINE_START(MT6592,MTK_TABLET_PLATFORM)
113 #else
114 MACHINE_START(MT6592,"MT6592")
115 #endif
116 .atag_offset = 0x00000100,
117 .map_io = mt_map_io,
118 .init_irq = mt_init_irq,
119 .timer = &mt_timer,
120 .init_machine = mt_init,
121 .fixup = mt_fixup,
122 .restart =arm_machine_restart,
123 .reserve = mt_reserve,
124 MACHINE_END
kernel/arch/arm/include/asm/mach/arch.h中定义MACHINE_START
#defineMACHINE_START(_type,_name) \
static conststruct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init")))= { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#defineMACHINE_END \
};
MACHINE_START主要是定义了"structmachine_desc"的类型,放在 section(".arch.info.init"),是初始化数据,Kernel起来之后将被丢弃。
117 .map_io = mt_map_io,
这里会把一组平台相关的物理地址(比如总线地址、设备基地址)映射到一组固定虚拟地址上,这组虚拟地址在整个内核空间可见
106 void __init mt_map_io(void)
107 {
108 iotable_init(mt_io_desc, ARRAY_SIZE(mt_io_desc));
109 }
iotable_init定义位于:
Kernel/arch/arm/mm/mmu.c
785 * Create the architecture specific mappings
786 */
787 void __init iotable_init(struct map_desc*io_desc, int nr)
788 {
789 struct map_desc *md;
790 struct vm_struct *vm;
791
792 if (!nr)
793 return;
794
795 vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
796
797 for (md = io_desc; nr; md++, nr--) {
798 create_mapping(md, false);
799 vm->addr = (void *)(md->virtual & PAGE_MASK);
800 vm->size = PAGE_ALIGN(md->length + (md->virtual &~PAGE_MASK));
801 vm->phys_addr = __pfn_to_phys(md->pfn);
802 vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
803 vm->flags |= VM_ARM_MTYPE(md->type);
804 vm->caller = iotable_init;
805 vm_area_add_early(vm++);
806 }
807 }
118 .init_irq = mt_init_irq,
platform/mt6592/kernel/core/irq.c
1054 void __initmt_init_irq(void)
1055 {
1056 spin_lock_init(&irq_lock);
1057 mt_gic_dist_init();
1058 mt_gic_cpu_init();
1059 }
119 .timer = &mt_timer,
platform/mt6592/kernel/core/tmer.c
50struct sys_timer mt_timer = {
51 .init = mt_timer_init,
52};
121 .fixup = mt_fixup,
platform/mt6592/kernel/core /mt_devs.c
对memory的一个fix。
122 .restart = arm_machine_restart,
kernel/arch/arm/kernel/process.c
void arm_machine_restart(char mode, const char *cmd)
146 {
147 /* Flush the console to make sure allthe relevant messages make it
148 * out to theconsole drivers */
149 arm_machine_flush_console();
150
151 /* Disableinterrupts first */
152 local_irq_disable();
153 local_fiq_disable();
154
155 /*
156 * Tell the mmsystem that we are going to reboot -
157 * we may need itto insert some 1:1 mappings so that
158 * soft bootworks.
159 */
160 setup_mm_for_reboot();
161
162 /* When l1 isdisabled and l2 is enabled, the spinlock cannot get the lock,
163 * so we need todisable the l2 as well. by Chia-Hao Hsu
164 */
165 outer_flush_all();
166 outer_disable();
167 outer_flush_all();
168
169 /* Clean andinvalidate caches */
170 flush_cache_all();
171
172 /* Turn offcaching */
173 cpu_proc_fin();
174
175 /* Push out anyfurther dirty data, and ensure cache is empty */
176 flush_cache_all();
177
178 /*
179 * Now call thearchitecture specific reboot code.
180 */
181 arch_reset(mode,cmd);
183 /*
184 * Whoops - thearchitecture was unable to reboot.
185 * Tell the user!
186 */
187 mdelay(1000);
188 printk("Reboot failed -- System halted\n");
189 while (1);
190 }
123 .reserve = mt_reserve,
platform/mt6592/kernel/core /mt_devs.c
主要是对memory的一个预留。
platform/mt6592/kernel/core /mt_devs.c主要实现以下函数:
HW_TP_Init
mt_board_init
is_pmem_range
mtk_get_max_DRAM_size
get_phys_offset
get_text_region
mt_reserve
For example1:(led)
在mt_board_init();
/注册设备信息,例如:***/
#if defined(CONFIG_MTK_LEDS)
retval= platform_device_register(&mt65xx_leds_device);
if(retval != 0)
returnretval;
printk("bei:deviceLEDS register\n");
#endif
static struct platform_device mt65xx_leds_device = {
.name= "leds-mt65xx",
.id= -1
};
驱动设备匹配如下:匹配driver name :“leds-mt65xx”,
/platform/mt6592/kernel/drivers/leds/leds.c
./kernel/drivers/leds/leds_drv.c
602 static struct platform_drivermt65xx_leds_driver = {
603 .driver = {
604 .name ="leds-mt65xx",
605 .owner = THIS_MODULE,
606 },
607 .probe = mt65xx_leds_probe,
608 .remove = mt65xx_leds_remove,
609 //.suspend = mt65xx_leds_suspend,
610 .shutdown =mt65xx_leds_shutdown,
611 };
再继续就是进入我们熟悉的probe函数,这里不再赘述!