TX1 kernel modification, build error

I’m trying to build a custom kernel for my TX1, where the PCIe host controller driver is broken out as a dynamically loadable module.

Using menuconfig, I’ve set the option for NVIDIA Tegra PCIe Host Controller from <*> to (found under Bus Support from the main menu). As far as I can tell, this should compile as a module instead of being built-in.

Following the kernel compilation instructions from the NVIDIA documentation, building the zImage and dtb’s works fine, but when I try to build the kernel modules (make O=$TEGRA_KERNEL_OUT modules), I get the following error:

ERROR: "disable_scx_states" [drivers/pci/host/pci-tegra.ko] undefined!

Doing a little digging, the disable_scx_states() function is being called from drivers/pci/host/pci-tegra.c. The function is defined in the kernel sources, in drivers/platform/tegra/pm_domains.c, which appears to be properly compiled to $TEGRA_KERNEL_OUT/drivers/platform/tegra/pm_domains.o. The function (and it’s signature in header file include/linux/tegra_pm_domains.h) is contained in an #ifdef, but after a little poking around it appears the macro is defined and the code should be executed.

Is this a linking problem? I looked at the Makefile in the kernel sources and found the build rule for modules, but I’m no make expert and it’s tough to understand what’s going on. For now, I’ve been able to get around this by commenting out the offending call, but it seems like a hack. Any ideas on how to fix this?

My testing is with Linaro 5.3 compiler and R24.2’s kernel, changing only “Bus support -> NVIDIA Tegra PCIe controller” from “*” to “M”. I can verify that this fails:

Building modules, stage 2.
  MODPOST 23 modules
ERROR: "disable_scx_states" [drivers/pci/host/pci-tegra.ko] undefined!
/home/build/Documents/embedded/L4T/R24.2/src/kernel/kernel-3.10.96-fix/scripts/Makefile.modpost:88: recipe for target '__modpost' failed
make[2]: *** [__modpost] Error 1
/home/build/Documents/embedded/L4T/R24.2/src/kernel/kernel-3.10.96-fix/Makefile:959: recipe for target 'modules' failed
make[1]: *** [modules] Error 2
Makefile:130: recipe for target 'sub-make' failed
make: *** [sub-make] Error 2

This function prototype is conditionally in “include/linux/tegra_pm_domains.h”. If CONFIG_ARCH_TEGRA_21x_SOC is defined, then this is an inline static implementation which does nothing (a placeholder with an empty body), otherwise it is declared extern. Apparently part of the code starts looking for the extern implementation when building as a module.

Within “drivers/pci/host/pci-tegra.c” the correct header is unconditionally included, as it should be. It appears that what fails is “defined(CONFIG_ARCH_TEGRA_21x_SOC)” results in an extern declaration with no extern implementation. This define should be in “arch/arm64/mach-tegra/Kconfig”, described as “Tegra 21x family SOC”, which is still checked, so I’m not sure why the other file would not find this.

The actual failure is from an attempt to use disable_scx_states in “drivers/pci/host/pci-tegra.c”, function tegra_pcie_probe_complete. The comment on that block of code is this:

3927         /* FIXME:In Bug 200160313, device hang is observed during LP0 with PCIe
3928          * device connected. When PCIe device is not under mc_clk power-domain,
3929          * this issue does not occur, but SC2/SC3 might break. So, we are calling
3930          * disable_scx_states(), that will disabled SCx states whenever PCIe
3931          * device is connected.
3932          */
3933         if (pcie->num_ports)
3934                 disable_scx_states();

This solution allows compile, but is unlikely to be correct (this shows where the definition is missing in “drivers/pci/host/pci-tegra.c”):

3927         /* FIXME:In Bug 200160313, device hang is observed during LP0 with PCIe
3928          * device connected. When PCIe device is not under mc_clk power-domain,
3929          * this issue does not occur, but SC2/SC3 might break. So, we are calling
3930          * disable_scx_states(), that will disabled SCx states whenever PCIe
3931          * device is connected.
3932          */
3933 #ifndef CONFIG_ARCH_TEGRA_21x_SOC
3934         if (pcie->num_ports)
3935                 disable_scx_states();
3936 #endif  
3937