watchdog module_amba_driver
[root@centos7 linux-5.14]# ls /dev/watchdog /dev/watchdog
[root@centos7 opensbi]# ls /sys/bus/amba/ devices drivers drivers_autoprobe drivers_probe uevent [root@centos7 opensbi]# ls /sys/bus/amba/devices/ [root@centos7 opensbi]#
[root@centos7 opensbi]# ls /sys/bus/amba/devices/ [root@centos7 opensbi]# ls /sys/bus/amba/ devices drivers drivers_autoprobe drivers_probe uevent [root@centos7 opensbi]# ls /sys/bus/amba/devices/ [root@centos7 opensbi]# ls /sys/bus/amba/devices/ [root@centos7 opensbi]# ls /sys/bus/amba/ devices drivers drivers_autoprobe drivers_probe uevent [root@centos7 opensbi]# ls /sys/bus/amba/drivers clcd-pl11x kmi-pl050 pl061_gpio rtc-pl031 uart-pl011 [root@centos7 opensbi]#
/* * module_amba_driver() - Helper macro for drivers that don't do anything * special in module init/exit. This eliminates a lot of boilerplate. Each * module may only use this macro once, and calling it replaces module_init() * and module_exit() */ #define module_amba_driver(__amba_drv) \ module_driver(__amba_drv, amba_driver_register, amba_driver_unregister)
#define module_driver(__driver, __register, __unregister, ...) \ static int __init __driver##_init(void) \ { \ return __register(&(__driver) , ##__VA_ARGS__); \ }
ARM_AMBA
drivers/amba/Kconfig:2:config ARM_AMBA
root@ubuntu:~/linux_arm64/linux-5.14# grep ARM64 .config CONFIG_ARM64=y
root@ubuntu:~/linux_arm64/linux-5.14# grep ARM_AMBA .config CONFIG_ARM_AMBA=y
drivers/amba/Makefile:2:obj-$(CONFIG_ARM_AMBA) += bus.o include/linux/amba/bus.h:108:#ifdef CONFIG_ARM_AMBA
drivers/amba/bus.c
EXPORT_SYMBOL(amba_driver_register);
EXPORT_SYMBOL(amba_driver_unregister);
EXPORT_SYMBOL(amba_device_register);
EXPORT_SYMBOL(amba_device_unregister);
EXPORT_SYMBOL(amba_find_device);
EXPORT_SYMBOL(amba_request_regions);
EXPORT_SYMBOL(amba_release_regions);
root@ubuntu:~/linux_arm64/linux-5.14# grep ARM_SP805_WATCHDOG .config CONFIG_ARM_SP805_WATCHDOG=m root@ubuntu:~/linux_arm64/linux-5.14# lscpu Architecture: aarch64 Byte Order: Little Endian CPU(s): 64 On-line CPU(s) list: 0-63 Thread(s) per core: 1 Core(s) per socket: 32 Socket(s): 2 NUMA node(s): 4 Vendor ID: ARM Model: 2 Model name: Cortex-A72 Stepping: r0p2 BogoMIPS: 100.00 L1d cache: 32K L1i cache: 48K L2 cache: 1024K L3 cache: 16384K NUMA node0 CPU(s): 0-15 NUMA node1 CPU(s): 16-31 NUMA node2 CPU(s): 32-47 NUMA node3 CPU(s): 48-63 Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid root@ubuntu:~/linux_arm64/linux-5.14#
CONFIG_ARM_AMBA
drivers/of/platform.c:28://#ifdef CONFIG_ARM_AMBA drivers/of/platform.c:218://#ifdef CONFIG_ARM_AMBA drivers/of/platform.c:573://#ifdef CONFIG_ARM_AMBA drivers/iommu/amd/iommu.c:1795:#ifdef CONFIG_ARM_AMBA drivers/iommu/arm/arm-smmu/arm-smmu.c:2030:#ifdef CONFIG_ARM_AMBA drivers/iommu/arm/arm-smmu/arm-smmu.c:2058:#ifdef CONFIG_ARM_AMBA drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c:3718:#ifdef CONFIG_ARM_AMBA drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c:3734:#ifdef CONFIG_ARM_AMBA drivers/iommu/virtio-iommu.c:1088:#ifdef CONFIG_ARM_AMBA drivers/xen/arm-device.c:146:#ifdef CONFIG_ARM_AMBA drivers/gpu/drm/pl111/pl111_drv.c:441:#ifdef CONFIG_ARM_AMBA drivers/acpi/internal.h:29:#ifdef CONFIG_ARM_AMBA include/linux/amba/bus.h:108://#ifdef CONFIG_ARM_AMBA
riscv SP805
# ALPHA Architecture # ARM Architecture config ARM_SP805_WATCHDOG tristate "ARM SP805 Watchdog" depends on (ARM || ARM64 || COMPILE_TEST) && ARM_AMBA select WATCHDOG_CORE help ARM Primecell SP805 Watchdog timer. This will reboot your system when the timeout is reached.
[root@centos7 linux-5.14]# grep SP805 .config CONFIG_ARM_SP805_WATCHDOG=y [root@centos7 linux-5.14]#
[root@centos7 linux-5.14]# make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j128 SYNC include/config/auto.conf.cmd CALL scripts/atomic/check-atomics.sh CALL scripts/checksyscalls.sh CHK include/generated/compile.h CC drivers/watchdog/watchdog_core.o CC drivers/watchdog/watchdog_dev.o CC drivers/watchdog/sp805_wdt.o UPD kernel/config_data GZIP kernel/config_data.gz CC kernel/configs.o AR kernel/built-in.a AR drivers/watchdog/built-in.a AR drivers/built-in.a GEN .version CHK include/generated/compile.h UPD include/generated/compile.h CC init/version.o AR init/built-in.a LD vmlinux.o MODPOST vmlinux.symvers MODINFO modules.builtin.modinfo GEN modules.builtin LD .tmp_vmlinux.kallsyms1 KSYMS .tmp_vmlinux.kallsyms1.S AS .tmp_vmlinux.kallsyms1.S LD .tmp_vmlinux.kallsyms2 KSYMS .tmp_vmlinux.kallsyms2.S AS .tmp_vmlinux.kallsyms2.S LD vmlinux SYSMAP System.map MODPOST modules-only.symvers OBJCOPY arch/riscv/boot/Image GEN Module.symvers GZIP arch/riscv/boot/Image.gz Kernel: arch/riscv/boot/Image.gz is ready [root@centos7 linux-5.14]# cat System.map | grep amba_driver_registe [root@centos7 linux-5.14]# cat System.map | grep
竟然没有
[root@centos7 linux-5.14]# cat System.map | grep sp805_wdt_probe [root@centos7 linux-5.14]# cat System.map | grep sp805_wdt_resume [root@centos7 linux-5.14]#
clean 下重新编译
[root@centos7 linux-5.14]# cat System.map | grep sp805_wdt_probe [root@centos7 linux-5.14]# cat System.map | grep sp805 ffffffff8061c276 t sp805_wdt_driver_init ffffffff8062ae7e t sp805_wdt_driver_exit ffffffff8080f5f8 d __initcall__kmod_sp805_wdt__324_358_sp805_wdt_driver_init6 [root@centos7 linux-5.14]# cat System.map | grep amba_driver_ [root@centos7 linux-5.14]#
但是还是没有amba_driver_
原来是.config 和 driver/xx/Kconfig driver/xx/Makefile 中的config_XXX不一致
[root@centos7 linux-5.14]# make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j128 CALL scripts/atomic/check-atomics.sh CALL scripts/checksyscalls.sh CHK include/generated/compile.h CC drivers/amba/bus.o drivers/amba/bus.c:343:5: error: redefinition of 'amba_driver_register' 343 | int amba_driver_register(struct amba_driver *drv) | ^~~~~~~~~~~~~~~~~~~~ In file included from drivers/amba/bus.c:16: ./include/linux/amba/bus.h:112:19: note: previous definition of 'amba_driver_register' with type 'int(struct amba_driver *)' 112 | static inline int amba_driver_register(struct amba_driver *drv) | ^~~~~~~~~~~~~~~~~~~~ drivers/amba/bus.c:361:6: error: redefinition of 'amba_driver_unregister' 361 | void amba_driver_unregister(struct amba_driver *drv) | ^~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/amba/bus.c:16: ./include/linux/amba/bus.h:116:20: note: previous definition of 'amba_driver_unregister' with type 'void(struct amba_driver *)' 116 | static inline void amba_driver_unregister(struct amba_driver *drv) | ^~~~~~~~~~~~~~~~~~~~~~ make[2]: *** [scripts/Makefile.build:271: drivers/amba/bus.o] Error 1 make[1]: *** [scripts/Makefile.build:514: drivers/amba] Error 2 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1851: drivers] Error 2 [root@centos7 linux-5.14]# find ./ -name amba ./include/linux/amba ./drivers/amba [root@centos7 linux-5.14]# vim
更改 vim include/linux/amba/bus.h +116
[root@centos7 linux-5.14]# make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j128 CALL scripts/atomic/check-atomics.sh CALL scripts/checksyscalls.sh CHK include/generated/compile.h CC drivers/amba/bus.o CC drivers/of/platform.o AR drivers/of/built-in.a AR drivers/amba/built-in.a AR drivers/built-in.a GEN .version CHK include/generated/compile.h UPD include/generated/compile.h CC init/version.o AR init/built-in.a LD vmlinux.o MODPOST vmlinux.symvers MODINFO modules.builtin.modinfo GEN modules.builtin LD .tmp_vmlinux.kallsyms1 KSYMS .tmp_vmlinux.kallsyms1.S AS .tmp_vmlinux.kallsyms1.S LD .tmp_vmlinux.kallsyms2 KSYMS .tmp_vmlinux.kallsyms2.S AS .tmp_vmlinux.kallsyms2.S LD vmlinux SYSMAP System.map MODPOST modules-only.symvers OBJCOPY arch/riscv/boot/Image GEN Module.symvers GZIP arch/riscv/boot/Image.gz Kernel: arch/riscv/boot/Image.gz is ready
[root@centos7 linux-5.14]# cat System.map | grep amba_driver_ ffffffff804f0d12 T amba_driver_register ffffffff804f0d38 T amba_driver_unregister ffffffff80f77568 r __ksymtab_amba_driver_register ffffffff80f77580 r __ksymtab_amba_driver_unregister ffffffff80faf548 r __kstrtabns_amba_driver_register ffffffff80faf548 r __kstrtabns_amba_driver_unregister ffffffff80fb98fd r __kstrtab_amba_driver_register ffffffff80fb9912 r __kstrtab_amba_driver_unregister [root@centos7 linux-5.14]#
[root@centos7 linux-5.14]# cat System.map | grep sp805_ ffffffff804ba33e t sp805_wdt_remove ffffffff804fa280 t sp805_wdt_probe ffffffff8061c276 t sp805_wdt_driver_init ffffffff8062aeb6 t sp805_wdt_driver_exit ffffffff8080f600 d __initcall__kmod_sp805_wdt__324_359_sp805_wdt_driver_init6 ffffffff80e8f4c0 d sp805_wdt_ids ffffffff80e8f4e0 d sp805_wdt_dev_pm_ops ffffffff812b1280 d sp805_wdt_driver
login[98]: root login on 'console'
#
# ls /sys/bus/amba/
devices drivers_autoprobe uevent
drivers drivers_probe
#
# ls /sys/bus/amba/devices/
#
# ls /sys/bus/amba/devices/
#
# ls /sys/bus/amba/devices/drivers
ls: /sys/bus/amba/devices/drivers: No such file or directory
#
# ls /sys/bus/amba/
devices drivers_autoprobe uevent
drivers drivers_probe
#
# ls /sys/bus/amba/drivers
sp805-wdt
#
# ls /sys/bus/amba/drivers/sp805-wdt/
bind uevent unbind
#
# ls /sys/bus/amba/devices/
#
# ls /dev/watchdog
ls: /dev/watchdog: No such file or directory
#
#
amba_device_create
customize_machine ->of_platform_populate ->of_platform_bus_create ->of_amba_device_create ->of_amba_device_create
-> ……
->call_driver_probe
-->amba_probe -->pcdrv->probe(pcdev, id) -->sp805_wdt_probe
sp805-wdt: probe of 20030000.watchdog failed with error -2
static int call_driver_probe(struct device *dev, struct device_driver *drv) { int ret = 0; if (dev->bus->probe) ret = dev->bus->probe(dev); else if (drv->probe) ret = drv->probe(dev); switch (ret) { case 0: break; case -EPROBE_DEFER: /* Driver requested deferred probing */ dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name); break; case -ENODEV: case -ENXIO: pr_debug("%s: probe of %s rejects match %d\n", drv->name, dev_name(dev), ret); break; default: /* driver matched but the probe failed */ pr_warn("%s: probe of %s failed with error %d\n", drv->name, dev_name(dev), ret); break; } return ret; }
amba_probe(struct device *dev) -->amba_get_enable_pclk-->clk_get
调用clk_get失败了
drivers/clk/clkdev.c
struct clk *clk_get(struct device *dev, const char *con_id) { const char *dev_id = dev ? dev_name(dev) : NULL; struct clk_hw *hw; if (dev && dev->of_node) { hw = of_clk_get_hw(dev->of_node, 0, con_id); if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER) return clk_hw_create_clk(dev, hw, dev_id, con_id); } return __clk_get_sys(dev, dev_id, con_id); }
struct device_node *of_node; /* associated device tree node */
[ 0.933175] OF: amba: of_address_to_resource() failed (-22) for /soc/timer@0
static struct amba_device *of_amba_device_create(struct device_node *node, const char *bus_id, void *platform_data, struct device *parent) { struct amba_device *dev; const void *prop; int i, ret; pr_err("Creating amba device %pOF\n", node); //pr_debug("Creating amba device %pOF\n", node); if (!of_device_is_available(node) || of_node_test_and_set_flag(node, OF_POPULATED)) return NULL; dev = amba_device_alloc(NULL, 0, 0); if (!dev) goto err_clear_flag; /* AMBA devices only support a single DMA mask */ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); dev->dev.dma_mask = &dev->dev.coherent_dma_mask; /* setup generic device info */ dev->dev.of_node = of_node_get(node); dev->dev.fwnode = &node->fwnode; dev->dev.parent = parent ? : &platform_bus; dev->dev.platform_data = platform_data; if (bus_id) dev_set_name(&dev->dev, "%s", bus_id); else of_device_make_bus_id(&dev->dev); /* Allow the HW Peripheral ID to be overridden */ prop = of_get_property(node, "arm,primecell-periphid", NULL); if (prop) dev->periphid = of_read_ulong(prop, 1); /* Decode the IRQs and address ranges */ for (i = 0; i < AMBA_NR_IRQS; i++) dev->irq[i] = irq_of_parse_and_map(node, i); ret = of_address_to_resource(node, 0, &dev->res); if (ret) { pr_err("amba: of_address_to_resource() failed (%d) for %pOF\n", ret, node); goto err_free; } ret = amba_device_add(dev, &iomem_resource); if (ret) { pr_err("amba_device_add() failed (%d) for %pOF\n", ret, node); goto err_free; } return dev; err_free: amba_device_put(dev); err_clear_flag: of_node_clear_flag(node, OF_POPULATED); return NULL; }
static int __of_address_to_resource(struct device_node *dev, int index, int bar_no, struct resource *r) { u64 taddr; const __be32 *addrp; u64 size; unsigned int flags; const char *name = NULL; addrp = __of_get_address(dev, index, bar_no, &size, &flags); pr_err("tracing %s __of_get_address %d" ,dev->full_name, addrp == NULL); if (addrp == NULL) return -EINVAL; /* Get optional "reg-names" property to add a name to a resource */ if (index >= 0) of_property_read_string_index(dev, "reg-names", index, &name); if (flags & IORESOURCE_MEM) taddr = of_translate_address(dev, addrp); else if (flags & IORESOURCE_IO) taddr = of_translate_ioport(dev, addrp, size); else return -EINVAL; if (taddr == OF_BAD_ADDR) return -EINVAL; memset(r, 0, sizeof(struct resource)); if (of_mmio_is_nonposted(dev)) flags |= IORESOURCE_MEM_NONPOSTED; r->start = taddr; r->end = taddr + size - 1; r->flags = flags; r->name = name ? name : dev->full_name; return 0; } /** * of_address_to_resource - Translate device tree address and return as resource * @dev: Caller's Device Node * @index: Index into the array * @r: Pointer to resource array * * Note that if your address is a PIO address, the conversion will fail if * the physical address can't be internally converted to an IO token with * pci_address_to_pio(), that is because it's either called too early or it * can't be matched to any host bridge IO space */ int of_address_to_resource(struct device_node *dev, int index, struct resource *r) { return __of_address_to_resource(dev, index, -1, r); } 0x4306_0000c EXPORT_SYMBOL_GPL(of_address_to_resource); /** * of_iomap - Maps the memory mapped IO for a given device_node * @np: the device whose io range will be mapped * @index: index of the io range * * Returns a pointer to the mapped memory */ void __iomem *of_iomap(struct device_node *np, int index) { struct resource res; if (of_address_to_resource(np, index, &res)) return NULL; if (res.flags & IORESOURCE_MEM_NONPOSTED) return ioremap_np(res.start, resource_size(&res)); else return ioremap(res.start, resource_size(&res)); } EXPORT_SYMBOL(of_iomap);
[ 1.337101] OF: __of_get_address parent == NULL ? 0 [ 1.337450] OF: __of_get_address prop == NULL? 0 [ 1.343550] OF: __of_get_address psize 2, onesize 4 [ 1.349286] OF: __of_get_address addrp == NULL ? 1
跟踪_of_get_address发现psize 小于onesize
const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no, u64 *size, unsigned int *flags) { const __be32 *prop; unsigned int psize; struct device_node *parent; struct of_bus *bus; int onesize, i, na, ns; /* Get parent & match bus type */ parent = of_get_parent(dev); pr_err("%s parent == NULL ? %d ",__func__, parent == NULL); if (parent == NULL) return NULL; bus = of_match_bus(parent); if (strcmp(bus->name, "pci") && (bar_no >= 0)) { of_node_put(parent); return NULL; } bus->count_cells(dev, &na, &ns); of_node_put(parent); if (!OF_CHECK_ADDR_COUNT(na)) return NULL; /* Get "reg" or "assigned-addresses" property */ pr_err(" %s prop == NULL? %d",__func__, prop == NULL); if (prop == NULL) return NULL; psize /= 4; onesize = na + ns; pr_err(" %s psize %x, onesize %x",__func__, psize, onesize); for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) { u32 val = be32_to_cpu(prop[0]); /* PCI bus matches on BAR number instead of index */ if (((bar_no >= 0) && ((val & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0))) || ((index >= 0) && (i == index))) { if (size) *size = of_read_number(prop + na, ns); if (flags) *flags = bus->get_flags(prop); return prop; } } return NULL; }
soc: soc {
#address-cells = <2>;
#size-cells = <2>;
timer0: timer0 { compatible = "arm,sp804", "arm,primecell"; reg = < 0x200A0000 0x1000>; interrupt-parent = <&plic0>; interrupts = <33>, <34>, <35>, <36>; clocks = <&timclk1 &timclk2>; clock-names = "timer1", "timer2"; };
原来是timer0继承了
#address-cells = <2>;
#size-cells = <2>;
改成如下,问题解决
timer0: timer0 { compatible = "arm,sp804", "arm,primecell"; reg = < 0x0 0x200A0000 0x0 0x1000>; interrupt-parent = <&plic0>; interrupts = <33>, <34>, <35>, <36>; clocks = <&timclk1 &timclk2>; clock-names = "timer1", "timer2"; };