How to debug a driver failing to bind to a device on Linux?

5,721

A working solution to get the driver to bind to the device is:

cgublock: jz4780-cgublock@10000000 {
    compatible = "simple-bus", "syscon";

    #address-cells = <1>;
    #size-cells = <1>;

    reg = <0x10000000 0x100>;
    ranges;

    cgu: jz4780-cgu@10000000 {
        compatible = "ingenic,jz4780-cgu";
        reg = <0x10000000 0x100>;

        clocks = <&ext>, <&rtc>;
        clock-names = "ext", "rtc";

        #clock-cells = <1>;
    };

    rng: rng@d8 {
        compatible = "ingenic,jz4780-rng";
        reg = <0x100000d8 0x8>;
    };
};

This was found by staring at other examples. I would prefer a solution where I get a proper diagnosis why the previous attempt is incorrect.

Share:
5,721

Related videos on Youtube

Fakt7
Author by

Fakt7

Updated on September 18, 2022

Comments

  • Fakt7
    Fakt7 over 1 year

    I am trying to figure out why the following device is not setup to its driver on my Creator CI20. For reference I am using a Linux kernel v4.13.0 and doing the compilation locally:

    make ARCH=mips ci20_defconfig
    make -j8 ARCH=mips CROSS_COMPILE=mipsel-linux-gnu- uImage
    

    From the running system I can see:

    ci20@ci20:~# find /sys | grep rng
    /sys/firmware/devicetree/base/jz4780-cgu@10000000/rng@d8
    /sys/firmware/devicetree/base/jz4780-cgu@10000000/rng@d8/compatible
    /sys/firmware/devicetree/base/jz4780-cgu@10000000/rng@d8/name
    /sys/bus/platform/drivers/jz4780-rng
    /sys/bus/platform/drivers/jz4780-rng/bind
    /sys/bus/platform/drivers/jz4780-rng/unbind
    /sys/bus/platform/drivers/jz4780-rng/uevent
    

    So the device is seen by the kernel at runtime, now the missing piece is why the driver is never binded ? I would have expected something like this:

    /sys/bus/platform/drivers/jz4780-rng/100000d8.rng
    

    I did find some other posts explaining how to debug a running system, such as:

    While the information is accurate on those posts, it is not very helpful for me. Since I am building locally my kernel (I added printk in the probe function of jz4780-rng driver), my question is instead:

    • what option should I turn on at compile time so that the kernel prints an accurate information on its failure to call the probe function for the jz4780-rng driver ?
    • In particular how do I print the complete list of the tested bus/driver for driver_probe_device ?

    I am ok to add printk anywhere in the code to debug this. The question is rather: which function is traversing the device tree and calling the probe/init function ?

    For reference:

    $ dtc -I fs -O dts /sys/firmware/devicetree/base | grep -A 1 rng
                  rng@d8 {
                          compatible = "ingenic,jz4780-rng";
                  };
    

    compatible string is declared as:

    cgu: jz4780-cgu@10000000 {
        compatible = "ingenic,jz4780-cgu", "syscon";
        reg = <0x10000000 0x100>;
    
        clocks = <&ext>, <&rtc>;
        clock-names = "ext", "rtc";
    
        #clock-cells = <1>;
    
        rng: rng@d8 {
            compatible = "ingenic,jz4780-rng";
        };
    };
    

    And in the driver as:

    static const struct of_device_id jz4780_rng_dt_match[] = {
        {
            .compatible = "ingenic,jz4780-rng",
        },
        { },
    };
    MODULE_DEVICE_TABLE(of, jz4780_rng_dt_match);
    
    static struct platform_driver jz4780_rng_driver = {
        .driver     = {
            .name   = "jz4780-rng",
            .of_match_table = jz4780_rng_dt_match,
        },
        .probe      = jz4780_rng_probe,
        .remove     = jz4780_rng_remove,
    };
    module_platform_driver(jz4780_rng_driver);
    

    Update1:

    When I build my kernel with CONFIG_DEBUG_DRIVER=y, here is what I can see:

    # grep driver_probe_device syslog
    Sep  6 10:08:07 ci20 kernel: [    0.098280] bus: 'platform': driver_probe_device: matched device 10031000.serial with driver ingenic-uart
    Sep  6 10:08:07 ci20 kernel: [    0.098742] bus: 'platform': driver_probe_device: matched device 10033000.serial with driver ingenic-uart
    Sep  6 10:08:07 ci20 kernel: [    0.099209] bus: 'platform': driver_probe_device: matched device 10034000.serial with driver ingenic-uart
    Sep  6 10:08:07 ci20 kernel: [    0.106945] bus: 'platform': driver_probe_device: matched device 1b000000.nand-controller with driver jz4780-nand
    Sep  6 10:08:07 ci20 kernel: [    0.107282] bus: 'platform': driver_probe_device: matched device 134d0000.bch with driver jz4780-bch
    Sep  6 10:08:07 ci20 kernel: [    0.107470] bus: 'platform': driver_probe_device: matched device 16000000.dm9000 with driver dm9000
    Sep  6 10:08:07 ci20 kernel: [    0.165618] bus: 'platform': driver_probe_device: matched device 10003000.rtc with driver jz4740-rtc
    Sep  6 10:08:07 ci20 kernel: [    0.166177] bus: 'platform': driver_probe_device: matched device 10002000.jz4780-watchdog with driver jz4740-wdt
    Sep  6 10:08:07 ci20 kernel: [    0.170930] bus: 'platform': driver_probe_device: matched device 1b000000.nand-controller with driver jz4780-nand
    

    But only:

    # grep rng syslog
    Sep  6 10:08:07 ci20 kernel: [    0.166842] bus: 'platform': add driver jz4780-rng
    Sep  6 10:08:42 ci20 kernel: [   54.584451] random: crng init done
    

    As a side note, the rng toplevel node: cgu is not referenced here, but there is a jz4780-cgu driver.


    Update2:

    If I move the rng node declaration outside the toplevel cgu node, I can at least see some binding happening at last:

    # grep rng /var/log/syslog 
    Sep  6 10:30:57 ci20 kernel: [    0.167017] bus: 'platform': add driver jz4780-rng
    Sep  6 10:30:57 ci20 kernel: [    0.167033] bus: 'platform': driver_probe_device: matched device 10000000.rng with driver jz4780-rng
    Sep  6 10:30:57 ci20 kernel: [    0.167038] bus: 'platform': really_probe: probing driver jz4780-rng with device 10000000.rng
    Sep  6 10:30:57 ci20 kernel: [    0.167050] jz4780-rng 10000000.rng: no pinctrl handle
    Sep  6 10:30:57 ci20 kernel: [    0.167066] devices_kset: Moving 10000000.rng to end of list
    Sep  6 10:30:57 ci20 kernel: [    0.172774] jz4780-rng: probe of 10000000.rng failed with error -22
    Sep  6 10:31:32 ci20 kernel: [   54.802794] random: crng init done
    

    Using:

        rng: rng@100000d8 {
            compatible = "ingenic,jz4780-rng";
        };
    

    I can also verify:

    # find /sys/ | grep rng
    /sys/devices/platform/10000000.rng
    /sys/devices/platform/10000000.rng/subsystem
    /sys/devices/platform/10000000.rng/driver_override
    /sys/devices/platform/10000000.rng/modalias
    /sys/devices/platform/10000000.rng/uevent
    /sys/devices/platform/10000000.rng/of_node
    /sys/firmware/devicetree/base/rng@100000d8
    /sys/firmware/devicetree/base/rng@100000d8/compatible
    /sys/firmware/devicetree/base/rng@100000d8/status
    /sys/firmware/devicetree/base/rng@100000d8/reg
    /sys/firmware/devicetree/base/rng@100000d8/name
    /sys/bus/platform/devices/10000000.rng
    /sys/bus/platform/drivers/jz4780-rng
    /sys/bus/platform/drivers/jz4780-rng/bind
    /sys/bus/platform/drivers/jz4780-rng/unbind
    /sys/bus/platform/drivers/jz4780-rng/uevent