MTk kernel啟動流程
late_initcall
所有的__init函式在區段.initcall.init中還儲存了一份函式指標,在初始化時核心會通過這些函式指標呼叫這些__init函式指標,並在整個初始化完成後,釋放整個init區段(包括.init.text,.initcall.init等)。
注意,這些函式在核心初始化過程中的呼叫順序只和這裡的函式指標的順序有關,和1)中所述的這些函式本身在.init.text區段中的順序無關。initcall.init區段分成7個子區段,分別是
.initcall1.init |
當需要把函式fn放到.initcall1.init區段時,只要宣告
core_initcall(fn); |
即可。
其他的各個區段的定義方法分別是:
core_initcall(fn) --->.initcall1.init |
在核心中,不同的init函式被放在不同的子區段中,因此也就決定了它們的呼叫順序。這樣也就解決了一些init函式之間必須保證一定的呼叫順序的問題。按照include/linux/init.h檔案所寫的,我在驅動裡償試了這樣兩種方式:
__define_initcall("7", 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函式,這裡不再贅述!