linux-kernellinux-device-driverembedded-linuxyocto

Lack of alias in kernel module .ko file built with Yocto


I am trying to build a driver for my IP in an FPGA. I have:

static const struct of_device_id myip_of_match[] = {
 { .compatible = "xlnx,myip-controller-1.022", },
 {},
};

MODULE_DEVICE_TABLE(of, myip_of_match);

static struct platform_driver myip_driver = {
.probe = myip_probe,
.remove = myip_remove,
.driver = {
.name = "myip",
.of_match_table = myip_of_match,
 },
};
module_platform_driver(myip_driver);

Of course, I also have a function in the file: static int myip_probe(struct platform_device *pdev).

I am building this using Yocto as my additional layer.

However, after copying the .ko file to Linux on Zynq-7000, when I do insmod myip.ko myip_probe does not start.

I read that the .ko file should contain an alias with which it is matched with devicetree. But modinfo does not show this alias at all.

What am I doing wrong?

I am correcting my negligence. My devicetree is built from several files. Crucial in this matter is a fragment of the auto-generated pl.dtsi file by Vivado. Here in the tree under amba_pl is the entry regarding my controller:

/ {
    amba_pl: amba_pl {
        ...
        <other_stuff>
        ...
        myip_control_0: myip_controller@42030000 {
            compatible = "xlnx,myip-controller-1.022";
            reg = <0x42030000 0x1000>;
        };
        ...

In addition, I have my own extension of this node with some parameters in another .dtsi file:

&myip_control_0 {
    memory-region = <&myip_mem>;
    interrupt-parent = <&intc>;
    interrupts = <0 34 1>, <0 35 1>, <0 36 1>;
};

In the system after startup I have:

cat /proc/device-tree/amba_pl/myip_controller\@42030000/

Output:

compatible
xlnx,myip-controller-1.022

and such a catalog is also available: /sys/bus/platform/devices/42030000.myip_controller/

I've made a patch to print out what's going on in the functions looking for a match between device and driver in the kernel, and as far as I can see, there isn't any driver to match on boot for my node in the devicetree:

[2025-07-20 15:54:45.758] of_match_device: matching device node: /amba_pl/myip_controller@42030000
[2025-07-20 15:54:45.758] OF: of_match_node: node=/amba_pl/myip_controller@42030000, matches=c09083f8
[2025-07-20 15:54:45.758] OF: of_match_node: MISS (no compatible match for node: /amba_pl/myip_controller@42030000)
[2025-07-20 15:54:45.758] of_match_device: MISS, none of these compatible entries matched for node /amba_pl/myip_controller@42030000:

But also no such entries appear as I do the insmod of this .ko file. Am I assuming correctly that this is due to the fact that the kernel doesn't find an alias in this .ko file, so it doesn't even try to match anything?

Makefile for the module in my Yocto meta layer:

obj-m := myip_controller.o
myip_controller-objs := myip_controller.o fpga_operations.o

KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

modules:
    $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules

modules_install:
    $(MAKE) -C $(KERNEL_SRC) M=$(PWD) INSTALL_MOD_PATH=$(INSTALL_MOD_PATH) modules_install

clean:
    $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean

And this is the important part of my *.bb file:

SRC_URI = "file://Makefile \
           file://myip_controller.h \
           file://myip_controller.c \
           file://fpga_operations.h \
           file://fpga_operations.c"

S = "${WORKDIR}"

inherit module

KERNEL_MODULE_AUTOLOAD = "myip_controller"

COMPATIBLE_MACHINE = ".*"

EXTRA_CFLAGS += "-g -O0"
EXTRA_OEMAKE += "KERNEL_SRC=${STAGING_KERNEL_DIR} KERNEL_VERSION=${KERNEL_VERSION} INSTALL_MOD_PATH=${D}"

do_compile() {
    oe_runmake
}

do_install() {
    oe_runmake modules_install
}

I used the hello_mod module example from yocto/poky/meta-skeleton/recipes-kernel/hello-mod, changed it hello.c to the following and the alias appears in the ko file :)

#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/device.h>

static int hello_probe(struct platform_device *pdev)
{
    pr_info("hello_probe: found device %s\n", dev_name(&pdev->dev));
    return 0;
}

static int hello_remove(struct platform_device *pdev)
{
    pr_info("hello_remove: removed device %s\n", dev_name(&pdev->dev));
    return 0;
}

static const struct of_device_id hello_of_match[] = {
    { .compatible = "xlnx,myip-controller-1.022", },
    {},
};
MODULE_DEVICE_TABLE(of, hello_of_match);

static struct platform_driver hello_driver = {
    .probe = hello_probe,
    .remove = hello_remove,
    .driver = {
        .name = "hello",
        .of_match_table = hello_of_match,
    },
};
module_platform_driver(hello_driver);

MODULE_LICENSE("GPL");

When I did insmod hello.ko, it showed me the messages from the kernel from the of_match_node function, i.e., as I assumed, the kernel saw that there was an alias it started to assign it.

OF: of_match_node: node=/amba_pl/axi_quad_spi@44010000, matches=bf008024
OF: of_match_node: MISS (no compatible match for node: /amba_pl/axi_quad_spi@44010000)
OF: of_match_node: node=/amba_pl/myip_controller@42030000, matches=bf008024
OF: of_match_node: HIT compatible = 'xlnx,myip-controller-1.022'
hello_probe: found device 42030000.myip_controller
OF: of_match_node: node=/amba_pl/gpio@42000000, matches=bf008024
OF: of_match_node: MISS (no compatible match for node: /amba_pl/gpio@42000000)
OF: of_match_node: node=/amba_pl/gpio@42010000, matches=bf008024
OF: of_match_node: MISS (no compatible match for node: /amba_pl/gpio@42010000)
OF: of_match_node: node=/amba_pl/gpio@42020000, matches=bf008024

So it works! I have to find why my module behaves in different way...

I found what makes the difference, but I don't know how to do it correctly.

The thing is that I am trying to build a module from several source files. When I add them in the Makefile this alias disappears in the resulting .ko file. When I built this hello_mod example from a single file then the alias was included in the .ko file.

I prepared a minimalist representation of my problem in a way that reflects my module. I have the following module files:

my_module/
├── Makefile
├── hello.c             # Main C file
├── hello.h             # Header for the main file
├── hw_access.c         # Hardware access functions
├── hw_access.h         # Header for the additional file

Makefile:

obj-m := hello.o
hello-objs := hello.o hw_access.o


SRC := $(shell pwd)

all:
    $(MAKE) -C $(KERNEL_SRC) M=$(SRC)

modules_install:
    $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install

clean:
    rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
    rm -f Module.markers Module.symvers modules.order
    rm -rf .tmp_versions Modules.symvers

hello.c:

#include "hello.h"

static int hello_probe(struct platform_device *pdev)
{
    pr_info("hello_probe: found device %s\n", dev_name(&pdev->dev));
    return 0;
}

static int hello_remove(struct platform_device *pdev)
{
    pr_info("hello_remove: removed device %s\n", dev_name(&pdev->dev));
    return 0;
}

static const struct of_device_id hello_of_match[] = {
    { .compatible = "xlnx,myip-controller-1.022", },
    {},
};
MODULE_DEVICE_TABLE(of, hello_of_match);

static struct platform_driver hello_driver = {
    .probe = hello_probe,
    .remove = hello_remove,
    .driver = {
        .name = "hello",
        .of_match_table = hello_of_match,
    },
};
module_platform_driver(hello_driver);

MODULE_LICENSE("GPL");

hello.h

#ifndef HELLO_H
#define HELLO_H

#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/device.h>

#define SOME_VALUE 14

struct hello_context {

    int some_parameter;

};

#endif /* HELLO_H */

hw_access.c

#include "hello.h"
#include "hw_access.h"

void set_parameter(struct hello_context *hc)
{
    hc->some_parameter = SOME_VALUE;

    pr_info("HELLO: Parameter context value = %d\n", hc->some_parameter);
}

void get_parameter(struct hello_context *hc)
{
    int parA = hc->some_parameter;

    pr_info("HELLO: Another parameter value = %d\n", parA);
}

hw_access.h

#ifndef HW_ACCESS_H
#define HW_ACCESS_H

#include "hello.h"

void set_parameter(struct hello_context *hc);
void get_parameter(struct hello_context *hc);


#endif // HW_ACCESS_H

So for the above files, it will generate a .ko file without an alias. But as in the Makefile, I will comment this line out:

# hello-objs := hello.o hw_access.o

, it generates a .ko file with an alias.

How can I do it correctly for a multi-source build?


Solution

  • I can't have the name of the main C file like the module name. When they differ, it works fine!