日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

如何調(diào)整Linux內(nèi)核啟動中的驅(qū)動初始化順序(zz)

 WUCANADA 2019-12-13
如何調(diào)整Linux內(nèi)核啟動中的驅(qū)動初始化順序

【問題】
此處我要實現(xiàn)的是將芯片的ID用于網(wǎng)卡MAC地址,網(wǎng)卡驅(qū)動是enc28j60_init。
但是,讀取芯片ID的函數(shù),在as352x_afe_init模塊中,所以要先初始化as352x_afe_init。
此處,內(nèi)核編譯完之后,在生成的system.map中可以看到,
enc28j60_init在as352x_afe_init之前,所以,無法去讀芯片ID。
所以我們的目標是,將as352x_afe_init驅(qū)動初始化放到enc28j60_init之前,
然后才能讀取芯片ID,才能用于網(wǎng)卡初始化的時候的,將芯片ID設(shè)置成網(wǎng)卡MAC地址。

解決過程】
【1】
最簡單想到的,是內(nèi)核里面的
arch\arm\mach-as352x\core.c
中,去改devices設(shè)備列表中的順序。
enc28j60_init對應(yīng)的是ssp_device,因為網(wǎng)卡初始化用到的是SPI驅(qū)動去進行和通訊的。
as352x_afe_init對應(yīng)的是afe_device。
原先是:
  1. static struct platform_device *devices[] =
  2. {
  3. &uart_device,
  4. &nand_device,
  5. &afe_device,
  6. &audio_device,
  7. &usb_device,
  8. &as352xkbd_device,
  9. &ssp_device,
  10. };
復(fù)制代碼
把afe改到最前面:
  1. static struct platform_device *devices[] =
  2. {
  3. &afe_device,
  4. &uart_device,
  5. &nand_device,
  6. &audio_device,
  7. &usb_device,
  8. &as352xkbd_device,
  9. &ssp_device,
  10. };
復(fù)制代碼


但是,實際結(jié)果是,沒有任何影響,連systemp.map生成的,那么模塊初始化順序,都沒有任何變化。
也就說明,想要實現(xiàn)驅(qū)動加載順序的改變,改core.c里面的設(shè)備列表順序是沒有用的。

【2】
在網(wǎng)上看到很多帖子,主要就是這幾個:
怎么確定驅(qū)動加載順序
http://inaunix.net/u2/72751/showart_1074704.html

Linux內(nèi)核驅(qū)動程序初始化順序的調(diào)整
http://www./tech/OS/Linux/2006-12-21/74501.html

內(nèi)核啟動時,設(shè)備及驅(qū)動初始化的實現(xiàn) 
http://linux./bbs/archiver/tid-1109340.html

其說明的也很清楚了,就是:
Linux內(nèi)核為不同驅(qū)動的加載順序?qū)?yīng)不同的優(yōu)先級,定義了一些宏:
include\linux\init.h

  1. #define pure_initcall(fn)   __define_initcall("0",fn,1)

  2. #define core_initcall(fn)   __define_initcall("1",fn,1)
  3. #define core_initcall_sync(fn)   __define_initcall("1s",fn,1s)
  4. #define postcore_initcall(fn)   __define_initcall("2",fn,2)
  5. #define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
  6. #define arch_initcall(fn)   __define_initcall("3",fn,3)
  7. #define arch_initcall_sync(fn)   __define_initcall("3s",fn,3s)
  8. #define subsys_initcall(fn)   __define_initcall("4",fn,4)
  9. #define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
  10. #define fs_initcall(fn)    __define_initcall("5",fn,5)
  11. #define fs_initcall_sync(fn)   __define_initcall("5s",fn,5s)
  12. #define rootfs_initcall(fn)   __define_initcall("rootfs",fn,rootfs)
  13. #define device_initcall(fn)   __define_initcall("6",fn,6)
  14. #define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
  15. #define late_initcall(fn)   __define_initcall("7",fn,7)
  16. #define late_initcall_sync(fn)   __define_initcall("7s",fn,7s)

  17. #define __initcall(fn) device_initcall(fn)
復(fù)制代碼

把自己的驅(qū)動的函數(shù)名用這些宏去定義之后,
就會對應(yīng)不同的加載時候的優(yōu)先級。

其中,我們寫驅(qū)動中所用到的module_init對應(yīng)的是
#define module_init(x) __initcall(x);

#define __initcall(fn) device_initcall(fn)
所以,驅(qū)動對應(yīng)的加載的優(yōu)先級為6

在上面的不同的優(yōu)先級中,
數(shù)字越小,優(yōu)先級越高。
同一等級的優(yōu)先級的驅(qū)動,加載順序是鏈接過程決定的,結(jié)果是不確定的,我們無法去手動設(shè)置誰先誰后。
不同等級的驅(qū)動加載的順序是先優(yōu)先級高,后優(yōu)先級低,這是可以確定的。

所以,像我們之前在驅(qū)動中用:
  1. module_init(i2c_dev_init);
  2. module_init(as352x_afe_init);
  3. module_init(as352x_afe_i2c_init);

  4. module_init(enc28j60_init);
復(fù)制代碼


所以,大家都是同一個優(yōu)先級去初始化,
最后這些驅(qū)動加載的順序,可以查看在根目錄下,
生成的system.map:

  1. 。。。
  2. c00197d8 t __initcall_alignment_init5
  3. 。。。。。
  4. c00197f4 t __initcall_default_rootfsrootfs
  5. c00197f8 t __initcall_timer_init_sysfs6
  6. c00197fc t __initcall_clock_dev_init6
  7. 。。。
  8. c00198d8 t __initcall_loop_init6
  9. c00198dc t __initcall_net_olddevs_init6
  10. c00198e0 t __initcall_loopback_init6
  11. c00198e4 t __initcall_enc28j60_init6
  12. 。。。
  13. c0019900 t __initcall_as352x_spi_init6
  14. c0019904 t __initcall_spidev_init6
  15. 。。。
  16. c0019920 t __initcall_i2c_dev_init6
  17. c0019924 t __initcall_as352x_afe_i2c_init6
  18. c0019928 t __initcall_as352x_afe_init6
  19. 。。。
  20. c0019970 t __initcall_random32_reseed7
  21. c0019974 t __initcall_seqgen_init7
  22. c0019978 t __initcall_rtc_hctosys7
  23. c001997c T __con_initcall_start
  24. c001997c t __initcall_con_init
  25. c001997c T __initcall_end
  26. 。。。
復(fù)制代碼

此處就是由于
c0019920 t __initcall_i2c_dev_init6
c0019924 t __initcall_as352x_afe_i2c_init6
c0019928 t __initcall_as352x_afe_init6

c00198e4 t __initcall_enc28j60_init6
之前,所以我這里才要去改。。。

知道原理,能想到的,就是
要么把
as352x_afe_init
改到
enc28j60_init
之前一級,即優(yōu)先級為5。
即在驅(qū)動中,調(diào)用:
fs_initcall(as352x_afe_init);

要么把
enc28j60_init
改到
as352x_afe_init
之后,即優(yōu)先級為7
即在驅(qū)動中,調(diào)用:
late_initcall(enc28j60_init);

但是,此處麻煩就麻煩在,
如果把
as352x_afe_init
改到
enc28j60_init
之前一級,
發(fā)現(xiàn)后面網(wǎng)卡初始化enc28j60_init中,雖然讀取芯片ID對了,
但是后面的IP-auto configure 有問題。
所以放棄。

如果把
enc28j60_init
改到
as352x_afe_init
之后,
但是,從system.map中看到的是,優(yōu)先級為7的驅(qū)動中,明顯有幾個驅(qū)動,
也是和網(wǎng)卡初始化相關(guān)的,所以,這樣改,嘗試后,還是失敗了。

所以,沒法簡單的通過調(diào)整現(xiàn)有的驅(qū)動的順序,去實現(xiàn)順序的調(diào)整。

最后,被逼無奈,想到了一個可以實現(xiàn)我們需求的辦法,
那就是,單獨定義一個優(yōu)先級,把afe相關(guān)的初始化都放到那里面去,
這樣,就可以保證,其他沒什么相關(guān)的沖突了。
最后證實,這樣是可以實現(xiàn)目的的。

具體添加一個新的優(yōu)先級的步驟如下:

1.定義新的優(yōu)先級

include\linux\init.h中:

  1. #define pure_initcall(fn)   __define_initcall("0",fn,1)

  2. #define core_initcall(fn)   __define_initcall("1",fn,1)
  3. #define core_initcall_sync(fn)   __define_initcall("1s",fn,1s)
  4. #define postcore_initcall(fn)   __define_initcall("2",fn,2)
  5. #define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
  6. #define arch_initcall(fn)   __define_initcall("3",fn,3)
  7. #define arch_initcall_sync(fn)   __define_initcall("3s",fn,3s)
  8. #define subsys_initcall(fn)   __define_initcall("4",fn,4)
  9. #define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
  10. #define fs_initcall(fn)    __define_initcall("5",fn,5)
  11. #define fs_initcall_sync(fn)   __define_initcall("5s",fn,5s)
  12. #define rootfs_initcall(fn)   __define_initcall("rootfs",fn,rootfs)
  13. #if 1
  14. #define prev_device_initcall(fn)   __define_initcall("6",fn,6)
  15. #define prev_device_initcall_sync(fn) __define_initcall("6s",fn,6s)
  16. #define device_initcall(fn)   __define_initcall("7",fn,7)
  17. #define device_initcall_sync(fn) __define_initcall("7s",fn,7s)
  18. #define late_initcall(fn)   __define_initcall("8",fn,8)
  19. #define late_initcall_sync(fn)   __define_initcall("8s",fn,8s)

  20. #else
  21. #define device_initcall(fn)   __define_initcall("6",fn,6)
  22. #define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
  23. #define late_initcall(fn)   __define_initcall("7",fn,7)
  24. #define late_initcall_sync(fn)   __define_initcall("7s",fn,7s)
  25. #endif
復(fù)制代碼

2.用對應(yīng)新的宏,定義我們的驅(qū)動:
  1. prev_device_initcall(i2c_dev_init);
  2. prev_device_initcall(as352x_afe_i2c_init);
  3. prev_device_initcall(as352x_afe_init);
復(fù)制代碼


做到這里,本以為可以了,但是編譯后,在system.map中,發(fā)現(xiàn)之前優(yōu)先級為7的那幾個函數(shù),
被放到system.map最后了,而不是預(yù)想的,
在優(yōu)先級7之后,在
  1. c001997c T __con_initcall_start
  2. c001997c t __initcall_con_init
  3. c001997c T __initcall_end
復(fù)制代碼
之前。

最后,發(fā)現(xiàn)時沒有把對應(yīng)的鏈接文件中的宏加進去:

3.

include\asm-generic\vmlinux.lds.h

  1. #if 1
  2. #define INITCALLS        \
  3. *(.initcall0.init)       \
  4. *(.initcall0s.init)       \
  5. *(.initcall1.init)       \
  6. *(.initcall1s.init)       \
  7. *(.initcall2.init)       \
  8. *(.initcall2s.init)       \
  9. *(.initcall3.init)       \
  10. *(.initcall3s.init)       \
  11. *(.initcall4.init)       \
  12. *(.initcall4s.init)       \
  13. *(.initcall5.init)       \
  14. *(.initcall5s.init)       \
  15. *(.initcallrootfs.init)       \
  16. *(.initcall6.init)       \
  17. *(.initcall6s.init)       \
  18. *(.initcall7.init)       \
  19. *(.initcall7s.init)       \
  20. *(.initcall8.init)       \
  21. *(.initcall8s.init)

  22. #else

  23. #define INITCALLS        \
  24. *(.initcall0.init)       \
  25. *(.initcall0s.init)       \
  26. *(.initcall1.init)       \
  27. *(.initcall1s.init)       \
  28. *(.initcall2.init)       \
  29. *(.initcall2s.init)       \
  30. *(.initcall3.init)       \
  31. *(.initcall3s.init)       \
  32. *(.initcall4.init)       \
  33. *(.initcall4s.init)       \
  34. *(.initcall5.init)       \
  35. *(.initcall5s.init)       \
  36. *(.initcallrootfs.init)       \
  37. *(.initcall6.init)       \
  38. *(.initcall6s.init)       \
  39. *(.initcall7.init)       \
  40. *(.initcall7s.init)

  41. #endif
復(fù)制代碼

最后,再重新編譯,就可以實現(xiàn)我們要的,
和afe相關(guān)的驅(qū)動初始化,都在網(wǎng)卡enc28j60_init之前了。
也就可以在網(wǎng)卡里面讀芯片ID了。
當(dāng)然,對應(yīng)編譯生成的system.map文件中,
對應(yīng)的通過module_init定義的驅(qū)動,優(yōu)先級也都變成7了。
而late_initcall對應(yīng)優(yōu)先級8了。

注:當(dāng)前開發(fā)板arm的板子,所以,對應(yīng)的load 腳本在:

linux-2.6.28.4\arch\arm\kernel\vmlinux.lds

看起來,應(yīng)該是這個文件:

linux-2.6.28.4\arch\arm\kernel\vmlinux.lds.S

生成上面那個腳本的。

vmlinux.lds中的這一行:

  1. __initcall_start = .;
  2.    *(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)
復(fù)制代碼

就是將之前那些對應(yīng)的init類型的函數(shù),展開,放到這對應(yīng)的位置。

【3】
不過,最后的最后,竟然發(fā)現(xiàn)網(wǎng)卡還是工作不正常,結(jié)果第二天,無意間發(fā)現(xiàn)是網(wǎng)卡地址設(shè)置導(dǎo)致網(wǎng)卡工作不正常的。
也就是說,實際是直接將afe設(shè)置到原先的優(yōu)先級5就可以的,而不用這么麻煩去改系統(tǒng)的東西的。。。

不過,至少這也是一種辦法,雖然不是那么的好。。。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多