How to adjust the driver initialization sequence in Linux kernel startup

Source: Internet
Author: User

The Board finds that framebuffer Initialization is very late. Just modify it as follows:

// Late_initcall (dovefb_init );
Module_init (dovefb_init );

Mainly refer to the followingArticle:

Bytes --------------------------------------------------------------------------------------

How to adjust the driver initialization sequence in Linux kernel startup

Http://hi.baidu.com/serial_story/blog/item/d40d49c6907212129c163ded.html

How to adjust the driver initialization sequence in Linux kernel startup

[Problem]
Here, I want to use the chip ID for the NIC MAC address, and the NIC Driver is enc28j60_init.
However, the function for reading the chip ID is in the as352x_afe_init module, so we need to initialize as352x_afe_init first.
After the kernel is compiled, you can see in the Generated System. Map,
Before as352x_afe_init, enc28j60_init cannot read the chip ID.
So our goal is to put the as352x_afe_init driver initialization before enc28j60_init,
Then, you can read the chip ID to set the chip ID to the MAC address of the NIC during Nic initialization.

[Solution process]
[1]
The simplest thing to think about is the kernel
Arch \ Arm \ mach-as352x \ core. c
To change the order in the devices device list.
The enc28j60_init corresponds to the ssp_device, because the NIC initialization uses the SPI driver for communication.
As352x_afe_init corresponds to afe_device.
Originally:
Static struct platform_device * devices [] =
{
& Uart_device,
& Nand_device,
& Afe_device,
& Audio_device,
& Usb_device,
& As352xkbd_device,
& Ssp_device,
};
Change the AFE to the beginning:
Static struct platform_device * devices [] =
{
& Afe_device,
& Uart_device,
& Nand_device,
& Audio_device,
& Usb_device,
& As352xkbd_device,
& Ssp_device,
};

However, the actual result is that the initialization sequence of the module remains unchanged even when systemp. MAP is generated.
It means that it is useless to change the device list sequence in core. C to change the driver loading sequence.

[2]
I have seen many posts on the internet, mainly including the following:
How to determine the driver Loading Sequence
Http://blog.chinaunix.net/u2/72751/showart_1074704.html

Linux Kernel DriverProgramAdjustment of initialization sequence
Http://www.itjj.net/tech/ OS /Linux/2006-12-21/74501.html

Device and driver initialization during kernel startup
Http://linux.chinaunix.net/bbs/archiver/tid-1109340.html

The explanation is also clear:
The Linux kernel has different priorities for different drivers. Some macros are defined:
Include \ Linux \ init. h

# Define pure_initcall (FN) _ define_initcall ("0", FN, 1)

# Define core_initcall (FN) _ define_initcall ("1", FN, 1)
# Define core_initcall_sync (FN) _ define_initcall ("1 s", FN, 1 s)
# Define postcore_initcall (FN) _ define_initcall ("2", FN, 2)
# Define postcore_initcall_sync (FN) _ define_initcall ("2 s", FN, 2 S)
# Define arch_initcall (FN) _ define_initcall ("3", FN, 3)
# Define arch_initcall_sync (FN) _ define_initcall ("3 S", FN, 3 S)
# Define subsys_initcall (FN) _ define_initcall ("4", FN, 4)
# Define subsys_initcall_sync (FN) _ define_initcall ("4 s", FN, 4S)
# Define fs_initcall (FN) _ define_initcall ("5", FN, 5)
# Define fs_initcall_sync (FN) _ define_initcall ("5 s", FN, 5S)
# Define rootfs_initcall (FN) _ define_initcall ("rootfs", FN, rootfs)
# Define device_initcall (FN) _ define_initcall ("6", FN, 6)
# Define device_initcall_sync (FN) _ define_initcall ("6 s", FN, 6 S)
# Define late_initcall (FN) _ define_initcall ("7", FN, 7)
# Define late_initcall_sync (FN) _ define_initcall ("7 s", FN, 7 S)

# DEFINE _ initcall (FN) device_initcall (FN)

After using these macros to define your own driver function names,
It will correspond to different loading priorities.

Among them, the module_init used in the write driver corresponds
# Define module_init (x) _ initcall (X );
While
# DEFINE _ initcall (FN) device_initcall (FN)
Therefore, the loading priority of the driver is 6.

In the preceding priorities,
The smaller the number, the higher the priority.
The loading sequence is determined by the link process, and the result is uncertain. We cannot manually set who is first and then who.
The loading sequence of drivers of different levels has a higher priority and a lower priority. This can be determined.

So, as we used in the driver:
Module_init (i2c_dev_init );
Module_init (as352x_afe_init );
Module_init (as352x_afe_i2c_init );

Module_init (enc28j60_init );

Therefore, all initialize with the same priority,
The order in which these drivers are loaded can be viewed in the root directory,
Generated System. MAP:

...
c00197d8 T _ initcall_alignment_init5
.....
c00197f4 T _ initcall_default_rootfsrootfs
c00197f8 T _ timeout
c00197fc T _ initcall_clock_dev_init6
...
c00198d8 T _ initcall_loop_init6
c00198dc T _ blank
c00198e0 T _ blank
c00198e4 T _ blank
...
c0019900 T _ initcall_as352x_spi_init6
c0019904 T _ initcall_spidev_init6
...
c0019920 T _ initcall_i2c_dev_init6
c0019924 T _ blank
c0019928 T _ initcall_as352x_afe_init6
...
c0019970 T _ partition
c0019974 T _ partition
c0019978 T _ partition
c001997c T _ con_initcall_start
c001997c T _ initcall_con_init
c001997c T _ initcall_end
...

This is because
C0019920 T _ initcall_i2c_dev_init6
C0019924 T _ initcall_as352x_afe_i2c_init6
C0019928 T _ initcall_as352x_afe_init6
In
C00198e4 T _ initcall_enc28j60_init6
That's why I have to change it here...

What I can think of when I know the principle is
Either
As352x_afe_init
Change
Enc28j60_init
The previous level, that is, the priority is 5.
In the driver, call:
Fs_initcall (as352x_afe_init );

Either
Enc28j60_init
Change
As352x_afe_init
Then, the priority is 7.
In the driver, call:
Late_initcall (enc28j60_init );

However, this is troublesome,
If
As352x_afe_init
Change
Enc28j60_init
Previous level,
It is found that in the enc28j60_init file initialized by the NIC later, although the chip ID is correct,
But there is a problem with the IP-auto configure.
So give up.

If
Enc28j60_init
Change
As352x_afe_init
After,
However, we can see from system. Map that there are several drivers with priority 7,
It is also related to NIC initialization. Therefore, after this change, it still fails.

Therefore, we cannot simply adjust the order of the existing drivers to adjust the order.

Finally, I was forced to think of a way to meet our needs,
That is, define a separate priority and put the AFE-related initialization in it,
In this way, we can ensure that there are no other conflicts.
Finally, it is confirmed that this can achieve the goal.

To add a new priority, follow these steps:

1. define a new priority

Include \ Linux \ init. h:

# Define pure_initcall (FN) _ define_initcall ("0", FN, 1)

# Define core_initcall (FN) _ define_initcall ("1", FN, 1)
# Define core_initcall_sync (FN) _ define_initcall ("1 s", FN, 1 s)
# Define postcore_initcall (FN) _ define_initcall ("2", FN, 2)
# Define postcore_initcall_sync (FN) _ define_initcall ("2 s", FN, 2 S)
# Define arch_initcall (FN) _ define_initcall ("3", FN, 3)
# Define arch_initcall_sync (FN) _ define_initcall ("3 S", FN, 3 S)
# Define subsys_initcall (FN) _ define_initcall ("4", FN, 4)
# Define subsys_initcall_sync (FN) _ define_initcall ("4 s", FN, 4S)
# Define fs_initcall (FN) _ define_initcall ("5", FN, 5)
# Define fs_initcall_sync (FN) _ define_initcall ("5 s", FN, 5S)
# Define rootfs_initcall (FN) _ define_initcall ("rootfs", FN, rootfs)
# If 1
# Define prev_device_initcall (FN) _ define_initcall ("6", FN, 6)
# Define prev_device_initcall_sync (FN) _ define_initcall ("6 s", FN, 6 S)
# Define device_initcall (FN) _ define_initcall ("7", FN, 7)
# Define device_initcall_sync (FN) _ define_initcall ("7 s", FN, 7 S)
# Define late_initcall (FN) _ define_initcall ("8", FN, 8)
# Define late_initcall_sync (FN) _ define_initcall ("8 s", FN, 8 s)

# Else
# Define device_initcall (FN) _ define_initcall ("6", FN, 6)
# Define device_initcall_sync (FN) _ define_initcall ("6 s", FN, 6 S)
# Define late_initcall (FN) _ define_initcall ("7", FN, 7)
# Define late_initcall_sync (FN) _ define_initcall ("7 s", FN, 7 S)
# Endif

2. Define our driver with the corresponding new macro:
Prev_device_initcall (i2c_dev_init );
Prev_device_initcall (as352x_afe_i2c_init );
Prev_device_initcall (as352x_afe_init );

Here, we thought we could do it. But after compilation, in system. map, we found the functions with the previous priority of 7,
Put it at the end of system. Map, not as expected,
After Priority 7
C001997c T _ con_initcall_start
C001997c T _ initcall_con_init
C001997c T _ initcall_end
Before.

At last, the macro in the corresponding link file was not added when it was found:

3.

Include \ ASM-generic \ vmlinux. LDS. h

# If 1
# Define initcils \
* (. 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 )\
* (. Initcall8.init )\
* (. Initcall8s. init)

# Else

# Define initcils \
* (. 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)

# Endif
Finally, re-compile to implement what we need,
The AFE-related driver initialization is prior to enc28j60_init.
You can also read the chip ID in the NIC.
Of course, in the system. map file generated by compilation,
The corresponding driver defined by module_init has a priority of 7.
Late_initcall corresponds to Priority 8.

Note: The current development board arm, so the corresponding load script is:

Linux-2.6.28.4 \ arch \ Arm \ kernel \ vmlinux. LDS

It looks like this file:

Linux-2.6.28.4 \ arch \ Arm \ kernel \ vmlinux. LDS. s

Generate the script above.

This line in vmlinux. LDS:

_ Initcall_start = .;
*(. 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)
It is to expand the corresponding init functions and place them in the corresponding position.

[3]
However, in the end, I found that the network card still works abnormally. As a result, on the second day, I accidentally found that the network card is not working properly due to the NIC address settings.
That is to say, you can directly set the AFE to the original priority of 5, instead of having to change the system...

However, at least this is also a method, although not so good...

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.