I read that Linux device tree as a datastructure defining the hardware of the device (components present such as I2C, USB etc)
Question: How is this different then .config file that tells make-file of the device drivers to be compiled for kernel i.e what modules in the device are present?
Device Tree Vs .Config file | Are they different?
Yes, they are different, and serve different purposes at different times.
The .config file is an integral component of the kernel's build procedure.
The .config file is data to control the building of the kernel, that is, its contents is used by makefiles.
A .config file could be customized to build a kernel specifically for just one specific version of a SBC.
Or the .config file could specify a kernel with a plethora of features, subsystems, and drivers for a variety of capabilities and support families of SBCs. Such a kernel image could be booted by any compatible board.
A .config file consists of lines of configuration symbols, e.g. CONFIG_xxx=....
Assignments of strings or numeric constants are rare, but do exist, e.g. CONFIG_LOCALVERSION="my_version" and CONFIG_INIT_ENV_ARG_LIMIT=32.
Typically the assignment is y to affirm that the configuration item is enabled.
A configuration item that is disabled is not asigned n, but rather commented out, e.g. # CONFIG_xxx is not set.
A configuration item that is "tristate" can be assigned m to affirm that the configuration item is enabled but built as a loadable module (rather than statically linked, aka built-in).
Note that although kernel source code may contain preprocessor directives (e.g. #ifdef for conditional compilation) utilizing CONFIG_xxx symbols that appear identical to the .config symbols, these symbols are not equivalent.
Kernel source code does not read or use the .config file.
Rather the .config file is converted into a C header file of preprocessor statements with a #define for each enabled CONFIG_xxx line, and stored in include/generated/autoconf.h (the exact path has changed for older versions).
It is the autoconf.h file that defines the CONFIG_xxx symbols used in kernel source code.
Note that a tristate configuration item that is assigned m in the .config becomes #define CONFIG_xxx_MODULE 1 in the autoconf.h file, rather than just #define CONFIG_xxx 1.
Device Tree is used by only a handful of CPU architectures in the Linux kernel.
The Device Tree (blob) is data to inform the executing kernel of its hardware environment (i.e. the target board). It also informs the kernel which device drivers to initialize (using the compatible property string).
Regardless of how many device drivers are statically linked into the kernel or available as loadable modules, a device driver is only initialized if there is a DT device node that references that device driver (e.g. see Driver code in kernel module doesn't execute?).
(The exception to that are buses that have self-identifying devices such as USB and PCI/PCIe, which have different procedures for initializing their device drivers.)
The Device Tree goes through several transformations before it is utilized by an executing kernel.
The DT source file(s) for a specific board exist as one .dts and optional .dtsi (included) files that are compiled into a .dtb file, aka DT blob.
It is the DT blob that is loaded with the kernel during boot, and then converted from its "flat" organization into a tree structure in kernel memory.
Kernel routines, e.g. device drivers, access the DT using methods provided by of_*() routines (where the "of" is for Open Foundation).
Related
I have a arm64 linux custom board with a spi-to-can chip, and the chip sometime is mcp2515, sometime is mcp2518fd.But they use different driver (mcp251x.ko/mcp25xxfd.ko).
This is my dts:
&spi4 {
status = "okay";
canfd#0 {
compatible = "microchip,mcp2515", "microchip,mcp2518fd";
reg = <0x0>;
clocks = <&clk20m>;
#interrupts = <&gpio3 RK_PB6 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio3>;
interrupts = <RK_PB6 IRQ_TYPE_LEVEL_LOW>;
spi-max-frequency = <4000000>;
};
};
The question is if the chip is mcp2518fd, kernel only match the first compatible "microchip,mcp2515 and then the driver(mcp251x.ko) probe failed.
Can i modify dts or driver src to meet this demand? If driver probe failed and kernel match next compatible ?
Or the only solution is to merge two driver into one?
The compatible strings are supposed to be in hierarchical order from most specific to most general, e.g. specifying an ID for a specific chip, followed by an ID for a "family" of related chips with a common programming interface (that will usually have less features than the chip-specific programming interfaces). That does not apply in this case, because microchip,mcp2515 and microchip,mcp2518fd refer to different specific chips with no hierarchical relationship.
The device tree node needs to specify which type of SPI-to-CAN controller is fitted. That means you need to load a different .dtb file for each type of board, or have a base .dtb file and load a different "device tree overlay" (.dtbo) file on top of the base .dtb file. Different .dtb files could be chosen by the bootloader based on some stored setting in the bootloader. Different .dtbo files could be loaded by the bootloader or by the Linux operating system based on some stored setting in the bootloader or in the Linux operating system, respectively.
It is possible to load different device tree overlays at runtime in the Linux operating system using the "DT-Overlay configfs interface" (CONFIG_OF_CONFIGFS), but that requires patched kernel sources. The patches can be found at topic/overlays.
How can I read from the PMU from inside Kernel space?
For a profiling task I need to read the retired instructions provided by the PMU from inside the kernel. The perf_event_open systemcall seems to offer this capability. In my source code I
#include <linux/syscalls.h>
set my parameters for the perf_event_attr struct and call the sys_perf_event_open(). The mentioned header contains the function declaration. When checking "/proc/kallsyms", it is confirmed that there is a systemcall with the name sys_perf_event_open. The symbol is globally available indicated by the T:
ffffffff8113fe70 T sys_perf_event_open
So everything should work as far as I can tell.
Still, when compiling or inserting the LKM I get a warning/error that sys_perf_event_open does not exist.
WARNING: "sys_perf_event_open" [/home/vagrant/mods/lkm_read_pmu/read_pmu.ko] undefined!
What do I need to do in order to get those retired instructions counter?
The /proc/kallsyms file shows all kernel symbols defined in the source. Right, the capital T indicates a global symbol in the text section of the kernel binary, but the meaning of "global" here is according to the C language. That is, it can be used in other files of the kernel itself. You can't call a kernel function from a kernel module just because it's global.
Kernel modules can only use kernel symbols that are exported with EXPORT_SYMBOL in the kernel source code. Since kernel 2.6.0, none of the system calls are exported, so you can't call any of them from a kernel module, including sys_perf_event_open. System calls are really designed to be called from user space. What this all means is that you can't use the perf_event subsystem from within a kernel module.
That said, I think you can modify the kernel to add EXPORT_SYMBOL to sys_perf_event_open. That will make it an exported symbol, which means it can be used from a kernel module.
I am trying to port drivers from old kernel to new one on ARM based platform. While porting one of the drivers I have noticed that request_irq fails on new kernel. Actually, what this driver have is a number of hard coded irq numbers, and it tries to request_irq for this HW lines. I started to search what is the reason of request_irq failure, - the reason is that the appropriate IRQ descriptor (irq_desc) have IRQ_NOREQUEST flag set.
I started to search where this flag is cleared, and found that it happens here:
of_platform_populate
|
...
|
of_device_alloc
|
...
|
irq_of_parse_and_map
(some levels below this flag is dropped)
So that code is invoked from mach init code and parse DTB, all interrupt numbers that are mentioned in DTB would be mapped to irq virtual space and will be accessible through appropriate devices structures, for example:
irq = platform_get_irq(pdev, 0);
As I already said, this old - fashion drivers just have hard-coded irq numbers in include files, and they don't have no appropriate dtb entries.
The question is what is the right way, from the kernel perspective of view, to port this? Do I need to make this old driver a platform device (now it is just a char device) and create appropriate dtb description for it? Or I can just use some kernel API to mark this interrupts as available? Is it a common/normal style?
LIO code base is scattered w/ a lot of constructs prefixed w/ se (e.g. se_cmd, se_session etc.)
What is the meaning of this se prefix ? (I've failed to find some comment about it in LIO kernel code base)
It came from "Storage Engine" term which is used widely in LIO.
In addition to modularizing the transport protocol used for carrying
SCSI commands ("fabrics"), the Linux kernel target, LIO, also
modularizes the actual data storage as well. These are referred to as
"backstores" or "storage engines". The target comes with backstores
that allow a file, a block device, RAM, or another SCSI device to be used
for the local storage needed for the exported SCSI LUN. Like the rest
of LIO, these are implemented entirely as kernel code.
I am going through the Uboot & kernel startup process. What exactly is the use of the FDT (Flat device tree) ?
Many link i have read they state that uboot pass the board & SOC configuration information to Kernel in the form of FDT
https://wiki.freebsd.org/FlattenedDeviceTree
Why kernel need the board configuration information ?
I am asking this question because when ever we make device driver in linux we use to initialize the device at probe() or module_init() call & use request_mem_region() & ioremap() function to get the range of address
& then set the clock & other register of the driver.
What does request_mem_region() actually do and when it is needed?
Now if my device drivers for onchip & offchip devices are doing the full board initialisation.
Then what is the use of flattened device tree for the kernel ?
You are right in assuming that the board files and device-trees are required for initialisation of on-chip blocks and off-chip peripherals.
While booting-up, the respective drivers for all on-chip blocks of an SoC and off-chip peripherals interfaced to it need to be "probed" i.e. loaded and called. On bus-es like USB and PCI, the peripherals can be detected physically and enumerated and their corresponding driver probed. However in general such a facility is NOT available is case of the rest of the peripherals on the rest of the buses like I2C, SPI etc.
In addition to above, when the device-driver is probed, one also needs to provide some information to it about the way in which we intend to configure and utilise the hardware. This varies depending upon the use case. For example the baud-rate at which we would like to operate an UART port.
Both the above classes of information i.e.
Physical Topology of the hardware.
Configuration options of the hardware.
were usually defined as structs within the "board" file.
However using the board-file approach required one to re-build the kernel even to simply modify a configurable option to a different value during initialisation. Also when several physical boards differing slightly in their topology/configuration exist, the "board" file approach becomes too cumbersome to maintain.
Hence the interest in maintaining this information separately in a device-tree. Any device-driver can parse the relevant branches and leaves of the device-tree to obtain the information it requires.
When developing your own device-driver, if your platform supports the device-tree, then you are encouraged to utilise the device tree to store the "platform data" required by your device-driver. This should help you clearly separate :
the generic driver code for your device in the <driver.c> file and
the device's config options specific to this platform into the device-tree.
A step-by-step approach to porting the Linux kernel to a board/SoC should help you appreciate the nuances involved and the advantages of using a device-tree.