do_initcalls()

<kernel v4.14>

do_initcalls()

init/main.c

static void __init do_initcalls(void)
{
        int level;

        for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
                do_initcall_level(level);
}

0 레벨부터  7 레벨까지 단계별로 *_initcall() 매크로 함수로 등록된 함수들을 모두 호출한다.

 

do_initcall_level()

init/main.c

static void __init do_initcall_level(int level)
{
        initcall_t *fn;

        strcpy(initcall_command_line, saved_command_line);
        parse_args(initcall_level_names[level],
                   initcall_command_line, __start___param,
                   __stop___param - __start___param,
                   level, level,
                   NULL, &repair_env_string);

        for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
                do_one_initcall(*fn);
}

커멘드 라인 파라메터들을 파싱하여 커널에 등록된 파라메터들 중 요청 레벨 및 이름이 모두 매치되는 파라메터를 해당함수를 호출하여 설정한다. 그 후 지정된 레벨에 등록된 initcall 함수들을 모두 호출한다.

 

do_one_initcall()

init/main.c

int __init_or_module do_one_initcall(initcall_t fn)
{
        int count = preempt_count();
        int ret;
        char msgbuf[64];

        if (initcall_blacklisted(fn))
                return -EPERM;

        if (initcall_debug)
                ret = do_one_initcall_debug(fn);
        else
                ret = fn();

        msgbuf[0] = 0;

        if (preempt_count() != count) {
                sprintf(msgbuf, "preemption imbalance ");
                preempt_count_set(count);
        }
        if (irqs_disabled()) {
                strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
                local_irq_enable();
        }
        WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf);

        add_latent_entropy();
        return ret;
}

initcall 함수 하나를 호출한다. 커널 파라메터를 사용하여 블랙리스트에 등록된 함수들은 실행하지 않는다.

 

initcall 레벨별 주요 파라메터

각 단계별 주요 파라메터명 및 호출 함수를 확인해보자. 참고로 현재 커널 소스에는 0레벨과 1레벨만 등록하여 사용하고 있다.

  •  레벨 0: 이 레벨은 셋업 함수와 연동된다.
    • early_param(“earlycon”, param_setup_earlycon);
    • early_param(“cma”, early_cma);
    • early_param(“sysfs.deprecated”, sysfs_deprecated_setup);
    • early_param(“kgdbdbgp”, kgdbdbgp_parse_config);
  • 레벨 1: 이 레벨은 변수와 연동된다.
    • core_param(panic, panic_timeout, int, 0644);
    • core_param(irqtime, irqtime, int, 0400);
    • core_param(nomodule, modules_disabled, bint, 0);
    • core_param(module_blacklist, module_blacklist, charp, 0400);
    • core_param(consoleblank, blankinterval, int, 0444);
    • core_param(initcall_debug, initcall_debug, bool, 0644);
  • 참고

 

각 단계별 initcall에 해당하는 이름은 다음에서 확인할 수 있다.

init/main.c

/* Keep these in sync with initcalls in include/linux/init.h */
static char *initcall_level_names[] __initdata = {
        "early",
        "core",
        "postcore",
        "arch",
        "subsys",
        "fs",
        "device",
        "late",
};

 

레벨별 initcall 함수가 모여있는 섹션의 시작 위치를 담은 배열은 다음에서 확인할 수 있다.

init/main.c

static initcall_t *initcall_levels[] __initdata = {
        __initcall0_start,
        __initcall1_start,
        __initcall2_start,
        __initcall3_start,
        __initcall4_start,
        __initcall5_start,
        __initcall6_start,
        __initcall7_start,
        __initcall_end,
};

 

initcall 섹션

initcall 함수들이 위치하는 곳은 컴파일 타임에 .init.data 섹션의 INIT_CALLS 매크로 자리에 위치하게된다.

arch/arm64/kernel/vmlinux.lds.S

...
        .init.data : {
                INIT_DATA
                INIT_SETUP(16)
                INIT_CALLS
                CON_INITCALL
                SECURITY_INITCALL
                INIT_RAM_FS
                *(.init.rodata.* .init.bss)     /* from the EFI stub */
        }
...

 

INIT_CALLS 매크로에는 early, 0~5, rootfs, 6, 7 레벨에 해당하는 함수들의 주소가 적재된다.

include/asm-generic/vmlinux.lds.h

#define INIT_CALLS                                                      \
                VMLINUX_SYMBOL(__initcall_start) = .;                   \
                KEEP(*(.initcallearly.init))                            \
                INIT_CALLS_LEVEL(0)                                     \
                INIT_CALLS_LEVEL(1)                                     \
                INIT_CALLS_LEVEL(2)                                     \
                INIT_CALLS_LEVEL(3)                                     \
                INIT_CALLS_LEVEL(4)                                     \
                INIT_CALLS_LEVEL(5)                                     \
                INIT_CALLS_LEVEL(rootfs)                                \
                INIT_CALLS_LEVEL(6)                                     \
                INIT_CALLS_LEVEL(7)                                     \
                VMLINUX_SYMBOL(__initcall_end) = .;

 

다음 매크로 함수에서 해당 레벨의 initcall 시작 심볼에 주소가 담기고, initcall 함수들 주소가 적재되는 섹션 위치를 알 수 있다.

include/asm-generic/vmlinux.lds.h

#define INIT_CALLS_LEVEL(level)                                         \
                VMLINUX_SYMBOL(__initcall##level##_start) = .;          \
                KEEP(*(.initcall##level##.init))                        \
                KEEP(*(.initcall##level##s.init))                       \

 

initcall 함수 등록

다음은 레벨 0보다 먼저 시작되어야 할 early 함수들이 컴파일 타임에 정적으로 등록하는 매크로 함수이다.

include/linux/init.h

/*
 * Early initcalls run before initializing SMP.
 *
 * Only for built-in code, not modules.
 */
#define early_initcall(fn)              __define_initcall(fn, early)

 

다음 매크로 함수는 컴파일된 호출 함수의 주소를 해당 레벨의 섹션 위치에 저장한다. (함수 포인터 하나를 저장한다)

include/linux/init.h

/*
 * initcalls are now grouped by functionality into separate
 * subsections. Ordering inside the subsections is determined
 * by link order. 
 * For backwards compatibility, initcall() puts the call in 
 * the device init subsection.
 *
 * The `id' arg to __define_initcall() is needed so that multiple initcalls
 * can point at the same handler without causing duplicate-symbol build errors.
 *
 * Initcalls are run by placing pointers in initcall sections that the
 * kernel iterates at runtime. The linker can do dead code / data elimination
 * and remove that completely, so the initcall sections have to be marked
 * as KEEP() in the linker script.
 */

#define __define_initcall(fn, id) \
        static initcall_t __initcall_##fn##id __used \
        __attribute__((__section__(".initcall" #id ".init"))) = fn;

 

다음 매크로 함수들은 initcall 함수들의 주소를 해당 레벨의 위치에 저장한다. (함수 포인터 하나를 저장한다)

include/linux/init.h

/*
 * A "pure" initcall has no dependencies on anything else, and purely
 * initializes variables that couldn't be statically initialized.
 *
 * This only exists for built-in code, not for modules.
 * Keep main.c:initcall_level_names[] in sync.
 */
#define pure_initcall(fn)               __define_initcall(fn, 0)

#define core_initcall(fn)               __define_initcall(fn, 1)
#define core_initcall_sync(fn)          __define_initcall(fn, 1s)
#define postcore_initcall(fn)           __define_initcall(fn, 2)
#define postcore_initcall_sync(fn)      __define_initcall(fn, 2s)
#define arch_initcall(fn)               __define_initcall(fn, 3)
#define arch_initcall_sync(fn)          __define_initcall(fn, 3s)
#define subsys_initcall(fn)             __define_initcall(fn, 4)
#define subsys_initcall_sync(fn)        __define_initcall(fn, 4s)
#define fs_initcall(fn)                 __define_initcall(fn, 5)
#define fs_initcall_sync(fn)            __define_initcall(fn, 5s)
#define rootfs_initcall(fn)             __define_initcall(fn, rootfs)
#define device_initcall(fn)             __define_initcall(fn, 6)
#define device_initcall_sync(fn)        __define_initcall(fn, 6s)
#define late_initcall(fn)               __define_initcall(fn, 7)
#define late_initcall_sync(fn)          __define_initcall(fn, 7s)

 

console에 대한 initcall이 별도로 정의되고 저장되는 위치도 별도로 두었다.

include/linux/init.h

#define console_initcall(fn)                                    \
        static initcall_t __initcall_##fn                       \
        __used __section(.con_initcall.init) = fn

 

initcall 레벨별 주요 호출 함수

다음은 QEMU에서 arm64 커널을 동작시킬 때 호출되는 initcall들이다.

 

early 레벨: early_initcall()

[    0.049844] initcall cpu_suspend_init+0x0/0x4c returned 0 after 0 usecs
[    0.050052] initcall asids_init+0x0/0xd0 returned 0 after 0 usecs
[    0.050120] initcall xen_guest_init+0x0/0x2e4 returned 0 after 0 usecs
[    0.060595] initcall spawn_ksoftirqd+0x0/0x50 returned 0 after 7812 usecs
[    0.060665] initcall migration_init+0x0/0x4c returned 0 after 0 usecs
[    0.060711] initcall check_cpu_stall_init+0x0/0x2c returned 0 after 0 usecs
[    0.060787] initcall srcu_bootup_announce+0x0/0x40 returned 0 after 0 usecs
[    0.061902] initcall rcu_spawn_gp_kthread+0x0/0x12c returned 0 after 0 usecs
[    0.072857] initcall cpu_stop_init+0x0/0xd4 returned 0 after 7812 usecs
[    0.072966] initcall jump_label_init_module+0x0/0x1c returned 0 after 0 usecs
[    0.073171] initcall its_pci_msi_init+0x0/0xc4 returned 0 after 0 usecs
[    0.073286] initcall its_pmsi_init+0x0/0xa8 returned 0 after 0 usecs
[    0.073394] initcall renesas_soc_init+0x0/0x214 returned -19 after 0 usecs
[    0.073566] initcall rcar_sysc_pd_init+0x0/0x2f0 returned -19 after 0 usecs
[    0.073800] initcall tegra_init_fuse+0x0/0x18c returned 0 after 0 usecs
[    0.073928] initcall tegra_flowctrl_init+0x0/0xc8 returned 0 after 0 usecs
[    0.074271] initcall tegra_pmc_early_init+0x0/0x58c returned 0 after 0 usecs
[    0.075707] initcall rand_initialize+0x0/0x128 returned 0 after 0 usecs
[    0.075794] initcall arm_enable_runtime_services+0x0/0x1fc returned 0 after 0 usecs
[    0.075943] initcall dummy_timer_register+0x0/0x34 returned 0 after 0 usecs

 

0 레벨: pure_initcall()

<pre “>[ 0.190141] initcall ipc_ns_init+0x0/0x68 returned 0 after 0 usecs [ 0.190196] initcall init_mmap_min_addr+0x0/0x18 returned 0 after 0 usecs [ 0.190316] initcall init_cpufreq_transition_notifier_list+0x0/0x34 returned 0 after 0 usecs [ 0.190369] initcall jit_init+0x0/0x8 returned 0 after 0 usecs [ 0.192294] initcall net_ns_init+0x0/0x154 returned 0 after 3906 usecs

 

1 레벨: core_initcall()

[    0.192760] initcall fpsimd_init+0x0/0x80 returned 0 after 0 usecs
[    0.192834] initcall enable_mrs_emulation+0x0/0x24 returned 0 after 0 usecs
[    0.193145] initcall map_entry_trampoline+0x0/0x128 returned 0 after 0 usecs
[    0.193216] initcall cpu_hotplug_pm_sync_init+0x0/0x24 returned 0 after 0 usecs
[    0.193252] initcall alloc_frozen_cpus+0x0/0x8 returned 0 after 0 usecs
[    0.193811] initcall wq_sysfs_init+0x0/0x40 returned 0 after 0 usecs
[    0.194052] initcall ksysfs_init+0x0/0xc0 returned 0 after 0 usecs
[    0.194327] initcall pm_init+0x0/0x80 returned 0 after 0 usecs
[    0.194407] initcall pm_disk_init+0x0/0x24 returned 0 after 0 usecs
[    0.195198] initcall swsusp_header_init+0x0/0x40 returned 0 after 0 usecs
[    0.195239] initcall rcu_set_runtime_mode+0x0/0x14 returned 0 after 0 usecs
[    0.195364] initcall init_jiffies_clocksource+0x0/0x24 returned 0 after 0 usecs
[    0.195683] initcall futex_init+0x0/0xfc returned 0 after 0 usecs
[    0.195819] initcall cgroup_wq_init+0x0/0x40 returned 0 after 0 usecs
[    0.195967] initcall cgroup1_wq_init+0x0/0x40 returned 0 after 0 usecs
[    0.196044] initcall cpu_pm_init+0x0/0x20 returned 0 after 0 usecs
[    0.196439] initcall init_per_zone_wmark_min+0x0/0x8c returned 0 after 0 usecs
[    0.196484] initcall init_zero_pfn+0x0/0x28 returned 0 after 0 usecs
[    0.197700] initcall cma_init_reserved_areas+0x0/0x1c4 returned 0 after 0 usecs
[    0.197821] initcall fsnotify_init+0x0/0x54 returned 0 after 0 usecs
[    0.197966] initcall filelock_init+0x0/0xbc returned 0 after 0 usecs
[    0.198259] initcall init_script_binfmt+0x0/0x24 returned 0 after 0 usecs
[    0.198304] initcall init_elf_binfmt+0x0/0x24 returned 0 after 0 usecs
[    0.198344] initcall init_compat_elf_binfmt+0x0/0x24 returned 0 after 0 usecs
[    0.198470] initcall configfs_init+0x0/0xb8 returned 0 after 0 usecs
[    0.198551] initcall debugfs_init+0x0/0x78 returned 0 after 0 usecs
[    0.198684] initcall prandom_init+0x0/0x154 returned 0 after 0 usecs
[    0.200146] initcall pinctrl_init+0x0/0xc0 returned 0 after 3906 usecs
[    0.200434] initcall gpiolib_dev_init+0x0/0xf4 returned 0 after 0 usecs
[    0.201001] initcall hi3516cv300_crg_init+0x0/0x20 returned 0 after 0 usecs
[    0.201145] initcall hi3519_clk_init+0x0/0x20 returned 0 after 0 usecs
[    0.201288] initcall hi3660_clk_init+0x0/0x20 returned 0 after 0 usecs
[    0.201408] initcall hi3798cv200_crg_init+0x0/0x20 returned 0 after 0 usecs
[    0.201534] initcall gcc_ipq8074_init+0x0/0x20 returned 0 after 0 usecs
[    0.201667] initcall gcc_msm8916_init+0x0/0x20 returned 0 after 0 usecs
[    0.201895] initcall gcc_msm8994_init+0x0/0x20 returned 0 after 0 usecs
[    0.202030] initcall gcc_msm8996_init+0x0/0x20 returned 0 after 0 usecs
[    0.202150] initcall rpm_smd_clk_init+0x0/0x20 returned 0 after 0 usecs
[    0.202295] initcall vexpress_osc_init+0x0/0x20 returned 0 after 0 usecs
[    0.202416] initcall zx_clk_init+0x0/0x20 returned 0 after 0 usecs
[    0.202539] initcall fsl_guts_init+0x0/0x20 returned 0 after 0 usecs
[    0.202866] initcall exynos4_pm_init_power_domain+0x0/0x2fc returned 0 after 0 usecs
[    0.203028] initcall virtio_init+0x0/0x30 returned 0 after 0 usecs
[    0.208022] initcall regulator_init+0x0/0xb0 returned 0 after 3906 usecs
[    0.208149] initcall iommu_init+0x0/0x3c returned 0 after 0 usecs
[    0.208221] initcall opp_debug_init+0x0/0x50 returned 0 after 0 usecs
[    0.208275] initcall dma_init_reserved_memory+0x0/0x60 returned -12 after 0 usecs
[    0.208417] initcall soc_bus_register+0x0/0x50 returned 0 after 0 usecs
[    0.208460] initcall register_cpufreq_notifier+0x0/0x54 returned -22 after 0 usecs
[    0.208668] initcall vexpress_syscfg_init+0x0/0x20 returned 0 after 0 usecs
[    0.208871] initcall vexpress_sysreg_init+0x0/0x70 returned 0 after 0 usecs
[    0.208958] initcall cpufreq_core_init+0x0/0x68 returned 0 after 0 usecs
[    0.209296] initcall cpuidle_init+0x0/0x54 returned 0 after 3906 usecs
[    0.209354] initcall capsule_reboot_register+0x0/0x20 returned 0 after 0 usecs
[    0.209450] initcall arm_dmi_init+0x0/0x28 returned 0 after 0 usecs
[    0.209628] initcall tegra_bpmp_init+0x0/0x20 returned 0 after 0 usecs
[    0.209779] initcall hi6220_mbox_init+0x0/0x20 returned 0 after 0 usecs
[    0.209914] initcall tegra_hsp_init+0x0/0x20 returned 0 after 0 usecs
[    0.213400] initcall sock_init+0x0/0xc0 returned 0 after 0 usecs
[    0.213537] initcall net_inuse_init+0x0/0x30 returned 0 after 0 usecs
[    0.213591] initcall net_defaults_init+0x0/0x30 returned 0 after 0 usecs
[    0.213715] initcall init_default_flow_dissectors+0x0/0x54 returned 0 after 0 usecs
[    0.229426] initcall netlink_proto_init+0x0/0x174 returned 0 after 15625 usecs

 

1 레벨: early_initcall_sync()

core_s
[    0.229483] initcall __gnttab_init+0x0/0x40 returned -19 after 0 usecs

 

2 레벨: postcore_initcall()

postcore
[    0.230197] initcall debug_monitors_init+0x0/0x38 returned 0 after 0 usecs
[    0.230610] initcall irq_sysfs_init+0x0/0xb4 returned 0 after 0 usecs
[    0.230880] initcall bdi_class_init+0x0/0x74 returned 0 after 0 usecs
[    0.230961] initcall mm_sysfs_init+0x0/0x3c returned 0 after 0 usecs
[    0.231166] initcall irqc_init+0x0/0x20 returned 0 after 0 usecs
[    0.231314] initcall vexpress_config_init+0x0/0xec returned 0 after 0 usecs
[    0.231499] initcall rockchip_pinctrl_drv_register+0x0/0x20 returned 0 after 0 usecs
[    0.231655] initcall samsung_pinctrl_drv_register+0x0/0x20 returned 0 after 0 usecs
[    0.231796] initcall sh_pfc_init+0x0/0x20 returned 0 after 0 usecs
[    0.231983] initcall gpiolib_sysfs_init+0x0/0xbc returned 0 after 0 usecs
[    0.232120] initcall tegra_gpio_init+0x0/0x20 returned 0 after 0 usecs
[    0.232222] initcall pcibus_class_init+0x0/0x24 returned 0 after 0 usecs
[    0.232382] initcall pci_driver_init+0x0/0x1c returned 0 after 0 usecs
[    0.232868] initcall backlight_class_init+0x0/0xc0 returned 0 after 0 usecs
[    0.233041] initcall amba_init+0x0/0x1c returned 0 after 0 usecs
[    0.233340] initcall rockchip_grf_init+0x0/0xf8 returned -19 after 0 usecs
[    0.233859] initcall rockchip_pm_domain_drv_register+0x0/0x20 returned 0 after 3906 usecs
[    0.234031] initcall exynos_pmu_init+0x0/0x20 returned 0 after 0 usecs
[    0.234103] initcall xenbus_init+0x0/0x2e8 returned -19 after 0 usecs
[    0.234250] initcall hi6220_reset_init+0x0/0x20 returned 0 after 0 usecs
[    0.234383] initcall tty_class_init+0x0/0x54 returned 0 after 0 usecs
[    0.234848] initcall vtconsole_class_init+0x0/0xfc returned 0 after 0 usecs
[    0.235077] initcall serdev_init+0x0/0x2c returned 0 after 0 usecs
[    0.235173] initcall iommu_dev_init+0x0/0x24 returned 0 after 0 usecs
[    0.235304] initcall mipi_dsi_bus_init+0x0/0x1c returned 0 after 0 usecs
[    0.235389] initcall wakeup_sources_debugfs_init+0x0/0x34 returned 0 after 0 usecs
[    0.235634] initcall register_node_type+0x0/0x20 returned 0 after 0 usecs
[    0.235745] initcall regmap_initcall+0x0/0x18 returned 0 after 0 usecs
[    0.235935] initcall sram_init+0x0/0x20 returned 0 after 0 usecs
[    0.236071] initcall syscon_init+0x0/0x24 returned 0 after 0 usecs
[    0.236334] initcall spi_init+0x0/0xac returned 0 after 0 usecs
[    0.236476] initcall spmi_init+0x0/0x30 returned 0 after 0 usecs
[    0.237354] initcall i2c_init+0x0/0xf0 returned 0 after 0 usecs
[    0.239930] initcall init_menu+0x0/0x1c returned 0 after 3906 usecs
[    0.239996] initcall pcc_init+0x0/0x3dc returned -19 after 0 usecs
[    0.240204] initcall qcom_hwspinlock_init+0x0/0x20 returned 0 after 0 usecs
[    0.240377] initcall rpmsg_init+0x0/0x4c returned 0 after 0 usecs
[    0.240680] initcall kobject_uevent_init+0x0/0x20 returned 0 after 0 usecs

 

2 레벨: postcore_initcall_sync()

[    0.241128] initcall of_iommu_init+0x0/0x88 returned 0 after 0 usecs

 

3 레벨: arch_initcall()

[    0.241563] initcall debug_traps_init+0x0/0x54 returned 0 after 0 usecs
[    0.241706] initcall vdso_init+0x0/0x150 returned 0 after 0 usecs
[    0.245891] initcall alloc_vectors_page+0x0/0xb4 returned 0 after 3906 usecs
[    0.246968] initcall arch_hw_breakpoint_init+0x0/0xf8 returned 0 after 0 usecs
[    0.247140] initcall __iommu_dma_init+0x0/0x14 returned 0 after 0 usecs
[    0.259147] initcall arm64_dma_init+0x0/0x48 returned 0 after 11718 usecs
[    0.259212] initcall p2m_init+0x0/0x18 returned 0 after 0 usecs
[    0.259253] initcall xen_mm_init+0x0/0x94 returned 0 after 0 usecs
[    0.260103] initcall ns2_pinmux_init+0x0/0x20 returned 0 after 0 usecs
[    0.260459] initcall ipq8074_pinctrl_init+0x0/0x20 returned 0 after 0 usecs
[    0.261524] initcall msm8916_pinctrl_init+0x0/0x20 returned 0 after 3906 usecs
[    0.262042] initcall msm8994_pinctrl_init+0x0/0x20 returned 0 after 0 usecs
[    0.262422] initcall msm8996_pinctrl_init+0x0/0x20 returned 0 after 0 usecs
[    0.262996] initcall qdf2xxx_pinctrl_init+0x0/0x20 returned 0 after 0 usecs
[    0.263438] initcall mtk_pinctrl_init+0x0/0x20 returned 0 after 0 usecs
[    0.263553] initcall acpi_pci_init+0x0/0x80 returned 0 after 0 usecs
[    0.264249] initcall clk_mt6797_init+0x0/0x20 returned 0 after 0 usecs
[    0.264306] initcall tegra_clocks_apply_init_table+0x0/0x2c returned 0 after 0 usecs
[    0.264978] initcall dma_bus_init+0x0/0xf4 returned 0 after 0 usecs
[    0.265462] initcall dma_channel_table_init+0x0/0x108 returned 0 after 0 usecs
[    0.266509] initcall qcom_smd_rpm_init+0x0/0x24 returned 0 after 0 usecs
[    0.268196] initcall qcom_smem_init+0x0/0x20 returned 0 after 3906 usecs
[    0.268251] initcall setup_vcpu_hotplug_event+0x0/0x34 returned -19 after 0 usecs
[    0.268300] initcall register_xen_amba_notifier+0x0/0x5c returned 0 after 0 usecs
[    0.268343] initcall register_xen_platform_notifier+0x0/0x58 returned 0 after 0 usecs
[    0.268381] initcall register_xen_pci_notifier+0x0/0x4c returned 0 after 0 usecs
[    0.268908] initcall hi3660_reset_init+0x0/0x20 returned 0 after 0 usecs
[    0.269749] initcall pl011_init+0x0/0x54 returned 0 after 0 usecs
[    0.271510] initcall mvebu_uart_init+0x0/0x60 returned 0 after 3906 usecs
[    0.271566] initcall dmi_id_init+0x0/0x334 returned -19 after 0 usecs

 

3 레벨: arch_initcall_sync()

[    0.272148] initcall iproc_gpio_init+0x0/0x20 returned 0 after 0 usecs
[    0.374345] initcall of_platform_default_populate_init+0x0/0x78 returned 0 after 85937 usecs

 

4 레벨: subsys_initcall()

[    0.379095] initcall topology_init+0x0/0xf4 returned 0 after 3906 usecs
[    0.379245] initcall uid_cache_init+0x0/0xa8 returned 0 after 0 usecs
[    0.547249] initcall param_sysfs_init+0x0/0x1b4 returned 0 after 140625 usecs
[    0.547505] initcall user_namespace_sysctl_init+0x0/0x4c returned 0 after 0 usecs
[    0.554072] initcall pm_sysrq_init+0x0/0x24 returned 0 after 3906 usecs
[    0.554137] initcall create_proc_profile+0x0/0xe8 returned 0 after 0 usecs
[    0.554859] initcall crash_save_vmcoreinfo_init+0x0/0x52c returned 0 after 0 usecs
[    0.554941] initcall crash_notes_memory_init+0x0/0x3c returned 0 after 0 usecs
[    0.554978] initcall cgroup_namespaces_init+0x0/0x8 returned 0 after 0 usecs
[    0.555111] initcall user_namespaces_init+0x0/0x38 returned 0 after 0 usecs
[    0.568422] initcall oom_init+0x0/0x6c returned 0 after 11718 usecs
[    0.570858] initcall default_bdi_init+0x0/0xa4 returned 0 after 0 usecs
[    0.570911] initcall percpu_enable_async+0x0/0x14 returned 0 after 0 usecs
[    0.571306] initcall kcompactd_init+0x0/0xbc returned 0 after 0 usecs
[    0.571350] initcall init_reserve_notifier+0x0/0x8 returned 0 after 0 usecs
[    0.571413] initcall init_admin_reserve+0x0/0x30 returned 0 after 0 usecs
[    0.571459] initcall init_user_reserve+0x0/0x30 returned 0 after 0 usecs
[    0.571562] initcall swap_init_sysfs+0x0/0x78 returned 0 after 0 usecs
[    0.572016] initcall swapfile_init+0x0/0xd8 returned 0 after 3906 usecs
[    0.573415] initcall hugetlb_init+0x0/0x47c returned 0 after 0 usecs
[    0.574489] initcall ksm_init+0x0/0x194 returned 0 after 0 usecs
[    0.575332] initcall hugepage_init+0x0/0x158 returned 0 after 0 usecs
[    0.575419] initcall mem_cgroup_swap_init+0x0/0x7c returned 0 after 0 usecs
[    0.575725] initcall mem_cgroup_init+0x0/0x190 returned 0 after 0 usecs
[    0.576955] initcall crypto_wq_init+0x0/0x44 returned 0 after 3906 usecs
[    0.577026] initcall cryptomgr_init+0x0/0x1c returned 0 after 0 usecs
[    0.577257] initcall cryptd_init+0x0/0xe4 returned 0 after 0 usecs
[    0.578228] initcall init_bio+0x0/0xec returned 0 after 0 usecs
[    0.578280] initcall blk_settings_init+0x0/0x30 returned 0 after 0 usecs
[    0.578363] initcall blk_ioc_init+0x0/0x38 returned 0 after 0 usecs
[    0.578458] initcall blk_softirq_init+0x0/0xa4 returned 0 after 0 usecs
[    0.578503] initcall blk_mq_init+0x0/0x38 returned 0 after 0 usecs
[    0.582086] initcall genhd_device_init+0x0/0x94 returned 0 after 3906 usecs
[    0.582163] initcall gpiolib_debugfs_init+0x0/0x38 returned 0 after 0 usecs
[    0.582368] initcall pca953x_init+0x0/0x20 returned 0 after 0 usecs
[    0.582445] initcall pwm_debugfs_init+0x0/0x38 returned 0 after 0 usecs
[    0.582551] initcall pwm_sysfs_init+0x0/0x28 returned 0 after 0 usecs
[    0.582644] initcall pci_slot_init+0x0/0x58 returned 0 after 0 usecs
[    0.583008] initcall xgene_pcie_msi_init+0x0/0x20 returned 0 after 0 usecs
[    0.583917] initcall fbmem_init+0x0/0x100 returned 0 after 0 usecs
[    0.584243] initcall acpi_init+0x0/0x334 returned -19 after 0 usecs
[    0.584436] initcall pnp_init+0x0/0x1c returned 0 after 0 usecs
[    0.584679] initcall s2mps11_clk_init+0x0/0x20 returned 0 after 0 usecs
[    0.584993] initcall hi6220_stub_clk_init+0x0/0x20 returned 0 after 0 usecs
[    0.586440] initcall cpg_mssr_init+0x0/0x28 returned -19 after 3906 usecs
[    0.586493] initcall balloon_init+0x0/0xd8 returned -19 after 0 usecs
[    0.586547] initcall xen_setup_shutdown_event+0x0/0x48 returned -19 after 0 usecs
[    0.586756] initcall xenbus_probe_backend_init+0x0/0x3c returned 0 after 0 usecs
[    0.586908] initcall xenbus_probe_frontend_init+0x0/0x3c returned 0 after 0 usecs
[    0.587323] initcall regulator_fixed_voltage_init+0x0/0x20 returned 0 after 0 usecs
[    0.587637] initcall gpio_regulator_init+0x0/0x20 returned 0 after 0 usecs
[    0.588079] initcall rpm_reg_init+0x0/0x20 returned 0 after 0 usecs
[    0.593126] initcall misc_init+0x0/0xe4 returned 0 after 3906 usecs
[    0.593282] initcall rk_iommu_init+0x0/0x9c returned 0 after 0 usecs
[    0.594535] initcall vga_arb_device_init+0x0/0xfc returned 0 after 0 usecs
[    0.594650] initcall register_cpu_capacity_sysctl+0x0/0x98 returned 0 after 0 usecs
[    0.595211] initcall sec_pmic_init+0x0/0x20 returned 0 after 0 usecs
[    0.595352] initcall dma_buf_init+0x0/0x98 returned 0 after 0 usecs
[    0.602516] initcall init_scsi+0x0/0x8c returned 0 after 7812 usecs
[    0.609111] initcall ata_init+0x0/0x338 returned 0 after 3906 usecs
[    0.609302] initcall pl022_init+0x0/0x1c returned 0 after 0 usecs
[    0.609785] initcall phy_init+0x0/0x78 returned 0 after 0 usecs
[    0.609921] initcall hnae_init+0x0/0x40 returned 0 after 0 usecs
[    0.613279] initcall usb_init+0x0/0x180 returned 0 after 3906 usecs
[    0.613813] initcall usb_phy_generic_init+0x0/0x20 returned 0 after 0 usecs
[    0.614019] initcall usb_udc_init+0x0/0x64 returned 0 after 0 usecs
[    0.614263] initcall serio_init+0x0/0x44 returned 0 after 0 usecs
[    0.615323] initcall input_init+0x0/0x128 returned 0 after 0 usecs
[    0.615478] initcall rtc_init+0x0/0x68 returned 0 after 0 usecs
[    0.616360] initcall dw_i2c_init_driver+0x0/0x20 returned 0 after 3906 usecs
[    0.617258] initcall i2c_adap_imx_init+0x0/0x20 returned 0 after 0 usecs
[    0.617753] initcall i2c_adap_pxa_init+0x0/0x20 returned 0 after 0 usecs
[    0.618487] initcall sh_mobile_i2c_adap_init+0x0/0x20 returned 0 after 0 usecs
[    0.619106] initcall tegra_i2c_init_driver+0x0/0x20 returned 0 after 0 usecs
[    0.635798] initcall pps_init+0x0/0xd0 returned 0 after 15625 usecs
[    0.636361] initcall ptp_init+0x0/0xb0 returned 0 after 0 usecs
[    0.636891] initcall brcmstb_reboot_init+0x0/0x28 returned -19 after 0 usecs
[    0.637068] initcall power_supply_class_init+0x0/0x60 returned 0 after 0 usecs
[    0.637178] initcall hwmon_init+0x0/0x48 returned 0 after 0 usecs
[    0.640240] initcall edac_init+0x0/0x90 returned 0 after 3906 usecs
[    0.640770] initcall mmc_init+0x0/0x4c returned 0 after 0 usecs
[    0.640921] initcall leds_init+0x0/0x5c returned 0 after 0 usecs
[    0.641354] initcall dmi_init+0x0/0x11c returned -61 after 0 usecs
[    0.641474] initcall qcom_scm_init+0x0/0x7c returned -19 after 0 usecs
[    0.641544] initcall efisubsys_init+0x0/0x26c returned 0 after 0 usecs
[    0.641590] initcall register_gop_device+0x0/0x64 returned 0 after 0 usecs
[    0.642107] initcall qcom_smd_init+0x0/0x24 returned 0 after 0 usecs
[    0.642548] initcall iio_init+0x0/0xac returned 0 after 0 usecs
[    0.642650] initcall arm_pmu_hp_init+0x0/0x60 returned 0 after 0 usecs
[    0.642717] initcall arm_pmu_acpi_init+0x0/0x1e8 returned 0 after 0 usecs
[    0.642957] initcall ras_init+0x0/0x18 returned 0 after 0 usecs
[    0.643260] initcall nvmem_init+0x0/0x20 returned 0 after 0 usecs
[    0.645159] initcall tee_init+0x0/0xac returned 0 after 0 usecs
[    0.646417] initcall init_soundcore+0x0/0x58 returned 0 after 0 usecs
[    0.648290] initcall alsa_sound_init+0x0/0xb8 returned 0 after 0 usecs
[    0.653378] initcall proto_init+0x0/0x1c returned 0 after 3906 usecs
[    0.659593] initcall net_dev_init+0x0/0x1f4 returned 0 after 7812 usecs
[    0.659668] initcall neigh_init+0x0/0xa0 returned 0 after 0 usecs
[    0.659724] initcall fib_notifier_init+0x0/0x1c returned 0 after 0 usecs
[    0.660292] initcall genl_init+0x0/0x4c returned 0 after 0 usecs
[    0.660368] initcall ipv4_netfilter_init+0x0/0x1c returned 0 after 0 usecs

 

4 레벨: subsys_initcall_sync()

[    0.663834] initcall watchdog_init+0x0/0x90 returned 0 after 3906 usecs

 

5 레벨: fs_initcall()

[    0.664462] initcall create_debug_debugfs_entry+0x0/0x30 returned 0 after 0 usecs
[    0.664502] initcall dma_debug_do_init+0x0/0x8 returned 0 after 0 usecs
[    0.666317] initcall clocksource_done_booting+0x0/0x58 returned 0 after 1403 usecs
[    0.668279] initcall init_pipe_fs+0x0/0x60 returned 0 after 1855 usecs
[    0.668480] initcall cgroup_writeback_init+0x0/0x44 returned 0 after 142 usecs
[    0.668640] initcall inotify_user_setup+0x0/0x5c returned 0 after 106 usecs
[    0.668859] initcall eventpoll_init+0x0/0xd4 returned 0 after 164 usecs
[    0.670573] initcall anon_inode_init+0x0/0x6c returned 0 after 1616 usecs
[    0.670691] initcall proc_locks_init+0x0/0x34 returned 0 after 67 usecs
[    0.671856] initcall dquot_init+0x0/0x168 returned 0 after 1091 usecs
[    0.671952] initcall proc_cmdline_init+0x0/0x30 returned 0 after 54 usecs
[    0.672014] initcall proc_consoles_init+0x0/0x30 returned 0 after 23 usecs
[    0.672079] initcall proc_cpuinfo_init+0x0/0x30 returned 0 after 25 usecs
[    0.672162] initcall proc_devices_init+0x0/0x30 returned 0 after 25 usecs
[    0.672222] initcall proc_interrupts_init+0x0/0x30 returned 0 after 22 usecs
[    0.672284] initcall proc_loadavg_init+0x0/0x30 returned 0 after 23 usecs
[    0.672371] initcall proc_meminfo_init+0x0/0x30 returned 0 after 47 usecs
[    0.672436] initcall proc_stat_init+0x0/0x30 returned 0 after 26 usecs
[    0.672499] initcall proc_uptime_init+0x0/0x30 returned 0 after 22 usecs
[    0.672563] initcall proc_version_init+0x0/0x30 returned 0 after 24 usecs
[    0.672623] initcall proc_softirqs_init+0x0/0x30 returned 0 after 21 usecs
[    0.672724] initcall vmcore_init+0x0/0x580 returned 0 after 60 usecs
[    0.672790] initcall proc_kmsg_init+0x0/0x30 returned 0 after 26 usecs
[    0.672876] initcall proc_page_init+0x0/0x6c returned 0 after 45 usecs
[    0.672922] initcall init_ramfs_fs+0x0/0x3c returned 0 after 9 usecs
[    0.674538] initcall init_hugetlbfs_fs+0x0/0x158 returned 0 after 1522 usecs
[    0.674614] initcall blk_scsi_ioctl_init+0x0/0xa4 returned 0 after 25 usecs
[    0.674675] initcall acpi_event_init+0x0/0x44 returned 0 after 17 usecs
[    0.674947] initcall pnp_system_init+0x0/0x1c returned 0 after 222 usecs
[    0.675284] initcall pnpacpi_init+0x0/0x8c returned 0 after 288 usecs
[    0.742028] initcall chr_dev_init+0x0/0xcc returned 0 after 65106 usecs
[    0.742135] initcall firmware_class_init+0x0/0xb8 returned 0 after 51 usecs
[    0.744481] initcall thermal_init+0x0/0xec returned 0 after 2218 usecs
[    0.744617] initcall cpufreq_gov_performance_init+0x0/0x1c returned 0 after 72 usecs
[    0.744849] initcall sysctl_core_init+0x0/0x40 returned 0 after 184 usecs
[    0.744974] initcall eth_offload_init+0x0/0x20 returned 0 after 68 usecs
[    0.776668] initcall inet_init+0x0/0x260 returned 0 after 30887 usecs
[    0.776794] initcall ipv4_offload_init+0x0/0x80 returned 0 after 72 usecs
[    0.778001] initcall af_unix_init+0x0/0x64 returned 0 after 1119 usecs
[    0.778153] initcall ipv6_offload_init+0x0/0x84 returned 0 after 104 usecs
[    0.787329] initcall init_sunrpc+0x0/0x84 returned 0 after 8894 usecs

 

5 레벨: fs_initcall_sync()

[    0.787473] initcall pci_apply_final_quirks+0x0/0x140 returned 0 after 94 usecs
[    0.787601] initcall acpi_reserve_resources+0x0/0xfc returned 0 after 85 usecs

 

rootfs 레벨: rootfs_initcall_sync()

[    0.790338] initcall populate_rootfs+0x0/0x134 returned 0 after 2594 usecs

 

__ 레벨: early_initcall_sync()

[    0.790986] initcall register_kernel_offset_dumper+0x0/0x28 returned 0 after 107 usecs

 

6 레벨: device_initcall_sync() 또는 module_

[    0.791836] initcall cpuinfo_regs_init+0x0/0xc4 returned 0 after 780 usecs
[    0.791913] initcall register_cpu_hwcaps_dumper+0x0/0x28 returned 0 after 21 usecs
[    0.796165] initcall armv8_pmu_driver_init+0x0/0x3c returned 0 after 4047 usecs
[    0.796243] initcall register_mem_limit_dumper+0x0/0x2c returned 0 after 16 usecs
[    0.796701] initcall arm_init+0x0/0x28 returned -19 after 387 usecs
[    0.799885] initcall cpu_feature_match_SHA1_init+0x0/0x30 returned 0 after 3021 usecs
[    0.801951] initcall cpu_feature_match_SHA2_init+0x0/0x34 returned 0 after 1894 usecs
[    0.803528] initcall ghash_ce_mod_init+0x0/0x98 returned 0 after 1448 usecs
[    0.804428] initcall cpu_feature_match_AES_init+0x0/0x30 returned 0 after 797 usecs
[    0.804948] initcall aes_mod_init+0x0/0x30 returned 0 after 442 usecs
[    0.816877] initcall cpu_feature_match_AES_init+0x0/0xcc returned 0 after 10510 usecs
[    0.819621] initcall sha256_mod_init+0x0/0x70 returned 0 after 2593 usecs
[    0.820286] initcall aes_init+0x0/0x1c returned 0 after 586 usecs
[    0.820537] initcall proc_execdomains_init+0x0/0x30 returned 0 after 196 usecs
[    0.820779] initcall cpuhp_sysfs_init+0x0/0x9c returned 0 after 191 usecs
[    0.820864] initcall ioresources_init+0x0/0x54 returned 0 after 41 usecs
[    0.821957] initcall snapshot_device_init+0x0/0x1c returned 0 after 1018 usecs
[    0.822012] initcall irq_gc_init_ops+0x0/0x24 returned 0 after 13 usecs
[    0.822104] initcall irq_debugfs_init+0x0/0x40 returned 0 after 53 usecs
[    0.822148] initcall irq_pm_init_ops+0x0/0x20 returned 0 after 10 usecs
[    0.823233] initcall irq_debugfs_init+0x0/0xa4 returned 0 after 1006 usecs
[    0.823294] initcall timekeeping_init_ops+0x0/0x20 returned 0 after 16 usecs
[    0.824201] initcall init_clocksource_sysfs+0x0/0x78 returned 0 after 803 usecs
[    0.824837] initcall init_timer_list_procfs+0x0/0x38 returned 0 after 545 usecs
[    0.830739] initcall alarmtimer_init+0x0/0x104 returned 0 after 5651 usecs
[    0.830889] initcall init_posix_timers+0x0/0x38 returned 0 after 91 usecs
[    0.838299] initcall clockevents_init_sysfs+0x0/0x108 returned 0 after 7163 usecs
[    0.838368] initcall sched_clock_syscore_init+0x0/0x24 returned 0 after 15 usecs
[    0.838855] initcall proc_modules_init+0x0/0x30 returned 0 after 435 usecs
[    0.839191] initcall kallsyms_init+0x0/0x30 returned 0 after 287 usecs
[    0.839360] initcall pid_namespaces_init+0x0/0x38 returned 0 after 124 usecs
[    0.839717] initcall ikconfig_init+0x0/0x44 returned 0 after 308 usecs
[    0.842610] initcall audit_init+0x0/0x158 returned 0 after 2762 usecs
[    0.842769] initcall audit_watch_init+0x0/0x40 returned 0 after 99 usecs
[    0.842826] initcall audit_fsnotify_init+0x0/0x40 returned 0 after 19 usecs
[    0.842919] initcall audit_tree_init+0x0/0x68 returned 0 after 53 usecs
[    0.843048] initcall seccomp_sysctl_init+0x0/0x38 returned 0 after 88 usecs
[    0.843123] initcall utsname_sysctl_init+0x0/0x20 returned 0 after 36 usecs
[    0.847383] initcall perf_event_sysfs_init+0x0/0xb8 returned 0 after 4039 usecs
[    0.848077] initcall kswapd_init+0x0/0xac returned 0 after 587 usecs
[    0.848410] initcall extfrag_debug_init+0x0/0x90 returned 0 after 253 usecs
[    0.848515] initcall mm_compute_batch_init+0x0/0x60 returned 0 after 44 usecs
[    0.849579] initcall slab_proc_init+0x0/0x30 returned 0 after 657 usecs
[    0.851874] initcall workingset_init+0x0/0xa8 returned 0 after 673 usecs
[    0.852271] initcall proc_vmalloc_init+0x0/0x30 returned 0 after 342 usecs
[    0.852531] initcall memblock_init_debugfs+0x0/0x8c returned 0 after 199 usecs
[    0.852602] initcall procswaps_init+0x0/0x34 returned 0 after 27 usecs
[    0.905566] initcall slab_sysfs_init+0x0/0x124 returned 0 after 51089 usecs
[    0.907179] initcall fcntl_init+0x0/0x38 returned 0 after 106 usecs
[    0.907569] initcall proc_filesystems_init+0x0/0x30 returned 0 after 338 usecs
[    0.907661] initcall start_dirtytime_writeback+0x0/0x3c returned 0 after 52 usecs
[    0.907835] initcall blkdev_init+0x0/0x38 returned 0 after 130 usecs
[    0.908349] initcall dio_init+0x0/0x38 returned 0 after 455 usecs
[    0.908758] initcall dnotify_init+0x0/0x88 returned 0 after 351 usecs
[    0.908889] initcall fanotify_user_setup+0x0/0x84 returned 0 after 87 usecs
[    0.909175] initcall aio_setup+0x0/0x94 returned 0 after 235 usecs
[    0.915272] initcall init_sys32_ioctl+0x0/0x34 returned 0 after 5885 usecs
[    0.915870] initcall mbcache_init+0x0/0x44 returned 0 after 521 usecs
[    0.915961] initcall init_grace+0x0/0x1c returned 0 after 47 usecs
[    0.916322] initcall init_devpts_fs+0x0/0x3c returned 0 after 313 usecs
[    0.919777] initcall ext4_init_fs+0x0/0x160 returned 0 after 3307 usecs
[    0.920333] initcall init_ext2_fs+0x0/0x78 returned 0 after 481 usecs
[    0.928362] initcall journal_init+0x0/0x110 returned 0 after 7765 usecs
[    0.930268] initcall init_squashfs_fs+0x0/0x88 returned 0 after 1768 usecs
[    0.932008] initcall init_fat_fs+0x0/0x5c returned 0 after 1628 usecs
[    0.932398] initcall init_vfat_fs+0x0/0x1c returned 0 after 327 usecs
[    0.938506] initcall init_nfs_fs+0x0/0x150 returned 0 after 5898 usecs
[    0.938626] initcall init_nfs_v2+0x0/0x20 returned 0 after 44 usecs
[    0.938668] initcall init_nfs_v3+0x0/0x20 returned 0 after 9 usecs
[    0.940279] initcall init_nfs_v4+0x0/0x48 returned 0 after 1532 usecs
[    0.940758] initcall nfs4filelayout_init+0x0/0x34 returned 0 after 428 usecs
[    0.943165] initcall init_nlm+0x0/0x88 returned 0 after 2254 usecs
[    0.943361] initcall init_nls_cp437+0x0/0x20 returned 0 after 121 usecs
[    0.943542] initcall init_nls_iso8859_1+0x0/0x20 returned 0 after 13 usecs
[    0.952865] initcall init_cifs+0x0/0x350 returned 0 after 9029 usecs
[    0.954912] initcall init_autofs4_fs+0x0/0x38 returned 0 after 1327 usecs
[    0.955893] initcall init_v9fs+0x0/0xfc returned 0 after 902 usecs
[    0.956240] initcall init_pstore_fs+0x0/0x64 returned 0 after 292 usecs
[    0.956286] initcall efivarfs_init+0x0/0x44 returned -19 after 8 usecs
[    0.959594] initcall ipc_init+0x0/0x64 returned 0 after 3154 usecs
[    0.959729] initcall ipc_sysctl_init+0x0/0x20 returned 0 after 75 usecs
[    0.961814] initcall init_mqueue_fs+0x0/0x104 returned 0 after 1930 usecs
[    0.964280] initcall key_proc_init+0x0/0x74 returned 0 after 2290 usecs
[    0.964574] initcall crypto_algapi_init+0x0/0x18 returned 0 after 215 usecs
[    0.964657] initcall seqiv_module_init+0x0/0x1c returned 0 after 43 usecs
[    0.964709] initcall echainiv_module_init+0x0/0x1c returned 0 after 15 usecs
[    0.964755] initcall crypto_cmac_module_init+0x0/0x1c returned 0 after 10 usecs
[    0.964799] initcall hmac_module_init+0x0/0x1c returned 0 after 10 usecs
[    0.967749] initcall crypto_null_mod_init+0x0/0x58 returned 0 after 2805 usecs
[    0.968429] initcall md4_mod_init+0x0/0x1c returned 0 after 576 usecs
[    0.970118] initcall md5_mod_init+0x0/0x1c returned 0 after 1568 usecs
[    0.971357] initcall sha1_generic_mod_init+0x0/0x1c returned 0 after 1123 usecs
[    0.973454] initcall sha256_generic_mod_init+0x0/0x20 returned 0 after 1965 usecs
[    0.973525] initcall crypto_ecb_module_init+0x0/0x1c returned 0 after 18 usecs
[    0.973593] initcall crypto_ctr_module_init+0x0/0x58 returned 0 after 30 usecs
[    0.973698] initcall crypto_ccm_module_init+0x0/0x90 returned 0 after 66 usecs
[    0.974890] initcall des_generic_mod_init+0x0/0x20 returned 0 after 1114 usecs
[    0.975638] initcall aes_init+0x0/0x1c returned 0 after 632 usecs
[    0.976787] initcall arc4_init+0x0/0x20 returned 0 after 1026 usecs
[    0.979462] initcall crc32c_mod_init+0x0/0x1c returned 0 after 2527 usecs
[    0.980201] initcall crct10dif_mod_init+0x0/0x1c returned 0 after 657 usecs
[    0.980644] initcall prng_mod_init+0x0/0x20 returned 0 after 379 usecs
[    0.988584] initcall drbg_init+0x0/0x1dc returned 0 after 7681 usecs
[    0.991197] initcall jent_mod_init+0x0/0x3c returned 0 after 2484 usecs
[    0.991501] initcall proc_genhd_init+0x0/0x54 returned 0 after 204 usecs
[    0.992870] initcall bsg_init+0x0/0x150 returned 0 after 1269 usecs
[    0.994240] initcall noop_init+0x0/0x1c returned 0 after 1282 usecs
[    0.995532] initcall cfq_init+0x0/0x74 returned 0 after 1209 usecs
[    0.995950] initcall deadline_init+0x0/0x1c returned 0 after 364 usecs
[    0.996254] initcall kyber_init+0x0/0x1c returned 0 after 256 usecs
[    0.996391] initcall crc_t10dif_mod_init+0x0/0x50 returned 0 after 94 usecs
[    0.998384] initcall percpu_counter_startup+0x0/0x6c returned 0 after 1855 usecs
[    0.998750] initcall audit_classes_init+0x0/0xb0 returned 0 after 233 usecs
[    0.999272] initcall sg_pool_init+0x0/0x108 returned 0 after 432 usecs
[    0.999858] initcall mbigen_platform_driver_init+0x0/0x20 returned 0 after 506 usecs
[    1.000271] initcall mvebu_gicp_driver_init+0x0/0x20 returned 0 after 354 usecs
[    1.000592] initcall mvebu_icu_driver_init+0x0/0x20 returned 0 after 268 usecs
[    1.001282] initcall mvebu_pic_driver_init+0x0/0x20 returned 0 after 291 usecs
[    1.003670] initcall ls_scfg_msi_driver_init+0x0/0x24 returned 0 after 1257 usecs
[    1.004119] initcall qcom_irq_combiner_probe_init+0x0/0x20 returned 0 after 358 usecs
[    1.005098] initcall uniphier_aidet_driver_init+0x0/0x20 returned 0 after 884 usecs
[    1.007038] initcall brcm_gisb_driver_init+0x0/0x28 returned -19 after 1802 usecs
[    1.007642] initcall qcom_ebi2_driver_init+0x0/0x20 returned 0 after 520 usecs
[    1.008102] initcall sunxi_rsb_init+0x0/0x54 returned 0 after 402 usecs
[    1.008419] initcall uniphier_system_bus_driver_init+0x0/0x20 returned 0 after 263 usecs
[    1.008555] initcall phy_core_init+0x0/0x68 returned 0 after 90 usecs
[    1.008955] initcall xgene_phy_driver_init+0x0/0x20 returned 0 after 329 usecs
[    1.015040] initcall sun4i_usb_phy_driver_init+0x0/0x20 returned 0 after 5828 usecs
[    1.015665] initcall phy_meson8b_usb2_driver_init+0x0/0x20 returned 0 after 546 usecs
[    1.016212] initcall phy_meson_gxl_usb2_driver_init+0x0/0x20 returned 0 after 479 usecs
[    1.016751] initcall rcar_gen3_phy_usb2_driver_init+0x0/0x20 returned 0 after 412 usecs
[    1.017076] initcall rockchip_emmc_driver_init+0x0/0x20 returned 0 after 271 usecs
[    1.017512] initcall rockchip_usb2phy_driver_init+0x0/0x20 returned 0 after 376 usecs
[    1.028836] initcall tegra_xusb_padctl_driver_init+0x0/0x24 returned 0 after 10990 usecs
[    1.029373] initcall mdio_module_init+0x0/0x1c returned 0 after 439 usecs
[    1.029720] initcall ns2_drd_phy_driver_init+0x0/0x20 returned 0 after 290 usecs
[    1.030199] initcall brcm_sata_phy_driver_init+0x0/0x20 returned 0 after 420 usecs
[    1.030585] initcall hi6220_phy_driver_init+0x0/0x20 returned 0 after 329 usecs
[    1.030982] initcall exynos_dp_video_phy_driver_init+0x0/0x20 returned 0 after 339 usecs
[    1.031486] initcall exynos_mipi_video_phy_driver_init+0x0/0x20 returned 0 after 428 usecs
[    1.031820] initcall samsung_usb2_phy_driver_init+0x0/0x20 returned 0 after 263 usecs
[    1.032258] initcall exynos5_usb3drd_phy_init+0x0/0x20 returned 0 after 378 usecs
[    1.032497] initcall max77620_pinctrl_driver_init+0x0/0x20 returned 0 after 185 usecs
[    1.039774] initcall meson_pinctrl_driver_init+0x0/0x20 returned 0 after 7032 usecs
[    1.040447] initcall pcs_driver_init+0x0/0x20 returned 0 after 593 usecs
[    1.040800] initcall tegra124_pinctrl_driver_init+0x0/0x20 returned 0 after 294 usecs
[    1.045937] initcall tegra210_pinctrl_driver_init+0x0/0x20 returned 0 after 4945 usecs
[    1.046327] initcall bcm2835_pinctrl_driver_init+0x0/0x24 returned 0 after 319 usecs
[    1.046681] initcall armada_ap806_pinctrl_driver_init+0x0/0x20 returned 0 after 297 usecs
[    1.047099] initcall armada_cp110_pinctrl_driver_init+0x0/0x20 returned 0 after 360 usecs
[    1.047581] initcall armada_37xx_pinctrl_driver_init+0x0/0x28 returned -19 after 419 usecs
[    1.048072] initcall pmic_gpio_driver_init+0x0/0x20 returned 0 after 430 usecs
[    1.048606] initcall pmic_mpp_driver_init+0x0/0x20 returned 0 after 473 usecs
[    1.049113] initcall a64_pinctrl_driver_init+0x0/0x20 returned 0 after 433 usecs
[    1.056448] initcall sun50i_a64_r_pinctrl_driver_init+0x0/0x20 returned 0 after 642 usecs
[    1.056865] initcall sun8i_h3_r_pinctrl_driver_init+0x0/0x20 returned 0 after 347 usecs
[    1.058279] initcall sun50i_h5_pinctrl_driver_init+0x0/0x20 returned 0 after 1319 usecs
[    1.058663] initcall uniphier_ld11_pinctrl_driver_init+0x0/0x20 returned 0 after 323 usecs
[    1.058991] initcall uniphier_ld20_pinctrl_driver_init+0x0/0x20 returned 0 after 275 usecs
[    1.059321] initcall uniphier_pxs3_pinctrl_driver_init+0x0/0x20 returned 0 after 277 usecs
[    1.059823] initcall bgpio_driver_init+0x0/0x20 returned 0 after 443 usecs
[    1.060156] initcall brcmstb_gpio_driver_init+0x0/0x20 returned 0 after 277 usecs
[    1.060573] initcall dwapb_gpio_driver_init+0x0/0x20 returned 0 after 345 usecs
[    1.060855] initcall max77620_gpio_driver_init+0x0/0x20 returned 0 after 217 usecs
[    1.063868] initcall mvebu_gpio_driver_init+0x0/0x20 returned 0 after 2780 usecs
[    1.064304] initcall pl061_gpio_init+0x0/0x1c returned 0 after 319 usecs
[    1.067876] initcall gpio_rcar_device_driver_init+0x0/0x20 returned 0 after 3383 usecs
[    1.068416] initcall xgene_gpio_driver_init+0x0/0x20 returned 0 after 458 usecs
[    1.068747] initcall xgene_gpio_sb_driver_init+0x0/0x20 returned 0 after 275 usecs
[    1.069692] initcall iproc_pwmc_driver_init+0x0/0x20 returned 0 after 874 usecs
[    1.070125] initcall rockchip_pwm_driver_init+0x0/0x20 returned 0 after 375 usecs
[    1.070636] initcall pwm_samsung_driver_init+0x0/0x20 returned 0 after 453 usecs
[    1.071312] initcall pci_proc_init+0x0/0x88 returned 0 after 608 usecs
[    1.071759] initcall pcie_portdrv_init+0x0/0xa4 returned 0 after 390 usecs
[    1.072022] initcall aer_service_init+0x0/0x4c returned 0 after 213 usecs
[    1.072142] initcall pcie_pme_service_init+0x0/0x1c returned 0 after 76 usecs
[    1.072178] initcall pci_hotplug_init+0x0/0x8 returned 0 after 3 usecs
[    1.072337] initcall pcied_init+0x0/0x7c returned 0 after 116 usecs
[    1.072679] initcall advk_pcie_driver_init+0x0/0x20 returned 0 after 289 usecs
[    1.077727] initcall rcar_pcie_driver_init+0x0/0x20 returned 0 after 4858 usecs
[    1.115609] initcall gen_pci_driver_init+0x0/0x20 returned 0 after 36874 usecs
[    1.116331] initcall iproc_pcie_pltfm_driver_init+0x0/0x20 returned 0 after 623 usecs
[    1.116655] initcall xgene_pcie_driver_init+0x0/0x20 returned 0 after 265 usecs
[    1.117921] initcall ls_pcie_driver_init+0x0/0x28 returned -19 after 1183 usecs
[    1.118455] initcall qcom_pcie_driver_init+0x0/0x20 returned 0 after 469 usecs
[    1.118854] initcall armada8k_pcie_driver_init+0x0/0x20 returned 0 after 342 usecs
[    1.119235] initcall kirin_pcie_driver_init+0x0/0x20 returned 0 after 315 usecs
[    1.119634] initcall hisi_pcie_almost_ecam_driver_init+0x0/0x24 returned 0 after 340 usecs
[    1.119989] initcall hisi_pcie_driver_init+0x0/0x20 returned 0 after 299 usecs
[    1.120235] initcall amba_clcdfb_init+0x0/0x3c returned 0 after 196 usecs
[    1.120284] initcall xenfb_init+0x0/0x54 returned -19 after 11 usecs
[    1.120550] initcall ged_driver_init+0x0/0x20 returned 0 after 214 usecs
[    1.120622] initcall acpi_button_driver_init+0x0/0x20 returned -19 after 31 usecs
[    1.120868] initcall acpi_fan_driver_init+0x0/0x20 returned 0 after 196 usecs
[    1.121381] initcall acpi_processor_driver_init+0x0/0xb0 returned 0 after 451 usecs
[    1.128339] initcall acpi_thermal_init+0x0/0x94 returned -19 after 6683 usecs
[    1.128410] initcall acpi_hed_driver_init+0x0/0x20 returned -19 after 11 usecs
[    1.128503] initcall erst_init+0x0/0x2d4 returned 0 after 55 usecs
[    1.128566] initcall ghes_init+0x0/0x210 returned -19 after 27 usecs
[    1.128631] initcall gtdt_sbsa_gwdt_init+0x0/0xe4 returned 0 after 25 usecs
[    1.130444] initcall tegra_ahb_driver_init+0x0/0x20 returned 0 after 1707 usecs
[    1.131101] initcall of_fixed_factor_clk_driver_init+0x0/0x20 returned 0 after 550 usecs
[    1.131651] initcall of_fixed_clk_driver_init+0x0/0x20 returned 0 after 472 usecs
[    1.132171] initcall gpio_clk_driver_init+0x0/0x20 returned 0 after 452 usecs
[    1.132329] initcall cs2000_driver_init+0x0/0x20 returned 0 after 111 usecs
[    1.132686] initcall clk_pwm_driver_init+0x0/0x20 returned 0 after 305 usecs
[    1.132963] initcall rk808_clkout_driver_init+0x0/0x20 returned 0 after 223 usecs
[    1.133309] initcall scpi_clocks_driver_init+0x0/0x20 returned 0 after 291 usecs
[    1.133665] initcall bcm2835_clk_driver_init+0x0/0x20 returned 0 after 300 usecs
[    1.137105] initcall bcm2835_aux_clk_driver_init+0x0/0x20 returned 0 after 3254 usecs
[    1.140914] initcall sr_clk_driver_init+0x0/0x20 returned 0 after 3625 usecs
[    1.142305] initcall gxbb_driver_init+0x0/0x20 returned 0 after 1294 usecs
[    1.142706] initcall gxbb_aoclkc_driver_init+0x0/0x20 returned 0 after 338 usecs
[    1.143107] initcall armada_3700_xtal_clock_driver_init+0x0/0x20 returned 0 after 343 usecs
[    1.143574] initcall armada_3700_tbg_clock_driver_init+0x0/0x20 returned 0 after 381 usecs
[    1.144487] initcall armada_3700_periph_clock_driver_init+0x0/0x20 returned 0 after 748 usecs
[    1.155650] initcall ap806_clock_driver_init+0x0/0x24 returned 0 after 10783 usecs
[    1.156219] initcall ap806_syscon_legacy_driver_init+0x0/0x20 returned 0 after 490 usecs
[    1.156567] initcall cp110_clock_driver_init+0x0/0x24 returned 0 after 290 usecs
[    1.157354] initcall cp110_syscon_legacy_driver_init+0x0/0x20 returned 0 after 712 usecs
[    1.157768] initcall mmcc_msm8996_driver_init+0x0/0x20 returned 0 after 352 usecs
[    1.158271] initcall exynos_audss_clk_driver_init+0x0/0x24 returned 0 after 437 usecs
[    1.158642] initcall sun4i_a10_mod0_clk_driver_init+0x0/0x20 returned 0 after 308 usecs
[    1.159039] initcall sun9i_a80_mmc_config_clk_driver_init+0x0/0x20 returned 0 after 290 usecs
[    1.159432] initcall sun50i_a64_ccu_driver_init+0x0/0x20 returned 0 after 319 usecs
[    1.160553] initcall uniphier_clk_driver_init+0x0/0x20 returned 0 after 1042 usecs
[    1.160917] initcall k3_pdma_driver_init+0x0/0x20 returned 0 after 305 usecs
[    1.161296] initcall mv_xor_v2_driver_init+0x0/0x20 returned 0 after 319 usecs
[    1.161474] initcall pl330_driver_init+0x0/0x1c returned 0 after 128 usecs
[    1.161556] initcall shdma_enter+0x0/0x48 returned 0 after 41 usecs
[    1.162729] initcall shdma_of_init+0x0/0x20 returned 0 after 366 usecs
[    1.163121] initcall rcar_dmac_driver_init+0x0/0x20 returned 0 after 327 usecs
[    1.163821] initcall tegra_dmac_driver_init+0x0/0x20 returned 0 after 601 usecs
[    1.164530] initcall bam_dma_driver_init+0x0/0x20 returned 0 after 619 usecs
[    1.166110] initcall hidma_mgmt_init+0x0/0x6c returned 0 after 1478 usecs
[    1.166561] initcall hidma_driver_init+0x0/0x20 returned 0 after 384 usecs
[    1.166951] initcall rpi_power_driver_init+0x0/0x20 returned 0 after 329 usecs
[    1.167489] initcall scpsys_drv_init+0x0/0x20 returned 0 after 473 usecs
[    1.167616] initcall meson_gx_socinfo_init+0x0/0x268 returned -19 after 80 usecs
[    1.168059] initcall qcom_smp2p_driver_init+0x0/0x20 returned 0 after 384 usecs
[    1.168429] initcall qcom_smsm_driver_init+0x0/0x20 returned 0 after 311 usecs
[    1.168875] initcall sunxi_sram_driver_init+0x0/0x20 returned 0 after 355 usecs
[    1.169047] initcall tegra_init_soc+0x0/0x5c returned 0 after 124 usecs
[    1.170853] initcall tegra_fuse_driver_init+0x0/0x20 returned 0 after 1670 usecs
[    1.171390] initcall tegra_flowctrl_driver_init+0x0/0x20 returned 0 after 446 usecs
[    1.172004] initcall tegra_pmc_driver_init+0x0/0x20 returned 0 after 543 usecs
[    1.172427] initcall tegra186_pmc_driver_init+0x0/0x20 returned 0 after 346 usecs
[    1.200380] initcall virtio_mmio_init+0x0/0x20 returned 0 after 27225 usecs
[    1.207300] initcall virtio_pci_driver_init+0x0/0x28 returned 0 after 6655 usecs
[    1.207725] initcall virtio_balloon_driver_init+0x0/0x1c returned 0 after 343 usecs
[    1.207782] initcall xenbus_probe_initcall+0x0/0x70 returned -19 after 15 usecs
[    1.207822] initcall xenbus_init+0x0/0x54 returned -19 after 6 usecs
[    1.207865] initcall xenbus_backend_init+0x0/0x68 returned -19 after 7 usecs
[    1.207951] initcall evtchn_init+0x0/0x64 returned -19 after 16 usecs
[    1.207993] initcall gntdev_init+0x0/0x6c returned -19 after 7 usecs
[    1.208055] initcall gntalloc_init+0x0/0x54 returned -19 after 23 usecs
[    1.208095] initcall xenfs_init+0x0/0x30 returned 0 after 7 usecs
[    1.208138] initcall hypervisor_subsys_init+0x0/0x2c returned -19 after 8 usecs
[    1.208191] initcall hyper_sysfs_init+0x0/0x138 returned -19 after 20 usecs
[    1.208232] initcall privcmd_init+0x0/0x54 returned -19 after 6 usecs
[    1.208685] initcall axp20x_regulator_driver_init+0x0/0x20 returned 0 after 393 usecs
[    1.208915] initcall fan53555_regulator_driver_init+0x0/0x20 returned 0 after 106 usecs
[    1.212681] initcall hi6421v530_regulator_driver_init+0x0/0x20 returned 0 after 1352 usecs
[    1.213269] initcall hi655x_regulator_driver_init+0x0/0x20 returned 0 after 510 usecs
[    1.214381] initcall max77620_regulator_driver_init+0x0/0x20 returned 0 after 1026 usecs
[    1.215728] initcall qcom_spmi_regulator_driver_init+0x0/0x20 returned 0 after 1191 usecs
[    1.219085] initcall pwm_regulator_driver_init+0x0/0x20 returned 0 after 3185 usecs
[    1.219857] initcall rk808_regulator_driver_init+0x0/0x20 returned 0 after 685 usecs
[    1.220691] initcall s2mps11_pmic_driver_init+0x0/0x20 returned 0 after 758 usecs
[    1.222473] initcall berlin_reset_driver_init+0x0/0x20 returned 0 after 1678 usecs
[    1.225723] initcall meson_reset_driver_init+0x0/0x20 returned 0 after 2448 usecs
[    1.227767] initcall sunxi_reset_driver_init+0x0/0x20 returned 0 after 863 usecs
[    1.229999] initcall uniphier_reset_driver_init+0x0/0x20 returned 0 after 2111 usecs
[    1.230068] initcall n_null_init+0x0/0x28 returned 0 after 20 usecs
[    1.276899] initcall pty_init+0x0/0x39c returned 0 after 45660 usecs
[    1.277958] initcall sysrq_init+0x0/0x90 returned 0 after 425 usecs
[    1.278008] initcall xen_hvc_init+0x0/0x288 returned -19 after 9 usecs
[    1.291375] initcall serial8250_init+0x0/0x17c returned 0 after 12983 usecs
[    1.291891] initcall serial_pci_driver_init+0x0/0x28 returned 0 after 438 usecs
[    1.292565] initcall exar_pci_driver_init+0x0/0x28 returned 0 after 597 usecs
[    1.295918] initcall bcm2835aux_serial_driver_init+0x0/0x20 returned 0 after 3180 usecs
[    1.297914] initcall dw8250_platform_driver_init+0x0/0x20 returned 0 after 1874 usecs
[    1.298605] initcall mtk8250_platform_driver_init+0x0/0x20 returned 0 after 609 usecs
[    1.299982] initcall uniphier_uart_platform_driver_init+0x0/0x20 returned 0 after 1251 usecs
[    1.301123] initcall of_platform_serial_driver_init+0x0/0x20 returned 0 after 1052 usecs
[    1.302984] initcall samsung_serial_driver_init+0x0/0x24 returned 0 after 1738 usecs
[    1.308461] initcall sci_init+0x0/0x34 returned 0 after 5176 usecs
[    1.311928] initcall meson_uart_init+0x0/0x60 returned 0 after 3280 usecs
[    1.315302] initcall msm_serial_init+0x0/0x5c returned 0 after 3215 usecs
[    1.316842] initcall cdns_uart_init+0x0/0x60 returned 0 after 1431 usecs
[    1.318819] initcall tegra_uart_init+0x0/0x88 returned 0 after 1844 usecs
[    1.318990] initcall init_kgdboc+0x0/0x2c returned 0 after 114 usecs
[    1.319537] initcall init+0x0/0x124 returned 0 after 471 usecs
[    1.320263] initcall arm_smmu_driver_init+0x0/0x24 returned 0 after 625 usecs
[    1.322183] initcall arm_smmu_driver_init+0x0/0x24 returned 0 after 1743 usecs
[    1.322510] initcall topology_sysfs_init+0x0/0x38 returned 0 after 255 usecs
[    1.327690] initcall cacheinfo_sysfs_init+0x0/0x38 returned -2 after 4950 usecs
[    1.379986] initcall loop_init+0x0/0x158 returned 0 after 50990 usecs
[    1.434777] initcall init+0x0/0xa8 returned 0 after 53435 usecs
[    1.434887] initcall xlblk_init+0x0/0x10c returned -19 after 23 usecs
[    1.435446] initcall cros_ec_driver_init+0x0/0x20 returned 0 after 501 usecs
[    1.435881] initcall cros_ec_driver_spi_init+0x0/0x20 returned 0 after 376 usecs
[    1.436446] initcall axp20x_rsb_driver_init+0x0/0x1c returned 0 after 503 usecs
[    1.436814] initcall max77620_driver_init+0x0/0x20 returned 0 after 311 usecs
[    1.437737] initcall pmic_spmi_driver_init+0x0/0x20 returned 0 after 851 usecs
[    1.438359] initcall rk808_i2c_driver_init+0x0/0x20 returned 0 after 555 usecs
[    1.439070] initcall hi6421_pmic_driver_init+0x0/0x20 returned 0 after 639 usecs
[    1.439893] initcall hi655x_pmic_driver_init+0x0/0x20 returned 0 after 750 usecs
[    1.443050] initcall sas_transport_init+0x0/0xd0 returned 0 after 3013 usecs
[    1.443241] initcall sas_class_init+0x0/0x44 returned 0 after 78 usecs
[    1.446843] initcall init_sd+0x0/0x184 returned 0 after 3451 usecs
[    1.447391] initcall hisi_sas_init+0x0/0x38 returned 0 after 478 usecs
[    1.449505] initcall hisi_sas_v1_driver_init+0x0/0x20 returned 0 after 2000 usecs
[    1.450612] initcall hisi_sas_v2_driver_init+0x0/0x20 returned 0 after 1017 usecs
[    1.451309] initcall sas_v3_pci_driver_init+0x0/0x28 returned 0 after 626 usecs
[    1.451834] initcall ahci_pci_driver_init+0x0/0x28 returned 0 after 458 usecs
[    1.453128] initcall ahci_driver_init+0x0/0x20 returned 0 after 1174 usecs
[    1.454652] initcall sil24_pci_driver_init+0x0/0x28 returned 0 after 1418 usecs
[    1.455526] initcall ceva_ahci_driver_init+0x0/0x20 returned 0 after 790 usecs
[    1.456835] initcall ahci_mvebu_driver_init+0x0/0x20 returned 0 after 1181 usecs
[    1.460396] initcall xgene_ahci_driver_init+0x0/0x20 returned 0 after 3397 usecs
[    1.461305] initcall ahci_qoriq_driver_init+0x0/0x20 returned 0 after 824 usecs
[    1.463532] initcall sata_rcar_driver_init+0x0/0x20 returned 0 after 2076 usecs
[    1.465937] initcall pata_platform_driver_init+0x0/0x24 returned 0 after 2131 usecs
[    1.468369] initcall pata_of_platform_driver_init+0x0/0x20 returned 0 after 2284 usecs
[    1.470490] initcall init_mtd+0x0/0x138 returned 0 after 2011 usecs
[    1.470597] initcall ofpart_parser_init+0x0/0x3c returned 0 after 61 usecs
[    1.470771] initcall init_mtdblock+0x0/0x1c returned 0 after 133 usecs
[    1.471460] initcall m25p80_driver_init+0x0/0x20 returned 0 after 627 usecs
[    1.472144] initcall denali_dt_driver_init+0x0/0x20 returned 0 after 616 usecs
[    1.473070] initcall bcm_iproc_driver_init+0x0/0x20 returned 0 after 851 usecs
[    1.473737] initcall brcmstb_qspi_driver_init+0x0/0x20 returned 0 after 598 usecs
[    1.475155] initcall orion_spi_driver_init+0x0/0x20 returned 0 after 1330 usecs
[    1.476101] initcall spi_qup_driver_init+0x0/0x20 returned 0 after 869 usecs
[    1.477410] initcall rockchip_spi_driver_init+0x0/0x20 returned 0 after 1225 usecs
[    1.478876] initcall s3c64xx_spi_driver_init+0x0/0x20 returned 0 after 1365 usecs
[    1.479590] initcall spmi_pmic_arb_driver_init+0x0/0x20 returned 0 after 638 usecs
[    1.479772] initcall net_olddevs_init+0x0/0x90 returned 0 after 135 usecs
[    1.481010] initcall mdiomux_iproc_driver_init+0x0/0x20 returned 0 after 1159 usecs
[    1.481822] initcall mdio_mux_mmioreg_driver_init+0x0/0x20 returned 0 after 559 usecs
[    1.483010] initcall xgene_mdio_driver_init+0x0/0x20 returned 0 after 886 usecs
[    1.485688] initcall fixed_mdio_bus_init+0x0/0xe0 returned 0 after 2564 usecs
[    1.493407] initcall phy_module_init+0x0/0x24 returned 0 after 7482 usecs
[    1.493757] initcall phy_module_init+0x0/0x24 returned 0 after 289 usecs
[    1.496330] initcall tun_init+0x0/0xd0 returned 0 after 2454 usecs
[    1.506304] initcall virtio_net_driver_init+0x0/0xb8 returned 0 after 9666 usecs
[    1.507837] initcall xgbe_mod_init+0x0/0x2c returned 0 after 1430 usecs
[    1.508372] initcall xgene_enet_driver_init+0x0/0x20 returned 0 after 470 usecs
[    1.509588] initcall macb_driver_init+0x0/0x20 returned 0 after 1137 usecs
[    1.510060] initcall bgmac_enet_driver_init+0x0/0x20 returned 0 after 411 usecs
[    1.510527] initcall hns_mdio_driver_init+0x0/0x20 returned 0 after 407 usecs
[    1.511005] initcall g_dsaf_driver_init+0x0/0x20 returned 0 after 359 usecs
[    1.511574] initcall hns_nic_dev_driver_init+0x0/0x20 returned 0 after 485 usecs
[    1.512543] initcall e1000_init_module+0x0/0x48 returned 0 after 893 usecs
[    1.520800] initcall igb_init_module+0x0/0x60 returned 0 after 7982 usecs
[    1.522971] initcall igbvf_init_module+0x0/0x5c returned 0 after 2054 usecs
[    1.523578] initcall orion_mdio_driver_init+0x0/0x20 returned 0 after 539 usecs
[    1.524163] initcall mvneta_driver_init+0x0/0xc0 returned 0 after 515 usecs
[    1.524649] initcall mvpp2_driver_init+0x0/0x20 returned 0 after 412 usecs
[    1.530106] initcall sky2_init_module+0x0/0x34 returned 0 after 5234 usecs
[    1.530877] initcall ravb_driver_init+0x0/0x20 returned 0 after 673 usecs
[    1.531788] initcall smc_driver_init+0x0/0x20 returned 0 after 753 usecs
[    1.532662] initcall smsc911x_init_module+0x0/0x20 returned 0 after 740 usecs
[    1.532736] initcall netif_init+0x0/0x78 returned -19 after 13 usecs
[    1.534867] initcall vfio_init+0x0/0x184 returned 0 after 2031 usecs
[    1.540978] initcall vfio_virqfd_init+0x0/0x50 returned 0 after 5896 usecs
[    1.541117] initcall vfio_iommu_type1_init+0x0/0x1c returned 0 after 81 usecs
[    1.542418] initcall vfio_pci_init+0x0/0x140 returned 0 after 1221 usecs
[    1.543172] initcall msm_otg_driver_init+0x0/0x20 returned 0 after 601 usecs
[    1.544077] initcall phy_8x16_driver_init+0x0/0x20 returned 0 after 782 usecs
[    1.544774] initcall dwc3_driver_init+0x0/0x20 returned 0 after 599 usecs
[    1.547131] initcall dwc3_exynos_driver_init+0x0/0x20 returned 0 after 2168 usecs
[    1.547468] initcall dwc3_pci_driver_init+0x0/0x28 returned 0 after 263 usecs
[    1.548097] initcall dwc3_of_simple_driver_init+0x0/0x20 returned 0 after 528 usecs
[    1.548906] initcall dwc2_platform_driver_init+0x0/0x20 returned 0 after 738 usecs
[    1.551572] initcall isp1760_init+0x0/0x68 returned 0 after 2535 usecs
[    1.552055] initcall ehci_hcd_init+0x0/0x70 returned 0 after 416 usecs
[    1.552631] initcall ehci_pci_init+0x0/0x88 returned 0 after 516 usecs
[    1.555084] initcall ehci_platform_init+0x0/0x60 returned 0 after 2330 usecs
[    1.555834] initcall ehci_orion_init+0x0/0x5c returned 0 after 677 usecs
[    1.556731] initcall ehci_exynos_init+0x0/0x5c returned 0 after 822 usecs
[    1.558700] initcall ehci_msm_init+0x0/0x5c returned 0 after 1854 usecs
[    1.559441] initcall ohci_hcd_mod_init+0x0/0x84 returned 0 after 596 usecs
[    1.560067] initcall ohci_pci_init+0x0/0x88 returned 0 after 560 usecs
[    1.560932] initcall ohci_platform_init+0x0/0x60 returned 0 after 795 usecs
[    1.566367] initcall ohci_exynos_init+0x0/0x5c returned 0 after 5234 usecs
[    1.566438] initcall xhci_hcd_init+0x0/0x20 returned 0 after 21 usecs
[    1.566834] initcall xhci_pci_init+0x0/0x5c returned 0 after 343 usecs
[    1.567610] initcall xhci_plat_init+0x0/0x34 returned 0 after 706 usecs
[    1.568097] initcall tegra_xusb_init+0x0/0x34 returned 0 after 421 usecs
[    1.568888] initcall usb_storage_driver_init+0x0/0x48 returned 0 after 721 usecs
[    1.579523] initcall usb3503_init+0x0/0x68 returned 0 after 1214 usecs
[    1.579901] initcall ci_hdrc_platform_register+0x0/0x28 returned 0 after 309 usecs
[    1.580325] initcall ci_hdrc_usb2_driver_init+0x0/0x20 returned 0 after 364 usecs
[    1.580751] initcall ci_hdrc_msm_driver_init+0x0/0x20 returned 0 after 366 usecs
[    1.581173] initcall ci_hdrc_zevio_driver_init+0x0/0x20 returned 0 after 362 usecs
[    1.582138] initcall ci_hdrc_pci_driver_init+0x0/0x28 returned 0 after 887 usecs
[    1.582876] initcall usbmisc_imx_driver_init+0x0/0x20 returned 0 after 669 usecs
[    1.583561] initcall ci_hdrc_imx_driver_init+0x0/0x20 returned 0 after 609 usecs
[    1.584318] initcall tegra_udc_driver_init+0x0/0x20 returned 0 after 614 usecs
[    1.585080] initcall udc_plat_driver_init+0x0/0x20 returned 0 after 660 usecs
[    1.592688] initcall bdc_driver_init+0x0/0x20 returned 0 after 7347 usecs
[    1.593717] initcall bdc_pci_driver_init+0x0/0x28 returned 0 after 935 usecs
[    1.593886] initcall ambakmi_driver_init+0x0/0x1c returned 0 after 114 usecs
[    1.593944] initcall input_leds_init+0x0/0x1c returned 0 after 19 usecs
[    1.593990] initcall evdev_init+0x0/0x1c returned 0 after 10 usecs
[    1.594579] initcall atkbd_init+0x0/0x34 returned 0 after 517 usecs
[    1.595613] initcall cros_ec_keyb_driver_init+0x0/0x20 returned 0 after 942 usecs
[    1.596091] initcall psmouse_init+0x0/0xa8 returned 0 after 413 usecs
[    1.596683] initcall hi65xx_powerkey_driver_init+0x0/0x20 returned 0 after 524 usecs
[    1.597103] initcall pm8941_pwrkey_driver_init+0x0/0x20 returned 0 after 357 usecs
[    1.597157] initcall xenkbd_init+0x0/0x50 returned -19 after 12 usecs
[    1.598769] initcall rtc_init+0x0/0x48 returned 0 after 1463 usecs
[    1.599877] initcall brcmstb_waketmr_driver_init+0x0/0x20 returned 0 after 965 usecs
[    1.600253] initcall ds323x_init+0x0/0x78 returned 0 after 291 usecs
[    1.600790] initcall efi_rtc_driver_init+0x0/0x28 returned -19 after 467 usecs
[    1.601123] initcall max77686_rtc_driver_init+0x0/0x20 returned 0 after 273 usecs
[    1.617394] initcall pl031_driver_init+0x0/0x1c returned 0 after 15816 usecs
[    1.618749] initcall s3c_rtc_driver_init+0x0/0x20 returned 0 after 1208 usecs
[    1.619188] initcall s5m_rtc_driver_init+0x0/0x20 returned 0 after 353 usecs
[    1.619647] initcall sun6i_rtc_driver_init+0x0/0x20 returned 0 after 388 usecs
[    1.620226] initcall tegra_rtc_driver_init+0x0/0x28 returned -19 after 503 usecs
[    1.620638] initcall xgene_rtc_driver_init+0x0/0x20 returned 0 after 351 usecs
[    1.622204] initcall i2c_dev_init+0x0/0xdc returned 0 after 1437 usecs
[    1.622724] initcall bcm_iproc_i2c_driver_init+0x0/0x20 returned 0 after 444 usecs
[    1.623288] initcall exynos5_i2c_driver_init+0x0/0x20 returned 0 after 489 usecs
[    1.623871] initcall meson_i2c_driver_init+0x0/0x20 returned 0 after 499 usecs
[    1.624817] initcall mv64xxx_i2c_driver_init+0x0/0x20 returned 0 after 826 usecs
[    1.627232] initcall qup_i2c_driver_init+0x0/0x20 returned 0 after 2245 usecs
[    1.627967] initcall rk3x_i2c_driver_init+0x0/0x20 returned 0 after 648 usecs
[    1.628374] initcall tegra_bpmp_i2c_driver_init+0x0/0x20 returned 0 after 344 usecs
[    1.628810] initcall uniphier_fi2c_drv_init+0x0/0x20 returned 0 after 372 usecs
[    1.630138] initcall rcar_i2c_driver_init+0x0/0x20 returned 0 after 1238 usecs
[    1.630594] initcall zx2967_i2c_driver_init+0x0/0x20 returned 0 after 392 usecs
[    1.631083] initcall brcmstb_i2c_driver_init+0x0/0x20 returned 0 after 425 usecs
[    1.631561] initcall ec_i2c_tunnel_driver_init+0x0/0x20 returned 0 after 414 usecs
[    1.631735] initcall pca954x_driver_init+0x0/0x20 returned 0 after 124 usecs
[    1.632174] initcall ptp_dte_driver_init+0x0/0x20 returned 0 after 379 usecs
[    1.632614] initcall msm_restart_init+0x0/0x20 returned 0 after 377 usecs
[    1.634403] initcall vexpress_reset_init+0x0/0x20 returned 0 after 1679 usecs
[    1.634837] initcall xgene_reboot_init+0x0/0x20 returned 0 after 366 usecs
[    1.635295] initcall syscon_reboot_driver_init+0x0/0x20 returned 0 after 355 usecs
[    1.635802] initcall syscon_reboot_mode_driver_init+0x0/0x20 returned 0 after 405 usecs
[    1.635993] initcall bq27xxx_battery_i2c_driver_init+0x0/0x20 returned 0 after 132 usecs
[    1.636697] initcall scpi_hwmon_platdrv_init+0x0/0x20 returned 0 after 631 usecs
[    1.638775] initcall exynos_tmu_driver_init+0x0/0x20 returned 0 after 1948 usecs
[    1.639429] initcall hisi_thermal_driver_init+0x0/0x20 returned 0 after 566 usecs
[    1.639933] initcall mtk_thermal_driver_init+0x0/0x20 returned 0 after 436 usecs
[    1.640496] initcall s3c2410wdt_driver_init+0x0/0x20 returned 0 after 497 usecs
[    1.645954] initcall bcm2835_wdt_driver_init+0x0/0x20 returned 0 after 5256 usecs
[    1.646588] initcall rwdt_driver_init+0x0/0x20 returned 0 after 529 usecs
[    1.647008] initcall uniphier_wdt_driver_init+0x0/0x20 returned 0 after 355 usecs
[    1.647387] initcall dt_cpufreq_platdrv_init+0x0/0x20 returned 0 after 275 usecs
[    1.647532] initcall cpufreq_dt_platdev_init+0x0/0xdc returned -19 after 98 usecs
[    1.648018] initcall brcm_avs_cpufreq_platdrv_init+0x0/0x20 returned 0 after 364 usecs
[    1.648358] initcall scpi_cpufreq_platdrv_init+0x0/0x20 returned 0 after 277 usecs
[    1.648489] initcall tegra_cpufreq_init+0x0/0xb0 returned -2 after 84 usecs
[    1.648572] initcall tegra_cpufreq_init+0x0/0x94 returned -19 after 42 usecs
[    1.648769] initcall arm_idle_init+0x0/0x1ec returned -19 after 150 usecs
[    1.660251] initcall mmc_pwrseq_simple_driver_init+0x0/0x20 returned 0 after 11123 usecs
[    1.668572] initcall mmc_pwrseq_emmc_driver_init+0x0/0x20 returned 0 after 7957 usecs
[    1.670498] initcall mmc_blk_init+0x0/0xa0 returned 0 after 1737 usecs
[    1.670709] initcall mmci_driver_init+0x0/0x1c returned 0 after 140 usecs
[    1.671503] initcall sdhci_drv_init+0x0/0x2c returned 0 after 732 usecs
[    1.671901] initcall sdhci_acpi_driver_init+0x0/0x20 returned 0 after 340 usecs
[    1.672040] initcall mmc_spi_driver_init+0x0/0x20 returned 0 after 90 usecs
[    1.672528] initcall renesas_internal_dmac_sdhi_driver_init+0x0/0x20 returned 0 after 427 usecs
[    1.672933] initcall dw_mci_init+0x0/0x20 returned 0 after 347 usecs
[    1.675560] initcall dw_mci_pltfm_driver_init+0x0/0x20 returned 0 after 858 usecs
[    1.676362] initcall dw_mci_exynos_pltfm_driver_init+0x0/0x20 returned 0 after 653 usecs
[    1.677170] initcall dw_mci_k3_pltfm_driver_init+0x0/0x20 returned 0 after 705 usecs
[    1.678732] initcall dw_mci_rockchip_pltfm_driver_init+0x0/0x20 returned 0 after 1455 usecs
[    1.679471] initcall meson_mmc_driver_init+0x0/0x20 returned 0 after 644 usecs
[    1.680429] initcall sunxi_mmc_driver_init+0x0/0x20 returned 0 after 852 usecs
[    1.680892] initcall bcm2835_driver_init+0x0/0x20 returned 0 after 398 usecs
[    1.682911] initcall sdhci_pltfm_drv_init+0x0/0x20 returned 0 after 1911 usecs
[    1.683659] initcall sdhci_cdns_driver_init+0x0/0x20 returned 0 after 668 usecs
[    1.684486] initcall sdhci_tegra_driver_init+0x0/0x20 returned 0 after 748 usecs
[    1.685846] initcall sdhci_arasan_driver_init+0x0/0x20 returned 0 after 1275 usecs
[    1.686419] initcall sdhci_esdhc_driver_init+0x0/0x20 returned 0 after 508 usecs
[    1.686971] initcall sdhci_iproc_driver_init+0x0/0x20 returned 0 after 490 usecs
[    1.687407] initcall sdhci_msm_driver_init+0x0/0x20 returned 0 after 378 usecs
[    1.687868] initcall sdhci_brcmstb_driver_init+0x0/0x20 returned 0 after 403 usecs
[    1.688581] initcall sdhci_xenon_driver_init+0x0/0x20 returned 0 after 628 usecs
[    1.693735] initcall gpio_led_driver_init+0x0/0x20 returned 0 after 4956 usecs
[    1.694320] initcall led_pwm_driver_init+0x0/0x20 returned 0 after 512 usecs
[    1.694776] initcall syscon_led_driver_init+0x0/0x20 returned 0 after 395 usecs
[    1.694889] initcall heartbeat_trig_init+0x0/0x4c returned 0 after 68 usecs
[    1.700264] initcall ledtrig_cpu_init+0x0/0x10c returned 0 after 5171 usecs
[    1.700345] initcall defon_trig_init+0x0/0x1c returned 0 after 24 usecs
[    1.703122] initcall scpi_driver_init+0x0/0x20 returned 0 after 2604 usecs
[    1.704221] initcall scpi_power_domain_driver_init+0x0/0x20 returned 0 after 942 usecs
[    1.704979] initcall rpi_firmware_driver_init+0x0/0x20 returned 0 after 661 usecs
[    1.710427] initcall meson_sm_init+0x0/0xc8 returned -19 after 116 usecs
[    1.710569] initcall esrt_sysfs_init+0x0/0x2a0 returned -38 after 56 usecs
[    1.710615] initcall efi_capsule_loader_init+0x0/0x58 returned -19 after 10 usecs
[    1.711094] initcall hid_init+0x0/0x64 returned 0 after 422 usecs
[    1.711363] initcall hid_generic_init+0x0/0x28 returned 0 after 215 usecs
[    1.711673] initcall a4_driver_init+0x0/0x28 returned 0 after 235 usecs
[    1.712047] initcall apple_driver_init+0x0/0x28 returned 0 after 294 usecs
[    1.712317] initcall belkin_driver_init+0x0/0x28 returned 0 after 193 usecs
[    1.712631] initcall ch_driver_init+0x0/0x28 returned 0 after 237 usecs
[    1.712824] initcall ch_driver_init+0x0/0x28 returned 0 after 129 usecs
[    1.713172] initcall cp_driver_init+0x0/0x28 returned 0 after 292 usecs
[    1.714330] initcall ez_driver_init+0x0/0x28 returned 0 after 1051 usecs
[    1.714769] initcall ite_driver_init+0x0/0x28 returned 0 after 322 usecs
[    1.715046] initcall ks_driver_init+0x0/0x28 returned 0 after 214 usecs
[    1.715267] initcall lg_driver_init+0x0/0x28 returned 0 after 163 usecs
[    1.715508] initcall ms_driver_init+0x0/0x28 returned 0 after 186 usecs
[    1.715708] initcall mr_driver_init+0x0/0x28 returned 0 after 145 usecs
[    1.716800] initcall hid_init+0x0/0x6c returned 0 after 1010 usecs
[    1.717872] initcall arm_mhu_driver_init+0x0/0x1c returned 0 after 994 usecs
[    1.718543] initcall platform_mhu_driver_init+0x0/0x20 returned 0 after 584 usecs
[    1.719424] initcall bcm2835_mbox_driver_init+0x0/0x20 returned 0 after 751 usecs
[    1.720295] initcall flexrm_mbox_driver_init+0x0/0x20 returned 0 after 705 usecs
[    1.720536] initcall extcon_class_init+0x0/0x28 returned 0 after 174 usecs
[    1.721918] initcall usb_extcon_driver_init+0x0/0x20 returned 0 after 1296 usecs
[    1.722652] initcall exynos_adc_driver_init+0x0/0x20 returned 0 after 662 usecs
[    1.723453] initcall meson_sar_adc_driver_init+0x0/0x20 returned 0 after 695 usecs
[    1.723973] initcall register_l2_cache_pmu_driver+0x0/0x50 returned 0 after 429 usecs
[    1.724359] initcall register_qcom_l3_cache_pmu_driver+0x0/0x50 returned 0 after 322 usecs
[    1.724894] initcall bcm_otpc_driver_init+0x0/0x20 returned 0 after 469 usecs
[    1.724983] initcall optee_driver_init+0x0/0x498 returned -19 after 43 usecs
[    1.727296] initcall alsa_timer_init+0x0/0x1c4 returned 0 after 2193 usecs
[    1.727742] initcall alsa_pcm_init+0x0/0x7c returned 0 after 379 usecs
[    1.734073] initcall snd_soc_init+0x0/0x100 returned 0 after 6110 usecs
[    1.734534] initcall asoc_simple_card_init+0x0/0x20 returned 0 after 376 usecs
[    1.735102] initcall sock_diag_init+0x0/0x4c returned 0 after 480 usecs
[    1.735167] initcall gre_offload_init+0x0/0x5c returned 0 after 24 usecs
[    1.735534] initcall sysctl_ipv4_init+0x0/0x5c returned 0 after 318 usecs
[    1.735656] initcall xfrm4_beet_init+0x0/0x20 returned 0 after 81 usecs
[    1.735707] initcall xfrm4_transport_init+0x0/0x20 returned 0 after 17 usecs
[    1.735751] initcall xfrm4_mode_tunnel_init+0x0/0x20 returned 0 after 9 usecs
[    1.735930] initcall inet_diag_init+0x0/0x98 returned 0 after 139 usecs
[    1.736015] initcall tcp_diag_init+0x0/0x1c returned 0 after 49 usecs
[    1.736091] initcall cubictcp_register+0x0/0x60 returned 0 after 41 usecs
[    1.753228] initcall packet_init+0x0/0x58 returned 0 after 16634 usecs
[    1.756392] initcall init_rpcsec_gss+0x0/0x88 returned 0 after 2924 usecs
[    1.758522] initcall init_p9+0x0/0x28 returned 0 after 1949 usecs
[    1.759400] initcall p9_virtio_init+0x0/0x40 returned 0 after 716 usecs
[    1.760137] initcall init_dns_resolver+0x0/0x108 returned 0 after 641 usecs

 

6 레벨: device_initcall_sync()

[    1.760203] initcall arm_smmu_legacy_bus_init+0x0/0x30 returned 0 after 23 usecs

 

7 레벨: late_initcall()

[    1.760773] initcall sys_reg_genericv8_init+0x0/0x6c returned 0 after 37 usecs
[    1.760822] initcall xen_pm_init+0x0/0xd4 returned -19 after 15 usecs
[    1.760880] initcall init_oops_id+0x0/0x40 returned 0 after 20 usecs
[    1.764204] initcall pm_qos_power_init+0x0/0xcc returned 0 after 3108 usecs
[    1.764341] initcall pm_debugfs_init+0x0/0x34 returned 0 after 64 usecs
[    1.764448] initcall printk_late_init+0x0/0x130 returned 0 after 66 usecs
[    1.764524] initcall tk_debug_sleep_time_init+0x0/0x4c returned 0 after 36 usecs
[    1.766003] initcall taskstats_init+0x0/0x4c returned 0 after 1395 usecs
[    1.766130] initcall fault_around_debugfs+0x0/0x44 returned 0 after 73 usecs
[    1.766174] initcall max_swapfiles_check+0x0/0x8 returned 0 after 4 usecs
[    1.766305] initcall split_huge_pages_debugfs+0x0/0x48 returned 0 after 90 usecs
[    1.766378] initcall check_early_ioremap_leak+0x0/0x5c returned 0 after 35 usecs
[    1.768147] initcall init_root_keyring+0x0/0x14 returned 0 after 1672 usecs
[    1.768324] initcall prandom_reseed+0x0/0x40 returned 0 after 124 usecs
[    1.768424] initcall pci_resource_alignment_sysfs_init+0x0/0x28 returned 0 after 54 usecs
[    1.771184] initcall pci_sysfs_init+0x0/0x60 returned 0 after 2629 usecs
[    1.771262] initcall bert_init+0x0/0x21c returned 0 after 27 usecs
[    1.771765] initcall clk_debug_init+0x0/0x14c returned 0 after 447 usecs
[    1.771855] initcall boot_wait_for_devices+0x0/0x28 returned 0 after 46 usecs
[    1.772122] initcall deferred_probe_initcall+0x0/0x48 returned 0 after 212 usecs
[    1.772248] initcall pm_genpd_debug_init+0x0/0x17c returned 0 after 77 usecs
[    1.772311] initcall genpd_power_off_unused+0x0/0x94 returned 0 after 28 usecs
[    1.775732] initcall gpio_keys_init+0x0/0x20 returned 0 after 3271 usecs
[    1.778098] initcall rtc_hctosys+0x0/0xe4 returned 0 after 2222 usecs
[    1.778189] initcall register_update_efi_random_seed+0x0/0x38 returned 0 after 36 usecs
[    1.778236] initcall efi_shutdown_init+0x0/0x54 returned -19 after 9 usecs
[    1.778530] initcall of_fdt_raw_init+0x0/0x7c returned 0 after 248 usecs
[    1.778648] initcall tcp_congestion_default+0x0/0x1c returned 0 after 69 usecs
[    1.778849] initcall ip_auto_config+0x0/0xebc returned 0 after 115 usecs

 

7 레벨: late_initcall_sync()

[    1.778931] initcall software_resume+0x0/0x298 returned -2 after 38 usecs
[    1.778976] initcall fb_logo_late_init+0x0/0x14 returned 0 after 6 usecs
[    1.779135] initcall clk_disable_unused+0x0/0x138 returned 0 after 115 usecs
[    1.779236] initcall regulator_init_complete+0x0/0x70 returned 0 after 56 usecs
[    1.779790] initcall alsa_sound_last_init+0x0/0x80 returned 0 after 497 usecs
[    2.441747] initcall inet6_init+0x0/0x350 [ipv6] returned 0 after 11985 usecs
[    2.452314] initcall xt_init+0x0/0x1000 [x_tables] returned 0 after 167 usecs
[    2.462849] initcall ip_tables_init+0x0/0x1000 [ip_tables] returned 0 after 3393 usecs
[   40.729837] initcall cpu_feature_match_PMULL_init+0x0/0x1000 [crct10dif_ce] returned 0 after 100664 usecs
[   40.868079] initcall crc32_pmull_mod_init+0x0/0x1000 [crc32_ce] returned 0 after 67230 usecs

 

참고

 

 

 

devtmpfs & kdevtmpfs 스레드

 

devtmpfs

 

기존 커널이 사용했던 devfs를 대신하여 커널 2.6에 도입된 udev 데몬을 통해 디바이스 드라이버의 로딩이 이루어진다. udev 데몬이 유저 프로세스에서 동작하므로 커널 부팅 후 루트 파일시스템을 마운트한 후에야 디바이스 드라이버의 로딩이 가능해진다. 대부분의 디바이스 드라이버들은 커널 부트업 과정에서 로딩이 이루어지므로 루트 파일 시스템을 로딩하기 전에 initrd/initramfs 등에 존재하는 디바이스 드라이버를 임시 파일 시스템인 devtmpfs에 로딩시켜 부팅 시간을 단축할 목적으로 사용한다.

 

다음 그림과 같이 루트 파일 시스템을 마운트하기 전에 디바이스 드라이버들이 devtmpfs에 로딩되어 부팅 시간을 단축시키는 과정을 보여준다.

 

devtmpfs_init()

drivers/base/devtmpfs.c

/*                                                                              
 * Create devtmpfs instance, driver-core devices will add their device          
 * nodes here.                                                                  
 */                                                                             
int __init devtmpfs_init(void)                                                  
{                                                                               
    int err = register_filesystem(&dev_fs_type);                                
    if (err) {                                                                  
        printk(KERN_ERR "devtmpfs: unable to register devtmpfs "                
               "type %i\n", err);                                               
        return err;                                                             
    }                                                                           
                                                                                
    thread = kthread_run(devtmpfsd, &err, "kdevtmpfs");                         
    if (!IS_ERR(thread)) {                                                      
        wait_for_completion(&setup_done);                                       
    } else {                                                                    
        err = PTR_ERR(thread);                                                  
        thread = NULL;                                                          
    }                                                                           
                                                                                
    if (err) {                                                                  
        printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);       
        unregister_filesystem(&dev_fs_type);                                    
        return err;                                                             
    }                                                                           
                                                                                
    printk(KERN_INFO "devtmpfs: initialized\n");                                
    return 0;                                                                   
}

다음 devtmpfs라는 이름을 가진 파일 시스템을 등록한다. 그런 후 “kdevtmpfs” 스레드를 동작시킨다.

static struct file_system_type dev_fs_type = {                                  
    .name = "devtmpfs",                                                         
    .mount = dev_mount,                                                         
    .kill_sb = kill_litter_super,                                               
};

 

kdevtmpfs 스레드

다음 그림은 디바이스 드라이버들의 로딩/언로딩 요청에 대해 devtmpfs에 디바이스 노드를 생성 및 삭제하는 과정을 보여준다.

 

devtmpfsd()

drivers/base/devtmpfs.c

static int devtmpfsd(void *p)                                                   
{                                                                               
    char options[] = "mode=0755";                                               
    int *err = p;                                                               
    *err = sys_unshare(CLONE_NEWNS);                                            
    if (*err)                                                                   
        goto out;                                                               
    *err = sys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options);          
    if (*err)                                                                   
        goto out;                                                               
    sys_chdir("/.."); /* will traverse into overmounted root */                 
    sys_chroot(".");                                                            
    complete(&setup_done);                                                      
    while (1) {                                                                 
        spin_lock(&req_lock);                                                   
        while (requests) {                                                      
            struct req *req = requests;                                         
            requests = NULL;                                                    
            spin_unlock(&req_lock);                                             
            while (req) {                                                       
                struct req *next = req->next;                                   
                req->err = handle(req->name, req->mode,                         
                          req->uid, req->gid, req->dev);                        
                complete(&req->done);                                           
                req = next;                                                     
            }                                                                   
            spin_lock(&req_lock);                                               
        }                                                                       
        __set_current_state(TASK_INTERRUPTIBLE);                                
        spin_unlock(&req_lock);                                                 
        schedule();                                                             
    }                                                                           
    return 0;                                                                   
out:                                                                            
    complete(&setup_done);                                                      
    return *err;                                                                
}

kdevtmpfs 스레드가 처음 동작하고 무한 루프를 돌며 디바이스 노드 생성 및 삭제 요청을 처리하는 함수이다.

  • 코드 라인 5~7에서 현재 동작중인 파일 시스템 정보를 복사하여 새 스레드에서 사용할 수 있게 한다.
  • 코드 라인 8~10에서 “devtmpfs” 파일 시스템을 마운트한다.
  • 코드 라인 11~13에서 루트 디렉토리로 이동시킨 후 setup_done 변수에 complete 신호를 보내 싱크 대기중인 부모 태스크를 동작하게 한다.
  • 코드 라인 14~33에서 반복 루프를 돌며 요청이 있는 경우 요청에 대한 처리를 수행한다.

 

handle()

base/devtmpfs.c

static int handle(const char *name, umode_t mode, kuid_t uid, kgid_t gid,       
          struct device *dev)                                                   
{                                                                               
    if (mode)                                                                   
        return handle_create(name, mode, uid, gid, dev);                        
    else                                                                        
        return handle_remove(name, dev);                                        
}

mode에 따라 핸들 생성 및 삭제 함수를 호출한다.

 

handle_create()

drivers/base/devtmpfs.c

static int handle_create(const char *nodename, umode_t mode, kuid_t uid,        
             kgid_t gid, struct device *dev)                                    
{                                                                               
    struct dentry *dentry;                                                      
    struct path path;                                                           
    int err;                                                                    
                                                                                
    dentry = kern_path_create(AT_FDCWD, nodename, &path, 0);                    
    if (dentry == ERR_PTR(-ENOENT)) {                                           
        create_path(nodename);                                                  
        dentry = kern_path_create(AT_FDCWD, nodename, &path, 0);                
    }                                                                           
    if (IS_ERR(dentry))                                                         
        return PTR_ERR(dentry);                                                 
                                                                                
    err = vfs_mknod(d_inode(path.dentry), dentry, mode, dev->devt);             
    if (!err) {                                                                 
        struct iattr newattrs;                                                  
                                                                                
        newattrs.ia_mode = mode;                                                
        newattrs.ia_uid = uid;                                                  
        newattrs.ia_gid = gid;                                                  
        newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;                        
        inode_lock(d_inode(dentry));                                            
        notify_change(dentry, &newattrs, NULL);                                 
        inode_unlock(d_inode(dentry));                                          
                                                                                
        /* mark as kernel-created inode */                                      
        d_inode(dentry)->i_private = &thread;                                   
    }                                                                           
    done_path_create(&path, dentry);                                            
    return err;                                                                 
}

디바이스 파일을 생성하고 디바이스 노드를 생성한다.

 

handle_remove()

drivers/base/devtmpfs.c

static int handle_remove(const char *nodename, struct device *dev)              
{                                                                               
    struct path parent;                                                         
    struct dentry *dentry;                                                      
    int deleted = 0;                                                            
    int err;                                                                    
                                                                                
    dentry = kern_path_locked(nodename, &parent);                               
    if (IS_ERR(dentry))                                                         
        return PTR_ERR(dentry);                                                 
                                                                                
    if (d_really_is_positive(dentry)) {                                         
        struct kstat stat;                                                      
        struct path p = {.mnt = parent.mnt, .dentry = dentry};                  
        err = vfs_getattr(&p, &stat, STATX_TYPE | STATX_MODE,                   
                  AT_STATX_SYNC_AS_STAT);                                       
        if (!err && dev_mynode(dev, d_inode(dentry), &stat)) {                  
            struct iattr newattrs;                                              
            /*                                                                  
             * before unlinking this node, reset permissions                    
             * of possible references like hardlinks                            
             */                                                                 
            newattrs.ia_uid = GLOBAL_ROOT_UID;                                  
            newattrs.ia_gid = GLOBAL_ROOT_GID;                                  
            newattrs.ia_mode = stat.mode & ~0777;                               
            newattrs.ia_valid =                                                 
                ATTR_UID|ATTR_GID|ATTR_MODE;                                    
            inode_lock(d_inode(dentry));                                        
            notify_change(dentry, &newattrs, NULL);                             
            inode_unlock(d_inode(dentry));                                      
            err = vfs_unlink(d_inode(parent.dentry), dentry, NULL);             
            if (!err || err == -ENOENT)                                         
                deleted = 1;                                                    
        }                                                                       
    } else {                                                                    
        err = -ENOENT;                                                          
    }                                                                           
    dput(dentry);                                                               
    inode_unlock(d_inode(parent.dentry));                                       
                                                                                
    path_put(&parent);                                                          
    if (deleted && strchr(nodename, '/'))                                       
        delete_path(nodename);                                                  
    return err;                                                                 
}

디바이스 노드를 삭제하고, 디바이스 파일도 삭제한다.

 

참고

 

driver_init()

 

리눅스 디바이스 드라이버 모델의 초기화

 

리눅스 디바이스 드라이버 모델을 표현하기위해 kobjectkset등이 사용된다.

  • sysfs는 kobject 및 kset 등으로 이루어진 하이라키 관계를 sysfs 가상 파일 시스템을 통해 표현되고 관리된다.

 

다음 그림은 디바이스 드라이버 모델의 초기화 호출 과정을 보여준다.

 

driver_init()

drivers/base/init.c

/**                                                                             
 * driver_init - initialize driver model.                                       
 *                                                                              
 * Call the driver model init functions to initialize their                     
 * subsystems. Called early from init/main.c.                                   
 */                                                                             
void __init driver_init(void)                                                   
{                                                                               
    /* These are the core pieces */                                             
    devtmpfs_init();                                                            
    devices_init();                                                             
    buses_init();                                                               
    classes_init();                                                             
    firmware_init();                                                            
    hypervisor_init();                                                          
                                                                                
    /* These are also core pieces, but must come after the                      
     * core core pieces.                                                        
     */                                                                         
    platform_bus_init();                                                        
    cpu_dev_init();                                                             
    memory_dev_init();                                                          
    container_dev_init();                                                       
    of_core_init();                                                             
}

리눅스 커널이 사용하는 드라이버 모델의 초기화를 수행한다.

  • 코드 라인 10에서 devtmpfs 파일 시스템을 마운트하고 kdevtmpfs 스레드를 생성하고 동작시킨다.
  • 코드 라인 11에서 디바이스를 표현 및 관리할 “/sys/devices” 및 “/sys/dev” 디렉토리를 생성한다. 또한 캐릭터 디바이스를 표현 및 관리할 “/sys/dev/block” 디렉토리와 블럭 디바이스를 표현 및 관리할 “/sys/dev/char” 디렉토리를 생성한다.
  • 코드 라인 12에서 버스 디바이스를 표현 및 관리할 “/sys/bus” 디렉토리를 생성한다. 또한 서브 시스템들이 등록될 “/sys/devices/system” 디렉토리도 생성한다.
  • 코드 라인 13에서 클래스 디바이스를 표현 및 관리할 “/sys/class” 디렉토리를 생성한다.
  • 코드 라인 14에서 펌웨어를 표현 및 관리할 “/sys/firmware” 디렉토리를 생성한다.
  • 코드 라인 15에서 하이퍼바이저를 표현 및 관리할 “/sys/hypervisor” 디렉토리를 생성한다.
  • 코드 라인 20에서 플랫폼 디바이스를 표현 및 관리할 “/sys/devices/platform” 디렉토리와 “/sys/bus/platform” 디렉토리를 생성한다.
  • 코드 라인 21에서 cpu 서브시스템의 cpu들을 표현 및 관리할  “/sys/devices/system/cpu” 디렉토리와 그 아래에 속성 파일들을 생성한다.
  • 코드 라인 22에서 hotplug 허용된 시스템에서 memory 서브시스템의 memory 블럭들을 표현 및 관리할  “/sys/devices/system/memory” 디렉토리와 그 아래에 속성 파일들을 생성한다.
  • 코드 라인 23에서 컨테이너 서브시스템의 컨테이너들을 표현 및 관리할 “/sys/devices/system/container” 디렉토리를 생성한다.
  • 코드 라인 24에서 디바이스 트리를 표현 및 관리할 “/sys/firmware/devicetree” 디렉토리를 생성하고, 그 이하에 모든 노드에 대한 디렉토리를 만든다. 그리고 각 노드의 속성들도 해당 노드 디렉토리에 각각 파일로 추가한다.

 

devices_init()

drivers/base/core.c

int __init devices_init(void)                                                   
{                                                                               
    devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);    
    if (!devices_kset)                                                          
        return -ENOMEM;                                                         
    dev_kobj = kobject_create_and_add("dev", NULL);                             
    if (!dev_kobj)                                                              
        goto dev_kobj_err;                                                      
    sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);           
    if (!sysfs_dev_block_kobj)                                                  
        goto block_kobj_err;                                                    
    sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);             
    if (!sysfs_dev_char_kobj)                                                   
        goto char_kobj_err;                                                     
                                                                                
    return 0;                                                                   
                                                                                
 char_kobj_err:                                                                 
    kobject_put(sysfs_dev_block_kobj);                                          
 block_kobj_err:                                                                
    kobject_put(dev_kobj);                                                      
 dev_kobj_err:                                                                  
    kset_unregister(devices_kset);                                              
    return -ENOMEM;                                                             
}

디바이스를 표현 및 관리할 “/sys/devices” 및 “/sys/dev” 디렉토리를 생성한다. 또한 캐릭터 디바이스를 표현 및 관리할 “/sys/dev/block” 디렉토리와 블럭 디바이스를 표현 및 관리할 “/sys/dev/char” 디렉토리를 생성한다.

  • 코드 라인 1~3에서 “devices” 이름을 갖는 kset를 생성하고 sysfs 루트에 추가한다.
  • 코드 라인 4~6에서 “dev” 이름을 갖는 kobject를 생성하고 sysfs 루트에 생성한다.
  • 코드 라인 7~9에서 “block” 이름을 갖는 kobject를 생성하고 “/sys/dev” 뒤에 추가한다.
  • 코드 라인 10~12에서 “char” 이름을 갖는 kobject를 생성하고 “/sys/dev” 뒤에 추가한다.

 

buses_init()

drivers/base/bus.c

int __init buses_init(void)                                                     
{                                                                               
    bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);               
    if (!bus_kset)                                                              
        return -ENOMEM;                                                         
                                                                                
    system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);     
    if (!system_kset)                                                           
        return -ENOMEM;                                                         
                                                                                
    return 0;                                                                   
}

버스 디바이스를 표현 및 관리할 “/sys/bus” 디렉토리를 생성한다. 또한 서브 시스템들이 등록될 “/sys/devices/system” 디렉토리도 생성한다.

  • 코드 라인 3~5에서 “bus” 이름을 갖는 kset를 생성하고 sysfs 루트에 추가한다.
  • 코드 라인 7~9에서 “system” 이름을 갖는 kset를 생성하고 “/sys/devices” 뒤에 추가한다.

 

classes_init()

drivers/base/class.c

int __init classes_init(void)                                                   
{                                                                               
    class_kset = kset_create_and_add("class", NULL, NULL);                      
    if (!class_kset)                                                            
        return -ENOMEM;                                                         
    return 0;                                                                   
}

클래스 디바이스를 표현 및 관리할 “/sys/class” 디렉토리를 생성한다.

  • 코드 라인 3~5에서 “class” 이름을 갖는 kset를 생성하고 sysfs 루트에 추가한다.

 

firmware_init()

drivers/base/firmware.c

int __init firmware_init(void)                                                  
{                                                                               
    firmware_kobj = kobject_create_and_add("firmware", NULL);                   
    if (!firmware_kobj)                                                         
        return -ENOMEM;                                                         
    return 0;                                                                   
}

펌웨어를 표현 및 관리할 “/sys/firmware” 디렉토리를 생성한다.

  • 코드 라인 3~5에서 “firmware” 이름을 갖는 kobject를 생성하고 sysfs 루트에 추가한다.

 

 

hypervisor_init()

drivers/base/hypervisor.c

int __init hypervisor_init(void)                                                
{                                                                               
    hypervisor_kobj = kobject_create_and_add("hypervisor", NULL);               
    if (!hypervisor_kobj)                                                       
        return -ENOMEM;                                                         
    return 0;                                                                   
}

하이퍼바이저를 표현 및 관리할 “/sys/hypervisor” 디렉토리를 생성한다.

  • 코드 라인 3~5에서 “hypervisor” 이름을 갖는 kobject를 생성하고 sysfs 루트에 추가한다.

 

platform_bus_init()

drivers/base/platform.c

int __init platform_bus_init(void)                                              
{                                                                               
    int error;                                                                  
                                                                                
    early_platform_cleanup();                                                   
                                                                                
    error = device_register(&platform_bus);                                     
    if (error)                                                                  
        return error;                                                           
    error =  bus_register(&platform_bus_type);                                  
    if (error)                                                                  
        device_unregister(&platform_bus);                                       
    of_platform_register_reconfig_notifier();                                   
    return error;                                                               
}

플랫폼 디바이스를 표현 및 관리할 “/sys/devices/platform” 디렉토리와 “/sys/bus/platform” 디렉토리를 생성한다.

  • 코드 라인 5에서 early 플랫폼 디바이스를 리스트에서 제거한다.
  • 코드 라인 7~9에서 플랫폼 버스 디바이스를 등록한다.
    • 플랫폼 버스 디바이스를 표현하고 관리할 “/sys/devices/platform” 디렉토리를 생성한다.
  • 코드 라인 10~12에서 플랫폼 버스를 등록한다.
    • 플랫폼 버스를 표현하고 관리할 “/sys/bus/platform” 디렉토리를 생성한다.
  • 코드 라인 13에서 디바이스 트리를 통해 플랫폼 디바이스가 추가/삭제될 때 마다 호출되도록 notifier block에 of_platform_notify() 함수를 등록한다.

 

등록될 디바이스

struct device platform_bus = {                                                  
    .init_name  = "platform",                                                   
};                                                                              
EXPORT_SYMBOL_GPL(platform_bus);

 

등록될 버스

struct bus_type platform_bus_type = {                                           
    .name       = "platform",                                                   
    .dev_groups = platform_dev_groups,                                          
    .match      = platform_match,                                               
    .uevent     = platform_uevent,                                              
    .pm     = &platform_dev_pm_ops,                                             
};                                                                              
EXPORT_SYMBOL_GPL(platform_bus_type);

 

예) 다음은 platform 버스 디바이스 아래에 등록된 플랫폼 디바이스들이다.

$ ls /sys/devices/platform -la
drwxr-xr-x    3 root     root             0 May 16 15:00 20020000.pcie
drwxr-xr-x    3 root     root             0 Mar 15 09:55 50020000.pcie
drwxr-xr-x    3 root     root             0 May 16 15:00 60c00000.pcie
drwxr-xr-x    3 root     root             0 May 28 16:17 Fixed MDIO bus.0
drwxr-xr-x    2 root     root             0 May 28 16:17 alarmtimer
drwxr-xr-x    2 root     root             0 May 28 16:17 pmu
drwxr-xr-x    2 root     root             0 May 28 16:17 psci
drwxr-xr-x    2 root     root             0 May 28 16:17 secure_rtc
drwxr-xr-x    2 root     root             0 May 28 16:17 serial8250
drwxr-xr-x   70 root     root             0 Mar 30 15:41 soc
drwxr-xr-x    2 root     root             0 May 28 16:17 timer
-rw-r--r--    1 root     root          4096 May 28 16:17 uevent

 

early_platform_cleanup()

drivers/base/platform.c

/**                                                                             
 * early_platform_cleanup - clean up early platform code                        
 */                                                                             
void __init early_platform_cleanup(void)                                        
{                                                                               
    struct platform_device *pd, *pd2;                                           
                                                                                
    /* clean up the devres list used to chain devices */                        
    list_for_each_entry_safe(pd, pd2, &early_platform_device_list,              
                 dev.devres_head) {                                             
        list_del(&pd->dev.devres_head);                                         
        memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));           
    }                                                                           
}

등록된 early 플랫폼 디바이스들을 리스트에서 제거한다.

  • early_platform_add_devices() 함수로 추가한 플랫폼 디바이스이다.
  • arm64에서는 early 플랫폼 디바이스를 등록하지 않는다.
  • 디바이스 트리를 통해 플랫폼 디바이스가 추가/삭제될 때 마다 of_platform_notify() 후크 함수가 호출되도록 등록한다.

 

of_platform_register_reconfig_notifier()

drivers/of/platform.c

void of_platform_register_reconfig_notifier(void)                               
{                                                                               
    WARN_ON(of_reconfig_notifier_register(&platform_of_notifier));              
}

디바이스 트리를 통해 플랫폼 디바이스가 추가/삭제될 때 마다 호출되도록 notifier block에 of_platform_notify() 함수를 등록한다.

  • CONFIG_OF_DYNAMIC 및 CONFIG_OF_ADDRESS 두 커널 옵션이 사용되어야 동작한다.
  • 참고: Platform Device | 문c

 

cpu_dev_init()

drivers/base/cpu.c

void __init cpu_dev_init(void)                                                  
{                                                                               
    if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))              
        panic("Failed to register CPU subsystem");                              
                                                                                
    cpu_dev_register_generic();                                                 
    cpu_register_vulnerabilities();                                             
}

cpu 서브시스템의 cpu들을 표현 및 관리할  “/sys/devices/system/cpu” 디렉토리와 그 아래에 속성 파일들을 생성한다.

  • 코드 라인 3~4에서 cpu 서브 시스템을 등록하고 그 밑에 속성들을 추가한다.
    • “/sys/devices/system/cpu” 디렉토리를 만들고 그 밑에 다음 속성들을 추가한다.
      • probe, release, online, possible, present, offline, isolated, nohz_full, modalias
  • 코드 라인 6~7에서 CONFIG_GENERIC_CPU_DEVICES 커널 옵션을 사용하는 경우 호출되지만 arm64 아키텍처는 관련 없다.

 

다음은 cpu 서브 시스템에 해당하는 버스 타입이다.

struct bus_type cpu_subsys = {                                                  
    .name = "cpu",                                                              
    .dev_name = "cpu",                                                          
    .match = cpu_subsys_match,                                                  
#ifdef CONFIG_HOTPLUG_CPU                                                       
    .online = cpu_subsys_online,                                                
    .offline = cpu_subsys_offline,                                              
#endif                                                                          
};                                                                              
EXPORT_SYMBOL_GPL(cpu_subsys);

 

다음은 cpu 서브 시스템에 추가될 속성들이다.

static struct attribute *cpu_root_attrs[] = {                                   
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE                                            
    &dev_attr_probe.attr,                                                       
    &dev_attr_release.attr,                                                     
#endif                                                                          
    &cpu_attrs[0].attr.attr,                                                    
    &cpu_attrs[1].attr.attr,                                                    
    &cpu_attrs[2].attr.attr,                                                    
    &dev_attr_kernel_max.attr,                                                  
    &dev_attr_offline.attr,                                                     
    &dev_attr_isolated.attr,                                                    
#ifdef CONFIG_NO_HZ_FULL                                                        
    &dev_attr_nohz_full.attr,                                                   
#endif                                                                          
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE                                             
    &dev_attr_modalias.attr,                                                    
#endif                                                                          
    NULL                                                                        
};

 

cpu 서브 시스템에 등록된 속성들을 간단히 알아본다.

  • probe
    • CONFIG_ARCH_CPU_PROBE_RELEASE 커널 옵션이 필요하다.
  • release
    • CONFIG_ARCH_CPU_PROBE_RELEASE 커널 옵션이 필요하다.
  • online
    • 현재 online 된 cpu를 보여준다. (장착되고 online된 상태의 cpu)
    • 예) 0-1
  • possible
    • possible cpu를 보여준다. (장착 되었거나 추가 장착 가능한 상태의 cpu)
    • 예) 0~3
  • present
    • preseent cpu를 보여준다. (장착된 상태의 cpu)
    • 예) 0~1
  • kernel_max
    • 현재 부팅된 커널이 지원하는 최고 cpu 번호 (NR_CPUS -1)
      • 예) 3
  • offline
    • offline된 cpu를 보여준다.
      • 예) 2~3
  • isolated
    • isolate된 cpu를 보여준다. (스케줄링에서 제외된 cpu)
      • 예) 기본적으로는 없으므로 아무것도 보여주지 않는다.
  • nohz_full
    • nohz full된 상태의 cpu를 보여준다.
    • CONFIG_NO_HZ_FULL 커널 옵션이 필요하다.
  • modalias
    • cpu 타입과 feature들을 보여준다.
    • 예) cpu:type:aarch64_be:feature:,0000,0001,0003,0004,0005,0006,0007
    • CONFIG_GENERIC_CPU_AUTOPROBE 커널 옵션이 필요하다.
    • arm, arm64, mips, s390, x86 등 많은 아키텍처들이 이 커널 옵션을 사용한다.

 

예) 다음은 cpu 서브 시스템에 등록된 cpu들과 속성들이다.

  • cpu0 ~ cpu3과 같은 cpu 디렉토리들은 cpu가 online/offline될 때마다 추가/제거된다.
$ ls /sys/devices/system/cpu -la
drwxr-xr-x    4 root     root             0 May 28 16:50 cpu0
drwxr-xr-x    4 root     root             0 May 28 16:50 cpu1
drwxr-xr-x    2 root     root             0 May 28 16:50 cpu2
drwxr-xr-x    2 root     root             0 May 28 16:50 cpu3
drwxr-xr-x    2 root     root             0 May 28 16:50 cpufreq
drwxr-xr-x    2 root     root             0 May 28 16:50 cpuidle
-r--r--r--    1 root     root          4096 May 28 16:50 isolated
-r--r--r--    1 root     root          4096 May 28 16:50 kernel_max
-r--r--r--    1 root     root          4096 May 28 16:50 modalias
-r--r--r--    1 root     root          4096 May 28 16:50 offline
-r--r--r--    1 root     root          4096 Mar 15 09:55 online
-r--r--r--    1 root     root          4096 May 28 16:50 possible
-r--r--r--    1 root     root          4096 May 28 16:50 present
-rw-r--r--    1 root     root          4096 May 28 16:50 uevent

 

예) 다음은 cpu0에 대한 속성들이다.

<pre “>$ ls /sys/devices/system/cpu/cpu0 -la drwxr-xr-x 5 root root 0 May 28 17:12 cache -r——– 1 root root 4096 May 28 17:12 frequency lrwxrwxrwx 1 root root 0 May 28 17:12 of_node -> ../../../../firmware/devicetree/base/cpus/cpu@0 -rw-r–r– 1 root root 4096 May 28 17:12 online lrwxrwxrwx 1 root root 0 May 28 17:12 subsystem -> ../../../../bus/cpu drwxr-xr-x 2 root root 0 May 28 17:12 topology -rw-r–r– 1 root root 4096 May 28 17:12 uevent

 

memory_dev_init()

drivers/base/memory.c

/*                                                                              
 * Initialize the sysfs support for memory devices...                           
 */                                                                             
int __init memory_dev_init(void)                                                
{                                                                               
    unsigned int i;                                                             
    int ret;                                                                    
    int err;                                                                    
    unsigned long block_sz;                                                     
                                                                                
    ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);      
    if (ret)                                                                    
        goto out;                                                               
                                                                                
    block_sz = get_memory_block_size();                                         
    sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;                      
                                                                                
    /*                                                                          
     * Create entries for memory sections that were found                       
     * during boot and have been initialized                                    
     */                                                                         
    mutex_lock(&mem_sysfs_mutex);                                               
    for (i = 0; i < NR_MEM_SECTIONS; i += sections_per_block) {                 
        /* Don't iterate over sections we know are !present: */                 
        if (i > __highest_present_section_nr)                                   
            break;                                                              
                                                                                
        err = add_memory_block(i);                                              
        if (!ret)                                                               
            ret = err;                                                          
    }                                                                           
    mutex_unlock(&mem_sysfs_mutex);                                             
                                                                                
out:                                                                            
    if (ret)                                                                    
        printk(KERN_ERR "%s() failed: %d\n", __func__, ret);                    
    return ret;                                                                 
}

hotplug 허용된 시스템(CONFIG_MEMORY_HOTPLUG_SPARSE 커널 옵션)에서 memory 서브시스템의 memory 블럭들을 표현 및 관리할  “/sys/devices/system/memory” 디렉토리와 그 아래에 속성 파일들을 생성한다.

  • 코드 라인 11~13에서 memory 서브시스템을 등록하고 관련 속성을 추가한다.
    • “/sys/devices/system/memory” 디렉토리를 만들고 그 밑에 다음 속성들을 추가한다.
      • probe, soft_offline_page, block_size_bytes, auto_online_blocks
  • 코드 라인에서 15~16에서 블럭당 섹션 수를 산출한다.
    • arm64는 블럭과 섹션 크기가 같으므로 항상 1이다.
  • 코드 라인 22~32에서 전체 섹션에 대해서 블럭 크기만큼 증가시키며 memory 서브시스템 밑에 메모리 블럭(디렉토리 및 파일들)을 추가한다.

 

다음은 memory 서브 시스템에 해당하는 버스 타입이다.

static struct bus_type memory_subsys = {                                        
    .name = MEMORY_CLASS_NAME,                                                  
    .dev_name = MEMORY_CLASS_NAME,                                              
    .online = memory_subsys_online,                                             
    .offline = memory_subsys_offline,                                           
};

 

다음은 memory 서브 시스템에 추가될 속성들이다.

static struct attribute *memory_root_attrs[] = {                                
#ifdef CONFIG_ARCH_MEMORY_PROBE                                                 
    &dev_attr_probe.attr,                                                       
#endif                                                                          
                                                                                
#ifdef CONFIG_MEMORY_FAILURE                                                    
    &dev_attr_soft_offline_page.attr,                                           
    &dev_attr_hard_offline_page.attr,                                           
#endif                                                                          
                                                                                
    &dev_attr_block_size_bytes.attr,                                            
    &dev_attr_auto_online_blocks.attr,                                          
    NULL                                                                        
};                                                                              
                                                                                
static struct attribute_group memory_root_attr_group = {                        
    .attrs = memory_root_attrs,                                                 
};                                                                              
                                                                                
static const struct attribute_group *memory_root_attr_groups[] = {              
    &memory_root_attr_group,                                                    
    NULL,                                                                       
};

 

예) 다음은 memory 서브 시스템에 등록된 메모리 블럭들과 속성들이다.

  • memory0 ~ memory27과 같은 memory 블럭 디렉토리들은 memory가 online/offline될 때마다 추가/제거된다.
$ ls -la
-r--r--r--  1 root root 4096  5월 29 14:14 block_size_bytes
--w-------  1 root root 4096  5월 29 14:14 hard_offline_page
drwxr-xr-x  3 root root    0  5월 29 14:18 memory0
drwxr-xr-x  3 root root    0  5월 29 13:36 memory1
...
drwxr-xr-x  3 root root    0  5월 29 13:36 memory27
drwxr-xr-x  2 root root    0  5월 29 14:14 power
--w-------  1 root root 4096  5월 29 14:14 probe
--w-------  1 root root 4096  5월 29 14:14 soft_offline_page
-rw-r--r--  1 root root 4096  5월 29 13:36 uevent

 

예) 다음은 memory0 블럭에 대한 속성들이다.

$ ls /sys/devices/system/memory/memory0 -la
lrwxrwxrwx 1 root root 0 5월 29 14:18 node0 -> ../../node/node0
-rw-r--r-- 1 root root 4096 5월 29 14:18 online
-r--r--r-- 1 root root 4096 5월 29 14:18 phys_device
-r--r--r-- 1 root root 4096 5월 29 14:18 phys_index
drwxr-xr-x 2 root root 0 5월 29 14:18 power
-r--r--r-- 1 root root 4096 5월 29 14:18 removable
-rw-r--r-- 1 root root 4096 5월 29 14:18 state
lrwxrwxrwx 1 root root 0 5월 29 14:18 subsystem -> ../../../../bus/memory
-rw-r--r-- 1 root root 4096 5월 29 14:18 uevent
-r--r--r-- 1 root root 4096 5월 29 14:18 valid_zones

 

get_memory_block_size()

drivers/base/memory.c

static unsigned long get_memory_block_size(void)                                
{                                                                               
    unsigned long block_sz;                                                     
                                                                                
    block_sz = memory_block_size_bytes();                                       
                                                                                
    /* Validate blk_sz is a power of 2 and not less than section size */        
    if ((block_sz & (block_sz - 1)) || (block_sz < MIN_MEMORY_BLOCK_SIZE)) {    
        WARN_ON(1);                                                             
        block_sz = MIN_MEMORY_BLOCK_SIZE;                                       
    }                                                                           
                                                                                
    return block_sz;                                                            
}

메모리 블럭 사이즈를 반환한다.

  • 아키텍처에 별도의 구현이 없는 디폴트: 섹션 사이즈(arm64)

 

container_dev_init()

drivers/base/container.c

void __init container_dev_init(void)                                            
{                                                                               
    int ret;                                                                    
                                                                                
    ret = subsys_system_register(&container_subsys, NULL);                      
    if (ret)                                                                    
        pr_err("%s() failed: %d\n", __func__, ret);                             
}

컨테이너 서브시스템의 컨테이너들을 표현 및 관리할 “/sys/devices/system/container” 디렉토리를 생성한다.  (추가할 속성들은 없다)

 

다음은 container 서브 시스템에 해당하는 버스 타입이다.

struct bus_type container_subsys = {                                            
    .name = CONTAINER_BUS_NAME,                                                 
    .dev_name = CONTAINER_BUS_NAME,                                             
    .online = trivial_online,                                                   
    .offline = container_offline,                                               
};

 

of_core_init()

drivers/of/base.c

void __init of_core_init(void)                                                  
{                                                                               
    struct device_node *np;                                                     
                                                                                
    /* Create the kset, and register existing nodes */                          
    mutex_lock(&of_mutex);                                                      
    of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);           
    if (!of_kset) {                                                             
        mutex_unlock(&of_mutex);                                                
        pr_err("failed to register existing nodes\n");                          
        return;                                                                 
    }                                                                           
    for_each_of_allnodes(np)                                                    
        __of_attach_node_sysfs(np);                                             
    mutex_unlock(&of_mutex);                                                    
                                                                                
    /* Symlink in /proc as required by userspace ABI */                         
    if (of_root)                                                                
        proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");     
}

디바이스 트리를 표현 및 관리할 “/sys/firmware/devicetree” 디렉토리를 생성하고, 그 이하에 모든 노드에 대한 디렉토리를 만든다. 그리고 각 노드의 속성들도 해당 노드 디렉토리에 각각 파일로 추가한다.

  • 코드 라인 8~12에서 “devicetree” kset을 생성하고 “/sys/firmware”에 추가한다.
    • “/sys/firmware/devicetree” 디렉토리를 만든다.
  • 코드 라인 13~14에서 “/sys/firmware/devicetree” 디렉토리 밑에 읽어온 디바이스 트리 노드들과 속성들을 추가한다.
    • 첫 번째 루트 노드는 base 라는 이름의 디렉토리에 존재한다.
  • 코드 라인 18~19에서 “/sys/firmware/devicetree/base”를 가리키는 심볼릭 링크를 proc 루트 디렉토리에 만든다.
    • “/proc/device-tree”  심볼릭 링크 파일을 생성한다.

 

예) 루트 디렉토리인 base 아래에 생긴 노드들과 속성들이다.

$ ls /sys/firmware/devicetree/base -la
-r--r--r--    1 root     root             4 Mar 30 15:45 #address-cells
-r--r--r--    1 root     root             4 Mar 30 15:45 #size-cells
drwxr-xr-x    2 root     root             0 Mar 30 15:45 aliases
drwxr-xr-x    2 root     root             0 Mar 30 15:45 bootst
drwxr-xr-x    2 root     root             0 Mar 30 15:45 chosen
-r--r--r--    1 root     root            22 Mar 30 15:45 compatible
drwxr-xr-x    7 root     root             0 Mar 30 15:45 cpus
-r--r--r--    1 root     root             4 Mar 30 15:45 interrupt-parent
drwxr-xr-x    2 root     root             0 Mar 30 15:45 memory
-r--r--r--    1 root     root            14 Mar 30 15:45 model
-r--r--r--    1 root     root             1 Mar 30 15:45 name
drwxr-xr-x    2 root     root             0 Mar 30 15:45 pcie@20020000
drwxr-xr-x    2 root     root             0 Mar 30 15:45 pcie@50020000
drwxr-xr-x    2 root     root             0 Mar 30 15:45 pcie@60c00000
drwxr-xr-x    2 root     root             0 Mar 30 15:45 pmu
drwxr-xr-x    2 root     root             0 Mar 30 15:45 psci
drwxr-xr-x    2 root     root             0 Mar 30 15:45 secure_rtc
drwxr-xr-x   70 root     root             0 Mar 30 15:45 soc
drwxr-xr-x    2 root     root             0 Mar 30 15:45 timer

 

참고

 

Sysfs (kobject & kset)

디바이스 드라이버 모델에서 디바이스들은 하이라키 토플로지 형태로 표현되고 있다.  이렇게 하이라키로 표현된 디바이스 드라이버들은 마운트된 sysfs라는 파일 시스템을 통해 디렉토리 구조로 보여주고 관리된다. 이러한 디바이스 드라이버들의 하이라키 표현을 도와주기 위해 다음 구조체들을 사용한다.

  • kobject
  • kset
  • ktype
  • kref

 

kobject(kernel object)

디바이스들은 여러 가지 객체(구조체)로 표현되는데 이들이 기본적으로 가져야 할 이름과 참조 카운터 및 하이 라키 관계를 표현하기 위해 여러 개의 필드가 필요하다. 리눅스 커널은 이러한 정보 및 하이라키 구성관계를 쉽게 사용할 수 있도록 kobject 구조체를 사용한다.

  • kobject 구조체는 그 자체로는 사용되지 않고 다른 객체(구조체) 내부에 임베드되는 형태로 사용된다.
  • kobject는 이름(name)과 참조 카운터(kref)를 가진다.
  • kobject는 하이라키를 표현하기 위해 부모 kobject 포인터 및 ktype, kset 등을 가진다.
  • kobject는 sysfs 가상 파일 시스템에 디렉토리와 연동되므로 모든 디바이스의 구조를 디렉토리 구조로 표현하고 제어할 수 있다.
    • sysfs 구조에서 하나의 디렉토리는 kobject이다.
  • 관련 API
    • kobject_init()
    • kobject_init_and_add()
    • kobject_register()
    • kobject_add()
    • kobject_rename()
    • kobject_move()
    • kobject_get_path()
    • kobject_set_name()
    • kobject_del()
    • kobject_get()
    • kobject_get_unless_zero()
    • kobject_put()
    • kobject_create_and_add()

 

다음 그림의 좌측을 보면 3개의 객체가 하이라키 구조를 갖는 것을 표현하기 위해 각각 name, kref, parent 등의 멤버가 필요함을 알 수 있다. 이러한 정보를 쉽게 처리하기 위해 화살표 우측과 같이 kobject 구조체를 각 객체에 임베드하여 손쉽게 연동할 수 있음을 알 수 있다.

 

kset(kernel object set)

kobject를 여러개 담을 수 있는 컨테이너이다.

  • kset는 기본적으로 하나의 kobject를 포함한다.
  • kset의 컨테이너 구현은 kobject들이 연결된 리스트이다.
    • 이 리스트에 child kobject들이 연결된다.
  • sysfs에서 하나의 디렉토리 아래에 여러 개의 디렉토리가 필요한 경우 kset을 사용한다.
  • 관련 API
    • kset_register()
    • kset_unregister()
    • kset_find_obj()
    • kset_create_and_add()

 

다음 그림과 같은 디렉토리 구조를 같기 위해서는 디렉토리 밑에 2 개 이상의 child 디렉토리가 포함되어야 한다. 이러한 컨테이너를 구현하기 위해 kobject이외에도 list_lock, list, entry 등의 추가 필드들이 필요함을 알 수 있다. 화살표 우측과 같이 kobject를 포함한 컨테이너를 쉽게 구현할 수 있도록 kset 구조체가 사용됨을 알 수 있다.

 

ktype(kernel object type)

kobject가 제거될 때 호출될 함수가 지정된다. 또한 sysfs를 통해 kobject에 대한 정보를 보여주거나 수정될 때 처리할 오퍼레이션이 지정된다.

  • kobj_type 구조체를 사용한다.
  • kobject의 참조 카운터가 0이되어 더 이상 사용하지 않게될 경우 처리 방법이 지정된다.
    • 디폴트로 kfree() 함수가 호출되어 kobject가 제거된다.
  • sysfs에서 기본적으로 표현되고 수정될 방법이 지정된다.
    • 디폴트로 어트리뷰트에 지정된 show() 후크 함수 및 store() 함수가 지정된다.

 

다음 그림은 kobject가 생성될 때 디폴트 ktype으로 dynamic_kobj_ktype이 가리키는 kobj_type 구조체가 지정되는 것을 보여준다.

 

kref(kernel object reference)

참조 카운터가 kobject에 임베드되어 사용된다.  참조 카운터를 관리하는 표준 API인 kref_*() 함수들을 사용할 수 있다.

  • kobject_get() 함수 호출 시 참조 카운터를 1 증가시키는 kref_get() 함수가 호출된다.
  • kobject_put() 함수 호출 시 참조 카운터를 1 감소시키는 kref_put() 함수가 호출된다.
  • kobject_init() 함수 호출 시 참조 카운터를 1로 초기화시키는 kref_init() 함수가 호출된다.
  • 기타 함수
    • kref_read()
    • kref_get_unless_zero()
    • kref_put_mutex()
    • kref_put_lock()

 

다음 그림은 kobject가 처음 초기화되고 참조 카운터가 1이된 것을 보여준다. 그리고 kobject가 추가된 후 sysfs에 연결된 상태의 kobject 상태 값들을 보여준다.

 

Sysfs 파일시스템

sysfs 파일시스템은 유저가 커널 자료 구조와 인터페이스를 하기 위한 가상파일시스템이다. 디렉토리 및 파일들은 kset, kobject로 표현된다. sysfs는 보통 다음과 같이 마운트된다.

  • mount -t sysfs sysfs /sys

 

sysfs는 최근의 Device Driver Model을 따라 하이라키 관계를 사용하여 관리되는 방법이며 다음 방법들을 대체하는 것을 권고하고 있다.

  • procfs
    • 프로세스 정보를 유저 application과의 인터페이스를 위해 심플하게 readable text 출력 포맷으로 출력하게 고안된 파일 시스템이다.
    • 과도하게 이 디렉토리에 파일들이 모여있는 것을 피하기 위해 sysfs가 사용된다.
  • character 디바이스
    • ioctl()을 포함한 file operation 방식으로 유저 application과의 인터페이스를 수행한다.
    • major 및 minor 넘버링이 필요하다.

 

최신 버전 sysfs

  • sysfs는 앞으로 구조가 대폭 변경된다. sys 디렉토리에 직접 접근해야 하는 low-level 유저 application은 앞으로 몇 가지 rule을 따라야 한다. 앞으로 표준화될 새로운 sysfs의 인터페이스 방법은 다음을 참고한다.

 

sysfs 디렉토리 구조

sysfs의 구조는 대략 다음 그림과 같다.

 

Sysfs 관련 API들

디렉토리
  • sysfs_create_mount_point()
  • sysfs_remove_mount_point()
파일
  • sysfs_notify()
  • sysfs_create_file()
  • sysfs_create_files()
  • sysfs_create_file_ns()
  • sysfs_add_file()
  • sysfs_chmod_file()
  • sysfs_add_file_to_group()
  • sysfs_add_file_mode_ns()
  • sysfs_remove_file_ns()
  • sysfs_remove_files()
  • sysfs_remove_file_from_group()
  • sysfs_create_bin_file()
  • sysfs_remove_bin_file()
그룹
  • sysfs_create_group()
  • sysfs_create_groups()
  • sysfs_update_group()
  • sysfs_remove_group()
  • sysfs_remove_groups()
  • sysfs_merge_group()
  • sysfs_unmerge_group()
  • sysfs_add_link_to_group()
  • sysfs_remove_link_from_group()
  • __compat_only_sysfs_link_entry_to_kobj()
링크
  • sysfs_create_link()
  • sysfs_create_link_nowarn()
  • sysfs_create_link_sd()
  • sysfs_remove_link()
  • sysfs_rename_link_ns()

 

Sysfs 샘플

샘플을 통해 속성을 사용하는 방법과 유저 application으로 이벤트를 전달하는 방법을 알아본다.

 

속성 구조체와 매크로 함수

샘플들을 사용하면서 attribute 및 device_attribute 에 대한 2가지 속성들을 알아보기로한다. bus_attribute, class_attribute 및 driver_attribute 등의 샘플은 사용방법이 유사하므로 생략한다. 다음은 5 가지 속성에 대한 구조체와 관련 매크로 함수들을 보여준다.

  • attribute 구조체
    • __ATTR(_name, _mode, _show, _store)
    • __ATTR_RW(_name)
    • __ATTR_RO(_name)
    • __ATTR_WO(_name)
  • device_attribute 구조체
    • DEVICE_ATTR(_name, _mode, _show, _store)
    • DEVICE_ATTR_RW(_name)
    • DEVICE_ATTR_RO(_name)
    • DEVICE_ATTR_WO(_name)
  •  bus_attribute 구조체
    • BUS_ATTR(_name, _mode, _show, _store)
    • BUS_ATTR_RW(_name)
    • BUS_ATTR_RO(_name)
  • class_attribute 구조체
    • CLASS_ATTR_RW(_name)
    • CLASS_ATTR_RO(_name)
    • CLASS_ATTR_WO(_name)
  • driver_attribute 구조체
    • DRIVER_ATTR_RW(_name)
    • DRIVER_ATTR_RO(_name)
    • DRIVER_ATTR_WO(_name)

 

1) kobject_init() & kobject_add() 사용

Makefile

obj-m := foo1.o foo2.o foo3.o
KER_DIR := /lib/modules/$(shell uname -r)/build

all:
	make -C ${KER_DIR} M=$(PWD) modules
	gcc test.c -o test

clean:
	make -C ${KER_DIR} M=$(PWD) clean
	rm -f test.o
	rm -f test

 

foo.1 샘플은 attribute 구조체를 사용하고 kobject API를 사용하여 /sys/foo/foo_value 및 /sys/foo/foo_notify 속성을 만든다.

foo1.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/string.h>
#include <linux/slab.h>

static struct kobject *foo_kobj;

struct foo_attr{
	struct attribute attr;
	int value;
};

static struct foo_attr foo_value = {
	.attr.name="foo_value",
	.attr.mode = 0644,
	.value = 0,
};

static struct foo_attr foo_notify = {
	.attr.name="foo_notify",
	.attr.mode = 0644,
	.value = 0,
};

static struct attribute * foo_attrs[] = {
	&foo_value.attr,
	&foo_notify.attr,
	NULL
};

static ssize_t foo_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
	struct foo_attr *foo = container_of(attr, struct foo_attr, attr);
	return scnprintf(buf, PAGE_SIZE, "%d\n", foo->value);
}

static ssize_t foo_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len)
{
	struct foo_attr *foo = container_of(attr, struct foo_attr, attr);

	sscanf(buf, "%d", &foo->value);
	foo_value.value = foo->value;
	sysfs_notify(foo_kobj, NULL, "foo_notify");
	return len;
}

static struct sysfs_ops foo_ops = {
	.show = foo_show,
	.store = foo_store,
};

static struct kobj_type foo_type = {
	.sysfs_ops = &foo_ops,
	.default_attrs = foo_attrs,
};

static int __init foo_init(void)
{
	int ret = 0;

	printk("%s\n", __func__);

	foo_kobj = kzalloc(sizeof(*foo_kobj), GFP_KERNEL);
	if (!foo_kobj)
	{
		printk("%s: kzalloc() failed\n", __func__);
		return -1;
	}

	kobject_init(foo_kobj, &foo_type);
	ret = kobject_add(foo_kobj, NULL, "%s", "foo");
	if (ret) {
		printk("kobject_add() failed. ret=%d\n", ret);
		kobject_put(foo_kobj);
		foo_kobj = NULL;
	}

	return ret;	/* 0=success */
}

static void __exit foo_exit(void)
{
	if (foo_kobj) {
		kobject_put(foo_kobj);
	}

	printk("%s\n", __func__);
}

module_init(foo_init);
module_exit(foo_exit);
MODULE_LICENSE("GPL");

 

위의 샘플을 동작시키면 다음과 같은 속성 파일이 생성된다.

$ su -
$ insmod foo1.ko
$ cd /sys/foo
$ ls
foo_notify   foo_value
$ echo 123 > foo_value
$ cat foo_value
123
$ rmmod foo1

 

2) kobject_create_and_add() &  sysfs_create_group() 사용

 

foo2.c 샘플은 kobj_attribute 구조체를 사용하고 kobject 및 sysfs API를 사용하여 /sys/foo/foo_value 및 /sys/foo/foo_notify 속성을 만든다. foo2.c의 사용법은 foo1.c와 동일하다.

foo2.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/string.h>
#include <linux/slab.h>

static struct kobject *foo_kobj;

struct foo_attr{
	struct kobj_attribute attr;
	int value;
};

static struct foo_attr foo_value;
static struct foo_attr foo_notify;

static struct attribute *foo_attrs[] = {
	&foo_value.attr.attr,
	&foo_notify.attr.attr,
	NULL
};

static struct attribute_group foo_group = {
	.attrs = foo_attrs,
};

static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr, 
		char *buf)
{
	struct foo_attr *foo = container_of(attr, struct foo_attr, attr);
	return scnprintf(buf, PAGE_SIZE, "%d\n", foo->value);
}

static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr, 
		const char *buf, size_t len)
{
	struct foo_attr *foo = container_of(attr, struct foo_attr, attr);

	sscanf(buf, "%d", &foo->value);
	sysfs_notify(foo_kobj, NULL, "foo_notify");
	return len;
}

static struct foo_attr foo_value = {
	.attr = __ATTR(foo_value, 0644,	foo_show, foo_store),
	.value = 0,
};

static struct foo_attr foo_notify = {
	.attr = __ATTR(foo_notify, 0644, foo_show, foo_store),
	.value = 0,
};

static int __init foo_init(void)
{
	int ret = 0;

	printk("%s\n", __func__);

	foo_kobj = kobject_create_and_add("foo", NULL);
	if (!foo_kobj) {
		printk("%s: kobject_create_and_add() failed\n", __func__);
		return -1;
	}

	ret = sysfs_create_group(foo_kobj, &foo_group);
	if (ret) 
		printk("%s: sysfs_create_group() failed. ret=%d\n", __func__, ret);

	return ret;	/* 0=success */
}

static void __exit foo_exit(void)
{
	if (foo_kobj) {
		kobject_put(foo_kobj);
	}

	printk("%s\n", __func__);
}

module_init(foo_init);
module_exit(foo_exit);
MODULE_LICENSE("GPL");

 

3) platform_device_register() 사용

 

foo3.c 샘플은 플랫폼 디바이스를 등록할 때 device_attribute 구조체를 사용한 디바이스 속성을 등록한다.

foo3.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/platform_device.h>                                              

struct foo_attr{
	struct device_attribute attr;
	int value;
};

static struct foo_attr foo_value;
static struct foo_attr foo_notify;

static struct attribute *foo_attrs[] = {
	&foo_value.attr.attr,
	&foo_notify.attr.attr,
	NULL
};

ATTRIBUTE_GROUPS(foo);

static ssize_t foo_show(struct device *dev, struct device_attribute *attr, 
		char *buf)
{
	struct foo_attr *foo = container_of(attr, struct foo_attr, attr);
	return scnprintf(buf, PAGE_SIZE, "%d\n", foo->value);
}

static ssize_t foo_store(struct device *dev, struct device_attribute *attr, 
		const char *buf, size_t len)
{
	struct foo_attr *foo = container_of(attr, struct foo_attr, attr);

	sscanf(buf, "%d", &foo->value);
	sysfs_notify(&dev->kobj, NULL, "foo_notify");
	return len;
}

static struct foo_attr foo_value = {
	.attr = __ATTR(foo_value, 0644, foo_show, foo_store),
	.value = 0,
};

static struct foo_attr foo_notify = {
	.attr = __ATTR(foo_notify, 0644, foo_show, foo_store),
	.value = 0,
};

static struct platform_device foo_device = {                                   
	.name = "foo",
	.id = -1,
	.dev.groups = foo_groups,
};                                                                              

static int __init foo_init(void)
{
	int ret = 0;

	printk("%s\n", __func__);

	ret = platform_device_register(&foo_device);
	if (ret < 0) {
		printk("%s: platform_device_register() failed. ret=%d\n",
				__func__, ret);
		ret = -1;
	}

	return ret;	/* 0=success */
}

static void __exit foo_exit(void)
{
	platform_device_unregister(&foo_device);

	printk("%s\n", __func__);
}

module_init(foo_init);
module_exit(foo_exit);
MODULE_LICENSE("GPL");

 

위의 foo3.c 샘플을 동작시키면 다음과 같이 플랫폼 디비이스 디렉토리 뒤에 foo 플랫폼 디바이스가 만들어지고 그 안에 속성 파일이 생성된다.

$ su -
$ insmod foo3.ko
$ cd /sys/devices/platform/foo
$ ls
driver_override foo_notify foo_value modalias power subsystem uevent
$ echo 123 > foo_value
$ cat foo_value
123
$ rmmod foo3

 

이벤트 테스트를 위한 유저 application

위에서 작성한 3가지의 샘플 모듈을 사용하여 유저 application에서 poll() API를 사용하여 이벤트를 받는 방법을 보여주기 위한 샘플이다.

  • 참고로 커널 모듈에서 속성에 이벤트를 전달하는 방법은 sysfs_notify() 함수를 사용한다.
  • 주의: foo3.c 샘플과 연동하여 테스트하려면 아래 FOO_VALUE 및 FOO_NOTIFY의 디렉토리 경로를 플랫폼 디바이스 위치로 변경해야 한다.
    • #define FOO_VALUE “/sys/devices/platform/foo/foo_value”
    • #define FOO_NOTIFY “/sys/devices/platform/foo/foo_notify”

test.c

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h> 
#include <sys/stat.h> 
#include <poll.h>

#define FOO_VALUE "/sys/foo/foo_value"
#define FOO_NOTIFY "/sys/foo/foo_notify"

int main(int argc, char **argv)
{
	int len, value_fd, notify_fd, recv;
	char attr_data[100];
	struct pollfd fds[1];

	if ((value_fd = open("/sys/foo/foo_value", O_RDWR)) < 0)
	{
		printf("Unable to open %s\n", FOO_VALUE);
		exit(1);
	}

	if ((notify_fd = open("/sys/foo/foo_notify", O_RDWR)) < 0)
	{
		printf("Unable to open %s\n", FOO_NOTIFY);
		exit(1);
	}

	fds[0].fd = notify_fd;
	fds[0].events = POLLPRI | POLLERR;

	/* read garvage data once */
	len = read(notify_fd, attr_data, 100);

	fds[0].revents = 0;

	/* wait until 60 sec */
	recv = poll(fds, 1, 60000);
	if (recv < 0)
	{
		perror("poll error");
	}
	else if (recv == 0)
	{
		printf("Timeout!\n");
	}
	else
	{
		memset(attr_data, 0, 100);
		len = lseek(value_fd, 0, SEEK_SET);
		len = read(value_fd, attr_data, 100);
		printf( "foo_value=%s (len=%d)\n", attr_data, len);
	}

	close(notify_fd);
	close(value_fd);
}

 

다음과 같이 두 개의 터미널을 열고 각각에서 다음과 같이 동작시킨다.

터미널 1
$ su -                 <- 루트 계정으로 접근한다.
$ ./test3              <- 60초 동안 이벤트를 대기한다.
foo_value=456          <- 이벤트가 발생하는 순간 출력된다.
 (len=4)

 

터미널 2
$ su -                         <- 루트 계정으로 접근한다.
$ cd /sys/devices/platform/foo
$ echo 456 > foo_value         <- 이 속성을 변경하는 순간 이벤트가 발생한다.

 

참고