diff options
128 files changed, 1814 insertions, 1134 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index b69482b29625..f68bf1cdb53b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1228,8 +1228,9 @@ Kernel parameters deferred probe to give up waiting on dependencies to probe. Only specific dependencies (subsystems or drivers) that have opted in will be ignored. A timeout - of 0 will timeout at the end of initcalls. If the time - out hasn't expired, it'll be restarted by each + of 0 will timeout at the end of initcalls; a negative + value is treated as an infinite timeout value. If the + timeout hasn't expired, it'll be restarted by each successful driver registration. This option will also dump out devices still on the deferred probe list after retrying. diff --git a/Documentation/driver-api/driver-model/platform.rst b/Documentation/driver-api/driver-model/platform.rst index cf5ff48d3115..9673470bded2 100644 --- a/Documentation/driver-api/driver-model/platform.rst +++ b/Documentation/driver-api/driver-model/platform.rst @@ -70,7 +70,8 @@ Kernel modules can be composed of several platform drivers. The platform core provides helpers to register and unregister an array of drivers:: int __platform_register_drivers(struct platform_driver * const *drivers, - unsigned int count, struct module *owner); + unsigned int count, struct module *owner, + const char *mod_name); void platform_unregister_drivers(struct platform_driver * const *drivers, unsigned int count); diff --git a/MAINTAINERS b/MAINTAINERS index 8c07f13abb50..8b8472456d11 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -297,6 +297,7 @@ F: include/linux/acpi.h F: include/linux/fwnode.h F: include/linux/fw_table.h F: lib/fw_table.c +F: rust/helpers/acpi.c F: rust/kernel/acpi.rs F: tools/power/acpi/ diff --git a/arch/arc/mm/dma.c b/arch/arc/mm/dma.c index 6b85e94f3275..9b9adb02b4c5 100644 --- a/arch/arc/mm/dma.c +++ b/arch/arc/mm/dma.c @@ -98,8 +98,8 @@ void arch_setup_dma_ops(struct device *dev, bool coherent) * DMA buffers. */ if (is_isa_arcv2() && ioc_enable && coherent) - dev->dma_coherent = true; + dev_set_dma_coherent(dev); dev_info(dev, "use %scoherent DMA ops\n", - dev->dma_coherent ? "" : "non"); + dev_dma_coherent(dev) ? "" : "non"); } diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index 47335c7dadf8..8b7d0929dac4 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c @@ -98,7 +98,7 @@ static int highbank_platform_notifier(struct notifier_block *nb, if (of_property_read_bool(dev->of_node, "dma-coherent")) { val = readl(sregs_base + reg); writel(val | 0xff01, sregs_base + reg); - dev->dma_coherent = true; + dev_set_dma_coherent(dev); } return NOTIFY_OK; diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index fa2c1e1aeb96..7234d487ff39 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -95,7 +95,7 @@ static int mvebu_hwcc_notifier(struct notifier_block *nb, if (event != BUS_NOTIFY_ADD_DEVICE) return NOTIFY_DONE; - dev->dma_coherent = true; + dev_set_dma_coherent(dev); return NOTIFY_OK; } diff --git a/arch/arm/mm/dma-mapping-nommu.c b/arch/arm/mm/dma-mapping-nommu.c index fecac107fd0d..c6a70686507b 100644 --- a/arch/arm/mm/dma-mapping-nommu.c +++ b/arch/arm/mm/dma-mapping-nommu.c @@ -42,11 +42,11 @@ void arch_setup_dma_ops(struct device *dev, bool coherent) * enough to check if MPU is in use or not since in absence of * MPU system memory map is used. */ - dev->dma_coherent = cacheid ? coherent : true; + dev_assign_dma_coherent(dev, cacheid ? coherent : true); } else { /* * Assume coherent DMA in case MMU/MPU has not been set up. */ - dev->dma_coherent = (get_cr() & CR_M) ? coherent : true; + dev_assign_dma_coherent(dev, (get_cr() & CR_M) ? coherent : true); } } diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index f304037d1c34..f9bc53b60f99 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1076,7 +1076,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL); struct page **pages; void *addr = NULL; - int coherent_flag = dev->dma_coherent ? COHERENT : NORMAL; + int coherent_flag = dev_dma_coherent(dev) ? COHERENT : NORMAL; *handle = DMA_MAPPING_ERROR; size = PAGE_ALIGN(size); @@ -1124,7 +1124,7 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, if (vma->vm_pgoff >= nr_pages) return -ENXIO; - if (!dev->dma_coherent) + if (!dev_dma_coherent(dev)) vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); err = vm_map_pages(vma, pages, nr_pages); @@ -1141,7 +1141,7 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, static void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle, unsigned long attrs) { - int coherent_flag = dev->dma_coherent ? COHERENT : NORMAL; + int coherent_flag = dev_dma_coherent(dev) ? COHERENT : NORMAL; struct page **pages; size = PAGE_ALIGN(size); @@ -1202,7 +1202,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, phys_addr_t phys = page_to_phys(sg_page(s)); unsigned int len = PAGE_ALIGN(s->offset + s->length); - if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) + if (!dev_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) arch_sync_dma_for_device(sg_phys(s), s->length, dir); prot = __dma_info_to_prot(dir, attrs); @@ -1304,7 +1304,7 @@ static void arm_iommu_unmap_sg(struct device *dev, if (sg_dma_len(s)) __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s)); - if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) + if (!dev_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) arch_sync_dma_for_cpu(sg_phys(s), s->length, dir); } } @@ -1323,7 +1323,7 @@ static void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *s; int i; - if (dev->dma_coherent) + if (dev_dma_coherent(dev)) return; for_each_sg(sg, s, nents, i) @@ -1345,7 +1345,7 @@ static void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *s; int i; - if (dev->dma_coherent) + if (dev_dma_coherent(dev)) return; for_each_sg(sg, s, nents, i) @@ -1371,7 +1371,7 @@ static dma_addr_t arm_iommu_map_phys(struct device *dev, phys_addr_t phys, dma_addr_t dma_addr; int ret, prot; - if (!dev->dma_coherent && + if (!dev_dma_coherent(dev) && !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) arch_sync_dma_for_device(phys, size, dir); @@ -1412,7 +1412,7 @@ static void arm_iommu_unmap_phys(struct device *dev, dma_addr_t handle, if (!iova) return; - if (!dev->dma_coherent && + if (!dev_dma_coherent(dev) && !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) { phys_addr_t phys = iommu_iova_to_phys(mapping->domain, iova); @@ -1431,7 +1431,7 @@ static void arm_iommu_sync_single_for_cpu(struct device *dev, unsigned int offset = handle & ~PAGE_MASK; phys_addr_t phys; - if (dev->dma_coherent || !iova) + if (dev_dma_coherent(dev) || !iova) return; phys = iommu_iova_to_phys(mapping->domain, iova); @@ -1446,7 +1446,7 @@ static void arm_iommu_sync_single_for_device(struct device *dev, unsigned int offset = handle & ~PAGE_MASK; phys_addr_t phys; - if (dev->dma_coherent || !iova) + if (dev_dma_coherent(dev) || !iova) return; phys = iommu_iova_to_phys(mapping->domain, iova); @@ -1701,13 +1701,13 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) { } void arch_setup_dma_ops(struct device *dev, bool coherent) { /* - * Due to legacy code that sets the ->dma_coherent flag from a bus - * notifier we can't just assign coherent to the ->dma_coherent flag + * Due to legacy code that sets the dma_coherent flag from a bus + * notifier we can't just assign coherent to the dma_coherent flag * here, but instead have to make sure we only set but never clear it * for now. */ if (coherent) - dev->dma_coherent = true; + dev_set_dma_coherent(dev); /* * Don't override the dma_ops if they have already been set. Ideally diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 6d53bb15cf7b..e592520e13b7 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -4052,7 +4052,7 @@ static int enable_mismatched_32bit_el0(unsigned int cpu) */ lucky_winner = cpu_32bit ? cpu : cpumask_any_and(cpu_32bit_el0_mask, cpu_active_mask); - get_cpu_device(lucky_winner)->offline_disabled = true; + dev_set_offline_disabled(get_cpu_device(lucky_winner)); setup_elf_hwcaps(compat_elf_hwcaps); elf_hwcap_fixup(); pr_info("Asymmetric 32-bit EL0 support detected on CPU %u; CPU hot-unplug disabled on CPU %u\n", diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index ae1ae0280eef..994b7b36e2b9 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -48,7 +48,7 @@ void arch_setup_dma_ops(struct device *dev, bool coherent) dev_driver_string(dev), dev_name(dev), ARCH_DMA_MINALIGN, cls); - dev->dma_coherent = coherent; + dev_assign_dma_coherent(dev, coherent); xen_setup_dma_ops(dev); } diff --git a/arch/mips/include/asm/mips_mt.h b/arch/mips/include/asm/mips_mt.h index 6ea02af29876..0358489e7d13 100644 --- a/arch/mips/include/asm/mips_mt.h +++ b/arch/mips/include/asm/mips_mt.h @@ -23,7 +23,6 @@ extern void mips_mt_set_cpuoptions(void); static inline void mips_mt_set_cpuoptions(void) { } #endif -struct class; extern const struct class mt_class; #endif /* __ASM_MIPS_MT_H */ diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c index ab4f2a75a7d0..30ef3e247eb7 100644 --- a/arch/mips/mm/dma-noncoherent.c +++ b/arch/mips/mm/dma-noncoherent.c @@ -139,6 +139,6 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, #ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS void arch_setup_dma_ops(struct device *dev, bool coherent) { - dev->dma_coherent = coherent; + dev_assign_dma_coherent(dev, coherent); } #endif diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index 8b4de508d2eb..1f8b5a0f69be 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -67,7 +67,7 @@ bool arch_dma_unmap_sg_direct(struct device *dev, struct scatterlist *sg, } bool arch_dma_alloc_direct(struct device *dev) { - if (dev->dma_ops_bypass && dev->bus_dma_limit) + if (dev_dma_ops_bypass(dev) && dev->bus_dma_limit) return true; return false; @@ -75,7 +75,7 @@ bool arch_dma_alloc_direct(struct device *dev) bool arch_dma_free_direct(struct device *dev, dma_addr_t dma_handle) { - if (!dev->dma_ops_bypass || !dev->bus_dma_limit) + if (!dev_dma_ops_bypass(dev) || !dev->bus_dma_limit) return false; return is_direct_handle(dev, dma_handle); @@ -164,7 +164,7 @@ int dma_iommu_dma_supported(struct device *dev, u64 mask) * fixed ops will be used for RAM. This is limited by * bus_dma_limit which is set when RAM is pre-mapped. */ - dev->dma_ops_bypass = true; + dev_set_dma_ops_bypass(dev); dev_info(dev, "iommu: 64-bit OK but direct DMA is limited by %llx\n", dev->bus_dma_limit); return 1; @@ -185,7 +185,7 @@ int dma_iommu_dma_supported(struct device *dev, u64 mask) } dev_dbg(dev, "iommu: not 64-bit, using default ops\n"); - dev->dma_ops_bypass = false; + dev_clear_dma_ops_bypass(dev); return 1; } diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index b2f14db59034..75f85a5da981 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -213,9 +213,9 @@ static int dlpar_change_lmb_state(struct drmem_lmb *lmb, bool online) return -EINVAL; } - if (online && mem_block->dev.offline) + if (online && dev_offline(&mem_block->dev)) rc = device_online(&mem_block->dev); - else if (!online && !mem_block->dev.offline) + else if (!online && !dev_offline(&mem_block->dev)) rc = device_offline(&mem_block->dev); else rc = 0; diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c index cb89d7e0ba88..a1ec2d71d1c9 100644 --- a/arch/riscv/mm/dma-noncoherent.c +++ b/arch/riscv/mm/dma-noncoherent.c @@ -140,7 +140,7 @@ void arch_setup_dma_ops(struct device *dev, bool coherent) "%s %s: device non-coherent but no non-coherent operations supported", dev_driver_string(dev), dev_name(dev)); - dev->dma_coherent = coherent; + dev_assign_dma_coherent(dev, coherent); } void riscv_noncoherent_supported(void) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b0e7181ae304..3b7db94b81f7 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -898,9 +898,9 @@ const struct acpi_device *acpi_companion_match(const struct device *dev) * identifiers and a _DSD object with the "compatible" property, use that * property to match against the given list of identifiers. */ -static bool acpi_of_match_device(const struct acpi_device *adev, - const struct of_device_id *of_match_table, - const struct of_device_id **of_id) +bool acpi_of_match_device(const struct acpi_device *adev, + const struct of_device_id *of_match_table, + const struct of_device_id **of_id) { const union acpi_object *of_compatible, *obj; int i, nval; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 075798d70ff1..9a7ac2eb9ce0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -122,7 +122,7 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) mutex_lock_nested(&adev->physical_node_lock, SINGLE_DEPTH_NESTING); list_for_each_entry(pn, &adev->physical_node_list, node) - if (device_supports_offline(pn->dev) && !pn->dev->offline) { + if (device_supports_offline(pn->dev) && !dev_offline(pn->dev)) { if (uevent) kobject_uevent_env(&pn->dev->kobj, KOBJ_CHANGE, envp); diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 6d479caf89cb..d721d64a9858 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -82,33 +82,6 @@ static void amba_put_disable_pclk(struct amba_device *pcdev) } -static ssize_t driver_override_show(struct device *_dev, - struct device_attribute *attr, char *buf) -{ - struct amba_device *dev = to_amba_device(_dev); - ssize_t len; - - device_lock(_dev); - len = sprintf(buf, "%s\n", dev->driver_override); - device_unlock(_dev); - return len; -} - -static ssize_t driver_override_store(struct device *_dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct amba_device *dev = to_amba_device(_dev); - int ret; - - ret = driver_set_override(_dev, &dev->driver_override, buf, count); - if (ret) - return ret; - - return count; -} -static DEVICE_ATTR_RW(driver_override); - #define amba_attr_func(name,fmt,arg...) \ static ssize_t name##_show(struct device *_dev, \ struct device_attribute *attr, char *buf) \ @@ -126,7 +99,6 @@ amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n", static struct attribute *amba_dev_attrs[] = { &dev_attr_id.attr, &dev_attr_resource.attr, - &dev_attr_driver_override.attr, NULL, }; ATTRIBUTE_GROUPS(amba_dev); @@ -209,10 +181,11 @@ static int amba_match(struct device *dev, const struct device_driver *drv) { struct amba_device *pcdev = to_amba_device(dev); const struct amba_driver *pcdrv = to_amba_driver(drv); + int ret; mutex_lock(&pcdev->periphid_lock); if (!pcdev->periphid) { - int ret = amba_read_periphid(pcdev); + ret = amba_read_periphid(pcdev); /* * Returning any error other than -EPROBE_DEFER from bus match @@ -230,8 +203,9 @@ static int amba_match(struct device *dev, const struct device_driver *drv) mutex_unlock(&pcdev->periphid_lock); /* When driver_override is set, only bind to the matching driver */ - if (pcdev->driver_override) - return !strcmp(pcdev->driver_override, drv->name); + ret = device_match_driver_override(dev, drv); + if (ret >= 0) + return ret; return amba_lookup(pcdrv->id_table, pcdev) != NULL; } @@ -436,6 +410,7 @@ static const struct dev_pm_ops amba_pm = { const struct bus_type amba_bustype = { .name = "amba", .dev_groups = amba_dev_groups, + .driver_override = true, .match = amba_match, .uevent = amba_uevent, .probe = amba_probe, diff --git a/drivers/base/base.h b/drivers/base/base.h index 30b416588617..a5b7abc10ff0 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -86,18 +86,6 @@ struct driver_private { }; #define to_driver(obj) container_of(obj, struct driver_private, kobj) -#ifdef CONFIG_RUST -/** - * struct driver_type - Representation of a Rust driver type. - */ -struct driver_type { - /** - * @id: Representation of core::any::TypeId. - */ - u8 id[16]; -} __packed; -#endif - /** * struct device_private - structure to hold the private to the driver core * portions of the device structure. @@ -115,7 +103,6 @@ struct driver_type { * dev_err_probe() for later retrieval via debugfs * @device: pointer back to the struct device that this structure is * associated with. - * @driver_type: The type of the bound Rust driver. * @dead: This device is currently either in the process of or has been * removed from the system. Any asynchronous events scheduled for this * device should exit without taking any action. @@ -132,9 +119,6 @@ struct device_private { const struct device_driver *async_driver; char *deferred_probe_reason; struct device *device; -#ifdef CONFIG_RUST - struct driver_type driver_type; -#endif u8 dead:1; }; #define to_device_private_parent(obj) \ @@ -188,6 +172,20 @@ static inline int driver_match_device(const struct device_driver *drv, return drv->bus->match ? drv->bus->match(dev, drv) : 1; } +static inline bool dev_has_sync_state(struct device *dev) +{ + struct device_driver *drv; + + if (!dev) + return false; + drv = READ_ONCE(dev->driver); + if (drv && drv->sync_state) + return true; + if (dev->bus && dev->bus->sync_state) + return true; + return false; +} + static inline void dev_sync_state(struct device *dev) { if (dev->bus->sync_state) @@ -196,8 +194,10 @@ static inline void dev_sync_state(struct device *dev) dev->driver->sync_state(dev); } -int driver_add_groups(const struct device_driver *drv, const struct attribute_group **groups); -void driver_remove_groups(const struct device_driver *drv, const struct attribute_group **groups); +int driver_add_groups(const struct device_driver *drv, + const struct attribute_group *const *groups); +void driver_remove_groups(const struct device_driver *drv, + const struct attribute_group *const *groups); void device_driver_detach(struct device *dev); static inline void device_set_driver(struct device *dev, const struct device_driver *drv) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 8b6722ff8590..d17bd91490ee 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -544,10 +544,10 @@ static const struct attribute_group driver_override_dev_group = { */ int bus_add_device(struct device *dev) { - struct subsys_private *sp = bus_to_subsys(dev->bus); + struct subsys_private *sp; int error; - if (!sp) { + if (!dev->bus) { /* * This is a normal operation for many devices that do not * have a bus assigned to them, just say that all went @@ -556,6 +556,13 @@ int bus_add_device(struct device *dev) return 0; } + sp = bus_to_subsys(dev->bus); + if (!sp) { + pr_err("%s: cannot add device '%s' to unregistered bus '%s'\n", + __func__, dev_name(dev), dev->bus->name); + return -EINVAL; + } + /* * Reference in sp is now incremented and will be dropped when * the device is removed from the bus diff --git a/drivers/base/core.c b/drivers/base/core.c index bd2ddf2aab50..4d026682944f 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -235,6 +235,79 @@ static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode, __fw_devlink_pickup_dangling_consumers(child, new_sup); } +static void fw_devlink_pickup_dangling_consumers(struct device *dev) +{ + struct fwnode_handle *child; + + guard(mutex)(&fwnode_link_lock); + + fwnode_for_each_available_child_node(dev->fwnode, child) + __fw_devlink_pickup_dangling_consumers(child, dev->fwnode); + __fw_devlink_link_to_consumers(dev); +} + +/** + * fw_devlink_refresh_fwnode - Recheck the tree under this firmware node + * @fwnode: The fwnode under which the fwnode tree has changed + * + * This function is mainly meant to adjust the supplier/consumer dependencies + * after a fwnode tree overlay has occurred. + */ +void fw_devlink_refresh_fwnode(struct fwnode_handle *fwnode) +{ + struct device *dev; + + /* + * Find the closest ancestor fwnode that has been converted to a device + * that can bind to a driver (bus device). + */ + fwnode_handle_get(fwnode); + do { + if (fwnode_test_flag(fwnode, FWNODE_FLAG_NOT_DEVICE)) + continue; + + dev = get_dev_from_fwnode(fwnode); + if (!dev) + continue; + + if (dev->bus) + break; + + put_device(dev); + } while ((fwnode = fwnode_get_next_parent(fwnode))); + + /* + * If none of the ancestor fwnodes have (yet) been converted to a device + * that can bind to a driver, there's nothing to fix up. + */ + if (!fwnode) + return; + + WARN(device_is_bound(dev) && dev->links.status != DL_DEV_DRIVER_BOUND, + "Don't multithread overlaying and probing the same device!\n"); + + /* + * If the device has already bound to a driver, then we need to redo + * some of the work that was done after the device was bound to a + * driver. If the device hasn't bound to a driver, running things too + * soon would incorrectly pick up consumers that it shouldn't. + */ + if (dev->links.status == DL_DEV_DRIVER_BOUND) { + fw_devlink_pickup_dangling_consumers(dev); + /* + * Some of dangling consumers could have been put previously in + * the deferred probe list due to the unavailability of their + * suppliers. Those consumers have been picked up and some of + * their suppliers links have been updated. Time to re-try their + * probe sequence. + */ + driver_deferred_probe_trigger(); + } + + put_device(dev); + fwnode_handle_put(fwnode); +} + static DEFINE_MUTEX(device_links_lock); DEFINE_STATIC_SRCU(device_links_srcu); @@ -422,7 +495,7 @@ void device_pm_move_to_tail(struct device *dev) #define to_devlink(dev) container_of((dev), struct device_link, link_dev) static ssize_t status_show(struct device *dev, - struct device_attribute *attr, char *buf) + const struct device_attribute *attr, char *buf) { const char *output; @@ -452,10 +525,10 @@ static ssize_t status_show(struct device *dev, return sysfs_emit(buf, "%s\n", output); } -static DEVICE_ATTR_RO(status); +static const DEVICE_ATTR_RO(status); static ssize_t auto_remove_on_show(struct device *dev, - struct device_attribute *attr, char *buf) + const struct device_attribute *attr, char *buf) { struct device_link *link = to_devlink(dev); const char *output; @@ -469,27 +542,27 @@ static ssize_t auto_remove_on_show(struct device *dev, return sysfs_emit(buf, "%s\n", output); } -static DEVICE_ATTR_RO(auto_remove_on); +static const DEVICE_ATTR_RO(auto_remove_on); static ssize_t runtime_pm_show(struct device *dev, - struct device_attribute *attr, char *buf) + const struct device_attribute *attr, char *buf) { struct device_link *link = to_devlink(dev); return sysfs_emit(buf, "%d\n", device_link_test(link, DL_FLAG_PM_RUNTIME)); } -static DEVICE_ATTR_RO(runtime_pm); +static const DEVICE_ATTR_RO(runtime_pm); static ssize_t sync_state_only_show(struct device *dev, - struct device_attribute *attr, char *buf) + const struct device_attribute *attr, char *buf) { struct device_link *link = to_devlink(dev); return sysfs_emit(buf, "%d\n", device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); } -static DEVICE_ATTR_RO(sync_state_only); +static const DEVICE_ATTR_RO(sync_state_only); -static struct attribute *devlink_attrs[] = { +static const struct attribute *const devlink_attrs[] = { &dev_attr_status.attr, &dev_attr_auto_remove_on.attr, &dev_attr_runtime_pm.attr, @@ -1011,7 +1084,7 @@ static void device_links_missing_supplier(struct device *dev) static bool dev_is_best_effort(struct device *dev) { - return (fw_devlink_best_effort && dev->can_match) || + return (fw_devlink_best_effort && dev_can_match(dev)) || (dev->fwnode && fwnode_test_flag(dev->fwnode, FWNODE_FLAG_BEST_EFFORT)); } @@ -1079,7 +1152,7 @@ int device_links_check_suppliers(struct device *dev) if (dev_is_best_effort(dev) && device_link_test(link, DL_FLAG_INFERRED) && - !link->supplier->can_match) { + !dev_can_match(link->supplier)) { ret = -EAGAIN; continue; } @@ -1123,7 +1196,7 @@ static void __device_links_queue_sync_state(struct device *dev, if (!dev_has_sync_state(dev)) return; - if (dev->state_synced) + if (dev_state_synced(dev)) return; list_for_each_entry(link, &dev->links.consumers, s_node) { @@ -1138,7 +1211,7 @@ static void __device_links_queue_sync_state(struct device *dev, * than once. This can happen if new consumers get added to the device * and probed before the list is flushed. */ - dev->state_synced = true; + dev_set_state_synced(dev); if (WARN_ON(!list_empty(&dev->links.defer_sync))) return; @@ -1233,7 +1306,7 @@ static void device_link_drop_managed(struct device_link *link) } static ssize_t waiting_for_supplier_show(struct device *dev, - struct device_attribute *attr, + const struct device_attribute *attr, char *buf) { bool val; @@ -1244,7 +1317,7 @@ static ssize_t waiting_for_supplier_show(struct device *dev, device_unlock(dev); return sysfs_emit(buf, "%u\n", val); } -static DEVICE_ATTR_RO(waiting_for_supplier); +static const DEVICE_ATTR_RO(waiting_for_supplier); /** * device_links_force_bind - Prepares device to be force bound @@ -1312,16 +1385,8 @@ void device_links_driver_bound(struct device *dev) * child firmware node. */ if (dev->fwnode && dev->fwnode->dev == dev) { - struct fwnode_handle *child; - fwnode_links_purge_suppliers(dev->fwnode); - - guard(mutex)(&fwnode_link_lock); - - fwnode_for_each_available_child_node(dev->fwnode, child) - __fw_devlink_pickup_dangling_consumers(child, - dev->fwnode); - __fw_devlink_link_to_consumers(dev); + fw_devlink_pickup_dangling_consumers(dev); } device_remove_file(dev, &dev_attr_waiting_for_supplier); @@ -1370,7 +1435,7 @@ void device_links_driver_bound(struct device *dev) } else if (dev_is_best_effort(dev) && device_link_test(link, DL_FLAG_INFERRED) && link->status != DL_STATE_CONSUMER_PROBE && - !link->supplier->can_match) { + !dev_can_match(link->supplier)) { /* * When dev_is_best_effort() is true, we ignore device * links to suppliers that don't have a driver. If the @@ -1435,7 +1500,8 @@ static void __device_links_no_driver(struct device *dev) if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) { WRITE_ONCE(link->status, DL_STATE_AVAILABLE); } else { - WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); + WARN_ON(link->supplier->links.status != DL_DEV_UNBINDING && + !device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); WRITE_ONCE(link->status, DL_STATE_DORMANT); } } @@ -1758,7 +1824,7 @@ static int fw_devlink_no_driver(struct device *dev, void *data) { struct device_link *link = to_devlink(dev); - if (!link->supplier->can_match) + if (!dev_can_match(link->supplier)) fw_devlink_relax_link(link); return 0; @@ -1779,7 +1845,7 @@ static int fw_devlink_dev_sync_state(struct device *dev, void *data) struct device *sup = link->supplier; if (!device_link_test(link, DL_FLAG_MANAGED) || - link->status == DL_STATE_ACTIVE || sup->state_synced || + link->status == DL_STATE_ACTIVE || dev_state_synced(sup) || !dev_has_sync_state(sup)) return 0; @@ -1793,7 +1859,7 @@ static int fw_devlink_dev_sync_state(struct device *dev, void *data) return 0; dev_warn(sup, "Timed out. Forcing sync_state()\n"); - sup->state_synced = true; + dev_set_state_synced(sup); get_device(sup); list_add_tail(&sup->links.defer_sync, data); @@ -2419,9 +2485,11 @@ static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); + else if (dev_attr->show_const) + ret = dev_attr->show_const(dev, dev_attr, buf); if (ret >= (ssize_t)PAGE_SIZE) { - printk("dev_attr_show: %pS returned bad count\n", - dev_attr->show); + printk("dev_attr_show: %pS/%pS returned bad count\n", + dev_attr->show, dev_attr->show_const); } return ret; } @@ -2435,6 +2503,8 @@ static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, if (dev_attr->store) ret = dev_attr->store(dev, dev_attr, buf, count); + else if (dev_attr->store_const) + ret = dev_attr->store_const(dev, dev_attr, buf, count); return ret; } @@ -2722,7 +2792,7 @@ static const struct kset_uevent_ops device_uevent_ops = { .uevent = dev_uevent, }; -static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, +static ssize_t uevent_show(struct device *dev, const struct device_attribute *attr, char *buf) { struct kobject *top_kobj; @@ -2765,7 +2835,7 @@ out: return len; } -static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, +static ssize_t uevent_store(struct device *dev, const struct device_attribute *attr, const char *buf, size_t count) { int rc; @@ -2779,20 +2849,20 @@ static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR_RW(uevent); +static const DEVICE_ATTR_RW(uevent); -static ssize_t online_show(struct device *dev, struct device_attribute *attr, +static ssize_t online_show(struct device *dev, const struct device_attribute *attr, char *buf) { bool val; device_lock(dev); - val = !dev->offline; + val = !dev_offline(dev); device_unlock(dev); return sysfs_emit(buf, "%u\n", val); } -static ssize_t online_store(struct device *dev, struct device_attribute *attr, +static ssize_t online_store(struct device *dev, const struct device_attribute *attr, const char *buf, size_t count) { bool val; @@ -2810,9 +2880,9 @@ static ssize_t online_store(struct device *dev, struct device_attribute *attr, unlock_device_hotplug(); return ret < 0 ? ret : count; } -static DEVICE_ATTR_RW(online); +static const DEVICE_ATTR_RW(online); -static ssize_t removable_show(struct device *dev, struct device_attribute *attr, +static ssize_t removable_show(struct device *dev, const struct device_attribute *attr, char *buf) { const char *loc; @@ -2829,7 +2899,7 @@ static ssize_t removable_show(struct device *dev, struct device_attribute *attr, } return sysfs_emit(buf, "%s\n", loc); } -static DEVICE_ATTR_RO(removable); +static const DEVICE_ATTR_RO(removable); int device_add_groups(struct device *dev, const struct attribute_group *const *groups) @@ -2913,7 +2983,7 @@ static int device_add_attrs(struct device *dev) if (error) goto err_remove_type_groups; - if (device_supports_offline(dev) && !dev->offline_disabled) { + if (device_supports_offline(dev) && !dev_offline_disabled(dev)) { error = device_create_file(dev, &dev_attr_online); if (error) goto err_remove_dev_groups; @@ -2980,12 +3050,12 @@ static void device_remove_attrs(struct device *dev) device_remove_groups(dev, class->dev_groups); } -static ssize_t dev_show(struct device *dev, struct device_attribute *attr, +static ssize_t dev_show(struct device *dev, const struct device_attribute *attr, char *buf) { return print_dev_t(buf, dev->devt); } -static DEVICE_ATTR_RO(dev); +static const DEVICE_ATTR_RO(dev); /* /sys/devices/ */ struct kset *devices_kset; @@ -3047,10 +3117,10 @@ int device_create_file(struct device *dev, int error = 0; if (dev) { - WARN(((attr->attr.mode & S_IWUGO) && !attr->store), + WARN(((attr->attr.mode & S_IWUGO) && !(attr->store || attr->store_const)), "Attribute %s: write permission without 'store'\n", attr->attr.name); - WARN(((attr->attr.mode & S_IRUGO) && !attr->show), + WARN(((attr->attr.mode & S_IRUGO) && !(attr->show || attr->show_const)), "Attribute %s: read permission without 'show'\n", attr->attr.name); error = sysfs_create_file(&dev->kobj, &attr->attr); @@ -3170,11 +3240,7 @@ void device_initialize(struct device *dev) INIT_LIST_HEAD(&dev->links.suppliers); INIT_LIST_HEAD(&dev->links.defer_sync); dev->links.status = DL_DEV_NO_DRIVER; -#if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ - defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \ - defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) - dev->dma_coherent = dma_default_coherent; -#endif + dev_assign_dma_coherent(dev, dma_default_coherent); swiotlb_dev_init(dev); } EXPORT_SYMBOL_GPL(device_initialize); @@ -3710,7 +3776,7 @@ int device_add(struct device *dev) * match with any driver, don't block its consumers from probing in * case the consumer device is able to operate without this supplier. */ - if (dev->fwnode && fw_devlink_drv_reg_done && !dev->can_match) + if (dev->fwnode && fw_devlink_drv_reg_done && !dev_can_match(dev)) fw_devlink_unblock_consumers(dev); if (parent) @@ -4180,7 +4246,7 @@ static int device_check_offline(struct device *dev, void *not_used) if (ret) return ret; - return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0; + return device_supports_offline(dev) && !dev_offline(dev) ? -EBUSY : 0; } /** @@ -4198,7 +4264,7 @@ int device_offline(struct device *dev) { int ret; - if (dev->offline_disabled) + if (dev_offline_disabled(dev)) return -EPERM; ret = device_for_each_child(dev, NULL, device_check_offline); @@ -4207,13 +4273,13 @@ int device_offline(struct device *dev) device_lock(dev); if (device_supports_offline(dev)) { - if (dev->offline) { + if (dev_offline(dev)) { ret = 1; } else { ret = dev->bus->offline(dev); if (!ret) { kobject_uevent(&dev->kobj, KOBJ_OFFLINE); - dev->offline = true; + dev_set_offline(dev); } } } @@ -4238,11 +4304,11 @@ int device_online(struct device *dev) device_lock(dev); if (device_supports_offline(dev)) { - if (dev->offline) { + if (dev_offline(dev)) { ret = dev->bus->online(dev); if (!ret) { kobject_uevent(&dev->kobj, KOBJ_ONLINE); - dev->offline = false; + dev_clear_offline(dev); } } else { ret = 1; @@ -4716,7 +4782,7 @@ static int device_attrs_change_owner(struct device *dev, kuid_t kuid, if (error) return error; - if (device_supports_offline(dev) && !dev->offline_disabled) { + if (device_supports_offline(dev) && !dev_offline_disabled(dev)) { /* Change online device attributes of @dev to @kuid/@kgid. */ error = sysfs_file_change_owner(kobj, dev_attr_online.attr.name, kuid, kgid); @@ -5283,7 +5349,7 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2) { of_node_put(dev->of_node); dev->of_node = of_node_get(dev2->of_node); - dev->of_node_reused = true; + dev_set_of_node_reused(dev); } EXPORT_SYMBOL_GPL(device_set_of_node_from_dev); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 875abdc9942e..19d288a3c80c 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -422,8 +422,8 @@ int register_cpu(struct cpu *cpu, int num) cpu->dev.id = num; cpu->dev.bus = &cpu_subsys; cpu->dev.release = cpu_device_release; - cpu->dev.offline_disabled = !cpu->hotpluggable; - cpu->dev.offline = !cpu_online(num); + dev_assign_offline_disabled(&cpu->dev, !cpu->hotpluggable); + dev_assign_offline(&cpu->dev, !cpu_online(num)); cpu->dev.of_node = of_get_cpu_node(num, NULL); cpu->dev.groups = common_cpu_attr_groups; if (cpu->hotpluggable) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 1dc1e3528043..60c005223844 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -132,7 +132,7 @@ static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func); void driver_deferred_probe_add(struct device *dev) { - if (!dev->can_match) + if (!dev_can_match(dev)) return; mutex_lock(&deferred_probe_mutex); @@ -323,12 +323,11 @@ void deferred_probe_extend_timeout(void) * If the work hasn't been queued yet or if the work expired, don't * start a new one. */ - if (cancel_delayed_work(&deferred_probe_timeout_work)) { - schedule_delayed_work(&deferred_probe_timeout_work, - driver_deferred_probe_timeout * HZ); + if (delayed_work_pending(&deferred_probe_timeout_work) && + mod_delayed_work(system_percpu_wq, &deferred_probe_timeout_work, + secs_to_jiffies(driver_deferred_probe_timeout))) pr_debug("Extended deferred probe timeout by %d secs\n", driver_deferred_probe_timeout); - } } /** @@ -569,12 +568,10 @@ static ssize_t state_synced_store(struct device *dev, return -EINVAL; device_lock(dev); - if (!dev->state_synced) { - dev->state_synced = true; + if (!dev_test_and_set_state_synced(dev)) dev_sync_state(dev); - } else { + else ret = -EINVAL; - } device_unlock(dev); return ret ? ret : count; @@ -586,7 +583,7 @@ static ssize_t state_synced_show(struct device *dev, bool val; device_lock(dev); - val = dev->state_synced; + val = dev_state_synced(dev); device_unlock(dev); return sysfs_emit(buf, "%u\n", val); @@ -595,9 +592,9 @@ static DEVICE_ATTR_RW(state_synced); static void device_unbind_cleanup(struct device *dev) { - devres_release_all(dev); if (dev->driver->p_cb.post_unbind_rust) dev->driver->p_cb.post_unbind_rust(dev); + devres_release_all(dev); arch_teardown_dma_ops(dev); kfree(dev->dma_range_map); dev->dma_range_map = NULL; @@ -849,14 +846,14 @@ static int __driver_probe_device(const struct device_driver *drv, struct device return dev_err_probe(dev, -EPROBE_DEFER, "Device not ready to probe\n"); /* - * Set can_match = true after calling dev_ready_to_probe(), so + * Call dev_set_can_match() after calling dev_ready_to_probe(), so * driver_deferred_probe_add() won't actually add the device to the * deferred probe list when dev_ready_to_probe() returns false. * * When dev_ready_to_probe() returns false, it means that device_add() * will do another probe() attempt for us. */ - dev->can_match = true; + dev_set_can_match(dev); dev_dbg(dev, "bus: '%s': %s: matched device with driver %s\n", drv->bus->name, __func__, drv->name); @@ -1002,7 +999,7 @@ static int __device_attach_driver(struct device_driver *drv, void *_data) return 0; } else if (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); - dev->can_match = true; + dev_set_can_match(dev); driver_deferred_probe_add(dev); /* * Device can't match with a driver right now, so don't attempt @@ -1254,7 +1251,7 @@ static int __driver_attach(struct device *dev, void *data) return 0; } else if (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); - dev->can_match = true; + dev_set_can_match(dev); driver_deferred_probe_add(dev); /* * Driver could not match with device, but may match with diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 7e4a491bf15e..8bb1763083dd 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -471,10 +471,3 @@ static int __init devcoredump_init(void) return class_register(&devcd_class); } __initcall(devcoredump_init); - -static void __exit devcoredump_exit(void) -{ - class_for_each_device(&devcd_class, NULL, NULL, devcd_free); - class_unregister(&devcd_class); -} -__exitcall(devcoredump_exit); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 8ab010ddf709..5d9c39081339 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -31,81 +31,6 @@ static struct device *next_device(struct klist_iter *i) } /** - * driver_set_override() - Helper to set or clear driver override. - * @dev: Device to change - * @override: Address of string to change (e.g. &device->driver_override); - * The contents will be freed and hold newly allocated override. - * @s: NUL-terminated string, new driver name to force a match, pass empty - * string to clear it ("" or "\n", where the latter is only for sysfs - * interface). - * @len: length of @s - * - * Helper to set or clear driver override in a device, intended for the cases - * when the driver_override field is allocated by driver/bus code. - * - * Returns: 0 on success or a negative error code on failure. - */ -int driver_set_override(struct device *dev, const char **override, - const char *s, size_t len) -{ - const char *new, *old; - char *cp; - - if (!override || !s) - return -EINVAL; - - /* - * The stored value will be used in sysfs show callback (sysfs_emit()), - * which has a length limit of PAGE_SIZE and adds a trailing newline. - * Thus we can store one character less to avoid truncation during sysfs - * show. - */ - if (len >= (PAGE_SIZE - 1)) - return -EINVAL; - - /* - * Compute the real length of the string in case userspace sends us a - * bunch of \0 characters like python likes to do. - */ - len = strlen(s); - - if (!len) { - /* Empty string passed - clear override */ - device_lock(dev); - old = *override; - *override = NULL; - device_unlock(dev); - kfree(old); - - return 0; - } - - cp = strnchr(s, len, '\n'); - if (cp) - len = cp - s; - - new = kstrndup(s, len, GFP_KERNEL); - if (!new) - return -ENOMEM; - - device_lock(dev); - old = *override; - if (cp != s) { - *override = new; - } else { - /* "\n" passed - clear override */ - kfree(new); - *override = NULL; - } - device_unlock(dev); - - kfree(old); - - return 0; -} -EXPORT_SYMBOL_GPL(driver_set_override); - -/** * driver_for_each_device - Iterator for devices bound to a driver. * @drv: Driver we're iterating. * @start: Device to begin with @@ -203,13 +128,13 @@ void driver_remove_file(const struct device_driver *drv, EXPORT_SYMBOL_GPL(driver_remove_file); int driver_add_groups(const struct device_driver *drv, - const struct attribute_group **groups) + const struct attribute_group *const *groups) { return sysfs_create_groups(&drv->p->kobj, groups); } void driver_remove_groups(const struct device_driver *drv, - const struct attribute_group **groups) + const struct attribute_group *const *groups) { sysfs_remove_groups(&drv->p->kobj, groups); } diff --git a/drivers/base/faux.c b/drivers/base/faux.c index fb3e42f21362..a8329f88222e 100644 --- a/drivers/base/faux.c +++ b/drivers/base/faux.c @@ -133,6 +133,9 @@ struct faux_device *faux_device_create_with_groups(const char *name, struct device *dev; int ret; + if (!faux_bus_root) + return NULL; + faux_obj = kzalloc_obj(*faux_obj); if (!faux_obj) return NULL; @@ -232,34 +235,29 @@ EXPORT_SYMBOL_GPL(faux_device_destroy); int __init faux_bus_init(void) { + struct device *root; int ret; - faux_bus_root = kzalloc_obj(*faux_bus_root); - if (!faux_bus_root) - return -ENOMEM; - - dev_set_name(faux_bus_root, "faux"); - - ret = device_register(faux_bus_root); - if (ret) { - put_device(faux_bus_root); - return ret; - } + root = root_device_register("faux"); + if (IS_ERR(root)) + return PTR_ERR(root); ret = bus_register(&faux_bus_type); if (ret) - goto error_bus; + goto err_deregister_root; ret = driver_register(&faux_driver); if (ret) - goto error_driver; + goto err_deregister_bus; - return ret; + faux_bus_root = root; + + return 0; -error_driver: +err_deregister_bus: bus_unregister(&faux_bus_type); +err_deregister_root: + root_device_unregister(root); -error_bus: - device_unregister(faux_bus_root); return ret; } diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index a11b30dda23b..c96312ac2be7 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -1503,9 +1503,10 @@ static void device_cache_fw_images(void) mutex_lock(&fw_lock); fwc->state = FW_LOADER_START_CACHE; - dpm_for_each_dev(NULL, dev_cache_fw_image); mutex_unlock(&fw_lock); + dpm_for_each_dev(NULL, dev_cache_fw_image); + /* wait for completion of caching firmware for all devices */ async_synchronize_full_domain(&fw_cache_domain); diff --git a/drivers/base/firmware_loader/sysfs_upload.c b/drivers/base/firmware_loader/sysfs_upload.c index f59a7856934c..efc33294212f 100644 --- a/drivers/base/firmware_loader/sysfs_upload.c +++ b/drivers/base/firmware_loader/sysfs_upload.c @@ -343,7 +343,6 @@ firmware_upload_register(struct module *module, struct device *parent, goto free_fw_upload_priv; } fw_upload->priv = fw_sysfs; - fw_sysfs->fw_upload_priv = fw_upload_priv; fw_dev = &fw_sysfs->dev; ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, NULL, 0, 0, @@ -351,10 +350,12 @@ firmware_upload_register(struct module *module, struct device *parent, if (ret != 0) { if (ret > 0) ret = -EINVAL; - goto free_fw_sysfs; + put_device(fw_dev); + goto free_fw_upload_priv; } fw_priv->is_paged_buf = true; fw_sysfs->fw_priv = fw_priv; + fw_sysfs->fw_upload_priv = fw_upload_priv; ret = device_add(fw_dev); if (ret) { @@ -365,9 +366,6 @@ firmware_upload_register(struct module *module, struct device *parent, return fw_upload; -free_fw_sysfs: - kfree(fw_sysfs); - free_fw_upload_priv: kfree(fw_upload_priv); diff --git a/drivers/base/isa.c b/drivers/base/isa.c index fd076cc63cb6..5887e4211f80 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -11,9 +11,7 @@ #include <linux/dma-mapping.h> #include <linux/isa.h> -static struct device isa_bus = { - .init_name = "isa" -}; +static struct device *isa_bus; struct isa_dev { struct device dev; @@ -131,7 +129,7 @@ int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) break; } - isa_dev->dev.parent = &isa_bus; + isa_dev->dev.parent = isa_bus; isa_dev->dev.bus = &isa_bus_type; dev_set_name(&isa_dev->dev, "%s.%u", @@ -169,9 +167,11 @@ static int __init isa_bus_init(void) error = bus_register(&isa_bus_type); if (!error) { - error = device_register(&isa_bus); - if (error) + isa_bus = root_device_register("isa"); + if (IS_ERR(isa_bus)) { + error = PTR_ERR(isa_bus); bus_unregister(&isa_bus_type); + } } return error; } diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 6981b55d582a..11d57cfa8d72 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -697,7 +697,7 @@ static int __add_memory_block(struct memory_block *memory) memory->dev.id = memory->start_section_nr / sections_per_block; memory->dev.release = memory_block_release; memory->dev.groups = memory_memblk_attr_groups; - memory->dev.offline = memory->state == MEM_OFFLINE; + dev_assign_offline(&memory->dev, memory->state == MEM_OFFLINE); ret = device_register(&memory->dev); if (ret) { diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c index 6e250272c843..0bbc83231234 100644 --- a/drivers/base/pinctrl.c +++ b/drivers/base/pinctrl.c @@ -24,7 +24,7 @@ int pinctrl_bind_pins(struct device *dev) { int ret; - if (dev->of_node_reused) + if (dev_of_node_reused(dev)) return 0; dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL); diff --git a/drivers/base/platform.c b/drivers/base/platform.c index a19dd22deef2..fb9120b0bcfe 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -870,7 +870,7 @@ struct platform_device *platform_device_register_full(const struct platform_devi pdev->dev.parent = pdevinfo->parent; pdev->dev.fwnode = pdevinfo->fwnode; pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode)); - pdev->dev.of_node_reused = pdevinfo->of_node_reused; + dev_assign_of_node_reused(&pdev->dev, pdevinfo->of_node_reused); if (pdevinfo->dma_mask) { pdev->platform_dma_mask = pdevinfo->dma_mask; @@ -915,11 +915,14 @@ EXPORT_SYMBOL_GPL(platform_device_register_full); * __platform_driver_register - register a driver for platform-level devices * @drv: platform driver structure * @owner: owning module/driver + * @mod_name: module name string */ -int __platform_driver_register(struct platform_driver *drv, struct module *owner) +int __platform_driver_register(struct platform_driver *drv, struct module *owner, + const char *mod_name) { drv->driver.owner = owner; drv->driver.bus = &platform_bus_type; + drv->driver.mod_name = mod_name; return driver_register(&drv->driver); } @@ -952,6 +955,7 @@ static int is_bound_to_driver(struct device *dev, void *driver) * @drv: platform driver structure * @probe: the driver probe routine, probably from an __init section * @module: module which will be the owner of the driver + * @mod_name: module name string * * Use this instead of platform_driver_register() when you know the device * is not hotpluggable and has already been registered, and you want to @@ -969,7 +973,8 @@ static int is_bound_to_driver(struct device *dev, void *driver) */ int __init_or_module __platform_driver_probe(struct platform_driver *drv, int (*probe)(struct platform_device *), - struct module *module) + struct module *module, + const char *mod_name) { int retval; @@ -997,7 +1002,7 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv, /* temporary section violation during probe() */ drv->probe = probe; - retval = __platform_driver_register(drv, module); + retval = __platform_driver_register(drv, module, mod_name); if (retval) return retval; @@ -1025,6 +1030,7 @@ EXPORT_SYMBOL_GPL(__platform_driver_probe); * @data: platform specific data for this platform device * @size: size of platform specific data * @module: module which will be the owner of the driver + * @mod_name: module name string * * Use this in legacy-style modules that probe hardware directly and * register a single platform device and corresponding platform driver. @@ -1035,7 +1041,7 @@ struct platform_device * __init_or_module __platform_create_bundle(struct platform_driver *driver, int (*probe)(struct platform_device *), struct resource *res, unsigned int n_res, - const void *data, size_t size, struct module *module) + const void *data, size_t size, struct module *module, const char *mod_name) { struct platform_device *pdev; int error; @@ -1058,7 +1064,7 @@ __platform_create_bundle(struct platform_driver *driver, if (error) goto err_pdev_put; - error = __platform_driver_probe(driver, probe, module); + error = __platform_driver_probe(driver, probe, module, mod_name); if (error) goto err_pdev_del; @@ -1078,6 +1084,7 @@ EXPORT_SYMBOL_GPL(__platform_create_bundle); * @drivers: an array of drivers to register * @count: the number of drivers to register * @owner: module owning the drivers + * @mod_name: module name string * * Registers platform drivers specified by an array. On failure to register a * driver, all previously registered drivers will be unregistered. Callers of @@ -1087,7 +1094,7 @@ EXPORT_SYMBOL_GPL(__platform_create_bundle); * Returns: 0 on success or a negative error code on failure. */ int __platform_register_drivers(struct platform_driver * const *drivers, - unsigned int count, struct module *owner) + unsigned int count, struct module *owner, const char *mod_name) { unsigned int i; int err; @@ -1095,7 +1102,7 @@ int __platform_register_drivers(struct platform_driver * const *drivers, for (i = 0; i < count; i++) { pr_debug("registering platform driver %ps\n", drivers[i]); - err = __platform_driver_register(drivers[i], owner); + err = __platform_driver_register(drivers[i], owner, mod_name); if (err < 0) { pr_err("failed to register platform driver %ps: %d\n", drivers[i], err); diff --git a/drivers/base/property.c b/drivers/base/property.c index 8e0148a37fff..e08eadd66f4f 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -1277,8 +1277,10 @@ fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode, if (fwnode_ep.port != port) continue; - if (fwnode_ep.id == endpoint) + if (fwnode_ep.id == endpoint) { + fwnode_handle_put(best_ep); return ep; + } if (!endpoint_next) continue; diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index a19f8f722bc8..869228a65cb3 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -374,20 +374,28 @@ EXPORT_SYMBOL_GPL(property_entries_free); /* -------------------------------------------------------------------------- */ /* fwnode operations */ -static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode) +static struct swnode *swnode_get(struct swnode *swnode) { - struct swnode *swnode = to_swnode(fwnode); - kobject_get(&swnode->kobj); + return swnode; +} + +static void swnode_put(struct swnode *swnode) +{ + kobject_put(&swnode->kobj); +} + +static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode) +{ + struct swnode *swnode = swnode_get(to_swnode(fwnode)); + return &swnode->fwnode; } static void software_node_put(struct fwnode_handle *fwnode) { - struct swnode *swnode = to_swnode(fwnode); - - kobject_put(&swnode->kobj); + swnode_put(to_swnode(fwnode)); } static bool software_node_property_present(const struct fwnode_handle *fwnode, @@ -493,7 +501,7 @@ software_node_get_named_child_node(const struct fwnode_handle *fwnode, list_for_each_entry(child, &swnode->children, entry) { if (!strcmp(childname, kobject_name(&child->kobj))) { - kobject_get(&child->kobj); + swnode_get(child); return &child->fwnode; } } @@ -737,7 +745,7 @@ software_node_find_by_name(const struct software_node *parent, const char *name) swnode = kobj_to_swnode(k); if (parent == swnode->node->parent && swnode->node->name && !strcmp(name, swnode->node->name)) { - kobject_get(&swnode->kobj); + swnode_get(swnode); break; } swnode = NULL; @@ -835,13 +843,13 @@ swnode_register(const struct software_node *node, struct swnode *parent, parent ? &parent->kobj : NULL, "node%d", swnode->id); if (ret) { - kobject_put(&swnode->kobj); + swnode_put(swnode); return ERR_PTR(ret); } /* * Assign the flag only in the successful case, so - * the above kobject_put() won't mess up with properties. + * the above swnode_put() won't mess up with properties. */ swnode->allocated = allocated; @@ -978,7 +986,7 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode) if (!swnode) return; - kobject_put(&swnode->kobj); + swnode_put(swnode); } EXPORT_SYMBOL_GPL(fwnode_remove_software_node); @@ -1002,7 +1010,7 @@ int device_add_software_node(struct device *dev, const struct software_node *nod swnode = software_node_to_swnode(node); if (swnode) { - kobject_get(&swnode->kobj); + swnode_get(swnode); } else { ret = software_node_register(node); if (ret) @@ -1044,7 +1052,7 @@ void device_remove_software_node(struct device *dev) software_node_notify_remove(dev); set_secondary_fwnode(dev, NULL); - kobject_put(&swnode->kobj); + swnode_put(swnode); } EXPORT_SYMBOL_GPL(device_remove_software_node); @@ -1097,7 +1105,7 @@ void software_node_notify(struct device *dev) if (!swnode) return; - kobject_get(&swnode->kobj); + swnode_get(swnode); ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node"); if (ret) return; @@ -1119,11 +1127,11 @@ void software_node_notify_remove(struct device *dev) sysfs_remove_link(&swnode->kobj, dev_name(dev)); sysfs_remove_link(&dev->kobj, "software_node"); - kobject_put(&swnode->kobj); + swnode_put(swnode); if (swnode->managed) { set_secondary_fwnode(dev, NULL); - kobject_put(&swnode->kobj); + swnode_put(swnode); } } diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index f735e0462c55..87070155b057 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -327,12 +327,6 @@ static int of_weim_notify(struct notifier_block *nb, unsigned long action, "Failed to setup timing for '%pOF'\n", rd->dn); if (!of_node_check_flag(rd->dn, OF_POPULATED)) { - /* - * Clear the flag before adding the device so that - * fw_devlink doesn't skip adding consumers to this - * device. - */ - fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE); if (!of_platform_device_create(rd->dn, NULL, &pdev->dev)) { dev_err(&pdev->dev, "Failed to create child device '%pOF'\n", diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index 9196dc50a48d..d3d230247262 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -156,8 +156,6 @@ static int cdx_unregister_device(struct device *dev, } else { cdx_destroy_res_attr(cdx_dev, MAX_CDX_DEV_RESOURCES); debugfs_remove_recursive(cdx_dev->debugfs_dir); - kfree(cdx_dev->driver_override); - cdx_dev->driver_override = NULL; } /* @@ -268,6 +266,7 @@ static int cdx_bus_match(struct device *dev, const struct device_driver *drv) const struct cdx_driver *cdx_drv = to_cdx_driver(drv); const struct cdx_device_id *found_id = NULL; const struct cdx_device_id *ids; + int ret; if (cdx_dev->is_bus) return false; @@ -275,7 +274,8 @@ static int cdx_bus_match(struct device *dev, const struct device_driver *drv) ids = cdx_drv->match_id_table; /* When driver_override is set, only bind to the matching driver */ - if (cdx_dev->driver_override && strcmp(cdx_dev->driver_override, drv->name)) + ret = device_match_driver_override(dev, drv); + if (ret == 0) return false; found_id = cdx_match_id(ids, cdx_dev); @@ -289,7 +289,7 @@ static int cdx_bus_match(struct device *dev, const struct device_driver *drv) */ if (!found_id->override_only) return true; - if (cdx_dev->driver_override) + if (ret > 0) return true; ids = found_id + 1; @@ -453,36 +453,6 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(modalias); -static ssize_t driver_override_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct cdx_device *cdx_dev = to_cdx_device(dev); - int ret; - - if (WARN_ON(dev->bus != &cdx_bus_type)) - return -EINVAL; - - ret = driver_set_override(dev, &cdx_dev->driver_override, buf, count); - if (ret) - return ret; - - return count; -} - -static ssize_t driver_override_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cdx_device *cdx_dev = to_cdx_device(dev); - ssize_t len; - - device_lock(dev); - len = sysfs_emit(buf, "%s\n", cdx_dev->driver_override); - device_unlock(dev); - return len; -} -static DEVICE_ATTR_RW(driver_override); - static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -552,7 +522,6 @@ static struct attribute *cdx_dev_attrs[] = { &dev_attr_class.attr, &dev_attr_revision.attr, &dev_attr_modalias.attr, - &dev_attr_driver_override.attr, NULL, }; @@ -646,6 +615,7 @@ ATTRIBUTE_GROUPS(cdx_bus); const struct bus_type cdx_bus_type = { .name = "cdx", + .driver_override = true, .match = cdx_bus_match, .probe = cdx_probe, .remove = cdx_remove, diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs index f17bf64c22e2..10106fa13095 100644 --- a/drivers/cpufreq/rcpufreq_dt.rs +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -201,12 +201,13 @@ kernel::of_device_table!( impl platform::Driver for CPUFreqDTDriver { type IdInfo = (); + type Data<'bound> = Self; const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); - fn probe( - pdev: &platform::Device<Core>, - _id_info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + fn probe<'bound>( + pdev: &'bound platform::Device<Core<'_>>, + _id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { cpufreq::Registration::<CPUFreqDTDriver>::new_foreign_owned(pdev.as_ref())?; Ok(Self {}) } diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c index 179de3cf6d6c..9e183cd8818c 100644 --- a/drivers/devfreq/devfreq-event.c +++ b/drivers/devfreq/devfreq-event.c @@ -17,7 +17,13 @@ #include <linux/list.h> #include <linux/of.h> -static struct class *devfreq_event_class; +static struct attribute *devfreq_event_attrs[]; +ATTRIBUTE_GROUPS(devfreq_event); + +static const struct class devfreq_event_class = { + .name = "devfreq-event", + .dev_groups = devfreq_event_groups +}; /* The list of all devfreq event list */ static LIST_HEAD(devfreq_event_list); @@ -321,7 +327,7 @@ struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, edev->desc = desc; edev->enable_count = 0; edev->dev.parent = dev; - edev->dev.class = devfreq_event_class; + edev->dev.class = &devfreq_event_class; edev->dev.release = devfreq_event_release_edev; dev_set_name(&edev->dev, "event%d", atomic_inc_return(&event_no)); @@ -461,18 +467,15 @@ static struct attribute *devfreq_event_attrs[] = { &dev_attr_enable_count.attr, NULL, }; -ATTRIBUTE_GROUPS(devfreq_event); static int __init devfreq_event_init(void) { - devfreq_event_class = class_create("devfreq-event"); - if (IS_ERR(devfreq_event_class)) { - pr_err("%s: couldn't create class\n", __FILE__); - return PTR_ERR(devfreq_event_class); - } + int err; - devfreq_event_class->dev_groups = devfreq_event_groups; + err = class_register(&devfreq_event_class); + if (err) + pr_err("%s: couldn't create class\n", __FILE__); - return 0; + return err; } subsys_initcall(devfreq_event_init); diff --git a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c index f87d244cc2d6..686dc140293e 100644 --- a/drivers/dma/ti/k3-udma-glue.c +++ b/drivers/dma/ti/k3-udma-glue.c @@ -312,7 +312,7 @@ k3_udma_glue_request_tx_chn_common(struct device *dev, if (xudma_is_pktdma(tx_chn->common.udmax)) { /* prepare the channel device as coherent */ - tx_chn->common.chan_dev.dma_coherent = true; + dev_set_dma_coherent(&tx_chn->common.chan_dev); dma_coerce_mask_and_coherent(&tx_chn->common.chan_dev, DMA_BIT_MASK(48)); } @@ -1003,7 +1003,7 @@ k3_udma_glue_request_rx_chn_priv(struct device *dev, const char *name, if (xudma_is_pktdma(rx_chn->common.udmax)) { /* prepare the channel device as coherent */ - rx_chn->common.chan_dev.dma_coherent = true; + dev_set_dma_coherent(&rx_chn->common.chan_dev); dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev, DMA_BIT_MASK(48)); } @@ -1104,7 +1104,7 @@ k3_udma_glue_request_remote_rx_chn_common(struct k3_udma_glue_rx_channel *rx_chn if (xudma_is_pktdma(rx_chn->common.udmax)) { /* prepare the channel device as coherent */ - rx_chn->common.chan_dev.dma_coherent = true; + dev_set_dma_coherent(&rx_chn->common.chan_dev); dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev, DMA_BIT_MASK(48)); rx_chn->single_fdq = false; diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index c964ebfcf3b6..1cf158eb7bdb 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -428,18 +428,18 @@ static void k3_configure_chan_coherency(struct dma_chan *chan, u32 asel) /* No special handling for the channel */ chan->dev->chan_dma_dev = false; - chan_dev->dma_coherent = false; + dev_clear_dma_coherent(chan_dev); chan_dev->dma_parms = NULL; } else if (asel == 14 || asel == 15) { chan->dev->chan_dma_dev = true; - chan_dev->dma_coherent = true; + dev_set_dma_coherent(chan_dev); dma_coerce_mask_and_coherent(chan_dev, DMA_BIT_MASK(48)); chan_dev->dma_parms = chan_dev->parent->dma_parms; } else { dev_warn(chan->device->dev, "Invalid ASEL value: %u\n", asel); - chan_dev->dma_coherent = false; + dev_clear_dma_coherent(chan_dev); chan_dev->dma_parms = NULL; } } diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs index b1af0a099551..aa08644012f7 100644 --- a/drivers/gpu/drm/nova/driver.rs +++ b/drivers/gpu/drm/nova/driver.rs @@ -51,9 +51,13 @@ kernel::auxiliary_device_table!( impl auxiliary::Driver for NovaDriver { type IdInfo = (); + type Data<'bound> = Self; const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE; - fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { + fn probe<'bound>( + adev: &'bound auxiliary::Device<Core<'_>>, + _info: &'bound Self::IdInfo, + ) -> impl PinInit<Self, Error> + 'bound { let data = try_pin_init!(NovaData { adev: adev.into() }); let drm = drm::Device::<Self>::new(adev.as_ref(), data)?; diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index 279710b36a10..04f83fcf0937 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -37,7 +37,7 @@ use crate::{ regs, // }; -pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>; +pub(crate) type IoMem = kernel::io::mem::IoMem<'static, SZ_2M>; pub(crate) struct TyrDrmDriver; @@ -91,12 +91,13 @@ kernel::of_device_table!( impl platform::Driver for TyrPlatformDriverData { type IdInfo = (); + type Data<'bound> = Self; const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); - fn probe( - pdev: &platform::Device<Core>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + fn probe<'bound>( + pdev: &'bound platform::Device<Core<'_>>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?; let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?; let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?; @@ -109,7 +110,7 @@ impl platform::Driver for TyrPlatformDriverData { let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?; let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; - let iomem = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?; + let iomem = Arc::new(request.iomap_sized::<SZ_2M>()?.into_devres()?, GFP_KERNEL)?; issue_soft_reset(pdev.as_ref(), &iomem)?; gpu::l2_power_on(pdev.as_ref(), &iomem)?; diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 84b0e1703150..d3f2245ba2e0 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -3,7 +3,6 @@ use kernel::{ auxiliary, device::Core, - devres::Devres, dma::Device, dma::DmaMask, pci, @@ -21,6 +20,7 @@ use kernel::{ }, Arc, }, + types::ForLt, }; use crate::gpu::Gpu; @@ -29,13 +29,15 @@ use crate::gpu::Gpu; static AUXILIARY_ID_COUNTER: Atomic<u32> = Atomic::new(0); #[pin_data] -pub(crate) struct NovaCore { +pub(crate) struct NovaCore<'bound> { #[pin] pub(crate) gpu: Gpu, - #[pin] - _reg: Devres<auxiliary::Registration>, + #[allow(clippy::type_complexity)] + _reg: auxiliary::Registration<'bound, ForLt!(())>, } +pub(crate) struct NovaCoreDriver; + const BAR0_SIZE: usize = SZ_16M; // For now we only support Ampere which can use up to 47-bit DMA addresses. @@ -46,12 +48,12 @@ const BAR0_SIZE: usize = SZ_16M; // DMA addresses. These systems should be quite rare. const GPU_DMA_BITS: u32 = 47; -pub(crate) type Bar0 = pci::Bar<BAR0_SIZE>; +pub(crate) type Bar0 = pci::Bar<'static, BAR0_SIZE>; kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, - <NovaCore as pci::Driver>::IdInfo, + <NovaCoreDriver as pci::Driver>::IdInfo, [ // Modern NVIDIA GPUs will show up as either VGA or 3D controllers. ( @@ -73,11 +75,15 @@ kernel::pci_device_table!( ] ); -impl pci::Driver for NovaCore { +impl pci::Driver for NovaCoreDriver { type IdInfo = (); + type Data<'bound> = NovaCore<'bound>; const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; - fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { + fn probe<'bound>( + pdev: &'bound pci::Device<Core<'_>>, + _info: &'bound Self::IdInfo, + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { pin_init::pin_init_scope(move || { dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); @@ -89,26 +95,28 @@ impl pci::Driver for NovaCore { // other threads of execution. unsafe { pdev.dma_set_mask_and_coherent(DmaMask::new::<GPU_DMA_BITS>())? }; - let bar = Arc::pin_init( - pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0"), + let bar = Arc::new( + pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0")? + .into_devres()?, GFP_KERNEL, )?; - Ok(try_pin_init!(Self { + Ok(try_pin_init!(NovaCore { gpu <- Gpu::new(pdev, bar.clone(), bar.access(pdev.as_ref())?), - _reg <- auxiliary::Registration::new( + _reg: auxiliary::Registration::new( pdev.as_ref(), c"nova-drm", // TODO[XARR]: Use XArray or perhaps IDA for proper ID allocation/recycling. For // now, use a simple atomic counter that never recycles IDs. AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed), - crate::MODULE_NAME - ), + crate::MODULE_NAME, + (), + )?, })) }) } - fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) { + fn unbind<'bound>(pdev: &'bound pci::Device<Core<'_>>, this: Pin<&Self::Data<'bound>>) { this.gpu.unbind(pdev.as_ref()); } } diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 0f6fe9a1b955..4ffb506342a9 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -278,7 +278,7 @@ impl Gpu { /// Called when the corresponding [`Device`](device::Device) is unbound. /// /// Note: This method must only be called from `Driver::unbind`. - pub(crate) fn unbind(&self, dev: &device::Device<device::Core>) { + pub(crate) fn unbind(&self, dev: &device::Device<device::Core<'_>>) { kernel::warn_on!(self .bar .access(dev) diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs index 04a1fa6b25f8..073d87714d3a 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -47,7 +47,7 @@ struct NovaCoreModule { // Fields are dropped in declaration order, so `_driver` is dropped first, // then `_debugfs_guard` clears `DEBUGFS_ROOT`. #[pin] - _driver: Registration<pci::Adapter<driver::NovaCore>>, + _driver: Registration<pci::Adapter<driver::NovaCoreDriver>>, _debugfs_guard: DebugfsRootGuard, } diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index b80a35c778ab..23206640c613 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -548,34 +548,6 @@ static ssize_t device_show(struct device *dev, } static DEVICE_ATTR_RO(device); -static ssize_t driver_override_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct hv_device *hv_dev = device_to_hv_device(dev); - int ret; - - ret = driver_set_override(dev, &hv_dev->driver_override, buf, count); - if (ret) - return ret; - - return count; -} - -static ssize_t driver_override_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hv_device *hv_dev = device_to_hv_device(dev); - ssize_t len; - - device_lock(dev); - len = sysfs_emit(buf, "%s\n", hv_dev->driver_override); - device_unlock(dev); - - return len; -} -static DEVICE_ATTR_RW(driver_override); - /* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */ static struct attribute *vmbus_dev_attrs[] = { &dev_attr_id.attr, @@ -606,7 +578,6 @@ static struct attribute *vmbus_dev_attrs[] = { &dev_attr_channel_vp_mapping.attr, &dev_attr_vendor.attr, &dev_attr_device.attr, - &dev_attr_driver_override.attr, NULL, }; @@ -718,9 +689,11 @@ static const struct hv_vmbus_device_id *hv_vmbus_get_id(const struct hv_driver * { const guid_t *guid = &dev->dev_type; const struct hv_vmbus_device_id *id; + int ret; - /* When driver_override is set, only bind to the matching driver */ - if (dev->driver_override && strcmp(dev->driver_override, drv->name)) + /* If a driver override is set, only bind to the matching driver */ + ret = device_match_driver_override(&dev->device, &drv->driver); + if (ret == 0) return NULL; /* Look at the dynamic ids first, before the static ones */ @@ -728,8 +701,11 @@ static const struct hv_vmbus_device_id *hv_vmbus_get_id(const struct hv_driver * if (!id) id = hv_vmbus_dev_match(drv->id_table, guid); - /* driver_override will always match, send a dummy id */ - if (!id && dev->driver_override) + /* + * If there's a matching driver override, this function should succeed, + * thus return a dummy device ID if no matching ID is found. + */ + if (!id && ret > 0) id = &vmbus_device_null; return id; @@ -1031,6 +1007,7 @@ static const struct dev_pm_ops vmbus_pm = { /* The one and only one */ static const struct bus_type hv_bus = { .name = "vmbus", + .driver_override = true, .match = vmbus_match, .shutdown = vmbus_shutdown, .remove = vmbus_remove, diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index ce71dcddfca2..0c8698c8fc5e 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -706,7 +706,7 @@ static int __init catu_init(void) { int ret; - ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver, THIS_MODULE); + ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver); tmc_etr_set_catu_ops(&etr_catu_buf_ops); return ret; } diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 46f247f73cf6..94ee24afdc6d 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1694,8 +1694,9 @@ static void __exit coresight_exit(void) module_init(coresight_init); module_exit(coresight_exit); -int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, - struct platform_driver *pdev_drv, struct module *owner) +int coresight_init_driver_with_owner(const char *drv, struct amba_driver *amba_drv, + struct platform_driver *pdev_drv, struct module *owner, + const char *mod_name) { int ret; @@ -1705,7 +1706,7 @@ int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, return ret; } - ret = __platform_driver_register(pdev_drv, owner); + ret = __platform_driver_register(pdev_drv, owner, mod_name); if (!ret) return 0; @@ -1713,7 +1714,7 @@ int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, amba_driver_unregister(amba_drv); return ret; } -EXPORT_SYMBOL_GPL(coresight_init_driver); +EXPORT_SYMBOL_GPL(coresight_init_driver_with_owner); void coresight_remove_driver(struct amba_driver *amba_drv, struct platform_driver *pdev_drv) diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 629614278e46..3a806c1d50ea 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -757,8 +757,7 @@ static struct platform_driver debug_platform_driver = { static int __init debug_init(void) { - return coresight_init_driver("debug", &debug_driver, &debug_platform_driver, - THIS_MODULE); + return coresight_init_driver("debug", &debug_driver, &debug_platform_driver); } static void __exit debug_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 3f56ceccd8c9..0abc11f0690c 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -412,8 +412,7 @@ static struct amba_driver dynamic_funnel_driver = { static int __init funnel_init(void) { - return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver, - THIS_MODULE); + return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver); } static void __exit funnel_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 07fc04f53b88..2f382de357ee 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -418,8 +418,7 @@ static struct amba_driver dynamic_replicator_driver = { static int __init replicator_init(void) { - return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver, - THIS_MODULE); + return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver); } static void __exit replicator_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index aca6cec7885a..4e860519a73f 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -1050,7 +1050,7 @@ static struct platform_driver stm_platform_driver = { static int __init stm_init(void) { - return coresight_init_driver("stm", &stm_driver, &stm_platform_driver, THIS_MODULE); + return coresight_init_driver("stm", &stm_driver, &stm_platform_driver); } static void __exit stm_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index c89fe996af23..bc5a133ada3e 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -1046,7 +1046,7 @@ static struct platform_driver tmc_platform_driver = { static int __init tmc_init(void) { - return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver, THIS_MODULE); + return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver); } static void __exit tmc_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c index 96a25877b824..9e8de4323d28 100644 --- a/drivers/hwtracing/coresight/coresight-tnoc.c +++ b/drivers/hwtracing/coresight/coresight-tnoc.c @@ -344,7 +344,7 @@ static struct platform_driver itnoc_driver = { static int __init tnoc_init(void) { - return coresight_init_driver("tnoc", &trace_noc_driver, &itnoc_driver, THIS_MODULE); + return coresight_init_driver("tnoc", &trace_noc_driver, &itnoc_driver); } static void __exit tnoc_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index eaf7210af648..8464edbba2d4 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -1563,8 +1563,7 @@ static struct platform_driver static_tpdm_driver = { static int __init tpdm_init(void) { - return coresight_init_driver("tpdm", &dynamic_tpdm_driver, &static_tpdm_driver, - THIS_MODULE); + return coresight_init_driver("tpdm", &dynamic_tpdm_driver, &static_tpdm_driver); } static void __exit tpdm_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index b8560b140e0f..7b029d2eb389 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -310,7 +310,7 @@ static struct platform_driver tpiu_platform_driver = { static int __init tpiu_init(void) { - return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver, THIS_MODULE); + return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver); } static void __exit tpiu_exit(void) diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 354a88d0599e..30b48a428c0b 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -176,11 +176,6 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, return NOTIFY_OK; } - /* - * Clear the flag before adding the device so that fw_devlink - * doesn't skip adding consumers to this device. - */ - fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE); client = of_i2c_register_device(adap, rd->dn); if (IS_ERR(client)) { dev_err(&adap->dev, "failed to create client for '%pOF'\n", diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 381b60d9e7ce..9b1bf6c8c6b3 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -2149,18 +2149,21 @@ EXPORT_SYMBOL_GPL(dma_iova_destroy); void iommu_setup_dma_ops(struct device *dev, struct iommu_domain *domain) { + bool dma_iommu; + if (dev_is_pci(dev)) dev->iommu->pci_32bit_workaround = !iommu_dma_forcedac; - dev->dma_iommu = iommu_is_dma_domain(domain); - if (dev->dma_iommu && iommu_dma_init_domain(domain, dev)) + dma_iommu = iommu_is_dma_domain(domain); + dev_assign_dma_iommu(dev, dma_iommu); + if (dma_iommu && iommu_dma_init_domain(domain, dev)) goto out_err; return; out_err: pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n", dev_name(dev)); - dev->dma_iommu = false; + dev_clear_dma_iommu(dev); } static bool has_msi_cookie(const struct iommu_domain *domain) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index d1a9e713d3a0..e8f13dcebbde 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -611,9 +611,8 @@ static void iommu_deinit_device(struct device *dev) dev->iommu_group = NULL; module_put(ops->owner); dev_iommu_free(dev); -#ifdef CONFIG_IOMMU_DMA - dev->dma_iommu = false; -#endif + if (IS_ENABLED(CONFIG_IOMMU_DMA)) + dev_clear_dma_iommu(dev); } static struct iommu_domain *pasid_array_entry_to_domain(void *entry) diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c index b8c48f9effbf..f4b1b8246ce9 100644 --- a/drivers/net/pcs/pcs-xpcs-plat.c +++ b/drivers/net/pcs/pcs-xpcs-plat.c @@ -349,7 +349,7 @@ static int xpcs_plat_init_dev(struct dw_xpcs_plat *pxpcs) * up later. Make sure DD-core is aware of the OF-node being re-used. */ device_set_node(&mdiodev->dev, fwnode_handle_get(dev_fwnode(dev))); - mdiodev->dev.of_node_reused = true; + dev_set_of_node_reused(&mdiodev->dev); /* Pass the data further so the DW XPCS driver core could use it */ mdiodev->dev.platform_data = (void *)device_get_match_data(dev); diff --git a/drivers/of/device.c b/drivers/of/device.c index f7e75e527667..be4e1584e0af 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -26,7 +26,7 @@ const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev) { - if (!matches || !dev->of_node || dev->of_node_reused) + if (!matches || !dev->of_node || dev_of_node_reused(dev)) return NULL; return of_match_node(matches, dev->of_node); } @@ -192,7 +192,7 @@ ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len) { ssize_t sl; - if (!dev || !dev->of_node || dev->of_node_reused) + if (!dev || !dev->of_node || dev_of_node_reused(dev)) return -ENODEV; sl = of_modalias(dev->of_node, str, len - 2); @@ -254,7 +254,7 @@ int of_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env * { int sl; - if ((!dev) || (!dev->of_node) || dev->of_node_reused) + if ((!dev) || (!dev->of_node) || dev_of_node_reused(dev)) return -ENODEV; /* Devicetree modalias is tricky, we add it in 2 steps */ diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index ade288372101..aa450425ec1e 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -225,7 +225,6 @@ static void __of_attach_node(struct device_node *np) np->sibling = np->parent->child; np->parent->child = np; of_node_clear_flag(np, OF_DETACHED); - fwnode_set_flag(&np->fwnode, FWNODE_FLAG_NOT_DEVICE); raw_spin_unlock_irqrestore(&devtree_lock, flags); diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index c1c5686fc7b1..4e45f3414c2c 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -185,6 +185,15 @@ static int overlay_notify(struct overlay_changeset *ovcs, return 0; } +static void overlay_fw_devlink_refresh(struct overlay_changeset *ovcs) +{ + for (int i = 0; i < ovcs->count; i++) { + struct device_node *np = ovcs->fragments[i].target; + + fw_devlink_refresh_fwnode(of_fwnode_handle(np)); + } +} + /* * The values of properties in the "/__symbols__" node are paths in * the ovcs->overlay_root. When duplicating the properties, the paths @@ -951,6 +960,12 @@ static int of_overlay_apply(struct overlay_changeset *ovcs, pr_err("overlay apply changeset entry notify error %d\n", ret); /* notify failure is not fatal, continue */ + /* + * Needs to happen after changeset notify to give the listeners a chance + * to finish creating all the devices they need to create. + */ + overlay_fw_devlink_refresh(ovcs); + ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_APPLY); if (ret_tmp) if (!ret) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index a42224f9d1a8..53bca8c6f781 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -744,11 +744,6 @@ static int of_platform_notify(struct notifier_block *nb, if (of_node_check_flag(rd->dn, OF_POPULATED)) return NOTIFY_OK; - /* - * Clear the flag before adding the device so that fw_devlink - * doesn't skip adding consumers to this device. - */ - fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE); /* pdev_parent may be NULL when no bus platform device */ pdev_parent = of_find_device_by_node(parent); pdev = of_platform_device_create(rd->dn, NULL, diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 6da569fd3b8f..8b18c4ba845c 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -38,7 +38,7 @@ int pci_set_of_node(struct pci_dev *dev) struct device *pdev __free(put_device) = bus_find_device_by_of_node(&platform_bus_type, node); if (pdev) - dev->bus->dev.of_node_reused = true; + dev_set_of_node_reused(&dev->bus->dev); device_set_node(&dev->dev, of_fwnode_handle(no_free_ptr(node))); return 0; diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c index 97cff5b8ca88..31246bac84f1 100644 --- a/drivers/pci/pwrctrl/core.c +++ b/drivers/pci/pwrctrl/core.c @@ -39,7 +39,7 @@ static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action, * If we got here then the PCI device is the second after the * power control platform device. Mark its OF node as reused. */ - dev->of_node_reused = true; + dev_set_of_node_reused(dev); break; } diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index ddd44a5ce497..48808cd80737 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -92,7 +92,7 @@ struct Th1520WfHw { #[pin_data(PinnedDrop)] struct Th1520PwmDriverData { #[pin] - iomem: devres::Devres<IoMem<TH1520_PWM_REG_SIZE>>, + iomem: devres::Devres<IoMem<'static, TH1520_PWM_REG_SIZE>>, clk: Clk, } @@ -316,12 +316,13 @@ kernel::of_device_table!( impl platform::Driver for Th1520PwmPlatformDriver { type IdInfo = (); + type Data<'bound> = Self; const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); - fn probe( - pdev: &platform::Device<Core>, - _id_info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + fn probe<'bound>( + pdev: &'bound platform::Device<Core<'_>>, + _id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { let dev = pdev.as_ref(); let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; @@ -351,7 +352,7 @@ impl platform::Driver for Th1520PwmPlatformDriver { dev, TH1520_MAX_PWM_NUM, try_pin_init!(Th1520PwmDriverData { - iomem <- request.iomap_sized::<TH1520_PWM_REG_SIZE>(), + iomem <- request.iomap_sized::<TH1520_PWM_REG_SIZE>()?.into_devres(), clk <- clk, }), )?; diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 401a4ece0c97..d9d4468e4cbd 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1626,7 +1626,6 @@ static void qcom_glink_rpdev_release(struct device *dev) { struct rpmsg_device *rpdev = to_rpmsg_device(dev); - kfree(rpdev->driver_override); kfree(rpdev); } @@ -1862,7 +1861,6 @@ static void qcom_glink_device_release(struct device *dev) /* Release qcom_glink_alloc_channel() reference */ kref_put(&channel->refcount, qcom_glink_channel_release); - kfree(rpdev->driver_override); kfree(rpdev); } diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index e7f7831d37f8..c56f69c22e42 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -358,33 +358,6 @@ rpmsg_show_attr(src, src, "0x%x\n"); rpmsg_show_attr(dst, dst, "0x%x\n"); rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n"); -static ssize_t driver_override_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct rpmsg_device *rpdev = to_rpmsg_device(dev); - int ret; - - ret = driver_set_override(dev, &rpdev->driver_override, buf, count); - if (ret) - return ret; - - return count; -} - -static ssize_t driver_override_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct rpmsg_device *rpdev = to_rpmsg_device(dev); - ssize_t len; - - device_lock(dev); - len = sysfs_emit(buf, "%s\n", rpdev->driver_override); - device_unlock(dev); - return len; -} -static DEVICE_ATTR_RW(driver_override); - static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -405,7 +378,6 @@ static struct attribute *rpmsg_dev_attrs[] = { &dev_attr_dst.attr, &dev_attr_src.attr, &dev_attr_announce.attr, - &dev_attr_driver_override.attr, NULL, }; ATTRIBUTE_GROUPS(rpmsg_dev); @@ -424,9 +396,11 @@ static int rpmsg_dev_match(struct device *dev, const struct device_driver *drv) const struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv); const struct rpmsg_device_id *ids = rpdrv->id_table; unsigned int i; + int ret; - if (rpdev->driver_override) - return !strcmp(rpdev->driver_override, drv->name); + ret = device_match_driver_override(dev, drv); + if (ret >= 0) + return ret; if (ids) for (i = 0; ids[i].name[0]; i++) @@ -535,6 +509,7 @@ static const struct bus_type rpmsg_bus = { .name = "rpmsg", .match = rpmsg_dev_match, .dev_groups = rpmsg_dev_groups, + .driver_override = true, .uevent = rpmsg_uevent, .probe = rpmsg_dev_probe, .remove = rpmsg_dev_remove, @@ -560,11 +535,9 @@ int rpmsg_register_device_override(struct rpmsg_device *rpdev, device_initialize(dev); if (driver_override) { - ret = driver_set_override(dev, &rpdev->driver_override, - driver_override, - strlen(driver_override)); + ret = device_set_driver_override(dev, driver_override); if (ret) { - dev_err(dev, "device_set_override failed: %d\n", ret); + dev_err(dev, "device_set_driver_override() failed: %d\n", ret); put_device(dev); return ret; } @@ -573,8 +546,6 @@ int rpmsg_register_device_override(struct rpmsg_device *rpdev, ret = device_add(dev); if (ret) { dev_err(dev, "device_add failed: %d\n", ret); - kfree(rpdev->driver_override); - rpdev->driver_override = NULL; put_device(dev); } diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 5ae15111fb4f..1b8bb05924af 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -374,7 +374,6 @@ static void virtio_rpmsg_release_device(struct device *dev) struct rpmsg_device *rpdev = to_rpmsg_device(dev); struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev); - kfree(rpdev->driver_override); kfree(vch); } diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c index ab75d50cc85c..2f69e104c838 100644 --- a/drivers/soc/tegra/cbb/tegra194-cbb.c +++ b/drivers/soc/tegra/cbb/tegra194-cbb.c @@ -2342,7 +2342,7 @@ static int __init tegra194_cbb_init(void) { return platform_driver_register(&tegra194_cbb_driver); } -pure_initcall(tegra194_cbb_init); +core_initcall(tegra194_cbb_init); static void __exit tegra194_cbb_exit(void) { diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c index fb26f085f691..785072fa4e85 100644 --- a/drivers/soc/tegra/cbb/tegra234-cbb.c +++ b/drivers/soc/tegra/cbb/tegra234-cbb.c @@ -1774,7 +1774,7 @@ static int __init tegra234_cbb_init(void) { return platform_driver_register(&tegra234_cbb_driver); } -pure_initcall(tegra234_cbb_init); +core_initcall(tegra234_cbb_init); static void __exit tegra234_cbb_exit(void) { diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 104279858f56..889e1eecc757 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -5003,11 +5003,6 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action, return NOTIFY_OK; } - /* - * Clear the flag before adding the device so that fw_devlink - * doesn't skip adding consumers to this device. - */ - fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE); spi = of_register_spi_device(ctlr, rd->dn); put_device(&ctlr->dev); diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index a12935f6b992..5f23284a8778 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -74,7 +74,7 @@ static int serial_base_device_init(struct uart_port *port, dev->parent = parent_dev; dev->bus = &serial_base_bus_type; dev->release = release; - dev->of_node_reused = true; + dev_set_of_node_reused(dev); device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev))); diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 2ecd049dacc2..8b9449d16324 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -593,7 +593,7 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx) d->gadget.max_speed = USB_SPEED_HIGH; d->gadget.speed = USB_SPEED_UNKNOWN; d->gadget.dev.of_node = vhub->pdev->dev.of_node; - d->gadget.dev.of_node_reused = true; + dev_set_of_node_reused(&d->gadget.dev); rc = usb_add_gadget_udc(d->port_dev, &d->gadget); if (rc != 0) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 6d47b8469642..97d9d227b66d 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -597,10 +597,13 @@ void kernfs_put(struct kernfs_node *kn) */ parent = kernfs_parent(kn); - WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS, - "kernfs_put: %s/%s: released with incorrect active_ref %d\n", - parent ? rcu_dereference(parent->name) : "", - rcu_dereference(kn->name), atomic_read(&kn->active)); + if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS) { + guard(rcu)(); + WARN_ONCE(1, + "kernfs_put: %s/%s: released with incorrect active_ref %d\n", + parent ? rcu_dereference(parent->name) : "", + rcu_dereference(kn->name), atomic_read(&kn->active)); + } if (kernfs_type(kn) == KERNFS_LINK) kernfs_put(kn->symlink.target_kn); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 5709cede1d75..cd5bb0f9fee6 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -70,9 +70,8 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v) * The code works fine with PAGE_SIZE return but it's likely to * indicate truncated result or overflow in normal use cases. */ - if (count >= (ssize_t)PAGE_SIZE) { - printk("fill_read_buffer: %pS returned bad count\n", - ops->show); + if (count >= PAGE_SIZE) { + WARN(1, "OOB write or bad count %zd at %pS\n", count, ops->show); /* Try to struggle along */ count = PAGE_SIZE - 1; } @@ -120,6 +119,10 @@ static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf, len = ops->show(kobj, of->kn->priv, buf); if (len < 0) return len; + if (len >= (ssize_t)PAGE_SIZE) { + printk("fill_read_buffer: %pS returned bad count\n", ops->show); + len = PAGE_SIZE - 1; + } if (pos) { if (len <= pos) return 0; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 7e57f9698f7c..714d111d8053 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -189,6 +189,10 @@ struct acpi_driver { * ----------- */ +bool acpi_of_match_device(const struct acpi_device *adev, + const struct of_device_id *of_match_table, + const struct of_device_id **of_id); + /* Status (_STA) */ struct acpi_device_status { @@ -996,6 +1000,13 @@ int acpi_scan_add_dep(acpi_handle handle, struct acpi_handle_list *dep_devices); u32 arch_acpi_add_auto_dep(acpi_handle handle); #else /* CONFIG_ACPI */ +static inline bool acpi_of_match_device(const struct acpi_device *adev, + const struct of_device_id *of_match_table, + const struct of_device_id **of_id) +{ + return false; +} + static inline int register_acpi_bus_type(void *bus) { return 0; } static inline int unregister_acpi_bus_type(void *bus) { return 0; } diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h index 9946276aff73..6c54d5c0d21f 100644 --- a/include/linux/amba/bus.h +++ b/include/linux/amba/bus.h @@ -71,11 +71,6 @@ struct amba_device { unsigned int cid; struct amba_cs_uci_id uci; unsigned int irq[AMBA_NR_IRQS]; - /* - * Driver name to force a match. Do not set directly, because core - * frees it. Use driver_set_override() to set or clear it. - */ - const char *driver_override; }; struct amba_driver { diff --git a/include/linux/auxiliary_bus.h b/include/linux/auxiliary_bus.h index bc09b55e3682..4e1ad8ccbcdd 100644 --- a/include/linux/auxiliary_bus.h +++ b/include/linux/auxiliary_bus.h @@ -62,6 +62,9 @@ * @sysfs.irqs: irqs xarray contains irq indices which are used by the device, * @sysfs.lock: Synchronize irq sysfs creation, * @sysfs.irq_dir_exists: whether "irqs" directory exists, + * @registration_data_rust: private data owned by the registering (parent) + * driver; valid for as long as the device is + * registered with the driver core, * * An auxiliary_device represents a part of its parent device's functionality. * It is given a name that, combined with the registering drivers @@ -148,6 +151,7 @@ struct auxiliary_device { struct mutex lock; /* Synchronize irq sysfs creation */ bool irq_dir_exists; } sysfs; + void *registration_data_rust; }; /** diff --git a/include/linux/cdx/cdx_bus.h b/include/linux/cdx/cdx_bus.h index b1ba97f6c9ad..f54770f110bc 100644 --- a/include/linux/cdx/cdx_bus.h +++ b/include/linux/cdx/cdx_bus.h @@ -137,9 +137,6 @@ struct cdx_controller { * @enabled: is this bus enabled * @msi_dev_id: MSI Device ID associated with CDX device * @num_msi: Number of MSI's supported by the device - * @driver_override: driver name to force a match; do not set directly, - * because core frees it; use driver_set_override() to - * set or clear it. * @irqchip_lock: lock to synchronize irq/msi configuration * @msi_write_pending: MSI write pending for this device */ @@ -165,7 +162,6 @@ struct cdx_device { bool enabled; u32 msi_dev_id; u32 num_msi; - const char *driver_override; struct mutex irqchip_lock; bool msi_write_pending; }; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 2131febebee9..1cf85d772bea 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -691,8 +691,11 @@ coresight_find_output_type(struct coresight_platform_data *pdata, enum coresight_dev_type type, union coresight_dev_subtype subtype); -int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, - struct platform_driver *pdev_drv, struct module *owner); +int coresight_init_driver_with_owner(const char *drv, struct amba_driver *amba_drv, + struct platform_driver *pdev_drv, struct module *owner, + const char *mod_name); +#define coresight_init_driver(drv, amba_drv, pdev_drv) \ + coresight_init_driver_with_owner(drv, amba_drv, pdev_drv, THIS_MODULE, KBUILD_MODNAME) void coresight_remove_driver(struct amba_driver *amba_drv, struct platform_driver *pdev_drv); diff --git a/include/linux/device.h b/include/linux/device.h index 9c8fde6a3d86..7b2baffdd2f5 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -38,7 +38,6 @@ struct device_private; struct device_driver; struct driver_private; struct module; -struct class; struct subsys_private; struct device_node; struct fwnode_handle; @@ -104,10 +103,18 @@ struct device_type { */ struct device_attribute { struct attribute attr; - ssize_t (*show)(struct device *dev, struct device_attribute *attr, - char *buf); - ssize_t (*store)(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); + __SYSFS_FUNCTION_ALTERNATIVE( + ssize_t (*show)(struct device *dev, struct device_attribute *attr, + char *buf); + ssize_t (*show_const)(struct device *dev, const struct device_attribute *attr, + char *buf); + ); + __SYSFS_FUNCTION_ALTERNATIVE( + ssize_t (*store)(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); + ssize_t (*store_const)(struct device *dev, const struct device_attribute *attr, + const char *buf, size_t count); + ); }; /** @@ -135,6 +142,77 @@ ssize_t device_store_bool(struct device *dev, struct device_attribute *attr, ssize_t device_show_string(struct device *dev, struct device_attribute *attr, char *buf); +typedef ssize_t __device_show_handler_const(struct device *dev, const struct device_attribute *attr, + char *buf); +typedef ssize_t __device_store_handler_const(struct device *dev, const struct device_attribute *attr, + const char *buf, size_t count); + +#ifdef CONFIG_CFI + +#define __DEVICE_ATTR_SHOW_STORE(_show, _store) \ + .show = _Generic(_show, \ + __device_show_handler_const * : NULL, \ + default : _show \ + ), \ + .show_const = _Generic(_show, \ + __device_show_handler_const * : _show, \ + default : NULL \ + ), \ + .store = _Generic(_store, \ + __device_store_handler_const * : NULL, \ + default : _store \ + ), \ + .store_const = _Generic(_store, \ + __device_store_handler_const * : _store, \ + default : NULL \ + ), + +#else + +#define __DEVICE_ATTR_SHOW_STORE(_show, _store) \ + .show = _Generic(_show, \ + __device_show_handler_const * : (void *)_show, \ + default : _show \ + ), \ + .store = _Generic(_store, \ + __device_store_handler_const * : (void *)_store, \ + default : _store \ + ), \ + +#endif + + +#define __DEVICE_ATTR(_name, _mode, _show, _store) { \ + .attr = {.name = __stringify(_name), \ + .mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \ + __DEVICE_ATTR_SHOW_STORE(_show, _store) \ +} + +#define __DEVICE_ATTR_RO_MODE(_name, _mode) \ + __DEVICE_ATTR(_name, _mode, _name##_show, NULL) + +#define __DEVICE_ATTR_RO(_name) \ + __DEVICE_ATTR_RO_MODE(_name, 0444) + +#define __DEVICE_ATTR_WO(_name) \ + __DEVICE_ATTR(_name, 0200, NULL, _name##_store) + +#define __DEVICE_ATTR_RW_MODE(_name, _mode) \ + __DEVICE_ATTR(_name, _mode, _name##_show, _name##_store) + +#define __DEVICE_ATTR_RW(_name) \ + __DEVICE_ATTR_RW_MODE(_name, 0644) + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +#define __DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) { \ + .attr = {.name = __stringify(_name), .mode = _mode, \ + .ignore_lockdep = true }, \ + __DEVICE_ATTR_SHOW_STORE(_show, _store) \ +} +#else +#define __DEVICE_ATTR_IGNORE_LOCKDEP __DEVICE_ATTR +#endif + /** * DEVICE_ATTR - Define a device attribute. * @_name: Attribute name. @@ -155,20 +233,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, * }; */ #define DEVICE_ATTR(_name, _mode, _show, _store) \ - struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) - -/** - * DEVICE_ATTR_PREALLOC - Define a preallocated device attribute. - * @_name: Attribute name. - * @_mode: File mode. - * @_show: Show handler. Optional, but mandatory if attribute is readable. - * @_store: Store handler. Optional, but mandatory if attribute is writable. - * - * Like DEVICE_ATTR(), but ``SYSFS_PREALLOC`` is set on @_mode. - */ -#define DEVICE_ATTR_PREALLOC(_name, _mode, _show, _store) \ - struct device_attribute dev_attr_##_name = \ - __ATTR_PREALLOC(_name, _mode, _show, _store) + struct device_attribute dev_attr_##_name = __DEVICE_ATTR(_name, _mode, _show, _store) /** * DEVICE_ATTR_RW - Define a read-write device attribute. @@ -178,7 +243,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, * and @_store is <_name>_store. */ #define DEVICE_ATTR_RW(_name) \ - struct device_attribute dev_attr_##_name = __ATTR_RW(_name) + struct device_attribute dev_attr_##_name = __DEVICE_ATTR_RW(_name) /** * DEVICE_ATTR_ADMIN_RW - Define an admin-only read-write device attribute. @@ -187,7 +252,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, * Like DEVICE_ATTR_RW(), but @_mode is 0600. */ #define DEVICE_ATTR_ADMIN_RW(_name) \ - struct device_attribute dev_attr_##_name = __ATTR_RW_MODE(_name, 0600) + struct device_attribute dev_attr_##_name = __DEVICE_ATTR_RW_MODE(_name, 0600) /** * DEVICE_ATTR_RW_NAMED - Define a read-write device attribute with a sysfs name @@ -201,8 +266,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, #define DEVICE_ATTR_RW_NAMED(_name, _attrname) \ struct device_attribute dev_attr_##_name = { \ .attr = { .name = _attrname, .mode = 0644 }, \ - .show = _name##_show, \ - .store = _name##_store, \ + __DEVICE_ATTR_SHOW_STORE(_name##_show, _name##_store) \ } /** @@ -212,7 +276,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, * Like DEVICE_ATTR(), but @_mode is 0444 and @_show is <_name>_show. */ #define DEVICE_ATTR_RO(_name) \ - struct device_attribute dev_attr_##_name = __ATTR_RO(_name) + struct device_attribute dev_attr_##_name = __DEVICE_ATTR_RO(_name) /** * DEVICE_ATTR_ADMIN_RO - Define an admin-only readable device attribute. @@ -221,7 +285,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, * Like DEVICE_ATTR_RO(), but @_mode is 0400. */ #define DEVICE_ATTR_ADMIN_RO(_name) \ - struct device_attribute dev_attr_##_name = __ATTR_RO_MODE(_name, 0400) + struct device_attribute dev_attr_##_name = __DEVICE_ATTR_RO_MODE(_name, 0400) /** * DEVICE_ATTR_RO_NAMED - Define a read-only device attribute with a sysfs name @@ -235,7 +299,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, #define DEVICE_ATTR_RO_NAMED(_name, _attrname) \ struct device_attribute dev_attr_##_name = { \ .attr = { .name = _attrname, .mode = 0444 }, \ - .show = _name##_show, \ + __DEVICE_ATTR_SHOW_STORE(_name##_show, NULL) \ } /** @@ -245,7 +309,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, * Like DEVICE_ATTR(), but @_mode is 0200 and @_store is <_name>_store. */ #define DEVICE_ATTR_WO(_name) \ - struct device_attribute dev_attr_##_name = __ATTR_WO(_name) + struct device_attribute dev_attr_##_name = __DEVICE_ATTR_WO(_name) /** * DEVICE_ATTR_WO_NAMED - Define a read-only device attribute with a sysfs name @@ -259,7 +323,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, #define DEVICE_ATTR_WO_NAMED(_name, _attrname) \ struct device_attribute dev_attr_##_name = { \ .attr = { .name = _attrname, .mode = 0200 }, \ - .store = _name##_store, \ + __DEVICE_ATTR_SHOW_STORE(NULL, _name##_store) \ } /** @@ -273,7 +337,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, */ #define DEVICE_ULONG_ATTR(_name, _mode, _var) \ struct dev_ext_attribute dev_attr_##_name = \ - { __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) } + { __DEVICE_ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) } /** * DEVICE_INT_ATTR - Define a device attribute backed by an int. @@ -285,7 +349,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, */ #define DEVICE_INT_ATTR(_name, _mode, _var) \ struct dev_ext_attribute dev_attr_##_name = \ - { __ATTR(_name, _mode, device_show_int, device_store_int), &(_var) } + { __DEVICE_ATTR(_name, _mode, device_show_int, device_store_int), &(_var) } /** * DEVICE_BOOL_ATTR - Define a device attribute backed by a bool. @@ -297,7 +361,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, */ #define DEVICE_BOOL_ATTR(_name, _mode, _var) \ struct dev_ext_attribute dev_attr_##_name = \ - { __ATTR(_name, _mode, device_show_bool, device_store_bool), &(_var) } + { __DEVICE_ATTR(_name, _mode, device_show_bool, device_store_bool), &(_var) } /** * DEVICE_STRING_ATTR_RO - Define a device attribute backed by a r/o string. @@ -310,11 +374,11 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, */ #define DEVICE_STRING_ATTR_RO(_name, _mode, _var) \ struct dev_ext_attribute dev_attr_##_name = \ - { __ATTR(_name, (_mode) & ~0222, device_show_string, NULL), (_var) } + { __DEVICE_ATTR(_name, (_mode) & ~0222, device_show_string, NULL), (_var) } #define DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \ struct device_attribute dev_attr_##_name = \ - __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) + __DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) int device_create_file(struct device *device, const struct device_attribute *entry); @@ -512,10 +576,40 @@ struct device_physical_location { * * @DEV_FLAG_READY_TO_PROBE: If set then device_add() has finished enough * initialization that probe could be called. + * @DEV_FLAG_CAN_MATCH: The device has matched with a driver at least once or it + * is in a bus (like AMBA) which can't check for matching drivers + * until other devices probe successfully. + * @DEV_FLAG_DMA_IOMMU: Device is using default IOMMU implementation for DMA and + * doesn't rely on dma_ops structure. + * @DEV_FLAG_DMA_SKIP_SYNC: DMA sync operations can be skipped for coherent + * buffers. + * @DEV_FLAG_DMA_OPS_BYPASS: If set then the dma_ops are bypassed for the + * streaming DMA operations (->map_* / ->unmap_* / ->sync_*), and + * optional (if the coherent mask is large enough) also for dma + * allocations. This flag is managed by the dma ops instance from + * ->dma_supported. + * @DEV_FLAG_STATE_SYNCED: The hardware state of this device has been synced to + * match the software state of this device by calling the + * driver/bus sync_state() callback. + * @DEV_FLAG_DMA_COHERENT: This particular device is dma coherent, even if the + * architecture supports non-coherent devices. + * @DEV_FLAG_OF_NODE_REUSED: Set if the device-tree node is shared with an + * ancestor device. + * @DEV_FLAG_OFFLINE_DISABLED: If set, the device is permanently online. + * @DEV_FLAG_OFFLINE: Set after successful invocation of bus type's .offline(). * @DEV_FLAG_COUNT: Number of defined struct_device_flags. */ enum struct_device_flags { DEV_FLAG_READY_TO_PROBE = 0, + DEV_FLAG_CAN_MATCH = 1, + DEV_FLAG_DMA_IOMMU = 2, + DEV_FLAG_DMA_SKIP_SYNC = 3, + DEV_FLAG_DMA_OPS_BYPASS = 4, + DEV_FLAG_STATE_SYNCED = 5, + DEV_FLAG_DMA_COHERENT = 6, + DEV_FLAG_OF_NODE_REUSED = 7, + DEV_FLAG_OFFLINE_DISABLED = 8, + DEV_FLAG_OFFLINE = 9, DEV_FLAG_COUNT }; @@ -594,27 +688,6 @@ enum struct_device_flags { * @removable: Whether the device can be removed from the system. This * should be set by the subsystem / bus driver that discovered * the device. - * - * @offline_disabled: If set, the device is permanently online. - * @offline: Set after successful invocation of bus type's .offline(). - * @of_node_reused: Set if the device-tree node is shared with an ancestor - * device. - * @state_synced: The hardware state of this device has been synced to match - * the software state of this device by calling the driver/bus - * sync_state() callback. - * @can_match: The device has matched with a driver at least once or it is in - * a bus (like AMBA) which can't check for matching drivers until - * other devices probe successfully. - * @dma_coherent: this particular device is dma coherent, even if the - * architecture supports non-coherent devices. - * @dma_ops_bypass: If set to %true then the dma_ops are bypassed for the - * streaming DMA operations (->map_* / ->unmap_* / ->sync_*), - * and optionall (if the coherent mask is large enough) also - * for dma allocations. This flag is managed by the dma ops - * instance from ->dma_supported. - * @dma_skip_sync: DMA sync operations can be skipped for coherent buffers. - * @dma_iommu: Device is using default IOMMU implementation for DMA and - * doesn't rely on dma_ops structure. * @flags: DEV_FLAG_XXX flags. Use atomic bitfield operations to modify. * * At the lowest level, every device in a Linux system is represented by an @@ -719,26 +792,6 @@ struct device { enum device_removable removable; - bool offline_disabled:1; - bool offline:1; - bool of_node_reused:1; - bool state_synced:1; - bool can_match:1; -#if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ - defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \ - defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) - bool dma_coherent:1; -#endif -#ifdef CONFIG_DMA_OPS_BYPASS - bool dma_ops_bypass : 1; -#endif -#ifdef CONFIG_DMA_NEED_SYNC - bool dma_skip_sync:1; -#endif -#ifdef CONFIG_IOMMU_DMA - bool dma_iommu:1; -#endif - DECLARE_BITMAP(flags, DEV_FLAG_COUNT); }; @@ -765,6 +818,15 @@ static inline bool dev_test_and_set_##accessor_name(struct device *dev) \ } __create_dev_flag_accessors(ready_to_probe, DEV_FLAG_READY_TO_PROBE); +__create_dev_flag_accessors(can_match, DEV_FLAG_CAN_MATCH); +__create_dev_flag_accessors(dma_iommu, DEV_FLAG_DMA_IOMMU); +__create_dev_flag_accessors(dma_skip_sync, DEV_FLAG_DMA_SKIP_SYNC); +__create_dev_flag_accessors(dma_ops_bypass, DEV_FLAG_DMA_OPS_BYPASS); +__create_dev_flag_accessors(state_synced, DEV_FLAG_STATE_SYNCED); +__create_dev_flag_accessors(dma_coherent, DEV_FLAG_DMA_COHERENT); +__create_dev_flag_accessors(of_node_reused, DEV_FLAG_OF_NODE_REUSED); +__create_dev_flag_accessors(offline_disabled, DEV_FLAG_OFFLINE_DISABLED); +__create_dev_flag_accessors(offline, DEV_FLAG_OFFLINE); #undef __create_dev_flag_accessors @@ -1063,17 +1125,6 @@ static inline void device_lock_assert(struct device *dev) lockdep_assert_held(&dev->mutex); } -static inline bool dev_has_sync_state(struct device *dev) -{ - if (!dev) - return false; - if (dev->driver && dev->driver->sync_state) - return true; - if (dev->bus && dev->bus->sync_state) - return true; - return false; -} - static inline int dev_set_drv_sync_state(struct device *dev, void (*fn)(struct device *dev)) { diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h index c1b463cd6464..a38f7229b8f4 100644 --- a/include/linux/device/bus.h +++ b/include/linux/device/bus.h @@ -83,9 +83,9 @@ struct fwnode_handle; struct bus_type { const char *name; const char *dev_name; - const struct attribute_group **bus_groups; - const struct attribute_group **dev_groups; - const struct attribute_group **drv_groups; + const struct attribute_group *const *bus_groups; + const struct attribute_group *const *dev_groups; + const struct attribute_group *const *drv_groups; int (*match)(struct device *dev, const struct device_driver *drv); int (*uevent)(const struct device *dev, struct kobj_uevent_env *env); diff --git a/include/linux/device/class.h b/include/linux/device/class.h index 78ab8d2b3e30..9db1d61ba743 100644 --- a/include/linux/device/class.h +++ b/include/linux/device/class.h @@ -34,7 +34,7 @@ struct fwnode_handle; * @class_release: Called to release this class. * @dev_release: Called to release the device. * @shutdown_pre: Called at shut-down time before driver shutdown. - * @ns_type: Callbacks so sysfs can detemine namespaces. + * @ns_type: Callbacks so sysfs can determine namespaces. * @namespace: Namespace of the device belongs to this class. * @get_ownership: Allows class to specify uid/gid of the sysfs directories * for the devices belonging to the class. Usually tied to diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index bbc67ec513ed..38048e74d10a 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -114,8 +114,8 @@ struct device_driver { void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); - const struct attribute_group **groups; - const struct attribute_group **dev_groups; + const struct attribute_group *const *groups; + const struct attribute_group *const *dev_groups; const struct dev_pm_ops *pm; void (*coredump) (struct device *dev); @@ -123,8 +123,8 @@ struct device_driver { struct driver_private *p; struct { /* - * Called after remove() and after all devres entries have been - * processed. This is a Rust only callback. + * Called after remove() but before devres entries are released. + * This is a Rust only callback. */ void (*post_unbind_rust)(struct device *dev); } p_cb; @@ -160,8 +160,6 @@ int __must_check driver_create_file(const struct device_driver *driver, void driver_remove_file(const struct device_driver *driver, const struct driver_attribute *attr); -int driver_set_override(struct device *dev, const char **override, - const char *s, size_t len); int __must_check driver_for_each_device(struct device_driver *drv, struct device *start, void *data, device_iter_t fn); struct device *driver_find_device(const struct device_driver *drv, diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h index 6a1832a73cad..bcb5b5428aea 100644 --- a/include/linux/dma-map-ops.h +++ b/include/linux/dma-map-ops.h @@ -225,7 +225,7 @@ int dma_direct_set_offset(struct device *dev, phys_addr_t cpu_start, extern bool dma_default_coherent; static inline bool dev_is_dma_coherent(struct device *dev) { - return dev->dma_coherent; + return dev_dma_coherent(dev); } #else #define dma_default_coherent true @@ -240,8 +240,8 @@ static inline void dma_reset_need_sync(struct device *dev) { #ifdef CONFIG_DMA_NEED_SYNC /* Reset it only once so that the function can be called on hotpath */ - if (unlikely(dev->dma_skip_sync)) - dev->dma_skip_sync = false; + if (unlikely(dev_dma_skip_sync(dev))) + dev_clear_dma_skip_sync(dev); #endif } diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index db8ab24a54f4..cc0823a99cfd 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -429,7 +429,7 @@ bool __dma_need_sync(struct device *dev, dma_addr_t dma_addr); static inline bool dma_dev_need_sync(const struct device *dev) { /* Always call DMA sync operations when debugging is enabled */ - return !dev->dma_skip_sync || IS_ENABLED(CONFIG_DMA_API_DEBUG); + return !dev_dma_skip_sync(dev) || IS_ENABLED(CONFIG_DMA_API_DEBUG); } static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index 31df7608737e..4e86e6990d28 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -210,8 +210,10 @@ static inline void fwnode_init(struct fwnode_handle *fwnode, { fwnode->secondary = NULL; fwnode->ops = ops; + fwnode->dev = NULL; INIT_LIST_HEAD(&fwnode->consumers); INIT_LIST_HEAD(&fwnode->suppliers); + fwnode->flags = 0; } static inline void fwnode_set_flag(struct fwnode_handle *fwnode, @@ -251,6 +253,7 @@ int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup, u8 flags); void fwnode_links_purge(struct fwnode_handle *fwnode); void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode); +void fw_devlink_refresh_fwnode(struct fwnode_handle *fwnode); bool fw_devlink_is_strict(void); #endif diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 734b7ef98f4d..9de2c8d6037a 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1272,11 +1272,6 @@ struct hv_device { u16 device_id; struct device device; - /* - * Driver name to force a match. Do not set directly, because core - * frees it. Use driver_set_override() to set or clear it. - */ - const char *driver_override; struct vmbus_channel *channel; struct kset *channels_kset; diff --git a/include/linux/iommu-dma.h b/include/linux/iommu-dma.h index a92b3ff9b934..060f6e23ab3c 100644 --- a/include/linux/iommu-dma.h +++ b/include/linux/iommu-dma.h @@ -7,12 +7,13 @@ #ifndef _LINUX_IOMMU_DMA_H #define _LINUX_IOMMU_DMA_H +#include <linux/device.h> #include <linux/dma-direction.h> #ifdef CONFIG_IOMMU_DMA static inline bool use_dma_iommu(struct device *dev) { - return dev->dma_iommu; + return dev_dma_iommu(dev); } #else static inline bool use_dma_iommu(struct device *dev) diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 975400a472e3..26e6a43358e2 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -293,18 +293,19 @@ struct platform_driver { * use a macro to avoid include chaining to get THIS_MODULE */ #define platform_driver_register(drv) \ - __platform_driver_register(drv, THIS_MODULE) + __platform_driver_register(drv, THIS_MODULE, KBUILD_MODNAME) extern int __platform_driver_register(struct platform_driver *, - struct module *); + struct module *, const char *mod_name); extern void platform_driver_unregister(struct platform_driver *); /* non-hotpluggable platform devices may use this so that probe() and * its support may live in __init sections, conserving runtime memory. */ #define platform_driver_probe(drv, probe) \ - __platform_driver_probe(drv, probe, THIS_MODULE) + __platform_driver_probe(drv, probe, THIS_MODULE, KBUILD_MODNAME) extern int __platform_driver_probe(struct platform_driver *driver, - int (*probe)(struct platform_device *), struct module *module); + int (*probe)(struct platform_device *), struct module *module, + const char *mod_name); static inline void *platform_get_drvdata(const struct platform_device *pdev) { @@ -368,19 +369,19 @@ static int __init __platform_driver##_init(void) \ device_initcall(__platform_driver##_init); \ #define platform_create_bundle(driver, probe, res, n_res, data, size) \ - __platform_create_bundle(driver, probe, res, n_res, data, size, THIS_MODULE) + __platform_create_bundle(driver, probe, res, n_res, data, size, THIS_MODULE, KBUILD_MODNAME) extern struct platform_device *__platform_create_bundle( struct platform_driver *driver, int (*probe)(struct platform_device *), struct resource *res, unsigned int n_res, - const void *data, size_t size, struct module *module); + const void *data, size_t size, struct module *module, const char *mod_name); int __platform_register_drivers(struct platform_driver * const *drivers, - unsigned int count, struct module *owner); + unsigned int count, struct module *owner, const char *mod_name); void platform_unregister_drivers(struct platform_driver * const *drivers, unsigned int count); #define platform_register_drivers(drivers, count) \ - __platform_register_drivers(drivers, count, THIS_MODULE) + __platform_register_drivers(drivers, count, THIS_MODULE, KBUILD_MODNAME) #ifdef CONFIG_SUSPEND extern int platform_pm_suspend(struct device *dev); diff --git a/include/linux/property.h b/include/linux/property.h index e30ef23a9af3..14c304db4664 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -471,12 +471,18 @@ struct property_entry { #define PROPERTY_ENTRY_STRING(_name_, _val_) \ __PROPERTY_ENTRY_ELEMENT(_name_, str, STRING, _val_) +#define __PROPERTY_ENTRY_REF_ARGS(_ref_, ...) \ + _Generic(_ref_, \ + const struct software_node_ref_args *: _ref_, \ + struct software_node_ref_args *: _ref_, \ + default: &SOFTWARE_NODE_REFERENCE(_ref_, ##__VA_ARGS__)) + #define PROPERTY_ENTRY_REF(_name_, _ref_, ...) \ (struct property_entry) { \ .name = _name_, \ .length = sizeof(struct software_node_ref_args), \ .type = DEV_PROP_REF, \ - { .pointer = &SOFTWARE_NODE_REFERENCE(_ref_, ##__VA_ARGS__), }, \ + { .pointer = __PROPERTY_ENTRY_REF_ARGS(_ref_, ##__VA_ARGS__) }, \ } #define PROPERTY_ENTRY_BOOL(_name_) \ diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 83266ce14642..2e40eb54155e 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -41,9 +41,6 @@ struct rpmsg_channel_info { * rpmsg_device - device that belong to the rpmsg bus * @dev: the device struct * @id: device id (used to match between rpmsg drivers and devices) - * @driver_override: driver name to force a match; do not set directly, - * because core frees it; use driver_set_override() to - * set or clear it. * @src: local address * @dst: destination address * @ept: the rpmsg endpoint of this channel @@ -53,7 +50,6 @@ struct rpmsg_channel_info { struct rpmsg_device { struct device dev; struct rpmsg_device_id id; - const char *driver_override; u32 src; u32 dst; struct rpmsg_endpoint *ept; diff --git a/kernel/cpu.c b/kernel/cpu.c index bc4f7a9ba64e..f975bb34915b 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -2639,7 +2639,7 @@ static void cpuhp_offline_cpu_device(unsigned int cpu) { struct device *dev = get_cpu_device(cpu); - dev->offline = true; + dev_set_offline(dev); /* Tell user space about the state change */ kobject_uevent(&dev->kobj, KOBJ_OFFLINE); } @@ -2648,7 +2648,7 @@ static void cpuhp_online_cpu_device(unsigned int cpu) { struct device *dev = get_cpu_device(cpu); - dev->offline = false; + dev_clear_offline(dev); /* Tell user space about the state change */ kobject_uevent(&dev->kobj, KOBJ_ONLINE); } diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c index e6b07f160d20..4eedb1a6273a 100644 --- a/kernel/dma/mapping.c +++ b/kernel/dma/mapping.c @@ -126,11 +126,9 @@ static bool dma_go_direct(struct device *dev, dma_addr_t mask, if (likely(!ops)) return true; -#ifdef CONFIG_DMA_OPS_BYPASS - if (dev->dma_ops_bypass) + if (IS_ENABLED(CONFIG_DMA_OPS_BYPASS) && dev_dma_ops_bypass(dev)) return min_not_zero(mask, dev->bus_dma_limit) >= dma_direct_get_required_mask(dev); -#endif return false; } @@ -472,7 +470,7 @@ bool dma_need_unmap(struct device *dev) { if (!dma_map_direct(dev, get_dma_ops(dev))) return true; - if (!dev->dma_skip_sync) + if (!dev_dma_skip_sync(dev)) return true; return IS_ENABLED(CONFIG_DMA_API_DEBUG); } @@ -488,16 +486,16 @@ static void dma_setup_need_sync(struct device *dev) * mapping, if any. During the device initialization, it's * enough to check only for the DMA coherence. */ - dev->dma_skip_sync = dev_is_dma_coherent(dev); + dev_assign_dma_skip_sync(dev, dev_is_dma_coherent(dev)); else if (!ops->sync_single_for_device && !ops->sync_single_for_cpu && !ops->sync_sg_for_device && !ops->sync_sg_for_cpu) /* * Synchronization is not possible when none of DMA sync ops * is set. */ - dev->dma_skip_sync = true; + dev_set_dma_skip_sync(dev); else - dev->dma_skip_sync = false; + dev_clear_dma_skip_sync(dev); } #else /* !CONFIG_DMA_NEED_SYNC */ static inline void dma_setup_need_sync(struct device *dev) { } diff --git a/kernel/params.c b/kernel/params.c index 74d620bc2521..a668863a4bb6 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -942,9 +942,9 @@ const struct kobj_type module_ktype = { /* * param_sysfs_init - create "module" kset * - * This must be done before the initramfs is unpacked and - * request_module() thus becomes possible, because otherwise the - * module load would fail in mod_sysfs_init. + * This must be done before any driver registration so that when a driver comes + * from a built-in module, the driver core can add the module under /sys/module + * and create the associated driver symlinks. */ static int __init param_sysfs_init(void) { @@ -957,7 +957,7 @@ static int __init param_sysfs_init(void) return 0; } -subsys_initcall(param_sysfs_init); +pure_initcall(param_sysfs_init); /* * param_sysfs_builtin_init - add sysfs version and parameter @@ -709,7 +709,7 @@ int hmm_dma_map_alloc(struct device *dev, struct hmm_dma_map *map, * best approximation to ensure no swiotlb buffering happens. */ #ifdef CONFIG_DMA_NEED_SYNC - dma_need_sync = !dev->dma_skip_sync; + dma_need_sync = !dev_dma_skip_sync(dev); #endif /* CONFIG_DMA_NEED_SYNC */ if (dma_need_sync || dma_addressing_limited(dev)) return -EOPNOTSUPP; diff --git a/rust/Makefile b/rust/Makefile index 2fbdebb93bf2..63b1e355321d 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -119,6 +119,7 @@ syn-cfgs := \ feature="parsing" \ feature="printing" \ feature="proc-macro" \ + feature="visit" \ feature="visit-mut" syn-flags := \ diff --git a/rust/helpers/acpi.c b/rust/helpers/acpi.c new file mode 100644 index 000000000000..e75c9807bbad --- /dev/null +++ b/rust/helpers/acpi.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/acpi.h> +#include <acpi/acpi_bus.h> + +__rust_helper bool rust_helper_acpi_of_match_device(const struct acpi_device *adev, + const struct of_device_id *of_match_table, + const struct of_device_id **of_id) +{ + return acpi_of_match_device(adev, of_match_table, of_id); +} + +__rust_helper struct acpi_device *rust_helper_to_acpi_device_node(struct fwnode_handle *fwnode) +{ + return to_acpi_device_node(fwnode); +} diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 625921e27dfb..38b34518eff1 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -38,6 +38,7 @@ #define __rust_helper __always_inline #endif +#include "acpi.c" #include "atomic.c" #include "atomic_ext.c" #include "auxiliary.c" diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index 80eb39364e86..35d1e015848d 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -279,6 +279,27 @@ where Ok(Box(ptr.cast(), PhantomData)) } + /// Creates a new zero-initialized `Box<T, A>`. + /// + /// New memory is allocated with `A` and the [`__GFP_ZERO`] flag. The allocation may fail, in + /// which case an error is returned. For ZSTs no memory is allocated. + /// + /// # Examples + /// + /// ``` + /// let b = KBox::<[u8; 128]>::zeroed(GFP_KERNEL)?; + /// assert_eq!(*b, [0; 128]); + /// # Ok::<(), Error>(()) + /// ``` + pub fn zeroed(flags: Flags) -> Result<Self, AllocError> + where + T: Zeroable, + { + // SAFETY: `__GFP_ZERO` guarantees the memory is zeroed; `T: Zeroable` guarantees that + // all-zeroes is a valid bit pattern for `T`. + Ok(unsafe { Self::new_uninit(flags | __GFP_ZERO)?.assume_init() }) + } + /// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement [`Unpin`], then `x` will be /// pinned in memory and can't be moved. #[inline] @@ -483,7 +504,7 @@ where // SAFETY: The pointer returned by `into_foreign` comes from a well aligned // pointer to `T` allocated by `A`. -unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A> +unsafe impl<T, A> ForeignOwnable for Box<T, A> where A: Allocator, { @@ -493,8 +514,14 @@ where core::mem::align_of::<T>() }; - type Borrowed<'a> = &'a T; - type BorrowedMut<'a> = &'a mut T; + type Borrowed<'a> + = &'a T + where + Self: 'a; + type BorrowedMut<'a> + = &'a mut T + where + Self: 'a; fn into_foreign(self) -> *mut c_void { Box::into_raw(self).cast() @@ -522,13 +549,19 @@ where // SAFETY: The pointer returned by `into_foreign` comes from a well aligned // pointer to `T` allocated by `A`. -unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>> +unsafe impl<T, A> ForeignOwnable for Pin<Box<T, A>> where A: Allocator, { const FOREIGN_ALIGN: usize = <Box<T, A> as ForeignOwnable>::FOREIGN_ALIGN; - type Borrowed<'a> = Pin<&'a T>; - type BorrowedMut<'a> = Pin<&'a mut T>; + type Borrowed<'a> + = Pin<&'a T> + where + Self: 'a; + type BorrowedMut<'a> + = Pin<&'a mut T> + where + Self: 'a; fn into_foreign(self) -> *mut c_void { // SAFETY: We are still treating the box as pinned. diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 93c0db1f6655..c42928d5a239 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -12,19 +12,25 @@ use crate::{ RawDeviceId, RawDeviceIdIndex, // }, - devres::Devres, + driver, error::{ from_result, to_result, // }, prelude::*, - types::Opaque, + types::{ + ForLt, + ForeignOwnable, + Opaque, // + }, ThisModule, // }; use core::{ + any::TypeId, marker::PhantomData, mem::offset_of, + pin::Pin, ptr::{ addr_of_mut, NonNull, // @@ -36,18 +42,18 @@ pub struct Adapter<T: Driver>(T); // SAFETY: // - `bindings::auxiliary_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `T::Data` is the type of the driver's device private data. // - `struct auxiliary_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. -unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> { +unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> { type DriverType = bindings::auxiliary_driver; - type DriverData = T; + type DriverData<'bound> = T::Data<'bound>; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { +unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> { unsafe fn register( adrv: &Opaque<Self::DriverType>, name: &'static CStr, @@ -73,7 +79,7 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { } } -impl<T: Driver + 'static> Adapter<T> { +impl<T: Driver> Adapter<T> { extern "C" fn probe_callback( adev: *mut bindings::auxiliary_device, id: *const bindings::auxiliary_device_id, @@ -82,7 +88,7 @@ impl<T: Driver + 'static> Adapter<T> { // `struct auxiliary_device`. // // INVARIANT: `adev` is valid for the duration of `probe_callback()`. - let adev = unsafe { &*adev.cast::<Device<device::CoreInternal>>() }; + let adev = unsafe { &*adev.cast::<Device<device::CoreInternal<'_>>>() }; // SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id` // and does not add additional invariants, so it's safe to transmute. @@ -102,12 +108,12 @@ impl<T: Driver + 'static> Adapter<T> { // `struct auxiliary_device`. // // INVARIANT: `adev` is valid for the duration of `remove_callback()`. - let adev = unsafe { &*adev.cast::<Device<device::CoreInternal>>() }; + let adev = unsafe { &*adev.cast::<Device<device::CoreInternal<'_>>>() }; // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called - // and stored a `Pin<KBox<T>>`. - let data = unsafe { adev.as_ref().drvdata_borrow::<T>() }; + // and stored a `Pin<KBox<T::Data<'_>>>`. + let data = unsafe { adev.as_ref().drvdata_borrow::<T::Data<'_>>() }; T::unbind(adev, data); } @@ -197,13 +203,19 @@ pub trait Driver { /// type IdInfo: 'static = (); type IdInfo: 'static; + /// The type of the driver's bus device private data. + type Data<'bound>: Send + 'bound; + /// The table of device ids supported by the driver. const ID_TABLE: IdTable<Self::IdInfo>; /// Auxiliary driver probe. /// /// Called when an auxiliary device is matches a corresponding driver. - fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>; + fn probe<'bound>( + dev: &'bound Device<device::Core<'_>>, + id_info: &'bound Self::IdInfo, + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; /// Auxiliary driver unbind. /// @@ -214,8 +226,8 @@ pub trait Driver { /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O /// operations to gracefully tear down the device. /// - /// Otherwise, release operations for driver resources should be performed in `Self::drop`. - fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { + /// Otherwise, release operations for driver resources should be performed in `Drop`. + fn unbind<'bound>(dev: &'bound Device<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) { let _ = (dev, this); } } @@ -257,6 +269,49 @@ impl Device<device::Bound> { // SAFETY: A bound auxiliary device always has a bound parent device. unsafe { parent.as_bound() } } + + /// Returns a pinned reference to the registration data set by the registering (parent) driver. + /// + /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The returned + /// reference has its lifetime shortened from `'static` to `&self`'s borrow lifetime via + /// [`ForLt::cast_ref`]. + /// + /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling + /// [`Registration::new()`]. + /// + /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was + /// registered by a C driver. + pub fn registration_data<F: ForLt + 'static>(&self) -> Result<Pin<&F::Of<'_>>> { + // SAFETY: By the type invariant, `self.as_raw()` is a valid `struct auxiliary_device`. + let ptr = unsafe { (*self.as_raw()).registration_data_rust }; + if ptr.is_null() { + dev_warn!( + self.as_ref(), + "No registration data set; parent is not a Rust driver.\n" + ); + return Err(ENOENT); + } + + // SAFETY: `ptr` is non-null and was set via `into_foreign()` in `Registration::new()`; + // `RegistrationData` is `#[repr(C)]` with `type_id` at offset 0, so reading a `TypeId` + // at the start of the allocation is valid regardless of `F`. + let type_id = unsafe { ptr.cast::<TypeId>().read() }; + if type_id != TypeId::of::<F>() { + return Err(EINVAL); + } + + // SAFETY: The `TypeId` check above confirms that the stored type matches + // `F::Of<'static>`; `ptr` remains valid until `Registration::drop()` calls + // `from_foreign()`. + let wrapper = unsafe { Pin::<KBox<RegistrationData<F::Of<'static>>>>::borrow(ptr) }; + + // SAFETY: `data` is a structurally pinned field of `RegistrationData`. + let pinned: Pin<&F::Of<'_>> = unsafe { wrapper.map_unchecked(|w| &w.data) }; + + // SAFETY: The data was pinned when stored; `cast_ref` only shortens + // the lifetime, so the pinning guarantee is preserved. + Ok(unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) }) + } } impl Device { @@ -326,87 +381,173 @@ unsafe impl Send for Device {} // (i.e. `Device<Normal>) are thread safe. unsafe impl Sync for Device {} +// SAFETY: Same as `Device<Normal>` -- the underlying `struct auxiliary_device` is the same; +// `Bound` is a zero-sized type-state marker that does not affect thread safety. +unsafe impl Sync for Device<device::Bound> {} + +/// Wrapper that stores a [`TypeId`] alongside the registration data for runtime type checking. +#[repr(C)] +#[pin_data] +struct RegistrationData<T> { + type_id: TypeId, + #[pin] + data: T, +} + /// The registration of an auxiliary device. /// /// This type represents the registration of a [`struct auxiliary_device`]. When its parent device /// is unbound, the corresponding auxiliary device will be unregistered from the system. /// +/// The type parameter `F` is a [`ForLt`](trait@ForLt) encoding of the registration +/// data type. For non-lifetime-parameterized types, use [`ForLt!(T)`](macro@ForLt). +/// The data can be accessed by the auxiliary driver through [`Device::registration_data()`]. +/// /// # Invariants /// -/// `self.0` always holds a valid pointer to an initialized and registered -/// [`struct auxiliary_device`]. -pub struct Registration(NonNull<bindings::auxiliary_device>); +/// `self.adev` always holds a valid pointer to an initialized and registered +/// [`struct auxiliary_device`] whose `registration_data_rust` field points to a +/// valid `Pin<KBox<RegistrationData<F::Of<'static>>>>`. +pub struct Registration<'a, F: ForLt + 'static> { + adev: NonNull<bindings::auxiliary_device>, + _phantom: PhantomData<F::Of<'a>>, +} -impl Registration { - /// Create and register a new auxiliary device. - pub fn new<'a>( +impl<'a, F: ForLt> Registration<'a, F> +where + for<'b> F::Of<'b>: Send + Sync, +{ + /// Create and register a new auxiliary device with the given registration data. + /// + /// The `data` is owned by the registration and can be accessed through the auxiliary device + /// via [`Device::registration_data()`]. + /// + /// # Safety + /// + /// The caller must not `mem::forget()` the returned [`Registration`] or otherwise prevent its + /// [`Drop`] implementation from running, since the registration data may contain borrowed + /// references that become invalid after `'a` ends. + /// + /// If the registration data is `'static`, use the safe [`Registration::new()`] instead. + pub unsafe fn new_with_lt<E>( parent: &'a device::Device<device::Bound>, - name: &'a CStr, + name: &CStr, id: u32, - modname: &'a CStr, - ) -> impl PinInit<Devres<Self>, Error> + 'a { - pin_init::pin_init_scope(move || { - let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?; - let adev = boxed.get(); - - // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. - unsafe { - (*adev).dev.parent = parent.as_raw(); - (*adev).dev.release = Some(Device::release); - (*adev).name = name.as_char_ptr(); - (*adev).id = id; - } - - // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, - // which has not been initialized yet. - unsafe { bindings::auxiliary_device_init(adev) }; - - // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be - // freed by `Device::release` when the last reference to the `struct auxiliary_device` - // is dropped. - let _ = KBox::into_raw(boxed); - - // SAFETY: - // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which - // has been initialized, - // - `modname.as_char_ptr()` is a NULL terminated string. - let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; - if ret != 0 { - // SAFETY: `adev` is guaranteed to be a valid pointer to a - // `struct auxiliary_device`, which has been initialized. - unsafe { bindings::auxiliary_device_uninit(adev) }; - - return Err(Error::from_errno(ret)); - } - - // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is - // called, which happens in `Self::drop()`. - Ok(Devres::new( - parent, - // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated - // successfully. - Self(unsafe { NonNull::new_unchecked(adev) }), - )) + modname: &CStr, + data: impl PinInit<F::Of<'a>, E>, + ) -> Result<Self> + where + Error: From<E>, + { + let data = KBox::pin_init::<Error>( + try_pin_init!(RegistrationData { + type_id: TypeId::of::<F>(), + data <- data, + }), + GFP_KERNEL, + )?; + + // SAFETY: `'a` is invariant (via `Registration`'s `PhantomData`). Lifetimes do not + // affect layout, so RegistrationData<F::Of<'a>> and RegistrationData<F::Of<'static>> + // have identical representation. + let data: Pin<KBox<RegistrationData<F::Of<'static>>>> = + unsafe { core::mem::transmute(data) }; + + let boxed: KBox<Opaque<bindings::auxiliary_device>> = KBox::zeroed(GFP_KERNEL)?; + let adev = boxed.get(); + + // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. + unsafe { + (*adev).dev.parent = parent.as_raw(); + (*adev).dev.release = Some(Device::release); + (*adev).name = name.as_char_ptr(); + (*adev).id = id; + (*adev).registration_data_rust = data.into_foreign(); + } + + // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, + // which has not been initialized yet. + unsafe { bindings::auxiliary_device_init(adev) }; + + // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be + // freed by `Device::release` when the last reference to the `struct auxiliary_device` + // is dropped. + let _ = KBox::into_raw(boxed); + + // SAFETY: + // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which + // has been initialized, + // - `modname.as_char_ptr()` is a NULL terminated string. + let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; + if ret != 0 { + // SAFETY: `registration_data` was set above via `into_foreign()`. + drop(unsafe { + Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign( + (*adev).registration_data_rust, + ) + }); + + // SAFETY: `adev` is guaranteed to be a valid pointer to a + // `struct auxiliary_device`, which has been initialized. + unsafe { bindings::auxiliary_device_uninit(adev) }; + + return Err(Error::from_errno(ret)); + } + + // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is + // called, which happens in `Self::drop()`. + Ok(Self { + // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated + // successfully. + adev: unsafe { NonNull::new_unchecked(adev) }, + _phantom: PhantomData, }) } + + /// Create and register a new auxiliary device with `'static` registration data. + /// + /// Safe variant of [`Registration::new_with_lt()`] for registration data that does not contain + /// borrowed references. + pub fn new<E>( + parent: &'a device::Device<device::Bound>, + name: &CStr, + id: u32, + modname: &CStr, + data: impl PinInit<F::Of<'a>, E>, + ) -> Result<Self> + where + F::Of<'a>: 'static, + Error: From<E>, + { + // SAFETY: `F::Of<'a>: 'static` guarantees the data contains no borrowed references, + // so forgetting the `Registration` cannot cause use-after-free. + unsafe { Self::new_with_lt(parent, name, id, modname, data) } + } } -impl Drop for Registration { +impl<F: ForLt> Drop for Registration<'_, F> { fn drop(&mut self) { - // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered + // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` is a valid registered // `struct auxiliary_device`. - unsafe { bindings::auxiliary_device_delete(self.0.as_ptr()) }; + unsafe { bindings::auxiliary_device_delete(self.adev.as_ptr()) }; + + // SAFETY: `registration_data` was set in `new()` via `into_foreign()`. + drop(unsafe { + Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign( + (*self.adev.as_ptr()).registration_data_rust, + ) + }); // This drops the reference we acquired through `auxiliary_device_init()`. // - // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered + // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` is a valid registered // `struct auxiliary_device`. - unsafe { bindings::auxiliary_device_uninit(self.0.as_ptr()) }; + unsafe { bindings::auxiliary_device_uninit(self.adev.as_ptr()) }; } } // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread. -unsafe impl Send for Registration {} +unsafe impl<F: ForLt> Send for Registration<'_, F> where for<'a> F::Of<'a>: Send {} // SAFETY: `Registration` does not expose any methods or fields that need synchronization. -unsafe impl Sync for Registration {} +unsafe impl<F: ForLt> Sync for Registration<'_, F> where for<'a> F::Of<'a>: Send {} diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index a20bd5006f38..58ac04c650a1 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -888,12 +888,13 @@ pub trait Driver { /// /// impl platform::Driver for SampleDriver { /// type IdInfo = (); +/// type Data<'bound> = Self; /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; /// -/// fn probe( -/// pdev: &platform::Device<Core>, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit<Self, Error> { +/// fn probe<'bound>( +/// pdev: &'bound platform::Device<Core<'_>>, +/// _id_info: Option<&'bound Self::IdInfo>, +/// ) -> impl PinInit<Self, Error> + 'bound { /// cpufreq::Registration::<SampleDriver>::new_foreign_owned(pdev.as_ref())?; /// Ok(Self {}) /// } diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 6d5396a43ebe..645afc49a27d 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -15,16 +15,12 @@ use crate::{ }, // }; use core::{ - any::TypeId, marker::PhantomData, ptr, // }; pub mod property; -// Assert that we can `read()` / `write()` a `TypeId` instance from / into `struct driver_type`. -static_assert!(core::mem::size_of::<bindings::driver_type>() >= core::mem::size_of::<TypeId>()); - /// The core representation of a device in the kernel's driver model. /// /// This structure represents the Rust abstraction for a C `struct device`. A [`Device`] can either @@ -205,30 +201,13 @@ impl Device { } } -impl Device<CoreInternal> { - fn set_type_id<T: 'static>(&self) { - // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. - let private = unsafe { (*self.as_raw()).p }; - - // SAFETY: For a bound device (implied by the `CoreInternal` device context), `private` is - // guaranteed to be a valid pointer to a `struct device_private`. - let driver_type = unsafe { &raw mut (*private).driver_type }; - - // SAFETY: `driver_type` is valid for (unaligned) writes of a `TypeId`. - unsafe { - driver_type - .cast::<TypeId>() - .write_unaligned(TypeId::of::<T>()) - }; - } - +impl<'a> Device<CoreInternal<'a>> { /// Store a pointer to the bound driver's private data. - pub fn set_drvdata<T: 'static>(&self, data: impl PinInit<T, Error>) -> Result { + pub fn set_drvdata<T>(&self, data: impl PinInit<T, Error>) -> Result { let data = KBox::pin_init(data, GFP_KERNEL)?; // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. unsafe { bindings::dev_set_drvdata(self.as_raw(), data.into_foreign().cast()) }; - self.set_type_id::<T>(); Ok(()) } @@ -239,7 +218,7 @@ impl Device<CoreInternal> { /// /// - The type `T` must match the type of the `ForeignOwnable` previously stored by /// [`Device::set_drvdata`]. - pub(crate) unsafe fn drvdata_obtain<T: 'static>(&self) -> Option<Pin<KBox<T>>> { + pub(crate) unsafe fn drvdata_obtain<T>(&self) -> Option<Pin<KBox<T>>> { // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) }; @@ -265,7 +244,7 @@ impl Device<CoreInternal> { /// device is fully unbound. /// - The type `T` must match the type of the `ForeignOwnable` previously stored by /// [`Device::set_drvdata`]. - pub unsafe fn drvdata_borrow<T: 'static>(&self) -> Pin<&T> { + pub unsafe fn drvdata_borrow<T>(&self) -> Pin<&T> { // SAFETY: `drvdata_unchecked()` has the exact same safety requirements as the ones // required by this method. unsafe { self.drvdata_unchecked() } @@ -281,7 +260,7 @@ impl Device<Bound> { /// the device is fully unbound. /// - The type `T` must match the type of the `ForeignOwnable` previously stored by /// [`Device::set_drvdata`]. - unsafe fn drvdata_unchecked<T: 'static>(&self) -> Pin<&T> { + unsafe fn drvdata_unchecked<T>(&self) -> Pin<&T> { // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) }; @@ -292,45 +271,6 @@ impl Device<Bound> { // in `into_foreign()`. unsafe { Pin::<KBox<T>>::borrow(ptr.cast()) } } - - fn match_type_id<T: 'static>(&self) -> Result { - // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. - let private = unsafe { (*self.as_raw()).p }; - - // SAFETY: For a bound device, `private` is guaranteed to be a valid pointer to a - // `struct device_private`. - let driver_type = unsafe { &raw mut (*private).driver_type }; - - // SAFETY: - // - `driver_type` is valid for (unaligned) reads of a `TypeId`. - // - A bound device guarantees that `driver_type` contains a valid `TypeId` value. - let type_id = unsafe { driver_type.cast::<TypeId>().read_unaligned() }; - - if type_id != TypeId::of::<T>() { - return Err(EINVAL); - } - - Ok(()) - } - - /// Access a driver's private data. - /// - /// Returns a pinned reference to the driver's private data or [`EINVAL`] if it doesn't match - /// the asserted type `T`. - pub fn drvdata<T: 'static>(&self) -> Result<Pin<&T>> { - // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. - if unsafe { bindings::dev_get_drvdata(self.as_raw()) }.is_null() { - return Err(ENOENT); - } - - self.match_type_id::<T>()?; - - // SAFETY: - // - The above check of `dev_get_drvdata()` guarantees that we are called after - // `set_drvdata()`. - // - We've just checked that the type of the driver's private data is in fact `T`. - Ok(unsafe { self.drvdata_unchecked() }) - } } impl<Ctx: DeviceContext> Device<Ctx> { @@ -527,6 +467,10 @@ unsafe impl Send for Device {} // synchronization in `struct device`. unsafe impl Sync for Device {} +// SAFETY: Same as `Device<Normal>` -- the underlying `struct device` is the same; `Bound` is a +// zero-sized type-state marker that does not affect thread safety. +unsafe impl Sync for Device<Bound> {} + /// Marker trait for the context or scope of a bus specific device. /// /// [`DeviceContext`] is a marker trait for types representing the context of a bus specific @@ -567,7 +511,7 @@ pub struct Normal; /// callback it appears in. It is intended to be used for synchronization purposes. Bus device /// implementations can implement methods for [`Device<Core>`], such that they can only be called /// from bus callbacks. -pub struct Core; +pub struct Core<'a>(PhantomData<&'a ()>); /// Semantically the same as [`Core`], but reserved for internal usage of the corresponding bus /// abstraction. @@ -578,7 +522,7 @@ pub struct Core; /// /// This context mainly exists to share generic [`Device`] infrastructure that should only be called /// from bus callbacks with bus abstractions, but without making them accessible for drivers. -pub struct CoreInternal; +pub struct CoreInternal<'a>(PhantomData<&'a ()>); /// The [`Bound`] context is the [`DeviceContext`] of a bus specific device when it is guaranteed to /// be bound to a driver. @@ -602,14 +546,14 @@ mod private { pub trait Sealed {} impl Sealed for super::Bound {} - impl Sealed for super::Core {} - impl Sealed for super::CoreInternal {} + impl<'a> Sealed for super::Core<'a> {} + impl<'a> Sealed for super::CoreInternal<'a> {} impl Sealed for super::Normal {} } impl DeviceContext for Bound {} -impl DeviceContext for Core {} -impl DeviceContext for CoreInternal {} +impl<'a> DeviceContext for Core<'a> {} +impl<'a> DeviceContext for CoreInternal<'a> {} impl DeviceContext for Normal {} impl<Ctx: DeviceContext> AsRef<Device<Ctx>> for Device<Ctx> { @@ -659,6 +603,22 @@ pub unsafe trait AsBusDevice<Ctx: DeviceContext>: AsRef<Device<Ctx>> { #[doc(hidden)] #[macro_export] macro_rules! __impl_device_context_deref { + (unsafe { $device:ident, <$lt:lifetime> $src:ty => $dst:ty }) => { + impl<$lt> ::core::ops::Deref for $device<$src> { + type Target = $device<$dst>; + + fn deref(&self) -> &Self::Target { + let ptr: *const Self = self; + + // CAST: `$device<$src>` and `$device<$dst>` transparently wrap the same type by the + // safety requirement of the macro. + let ptr = ptr.cast::<Self::Target>(); + + // SAFETY: `ptr` was derived from `&self`. + unsafe { &*ptr } + } + } + }; (unsafe { $device:ident, $src:ty => $dst:ty }) => { impl ::core::ops::Deref for $device<$src> { type Target = $device<$dst>; @@ -691,14 +651,14 @@ macro_rules! impl_device_context_deref { // `__impl_device_context_deref!`. ::kernel::__impl_device_context_deref!(unsafe { $device, - $crate::device::CoreInternal => $crate::device::Core + <'a> $crate::device::CoreInternal<'a> => $crate::device::Core<'a> }); // SAFETY: This macro has the exact same safety requirement as // `__impl_device_context_deref!`. ::kernel::__impl_device_context_deref!(unsafe { $device, - $crate::device::Core => $crate::device::Bound + <'a> $crate::device::Core<'a> => $crate::device::Bound }); // SAFETY: This macro has the exact same safety requirement as @@ -713,6 +673,13 @@ macro_rules! impl_device_context_deref { #[doc(hidden)] #[macro_export] macro_rules! __impl_device_context_into_aref { + (<$lt:lifetime> $src:ty, $device:tt) => { + impl<$lt> ::core::convert::From<&$device<$src>> for $crate::sync::aref::ARef<$device> { + fn from(dev: &$device<$src>) -> Self { + (&**dev).into() + } + } + }; ($src:ty, $device:tt) => { impl ::core::convert::From<&$device<$src>> for $crate::sync::aref::ARef<$device> { fn from(dev: &$device<$src>) -> Self { @@ -727,8 +694,12 @@ macro_rules! __impl_device_context_into_aref { #[macro_export] macro_rules! impl_device_context_into_aref { ($device:tt) => { - ::kernel::__impl_device_context_into_aref!($crate::device::CoreInternal, $device); - ::kernel::__impl_device_context_into_aref!($crate::device::Core, $device); + ::kernel::__impl_device_context_into_aref!( + <'a> $crate::device::CoreInternal<'a>, $device + ); + ::kernel::__impl_device_context_into_aref!( + <'a> $crate::device::Core<'a>, $device + ); ::kernel::__impl_device_context_into_aref!($crate::device::Bound, $device); }; } diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 9e5f93aed20c..11ce500e9b76 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -122,7 +122,7 @@ struct Inner<T> { /// # Ok(()) /// # } /// ``` -pub struct Devres<T: Send> { +pub struct Devres<T: Send + 'static> { dev: ARef<Device>, inner: Arc<Inner<T>>, } @@ -184,7 +184,7 @@ mod base { } } -impl<T: Send> Devres<T> { +impl<T: Send + 'static> Devres<T> { /// Creates a new [`Devres`] instance of the given `data`. /// /// The `data` encapsulated within the returned `Devres` instance' `data` will be @@ -304,7 +304,7 @@ impl<T: Send> Devres<T> { /// pci, // /// }; /// - /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result { + /// fn from_core(dev: &pci::Device<Core<'_>>, devres: Devres<pci::Bar<'_, 0x4>>) -> Result { /// let bar = devres.access(dev.as_ref())?; /// /// let _ = bar.read32(0x0); @@ -349,7 +349,7 @@ unsafe impl<T: Send> Send for Devres<T> {} // SAFETY: `Devres` can be shared with any task, if `T: Sync`. unsafe impl<T: Send + Sync> Sync for Devres<T> {} -impl<T: Send> Drop for Devres<T> { +impl<T: Send + 'static> Drop for Devres<T> { fn drop(&mut self) { // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data // anymore, hence it is safe not to wait for the grace period to finish. diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 642ccff465c8..200def84fb69 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -47,7 +47,7 @@ pub type DmaAddress = bindings::dma_addr_t; /// where the underlying bus is DMA capable, such as: #[cfg_attr(CONFIG_PCI, doc = "* [`pci::Device`](kernel::pci::Device)")] /// * [`platform::Device`](::kernel::platform::Device) -pub trait Device: AsRef<device::Device<Core>> { +pub trait Device<'a>: AsRef<device::Device<Core<'a>>> { /// Set up the device's DMA streaming addressing capabilities. /// /// This method is usually called once from `probe()` as soon as the device capabilities are diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index 36de8098754d..bf5ba0d27553 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -13,10 +13,13 @@ //! The main driver interface is defined by a bus specific driver trait. For instance: //! //! ```ignore -//! pub trait Driver: Send { +//! pub trait Driver { //! /// The type holding information about each device ID supported by the driver. //! type IdInfo: 'static; //! +//! /// The type of the driver's bus device private data. +//! type Data<'bound>: Send + 'bound; +//! //! /// The table of OF device ids supported by the driver. //! const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; //! @@ -24,10 +27,16 @@ //! const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None; //! //! /// Driver probe. -//! fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>; +//! fn probe<'bound>( +//! dev: &'bound Device<device::Core<'_>>, +//! id_info: &'bound Self::IdInfo, +//! ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; //! //! /// Driver unbind (optional). -//! fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { +//! fn unbind<'bound>( +//! dev: &'bound Device<device::Core<'_>>, +//! this: Pin<&Self::Data<'bound>>, +//! ) { //! let _ = (dev, this); //! } //! } @@ -42,8 +51,9 @@ )] #")] //! -//! The `probe()` callback should return a `impl PinInit<Self, Error>`, i.e. the driver's private -//! data. The bus abstraction should store the pointer in the corresponding bus device. The generic +//! The `probe()` callback should return a +//! `impl PinInit<Self::Data<'bound>, Error>`, i.e. the driver's private data. The bus +//! abstraction should store the pointer in the corresponding bus device. The generic //! [`Device`] infrastructure provides common helpers for this purpose on its //! [`Device<CoreInternal>`] implementation. //! @@ -118,8 +128,8 @@ pub unsafe trait DriverLayout { /// The specific driver type embedding a `struct device_driver`. type DriverType: Default; - /// The type of the driver's device private data. - type DriverData; + /// The type of the driver's bus device private data. + type DriverData<'bound>; /// Byte offset of the embedded `struct device_driver` within `DriverType`. /// @@ -181,20 +191,20 @@ unsafe impl<T: RegistrationOps> Sync for Registration<T> {} // any thread, so `Registration` is `Send`. unsafe impl<T: RegistrationOps> Send for Registration<T> {} -impl<T: RegistrationOps + 'static> Registration<T> { +impl<T: RegistrationOps> Registration<T> { extern "C" fn post_unbind_callback(dev: *mut bindings::device) { // SAFETY: The driver core only ever calls the post unbind callback with a valid pointer to // a `struct device`. // // INVARIANT: `dev` is valid for the duration of the `post_unbind_callback()`. - let dev = unsafe { &*dev.cast::<device::Device<device::CoreInternal>>() }; + let dev = unsafe { &*dev.cast::<device::Device<device::CoreInternal<'_>>>() }; - // `remove()` and all devres callbacks have been completed at this point, hence drop the - // driver's device private data. + // `remove()` has been completed at this point; devres resources are still valid and will + // be released after the driver's bus device private data is dropped. // // SAFETY: By the safety requirements of the `Driver` trait, `T::DriverData` is the - // driver's device private data type. - drop(unsafe { dev.drvdata_obtain::<T::DriverData>() }); + // driver's bus device private data type. + drop(unsafe { dev.drvdata_obtain::<T::DriverData<'_>>() }); } /// Attach generic `struct device_driver` callbacks. @@ -215,7 +225,10 @@ impl<T: RegistrationOps + 'static> Registration<T> { } /// Creates a new instance of the registration object. - pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { + pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> + where + T: 'static, + { try_pin_init!(Self { reg <- Opaque::try_ffi_init(|ptr: *mut T::DriverType| { // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write. @@ -278,6 +291,26 @@ macro_rules! module_driver { } } +// Calling the FFI function directly from the `Adapter` impl may result in it being called +// directly from driver modules. This happens since the Rust compiler will use monomorphisation, so +// it might happen that functions are instantiated within the calling driver module. For now, work +// around this with `#[inline(never)]` helpers. +// +// TODO: Remove once a more generic solution has been implemented. For instance, we may be able to +// leverage `bindgen` to take care of this depending on whether a symbol is (already) exported. +#[inline(never)] +#[allow(clippy::missing_safety_doc)] +#[allow(dead_code)] +#[must_use] +unsafe fn acpi_of_match_device( + adev: *const bindings::acpi_device, + of_match_table: *const bindings::of_device_id, + of_id: *mut *const bindings::of_device_id, +) -> bool { + // SAFETY: Safety requirements are the same as `bindings::acpi_of_match_device`. + unsafe { bindings::acpi_of_match_device(adev, of_match_table, of_id) } +} + /// The bus independent adapter to match a drivers and a devices. /// /// This trait should be implemented by the bus specific adapter, which represents the connection @@ -329,35 +362,63 @@ pub trait Adapter { /// /// If this returns `None`, it means there is no match with an entry in the [`of::IdTable`]. fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { - #[cfg(not(CONFIG_OF))] + let table = Self::of_id_table()?; + + #[cfg(not(any(CONFIG_OF, CONFIG_ACPI)))] { - let _ = dev; - None + let _ = (dev, table); } #[cfg(CONFIG_OF)] { - let table = Self::of_id_table()?; - // SAFETY: // - `table` has static lifetime, hence it's valid for read, // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`. let raw_id = unsafe { bindings::of_match_device(table.as_ptr(), dev.as_raw()) }; - if raw_id.is_null() { - None - } else { + if !raw_id.is_null() { // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id` // and does not add additional invariants, so it's safe to transmute. let id = unsafe { &*raw_id.cast::<of::DeviceId>() }; - Some( - table.info(<of::DeviceId as crate::device_id::RawDeviceIdIndex>::index( - id, - )), - ) + return Some(table.info( + <of::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id), + )); + } + } + + #[cfg(CONFIG_ACPI)] + { + use core::ptr; + use device::property::FwNode; + + let mut raw_id = ptr::null(); + + let fwnode = dev.fwnode().map_or(ptr::null_mut(), FwNode::as_raw); + + // SAFETY: `fwnode` is a pointer to a valid `fwnode_handle`. A null pointer will be + // passed through the function. + let adev = unsafe { bindings::to_acpi_device_node(fwnode) }; + + // SAFETY: + // - `adev` is a valid pointer to `acpi_device` or is null. It is guaranteed to be + // valid as long as `dev` is alive. + // - `table` has static lifetime, hence it's valid for read. + if unsafe { acpi_of_match_device(adev, table.as_ptr(), &raw mut raw_id) } { + // SAFETY: + // - the function returns true, therefore `raw_id` has been set to a pointer to a + // valid `of_device_id`. + // - `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id` + // and does not add additional invariants, so it's safe to transmute. + let id = unsafe { &*raw_id.cast::<of::DeviceId>() }; + + return Some(table.info( + <of::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id), + )); } } + + None } /// Returns the driver's private data from the matching entry of any of the ID tables, if any. diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index c084a45b1916..624b971ca8b0 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -93,18 +93,18 @@ pub struct Adapter<T: Driver>(T); // SAFETY: // - `bindings::i2c_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `T::Data` is the type of the driver's device private data. // - `struct i2c_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. -unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> { +unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> { type DriverType = bindings::i2c_driver; - type DriverData = T; + type DriverData<'bound> = T::Data<'bound>; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { +unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> { unsafe fn register( idrv: &Opaque<Self::DriverType>, name: &'static CStr, @@ -151,13 +151,13 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { } } -impl<T: Driver + 'static> Adapter<T> { +impl<T: Driver> Adapter<T> { extern "C" fn probe_callback(idev: *mut bindings::i2c_client) -> kernel::ffi::c_int { // SAFETY: The I2C bus only ever calls the probe callback with a valid pointer to a // `struct i2c_client`. // // INVARIANT: `idev` is valid for the duration of `probe_callback()`. - let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() }; + let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal<'_>>>() }; let info = Self::i2c_id_info(idev).or_else(|| <Self as driver::Adapter>::id_info(idev.as_ref())); @@ -172,24 +172,24 @@ impl<T: Driver + 'static> Adapter<T> { extern "C" fn remove_callback(idev: *mut bindings::i2c_client) { // SAFETY: `idev` is a valid pointer to a `struct i2c_client`. - let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() }; + let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal<'_>>>() }; // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `I2cClient::set_drvdata()` has been called - // and stored a `Pin<KBox<T>>`. - let data = unsafe { idev.as_ref().drvdata_borrow::<T>() }; + // and stored a `Pin<KBox<T::Data<'_>>>`. + let data = unsafe { idev.as_ref().drvdata_borrow::<T::Data<'_>>() }; T::unbind(idev, data); } extern "C" fn shutdown_callback(idev: *mut bindings::i2c_client) { // SAFETY: `shutdown_callback` is only ever called for a valid `idev` - let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() }; + let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal<'_>>>() }; // SAFETY: `shutdown_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called - // and stored a `Pin<KBox<T>>`. - let data = unsafe { idev.as_ref().drvdata_borrow::<T>() }; + // and stored a `Pin<KBox<T::Data<'_>>>`. + let data = unsafe { idev.as_ref().drvdata_borrow::<T::Data<'_>>() }; T::shutdown(idev, data); } @@ -222,7 +222,7 @@ impl<T: Driver + 'static> Adapter<T> { } } -impl<T: Driver + 'static> driver::Adapter for Adapter<T> { +impl<T: Driver> driver::Adapter for Adapter<T> { type IdInfo = T::IdInfo; fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> { @@ -294,22 +294,26 @@ macro_rules! module_i2c_driver { /// /// impl i2c::Driver for MyDriver { /// type IdInfo = (); +/// type Data<'bound> = Self; /// const I2C_ID_TABLE: Option<i2c::IdTable<Self::IdInfo>> = Some(&I2C_TABLE); /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); /// const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); /// -/// fn probe( -/// _idev: &i2c::I2cClient<Core>, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit<Self, Error> { +/// fn probe<'bound>( +/// _idev: &'bound i2c::I2cClient<Core<'_>>, +/// _id_info: Option<&'bound Self::IdInfo>, +/// ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { /// Err(ENODEV) /// } /// -/// fn shutdown(_idev: &i2c::I2cClient<Core>, this: Pin<&Self>) { +/// fn shutdown<'bound>( +/// _idev: &'bound i2c::I2cClient<Core<'_>>, +/// this: Pin<&Self::Data<'bound>>, +/// ) { /// } /// } ///``` -pub trait Driver: Send { +pub trait Driver { /// The type holding information about each device id supported by the driver. // TODO: Use `associated_type_defaults` once stabilized: // @@ -318,6 +322,9 @@ pub trait Driver: Send { // ``` type IdInfo: 'static; + /// The type of the driver's bus device private data. + type Data<'bound>: Send + 'bound; + /// The table of device ids supported by the driver. const I2C_ID_TABLE: Option<IdTable<Self::IdInfo>> = None; @@ -331,10 +338,10 @@ pub trait Driver: Send { /// /// Called when a new i2c client is added or discovered. /// Implementers should attempt to initialize the client here. - fn probe( - dev: &I2cClient<device::Core>, - id_info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error>; + fn probe<'bound>( + dev: &'bound I2cClient<device::Core<'_>>, + id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; /// I2C driver shutdown. /// @@ -346,8 +353,8 @@ pub trait Driver: Send { /// /// This callback is distinct from final resource cleanup, as the driver instance remains valid /// after it returns. Any deallocation or teardown of driver-owned resources should instead be - /// handled in `Self::drop`. - fn shutdown(dev: &I2cClient<device::Core>, this: Pin<&Self>) { + /// handled in `Drop`. + fn shutdown<'bound>(dev: &'bound I2cClient<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) { let _ = (dev, this); } @@ -360,8 +367,8 @@ pub trait Driver: Send { /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O /// operations to gracefully tear down the device. /// - /// Otherwise, release operations for driver resources should be performed in `Self::drop`. - fn unbind(dev: &I2cClient<device::Core>, this: Pin<&Self>) { + /// Otherwise, release operations for driver resources should be performed in `Drop`. + fn unbind<'bound>(dev: &'bound I2cClient<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) { let _ = (dev, this); } } diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index 7dc78d547f7a..fc2a3e24f8d5 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -62,33 +62,31 @@ impl<'a> IoRequest<'a> { /// /// impl platform::Driver for SampleDriver { /// # type IdInfo = (); + /// # type Data<'bound> = Self; /// - /// fn probe( - /// pdev: &platform::Device<Core>, - /// info: Option<&Self::IdInfo>, - /// ) -> impl PinInit<Self, Error> { + /// fn probe<'bound>( + /// pdev: &'bound platform::Device<Core<'_>>, + /// info: Option<&'bound Self::IdInfo>, + /// ) -> impl PinInit<Self, Error> + 'bound { /// let offset = 0; // Some offset. /// /// // If the size is known at compile time, use [`Self::iomap_sized`]. /// // /// // No runtime checks will apply when reading and writing. /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; - /// let iomem = request.iomap_sized::<42>(); - /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?; - /// - /// let io = iomem.access(pdev.as_ref())?; + /// let iomem = request.iomap_sized::<42>()?; /// /// // Read and write a 32-bit value at `offset`. - /// let data = io.read32(offset); + /// let data = iomem.read32(offset); /// - /// io.write32(data, offset); + /// iomem.write32(data, offset); /// /// # Ok(SampleDriver) /// } /// } /// ``` - pub fn iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a { - IoMem::new(self) + pub fn iomap_sized<const SIZE: usize>(self) -> Result<IoMem<'a, SIZE>> { + IoMem::ioremap(self.device, self.resource) } /// Same as [`Self::iomap_sized`] but with exclusive access to the @@ -97,10 +95,8 @@ impl<'a> IoRequest<'a> { /// This uses the [`ioremap()`] C API. /// /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device - pub fn iomap_exclusive_sized<const SIZE: usize>( - self, - ) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a { - ExclusiveIoMem::new(self) + pub fn iomap_exclusive_sized<const SIZE: usize>(self) -> Result<ExclusiveIoMem<'a, SIZE>> { + ExclusiveIoMem::ioremap(self.device, self.resource) } /// Maps an [`IoRequest`] where the size is not known at compile time, @@ -126,11 +122,12 @@ impl<'a> IoRequest<'a> { /// /// impl platform::Driver for SampleDriver { /// # type IdInfo = (); + /// # type Data<'bound> = Self; /// - /// fn probe( - /// pdev: &platform::Device<Core>, - /// info: Option<&Self::IdInfo>, - /// ) -> impl PinInit<Self, Error> { + /// fn probe<'bound>( + /// pdev: &'bound platform::Device<Core<'_>>, + /// info: Option<&'bound Self::IdInfo>, + /// ) -> impl PinInit<Self, Error> + 'bound { /// let offset = 0; // Some offset. /// /// // Unlike [`Self::iomap_sized`], here the size of the memory region @@ -138,27 +135,24 @@ impl<'a> IoRequest<'a> { /// // family of functions should be used, leading to runtime checks on every /// // access. /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; - /// let iomem = request.iomap(); - /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?; - /// - /// let io = iomem.access(pdev.as_ref())?; + /// let iomem = request.iomap()?; /// - /// let data = io.try_read32(offset)?; + /// let data = iomem.try_read32(offset)?; /// - /// io.try_write32(data, offset)?; + /// iomem.try_write32(data, offset)?; /// /// # Ok(SampleDriver) /// } /// } /// ``` - pub fn iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a { - Self::iomap_sized::<0>(self) + pub fn iomap(self) -> Result<IoMem<'a>> { + self.iomap_sized::<0>() } /// Same as [`Self::iomap`] but with exclusive access to the underlying /// region. - pub fn iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a { - Self::iomap_exclusive_sized::<0>(self) + pub fn iomap_exclusive(self) -> Result<ExclusiveIoMem<'a, 0>> { + self.iomap_exclusive_sized::<0>() } } @@ -167,9 +161,9 @@ impl<'a> IoRequest<'a> { /// # Invariants /// /// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`]. -pub struct ExclusiveIoMem<const SIZE: usize> { +pub struct ExclusiveIoMem<'a, const SIZE: usize> { /// The underlying `IoMem` instance. - iomem: IoMem<SIZE>, + iomem: IoMem<'a, SIZE>, /// The region abstraction. This represents exclusive access to the /// range represented by the underlying `iomem`. @@ -178,9 +172,9 @@ pub struct ExclusiveIoMem<const SIZE: usize> { _region: Region, } -impl<const SIZE: usize> ExclusiveIoMem<SIZE> { +impl<'a, const SIZE: usize> ExclusiveIoMem<'a, SIZE> { /// Creates a new `ExclusiveIoMem` instance. - fn ioremap(resource: &Resource) -> Result<Self> { + fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> { let start = resource.start(); let size = resource.size(); let name = resource.name().unwrap_or_default(); @@ -194,26 +188,29 @@ impl<const SIZE: usize> ExclusiveIoMem<SIZE> { ) .ok_or(EBUSY)?; - let iomem = IoMem::ioremap(resource)?; + let iomem = IoMem::ioremap(dev, resource)?; - let iomem = ExclusiveIoMem { + Ok(ExclusiveIoMem { iomem, _region: region, - }; - - Ok(iomem) + }) } - /// Creates a new `ExclusiveIoMem` instance from a previously acquired [`IoRequest`]. - pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a { - let dev = io_request.device; - let res = io_request.resource; - - Devres::new(dev, Self::ioremap(res)) + /// Consume the `ExclusiveIoMem` and register it as a device-managed resource. + /// + /// The returned `Devres<ExclusiveIoMem<'static, SIZE>>` can outlive the original lifetime + /// `'a`. Access to the I/O memory is revoked when the device is unbound. + pub fn into_devres(self) -> Result<Devres<ExclusiveIoMem<'static, SIZE>>> { + // SAFETY: Casting to `'static` is sound because `Devres` guarantees the + // `ExclusiveIoMem` does not actually outlive the device -- access is revoked and the + // resource is released when the device is unbound. + let iomem: ExclusiveIoMem<'static, SIZE> = unsafe { core::mem::transmute(self) }; + let dev = iomem.iomem.dev; + Devres::new(dev, iomem) } } -impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { +impl<const SIZE: usize> Deref for ExclusiveIoMem<'_, SIZE> { type Target = Mmio<SIZE>; fn deref(&self) -> &Self::Target { @@ -230,12 +227,13 @@ impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { /// /// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid pointer to the /// start of the I/O memory mapped region. -pub struct IoMem<const SIZE: usize = 0> { +pub struct IoMem<'a, const SIZE: usize = 0> { + dev: &'a Device<Bound>, io: MmioRaw<SIZE>, } -impl<const SIZE: usize> IoMem<SIZE> { - fn ioremap(resource: &Resource) -> Result<Self> { +impl<'a, const SIZE: usize> IoMem<'a, SIZE> { + fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> { // Note: Some ioremap() implementations use types that depend on the CPU // word width rather than the bus address width. // @@ -267,28 +265,33 @@ impl<const SIZE: usize> IoMem<SIZE> { } let io = MmioRaw::new(addr as usize, size)?; - let io = IoMem { io }; - Ok(io) + Ok(IoMem { dev, io }) } - /// Creates a new `IoMem` instance from a previously acquired [`IoRequest`]. - pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a { - let dev = io_request.device; - let res = io_request.resource; - - Devres::new(dev, Self::ioremap(res)) + /// Consume the `IoMem` and register it as a device-managed resource. + /// + /// The returned `Devres<IoMem<'static, SIZE>>` can outlive the original + /// lifetime `'a`. Access to the I/O memory is revoked when the device + /// is unbound. + pub fn into_devres(self) -> Result<Devres<IoMem<'static, SIZE>>> { + // SAFETY: Casting to `'static` is sound because `Devres` guarantees the `IoMem` does not + // actually outlive the device -- access is revoked and the resource is released when the + // device is unbound. + let iomem: IoMem<'static, SIZE> = unsafe { core::mem::transmute(self) }; + let dev = iomem.dev; + Devres::new(dev, iomem) } } -impl<const SIZE: usize> Drop for IoMem<SIZE> { +impl<const SIZE: usize> Drop for IoMem<'_, SIZE> { fn drop(&mut self) { // SAFETY: Safe as by the invariant of `Io`. unsafe { bindings::iounmap(self.io.addr() as *mut c_void) } } } -impl<const SIZE: usize> Deref for IoMem<SIZE> { +impl<const SIZE: usize> Deref for IoMem<'_, SIZE> { type Target = Mmio<SIZE>; fn deref(&self) -> &Self::Target { diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index af74ddff6114..5071cae6543f 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -59,18 +59,18 @@ pub struct Adapter<T: Driver>(T); // SAFETY: // - `bindings::pci_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `T::Data` is the type of the driver's device private data. // - `struct pci_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. -unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> { +unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> { type DriverType = bindings::pci_driver; - type DriverData = T; + type DriverData<'bound> = T::Data<'bound>; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { +unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> { unsafe fn register( pdrv: &Opaque<Self::DriverType>, name: &'static CStr, @@ -96,7 +96,7 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { } } -impl<T: Driver + 'static> Adapter<T> { +impl<T: Driver> Adapter<T> { extern "C" fn probe_callback( pdev: *mut bindings::pci_dev, id: *const bindings::pci_device_id, @@ -105,7 +105,7 @@ impl<T: Driver + 'static> Adapter<T> { // `struct pci_dev`. // // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. - let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; + let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() }; // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct pci_device_id` and // does not add additional invariants, so it's safe to transmute. @@ -125,12 +125,12 @@ impl<T: Driver + 'static> Adapter<T> { // `struct pci_dev`. // // INVARIANT: `pdev` is valid for the duration of `remove_callback()`. - let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; + let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() }; // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called - // and stored a `Pin<KBox<T>>`. - let data = unsafe { pdev.as_ref().drvdata_borrow::<T>() }; + // and stored a `Pin<KBox<T::Data<'_>>>`. + let data = unsafe { pdev.as_ref().drvdata_borrow::<T::Data<'_>>() }; T::unbind(pdev, data); } @@ -279,19 +279,20 @@ macro_rules! pci_device_table { /// /// impl pci::Driver for MyDriver { /// type IdInfo = (); +/// type Data<'bound> = Self; /// const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; /// -/// fn probe( -/// _pdev: &pci::Device<Core>, -/// _id_info: &Self::IdInfo, -/// ) -> impl PinInit<Self, Error> { +/// fn probe<'bound>( +/// _pdev: &'bound pci::Device<Core<'_>>, +/// _id_info: &'bound Self::IdInfo, +/// ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { /// Err(ENODEV) /// } /// } ///``` /// Drivers must implement this trait in order to get a PCI driver registered. Please refer to the /// `Adapter` documentation for an example. -pub trait Driver: Send { +pub trait Driver { /// The type holding information about each device id supported by the driver. // TODO: Use `associated_type_defaults` once stabilized: // @@ -300,6 +301,9 @@ pub trait Driver: Send { // ``` type IdInfo: 'static; + /// The type of the driver's bus device private data. + type Data<'bound>: Send + 'bound; + /// The table of device ids supported by the driver. const ID_TABLE: IdTable<Self::IdInfo>; @@ -307,7 +311,10 @@ pub trait Driver: Send { /// /// Called when a new pci device is added or discovered. Implementers should /// attempt to initialize the device here. - fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>; + fn probe<'bound>( + dev: &'bound Device<device::Core<'_>>, + id_info: &'bound Self::IdInfo, + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; /// PCI driver unbind. /// @@ -318,8 +325,8 @@ pub trait Driver: Send { /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O /// operations to gracefully tear down the device. /// - /// Otherwise, release operations for driver resources should be performed in `Self::drop`. - fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { + /// Otherwise, release operations for driver resources should be performed in `Drop`. + fn unbind<'bound>(dev: &'bound Device<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) { let _ = (dev, this); } } @@ -354,7 +361,7 @@ impl Device { /// /// ``` /// # use kernel::{device::Core, pci::{self, Vendor}, prelude::*}; - /// fn log_device_info(pdev: &pci::Device<Core>) -> Result { + /// fn log_device_info(pdev: &pci::Device<Core<'_>>) -> Result { /// // Get an instance of `Vendor`. /// let vendor = pdev.vendor_id(); /// dev_info!( @@ -445,7 +452,7 @@ impl Device { } } -impl Device<device::Core> { +impl<'a> Device<device::Core<'a>> { /// Enable memory resources for this device. pub fn enable_device_mem(&self) -> Result { // SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`. @@ -471,7 +478,7 @@ unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> kernel::impl_device_context_deref!(unsafe { Device }); kernel::impl_device_context_into_aref!(Device); -impl crate::dma::Device for Device<device::Core> {} +impl<'a> crate::dma::Device<'a> for Device<device::Core<'a>> {} // SAFETY: Instances of `Device` are always reference-counted. unsafe impl crate::sync::aref::AlwaysRefCounted for Device { @@ -523,3 +530,7 @@ unsafe impl Send for Device {} // SAFETY: `Device` can be shared among threads because all methods of `Device` // (i.e. `Device<Normal>) are thread safe. unsafe impl Sync for Device {} + +// SAFETY: Same as `Device<Normal>` -- the underlying `struct pci_dev` is the same; +// `Bound` is a zero-sized type-state marker that does not affect thread safety. +unsafe impl Sync for Device<device::Bound> {} diff --git a/rust/kernel/pci/id.rs b/rust/kernel/pci/id.rs index 50005d176561..dbaf301666e7 100644 --- a/rust/kernel/pci/id.rs +++ b/rust/kernel/pci/id.rs @@ -19,7 +19,7 @@ use crate::{ /// /// ``` /// # use kernel::{device::Core, pci::{self, Class}, prelude::*}; -/// fn probe_device(pdev: &pci::Device<Core>) -> Result { +/// fn probe_device(pdev: &pci::Device<Core<'_>>) -> Result { /// let pci_class = pdev.pci_class(); /// dev_info!( /// pdev, diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index ae78676c927f..0461e01aaa20 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -14,8 +14,7 @@ use crate::{ Mmio, MmioRaw, // }, - prelude::*, - sync::aref::ARef, // + prelude::*, // }; use core::{ marker::PhantomData, @@ -146,14 +145,18 @@ impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'a, S> { /// /// `Bar` always holds an `IoRaw` instance that holds a valid pointer to the start of the I/O /// memory mapped PCI BAR and its size. -pub struct Bar<const SIZE: usize = 0> { - pdev: ARef<Device>, +pub struct Bar<'a, const SIZE: usize = 0> { + pdev: &'a Device<device::Bound>, io: MmioRaw<SIZE>, num: i32, } -impl<const SIZE: usize> Bar<SIZE> { - pub(super) fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> { +impl<'a, const SIZE: usize> Bar<'a, SIZE> { + pub(super) fn new( + pdev: &'a Device<device::Bound>, + num: u32, + name: &'static CStr, + ) -> Result<Self> { let len = pdev.resource_len(num)?; if len == 0 { return Err(ENOMEM); @@ -196,11 +199,7 @@ impl<const SIZE: usize> Bar<SIZE> { } }; - Ok(Bar { - pdev: pdev.into(), - io, - num, - }) + Ok(Bar { pdev, io, num }) } /// # Safety @@ -219,11 +218,24 @@ impl<const SIZE: usize> Bar<SIZE> { fn release(&self) { // SAFETY: The safety requirements are guaranteed by the type invariant of `self.pdev`. - unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) }; + unsafe { Self::do_release(self.pdev, self.io.addr(), self.num) }; + } + + /// Consume the `Bar` and register it as a device-managed resource. + /// + /// The returned `Devres<Bar<'static, SIZE>>` can outlive the original lifetime `'a`. Access + /// to the BAR is revoked when the device is unbound. + pub fn into_devres(self) -> Result<Devres<Bar<'static, SIZE>>> { + // SAFETY: Casting to `'static` is sound because `Devres` guarantees the `Bar` does not + // actually outlive the device -- access is revoked and the resource is released when the + // device is unbound. + let bar: Bar<'static, SIZE> = unsafe { core::mem::transmute(self) }; + let pdev = bar.pdev; + Devres::new(pdev.as_ref(), bar) } } -impl Bar { +impl Bar<'_> { #[inline] pub(super) fn index_is_valid(index: u32) -> bool { // A `struct pci_dev` owns an array of resources with at most `PCI_NUM_RESOURCES` entries. @@ -231,13 +243,13 @@ impl Bar { } } -impl<const SIZE: usize> Drop for Bar<SIZE> { +impl<const SIZE: usize> Drop for Bar<'_, SIZE> { fn drop(&mut self) { self.release(); } } -impl<const SIZE: usize> Deref for Bar<SIZE> { +impl<const SIZE: usize> Deref for Bar<'_, SIZE> { type Target = Mmio<SIZE>; fn deref(&self) -> &Self::Target { @@ -252,17 +264,13 @@ impl Device<device::Bound> { pub fn iomap_region_sized<'a, const SIZE: usize>( &'a self, bar: u32, - name: &'a CStr, - ) -> impl PinInit<Devres<Bar<SIZE>>, Error> + 'a { - Devres::new(self.as_ref(), Bar::<SIZE>::new(self, bar, name)) + name: &'static CStr, + ) -> Result<Bar<'a, SIZE>> { + Bar::new(self, bar, name) } /// Maps an entire PCI BAR after performing a region-request on it. - pub fn iomap_region<'a>( - &'a self, - bar: u32, - name: &'a CStr, - ) -> impl PinInit<Devres<Bar>, Error> + 'a { + pub fn iomap_region<'a>(&'a self, bar: u32, name: &'static CStr) -> Result<Bar<'a>> { self.iomap_region_sized::<0>(bar, name) } diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 8917d4ee499f..9b362e0495d3 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -45,18 +45,18 @@ pub struct Adapter<T: Driver>(T); // SAFETY: // - `bindings::platform_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `T::Data` is the type of the driver's device private data. // - `struct platform_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. -unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> { +unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> { type DriverType = bindings::platform_driver; - type DriverData = T; + type DriverData<'bound> = T::Data<'bound>; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { +unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> { unsafe fn register( pdrv: &Opaque<Self::DriverType>, name: &'static CStr, @@ -82,7 +82,9 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { } // SAFETY: `pdrv` is guaranteed to be a valid `DriverType`. - to_result(unsafe { bindings::__platform_driver_register(pdrv.get(), module.0) }) + to_result(unsafe { + bindings::__platform_driver_register(pdrv.get(), module.0, name.as_char_ptr()) + }) } unsafe fn unregister(pdrv: &Opaque<Self::DriverType>) { @@ -91,13 +93,13 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { } } -impl<T: Driver + 'static> Adapter<T> { +impl<T: Driver> Adapter<T> { extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ffi::c_int { // SAFETY: The platform bus only ever calls the probe callback with a valid pointer to a // `struct platform_device`. // // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. - let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; + let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() }; let info = <Self as driver::Adapter>::id_info(pdev.as_ref()); from_result(|| { @@ -113,18 +115,18 @@ impl<T: Driver + 'static> Adapter<T> { // `struct platform_device`. // // INVARIANT: `pdev` is valid for the duration of `remove_callback()`. - let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; + let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() }; // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called - // and stored a `Pin<KBox<T>>`. - let data = unsafe { pdev.as_ref().drvdata_borrow::<T>() }; + // and stored a `Pin<KBox<T::Data<'_>>>`. + let data = unsafe { pdev.as_ref().drvdata_borrow::<T::Data<'_>>() }; T::unbind(pdev, data); } } -impl<T: Driver + 'static> driver::Adapter for Adapter<T> { +impl<T: Driver> driver::Adapter for Adapter<T> { type IdInfo = T::IdInfo; fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> { @@ -192,18 +194,19 @@ macro_rules! module_platform_driver { /// /// impl platform::Driver for MyDriver { /// type IdInfo = (); +/// type Data<'bound> = Self; /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); /// const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); /// -/// fn probe( -/// _pdev: &platform::Device<Core>, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit<Self, Error> { +/// fn probe<'bound>( +/// _pdev: &'bound platform::Device<Core<'_>>, +/// _id_info: Option<&'bound Self::IdInfo>, +/// ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { /// Err(ENODEV) /// } /// } ///``` -pub trait Driver: Send { +pub trait Driver { /// The type holding driver private data about each device id supported by the driver. // TODO: Use associated_type_defaults once stabilized: // @@ -212,6 +215,9 @@ pub trait Driver: Send { // ``` type IdInfo: 'static; + /// The type of the driver's bus device private data. + type Data<'bound>: Send + 'bound; + /// The table of OF device ids supported by the driver. const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; @@ -222,10 +228,10 @@ pub trait Driver: Send { /// /// Called when a new platform device is added or discovered. /// Implementers should attempt to initialize the device here. - fn probe( - dev: &Device<device::Core>, - id_info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error>; + fn probe<'bound>( + dev: &'bound Device<device::Core<'_>>, + id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; /// Platform driver unbind. /// @@ -236,8 +242,8 @@ pub trait Driver: Send { /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O /// operations to gracefully tear down the device. /// - /// Otherwise, release operations for driver resources should be performed in `Self::drop`. - fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { + /// Otherwise, release operations for driver resources should be performed in `Drop`. + fn unbind<'bound>(dev: &'bound Device<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) { let _ = (dev, this); } } @@ -509,7 +515,7 @@ impl Device<Bound> { kernel::impl_device_context_deref!(unsafe { Device }); kernel::impl_device_context_into_aref!(Device); -impl crate::dma::Device for Device<device::Core> {} +impl<'a> crate::dma::Device<'a> for Device<device::Core<'a>> {} // SAFETY: Instances of `Device` are always reference-counted. unsafe impl crate::sync::aref::AlwaysRefCounted for Device { @@ -561,3 +567,7 @@ unsafe impl Send for Device {} // SAFETY: `Device` can be shared among threads because all methods of `Device` // (i.e. `Device<Normal>) are thread safe. unsafe impl Sync for Device {} + +// SAFETY: Same as `Device<Normal>` -- the underlying `struct platform_device` is the same; +// `Bound` is a zero-sized type-state marker that does not affect thread safety. +unsafe impl Sync for Device<device::Bound> {} diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 4329d3c2c2e5..ac316fd7b538 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -11,6 +11,10 @@ use core::{ }; use pin_init::{PinInit, Wrapper, Zeroable}; +#[doc(hidden)] +pub mod for_lt; +pub use for_lt::ForLt; + /// Used to transfer ownership to and from foreign (non-Rust) languages. /// /// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and @@ -27,10 +31,14 @@ pub unsafe trait ForeignOwnable: Sized { const FOREIGN_ALIGN: usize; /// Type used to immutably borrow a value that is currently foreign-owned. - type Borrowed<'a>; + type Borrowed<'a> + where + Self: 'a; /// Type used to mutably borrow a value that is currently foreign-owned. - type BorrowedMut<'a>; + type BorrowedMut<'a> + where + Self: 'a; /// Converts a Rust-owned object to a foreign-owned one. /// diff --git a/rust/kernel/types/for_lt.rs b/rust/kernel/types/for_lt.rs new file mode 100644 index 000000000000..d44323c28e8d --- /dev/null +++ b/rust/kernel/types/for_lt.rs @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! Provide implementation and test of the `ForLt` trait and macro. +//! +//! This module is hidden and user should just use `ForLt!` directly. + +use core::marker::PhantomData; + +/// Representation of types generic over a lifetime. +/// +/// The type must be covariant over the generic lifetime, i.e. the lifetime parameter +/// can be soundly shortened. +/// +/// The lifetime involved must be covariant. +/// +/// # Macro +/// +/// It is not recommended to implement this trait directly. `ForLt!` macro is provided to obtain a +/// type that implements this trait. +/// +/// The full syntax is +/// +/// ``` +/// # use kernel::types::ForLt; +/// # fn expect_lt<F: ForLt>() {} +/// # struct TypeThatUse<'a>(&'a ()); +/// # expect_lt::< +/// ForLt!(for<'a> TypeThatUse<'a>) +/// # >(); +/// ``` +/// +/// which gives a type so that `<ForLt!(for<'a> TypeThatUse<'a>) as ForLt>::Of<'b>` +/// is `TypeThatUse<'b>`. +/// +/// You may also use a short-hand syntax which works similar to lifetime elision. +/// The macro also accepts types that do not involve a lifetime at all. +/// +/// ``` +/// # use kernel::types::ForLt; +/// # fn expect_lt<F: ForLt>() {} +/// # struct TypeThatUse<'a>(&'a ()); +/// # expect_lt::< +/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'a>)`. +/// # >(); +/// # expect_lt::< +/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)`. +/// # >(); +/// # expect_lt::< +/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)`. +/// # >(); +/// ``` +/// +/// The macro will attempt to prove that the type is indeed covariant over the lifetime supplied. +/// When it cannot be syntactically proven, it will emit checks to ask the Rust compiler to prove +/// it. +/// +/// ```ignore,compile_fail +/// # use kernel::types::ForLt; +/// # fn expect_lt<F: ForLt>() {} +/// # expect_lt::< +/// ForLt!(fn(&u32)) // Contravariant, will fail compilation. +/// # >(); +/// ``` +/// +/// There is a limitation if the type refers to generic parameters; if the macro cannot prove the +/// covariance syntactically, the emitted checks will fail the compilation as it needs to refer to +/// the generic parameter but is in a separate item. +/// +/// ``` +/// # use kernel::types::ForLt; +/// fn expect_lt<F: ForLt>() {} +/// # #[allow(clippy::unnecessary_safety_comment, reason = "false positive")] +/// fn generic_fn<T: 'static>() { +/// // Syntactically proven by the macro +/// expect_lt::<ForLt!(&T)>(); +/// // Syntactically proven by the macro +/// expect_lt::<ForLt!(&KBox<T>)>(); +/// // Cannot be syntactically proven, need to check covariance of `KBox` +/// // expect_lt::<ForLt!(&KBox<&T>)>(); +/// } +/// ``` +/// +/// # Safety +/// +/// `Self::Of<'a>` must be covariant over the lifetime `'a`. +pub unsafe trait ForLt { + /// The type parameterized by the lifetime. + type Of<'a>: 'a; + + /// Cast a reference to a shorter lifetime. + #[inline(always)] + fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Self::Of<'short> { + // SAFETY: This is sound as this trait guarantees covariance. + unsafe { core::mem::transmute(long) } + } +} +pub use macros::ForLt; + +/// This is intended to be an "unsafe-to-refer-to" type. +/// +/// Must only be used by the `ForLt!` macro. +/// +/// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro. +/// +/// `WF` is a type that the macro can use to assert some specific type is well-formed. +/// +/// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove +/// additional properties. +#[doc(hidden)] +pub struct UnsafeForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>); + +// This is a helper trait for implementation `ForLt` to be able to use HRTB. +#[doc(hidden)] +pub trait WithLt<'a> { + type Of: 'a; +} + +// SAFETY: In `ForLt!` macro, a covariance proof is generated when naming `UnsafeForLtImpl` +// and it will fail to evaluate if the type is not covariant. +unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for UnsafeForLtImpl<T, WF, 0> { + type Of<'a> = <T as WithLt<'a>>::Of; +} diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 9c17a672cd27..7aff0c82d0af 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -36,18 +36,18 @@ pub struct Adapter<T: Driver>(T); // SAFETY: // - `bindings::usb_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `T::Data` is the type of the driver's device private data. // - `struct usb_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. -unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> { +unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> { type DriverType = bindings::usb_driver; - type DriverData = T; + type DriverData<'bound> = T::Data<'bound>; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { +unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> { unsafe fn register( udrv: &Opaque<Self::DriverType>, name: &'static CStr, @@ -73,7 +73,7 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { } } -impl<T: Driver + 'static> Adapter<T> { +impl<T: Driver> Adapter<T> { extern "C" fn probe_callback( intf: *mut bindings::usb_interface, id: *const bindings::usb_device_id, @@ -82,7 +82,7 @@ impl<T: Driver + 'static> Adapter<T> { // `struct usb_interface` and `struct usb_device_id`. // // INVARIANT: `intf` is valid for the duration of `probe_callback()`. - let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal>>() }; + let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal<'_>>>() }; from_result(|| { // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct usb_device_id` and @@ -92,7 +92,7 @@ impl<T: Driver + 'static> Adapter<T> { let info = T::ID_TABLE.info(id.index()); let data = T::probe(intf, id, info); - let dev: &device::Device<device::CoreInternal> = intf.as_ref(); + let dev: &device::Device<device::CoreInternal<'_>> = intf.as_ref(); dev.set_drvdata(data)?; Ok(0) }) @@ -103,14 +103,14 @@ impl<T: Driver + 'static> Adapter<T> { // `struct usb_interface`. // // INVARIANT: `intf` is valid for the duration of `disconnect_callback()`. - let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal>>() }; + let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal<'_>>>() }; - let dev: &device::Device<device::CoreInternal> = intf.as_ref(); + let dev: &device::Device<device::CoreInternal<'_>> = intf.as_ref(); // SAFETY: `disconnect_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called - // and stored a `Pin<KBox<T>>`. - let data = unsafe { dev.drvdata_borrow::<T>() }; + // and stored a `Pin<KBox<T::Data<'_>>>`. + let data = unsafe { dev.drvdata_borrow::<T::Data<'_>>() }; T::disconnect(intf, data); } @@ -287,23 +287,31 @@ macro_rules! usb_device_table { /// /// impl usb::Driver for MyDriver { /// type IdInfo = (); +/// type Data<'bound> = Self; /// const ID_TABLE: usb::IdTable<Self::IdInfo> = &USB_TABLE; /// -/// fn probe( -/// _interface: &usb::Interface<Core>, +/// fn probe<'bound>( +/// _interface: &'bound usb::Interface<Core<'_>>, /// _id: &usb::DeviceId, -/// _info: &Self::IdInfo, -/// ) -> impl PinInit<Self, Error> { +/// _info: &'bound Self::IdInfo, +/// ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { /// Err(ENODEV) /// } /// -/// fn disconnect(_interface: &usb::Interface<Core>, _data: Pin<&Self>) {} +/// fn disconnect<'bound>( +/// _interface: &'bound usb::Interface<Core<'_>>, +/// _data: Pin<&Self::Data<'bound>>, +/// ) { +/// } /// } ///``` pub trait Driver { /// The type holding information about each one of the device ids supported by the driver. type IdInfo: 'static; + /// The type of the driver's bus device private data. + type Data<'bound>: Send + 'bound; + /// The table of device ids supported by the driver. const ID_TABLE: IdTable<Self::IdInfo>; @@ -311,16 +319,19 @@ pub trait Driver { /// /// Called when a new USB interface is bound to this driver. /// Implementers should attempt to initialize the interface here. - fn probe( - interface: &Interface<device::Core>, + fn probe<'bound>( + interface: &'bound Interface<device::Core<'_>>, id: &DeviceId, - id_info: &Self::IdInfo, - ) -> impl PinInit<Self, Error>; + id_info: &'bound Self::IdInfo, + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; /// USB driver disconnect. /// /// Called when the USB interface is about to be unbound from this driver. - fn disconnect(interface: &Interface<device::Core>, data: Pin<&Self>); + fn disconnect<'bound>( + interface: &'bound Interface<device::Core<'_>>, + data: Pin<&Self::Data<'bound>>, + ); } /// A USB interface. @@ -464,6 +475,10 @@ unsafe impl Send for Device {} // allow any mutation through a shared reference. unsafe impl Sync for Device {} +// SAFETY: Same as `Device<Normal>` -- the underlying `struct usb_device` is the same; +// `Bound` is a zero-sized type-state marker that does not affect thread safety. +unsafe impl Sync for Device<device::Bound> {} + /// Declares a kernel module that exposes a single USB driver. /// /// # Examples diff --git a/rust/macros/for_lt.rs b/rust/macros/for_lt.rs new file mode 100644 index 000000000000..364d4113cd10 --- /dev/null +++ b/rust/macros/for_lt.rs @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use proc_macro2::{ + Span, + TokenStream, // +}; +use quote::{ + format_ident, + quote, // +}; +use syn::{ + parse::{ + Parse, + ParseStream, // + }, + visit::Visit, + visit_mut::VisitMut, + Lifetime, + Result, + Token, + Type, // +}; + +pub(crate) enum HigherRankedType { + Explicit { + _for_token: Token![for], + _lt_token: Token![<], + lifetime: Lifetime, + _gt_token: Token![>], + ty: Type, + }, + Implicit { + ty: Type, + }, +} + +impl Parse for HigherRankedType { + fn parse(input: ParseStream<'_>) -> Result<Self> { + if input.peek(Token![for]) { + Ok(Self::Explicit { + _for_token: input.parse()?, + _lt_token: input.parse()?, + lifetime: input.parse()?, + _gt_token: input.parse()?, + ty: input.parse()?, + }) + } else { + Ok(Self::Implicit { ty: input.parse()? }) + } + } +} + +trait TypeExt { + fn expand_elided_lifetime(&self, explicit_lt: &Lifetime) -> Type; + fn replace_lifetime(&self, src: &Lifetime, dst: &Lifetime) -> Type; + fn has_lifetime(&self, lt: &Lifetime) -> bool; +} + +impl TypeExt for Type { + fn expand_elided_lifetime(&self, explicit_lt: &Lifetime) -> Type { + struct ElidedLifetimeExpander<'a>(&'a Lifetime); + + impl VisitMut for ElidedLifetimeExpander<'_> { + fn visit_lifetime_mut(&mut self, lifetime: &mut Lifetime) { + // Expand explicit `'_` + if lifetime.ident == "_" { + *lifetime = self.0.clone(); + } + } + + fn visit_type_reference_mut(&mut self, reference: &mut syn::TypeReference) { + syn::visit_mut::visit_type_reference_mut(self, reference); + + if reference.lifetime.is_none() { + reference.lifetime = Some(self.0.clone()); + } + } + } + + let mut ret = self.clone(); + ElidedLifetimeExpander(explicit_lt).visit_type_mut(&mut ret); + ret + } + + fn replace_lifetime(&self, src: &Lifetime, dst: &Lifetime) -> Type { + struct LifetimeReplacer<'a>(&'a Lifetime, &'a Lifetime); + + impl VisitMut for LifetimeReplacer<'_> { + fn visit_lifetime_mut(&mut self, lifetime: &mut Lifetime) { + if lifetime.ident == self.0.ident { + *lifetime = self.1.clone(); + } + } + } + + let mut ret = self.clone(); + LifetimeReplacer(src, dst).visit_type_mut(&mut ret); + ret + } + + fn has_lifetime(&self, lt: &Lifetime) -> bool { + struct HasLifetime<'a>(&'a Lifetime, bool); + + impl Visit<'_> for HasLifetime<'_> { + fn visit_lifetime(&mut self, lifetime: &Lifetime) { + if lifetime.ident == self.0.ident { + self.1 = true; + } + } + + // Macro invocations are opaque; conservatively assume they may + // reference the lifetime. + fn visit_macro(&mut self, _: &syn::Macro) { + self.1 = true; + } + } + + let mut visitor = HasLifetime(lt, false); + visitor.visit_type(self); + visitor.1 + } +} + +struct Prover<'a>(&'a Lifetime, Vec<&'a Type>); + +impl<'a> Prover<'a> { + /// Prove that `ty` is covariant over `'lt`. + /// + /// This also needs to prove that it'll be wellformed for any instance of `'lt`. + /// It can be assumed that `ty` will be wellformed if `'lt` is substituted to `'static`. + fn prove(&mut self, ty: &'a Type) { + match ty { + Type::Paren(ty) => self.prove(&ty.elem), + Type::Group(ty) => self.prove(&ty.elem), + + // No lifetime involved + Type::Never(_) => {} + + // `[T; N]` and `[T]` is covariant over `T`. + Type::Array(ty) => self.prove(&ty.elem), + Type::Slice(ty) => self.prove(&ty.elem), + + Type::Tuple(ty) => { + for elem in &ty.elems { + self.prove(elem); + } + } + + // `*const T` is covariant over `T` + Type::Ptr(ty) if ty.const_token.is_some() => self.prove(&ty.elem), + + // `&T` is covariant over `T` and lifetime. + // + // Note that if we encounter `&'other_lt T`, then we still need to make sure the type + // is wellformed if `T` involves `&'lt`, so we defer to the compiler. + // + // This is to block cases like `ForLt!(for<'a> &'static &'a u32)`, as the presence of + // the type implies `'a: 'static` but this is unsound. + Type::Reference(ty) + if ty.mutability.is_none() && ty.lifetime.as_ref() == Some(self.0) => + { + self.prove(&ty.elem) + } + + // `&[mut] T` is covariant over lifetime. + // In case we have `&[mut] NoLifetime`, we don't need to do additional checks. + Type::Reference(ty) if !ty.elem.has_lifetime(self.0) => (), + + // No mention of lifetime at all, no need to perform compiler check. + ty if !ty.has_lifetime(self.0) => (), + + // Otherwise, we need to emit checks so that compiler can determine if the types are + // actually covariant. + ty => self.1.push(ty), + } + } +} + +pub(crate) fn for_lt(input: HigherRankedType) -> TokenStream { + let (ty, lifetime) = match input { + HigherRankedType::Explicit { lifetime, ty, .. } => (ty, lifetime), + HigherRankedType::Implicit { ty } => { + // If there's no explicit `for<'a>` binder, inject a synthetic `'__elided` lifetime + // and expand elided sites. + let lifetime = Lifetime { + apostrophe: Span::mixed_site(), + ident: format_ident!("__elided", span = Span::mixed_site()), + }; + (ty.expand_elided_lifetime(&lifetime), lifetime) + } + }; + + let mut prover = Prover(&lifetime, Vec::new()); + prover.prove(&ty); + + let mut proof = Vec::new(); + + // Emit proofs for every type that requires additional compiler help in proving covariance. + for (idx, required_proof) in prover.1.into_iter().enumerate() { + // Insert a proof that the type is well-formed. + // + // This is intended to workaround a Rust compiler soundness bug related to HRTB. + // https://github.com/rust-lang/rust/issues/152489 + // + // This needs to be a struct instead of fn to avoid the implied WF bounds. + let wf_proof_name = format_ident!("ProveWf{idx}"); + proof.push(quote!( + struct #wf_proof_name<#lifetime>( + ::core::marker::PhantomData<&#lifetime ()>, #required_proof + ); + )); + + // Insert a proof that the type is covariant. + let cov_proof_name = format_ident!("prove_covariant_{idx}"); + proof.push(quote!( + fn #cov_proof_name<'__short, '__long: '__short>( + long: #wf_proof_name<'__long> + ) -> #wf_proof_name<'__short> { + long + } + )); + } + + // Make sure that the type is wellformed when substituting lifetime with `'static`. + // + // Currently the Rust compiler doesn't check this, see the above `ProveWf` documentation. + // + // We prefer to use this way of proving WF-ness as it can work when generics are involved. + let ty_static = ty.replace_lifetime( + &lifetime, + &Lifetime { + apostrophe: Span::mixed_site(), + ident: format_ident!("static"), + }, + ); + + quote!( + ::kernel::types::for_lt::UnsafeForLtImpl::< + dyn for<#lifetime> ::kernel::types::for_lt::WithLt<#lifetime, Of = #ty>, + #ty_static, + { + #(#proof)* + + 0 + } + > + ) +} diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 2cfd59e0f9e7..4a48fabbc268 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -17,6 +17,7 @@ mod concat_idents; mod export; mod fmt; +mod for_lt; mod helpers; mod kunit; mod module; @@ -489,3 +490,15 @@ pub fn kunit_tests(attr: TokenStream, input: TokenStream) -> TokenStream { .unwrap_or_else(|e| e.into_compile_error()) .into() } + +/// Obtain a type that implements [`ForLt`] for the given higher-ranked type. +/// +/// Please refer to the documentation of the [`ForLt`] trait. +/// +/// [`ForLt`]: trait.ForLt.html +#[proc_macro] +// The macro shares the name with the trait. +#[allow(non_snake_case)] +pub fn ForLt(input: TokenStream) -> TokenStream { + for_lt::for_lt(parse_macro_input!(input)).into() +} diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs index 0963efe19f93..1f59e08aaa4b 100644 --- a/samples/rust/rust_debugfs.rs +++ b/samples/rust/rust_debugfs.rs @@ -117,13 +117,14 @@ kernel::acpi_device_table!( impl platform::Driver for RustDebugFs { type IdInfo = (); + type Data<'bound> = Self; const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); - fn probe( - pdev: &platform::Device<Core>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + fn probe<'bound>( + pdev: &'bound platform::Device<Core<'_>>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { RustDebugFs::new(pdev).pin_chain(|this| { this.counter.store(91, Relaxed); { @@ -146,7 +147,7 @@ impl RustDebugFs { dir.read_write_file(c"pair", new_mutex!(Inner { x: 3, y: 10 })) } - fn new(pdev: &platform::Device<Core>) -> impl PinInit<Self, Error> + '_ { + fn new<'a>(pdev: &'a platform::Device<Core<'_>>) -> impl PinInit<Self, Error> + 'a { let debugfs = Dir::new(c"sample_debugfs"); let dev = pdev.as_ref(); diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index a2c34bb74273..5046b4628d0e 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -58,9 +58,13 @@ kernel::pci_device_table!( impl pci::Driver for DmaSampleDriver { type IdInfo = (); + type Data<'bound> = Self; const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; - fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { + fn probe<'bound>( + pdev: &'bound pci::Device<Core<'_>>, + _info: &'bound Self::IdInfo, + ) -> impl PinInit<Self, Error> + 'bound { pin_init::pin_init_scope(move || { dev_info!(pdev, "Probe DMA test driver.\n"); diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index 5c5a5105a3ff..2c1351040e45 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -10,15 +10,13 @@ use kernel::{ Bound, Core, // }, - devres::Devres, driver, pci, prelude::*, + types::ForLt, InPlaceModule, // }; -use core::any::TypeId; - const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME; const AUXILIARY_NAME: &CStr = c"auxiliary"; @@ -33,10 +31,14 @@ kernel::auxiliary_device_table!( impl auxiliary::Driver for AuxiliaryDriver { type IdInfo = (); + type Data<'bound> = Self; const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE; - fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { + fn probe<'bound>( + adev: &'bound auxiliary::Device<Core<'_>>, + _info: &'bound Self::IdInfo, + ) -> impl PinInit<Self, Error> + 'bound { dev_info!( adev, "Probing auxiliary driver for auxiliary device with id={}\n", @@ -49,13 +51,17 @@ impl auxiliary::Driver for AuxiliaryDriver { } } -#[pin_data] -struct ParentDriver { - private: TypeId, - #[pin] - _reg0: Devres<auxiliary::Registration>, - #[pin] - _reg1: Devres<auxiliary::Registration>, +struct Data<'bound> { + index: u32, + parent: &'bound pci::Device<Bound>, +} + +struct ParentDriver; + +#[allow(clippy::type_complexity)] +struct ParentData<'bound> { + _reg0: auxiliary::Registration<'bound, ForLt!(Data<'_>)>, + _reg1: auxiliary::Registration<'bound, ForLt!(Data<'_>)>, } kernel::pci_device_table!( @@ -67,26 +73,53 @@ kernel::pci_device_table!( impl pci::Driver for ParentDriver { type IdInfo = (); + type Data<'bound> = ParentData<'bound>; const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; - fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { - try_pin_init!(Self { - private: TypeId::of::<Self>(), - _reg0 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME), - _reg1 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME), + fn probe<'bound>( + pdev: &'bound pci::Device<Core<'_>>, + _info: &'bound Self::IdInfo, + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { + Ok(ParentData { + // SAFETY: `ParentData` is the driver's private data, which is dropped when the + // device is unbound; i.e. `mem::forget()` is never called on it. + _reg0: unsafe { + auxiliary::Registration::new_with_lt( + pdev.as_ref(), + AUXILIARY_NAME, + 0, + MODULE_NAME, + Data { + index: 0, + parent: pdev, + }, + )? + }, + // SAFETY: See `_reg0` above. + _reg1: unsafe { + auxiliary::Registration::new_with_lt( + pdev.as_ref(), + AUXILIARY_NAME, + 1, + MODULE_NAME, + Data { + index: 1, + parent: pdev, + }, + )? + }, }) } } impl ParentDriver { fn connect(adev: &auxiliary::Device<Bound>) -> Result { - let dev = adev.parent(); - let pdev: &pci::Device<Bound> = dev.try_into()?; - let drvdata = dev.drvdata::<Self>()?; + let data = adev.registration_data::<ForLt!(Data<'_>)>()?; + let pdev = data.parent; dev_info!( - dev, + pdev, "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n", adev.id(), pdev.vendor_id(), @@ -94,9 +127,9 @@ impl ParentDriver { ); dev_info!( - dev, - "We have access to the private data of {:?}.\n", - drvdata.private + pdev, + "Connected to auxiliary device with index {}.\n", + data.index ); Ok(()) diff --git a/samples/rust/rust_driver_i2c.rs b/samples/rust/rust_driver_i2c.rs index 6be79f9e9fb5..ead8263a7d48 100644 --- a/samples/rust/rust_driver_i2c.rs +++ b/samples/rust/rust_driver_i2c.rs @@ -35,15 +35,16 @@ kernel::of_device_table! { impl i2c::Driver for SampleDriver { type IdInfo = u32; + type Data<'bound> = Self; const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); const I2C_ID_TABLE: Option<i2c::IdTable<Self::IdInfo>> = Some(&I2C_TABLE); const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); - fn probe( - idev: &i2c::I2cClient<Core>, - info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + fn probe<'bound>( + idev: &'bound i2c::I2cClient<Core<'_>>, + info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { let dev = idev.as_ref(); dev_info!(dev, "Probe Rust I2C driver sample.\n"); @@ -55,11 +56,11 @@ impl i2c::Driver for SampleDriver { Ok(Self) } - fn shutdown(idev: &i2c::I2cClient<Core>, _this: Pin<&Self>) { + fn shutdown<'bound>(idev: &'bound i2c::I2cClient<Core<'_>>, _this: Pin<&Self>) { dev_info!(idev.as_ref(), "Shutdown Rust I2C driver sample.\n"); } - fn unbind(idev: &i2c::I2cClient<Core>, _this: Pin<&Self>) { + fn unbind<'bound>(idev: &'bound i2c::I2cClient<Core<'_>>, _this: Pin<&Self>) { dev_info!(idev.as_ref(), "Unbind Rust I2C driver sample.\n"); } } diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 47d3e84fab63..1aa8197d8698 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -9,7 +9,6 @@ use kernel::{ Bound, Core, // }, - devres::Devres, io::{ register, register::Array, @@ -17,8 +16,7 @@ use kernel::{ }, num::Bounded, pci, - prelude::*, - sync::aref::ARef, // + prelude::*, // }; mod regs { @@ -45,7 +43,7 @@ mod regs { pub(super) const END: usize = 0x10; } -type Bar0 = pci::Bar<{ regs::END }>; +type Bar0<'bound> = pci::Bar<'bound, { regs::END }>; #[derive(Copy, Clone, Debug)] struct TestIndex(u8); @@ -66,14 +64,14 @@ impl TestIndex { const NO_EVENTFD: Self = Self(0); } -#[pin_data(PinnedDrop)] -struct SampleDriver { - pdev: ARef<pci::Device>, - #[pin] - bar: Devres<Bar0>, +struct SampleDriverData<'bound> { + pdev: &'bound pci::Device, + bar: Bar0<'bound>, index: TestIndex, } +struct SampleDriver; + kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, @@ -84,8 +82,8 @@ kernel::pci_device_table!( )] ); -impl SampleDriver { - fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> { +impl SampleDriverData<'_> { + fn testdev(index: &TestIndex, bar: &Bar0<'_>) -> Result<u32> { // Select the test. bar.write_reg(regs::TEST::zeroed().with_index(*index)); @@ -140,51 +138,49 @@ impl SampleDriver { impl pci::Driver for SampleDriver { type IdInfo = TestIndex; + type Data<'bound> = SampleDriverData<'bound>; const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; - fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> impl PinInit<Self, Error> { - pin_init::pin_init_scope(move || { - let vendor = pdev.vendor_id(); - dev_dbg!( - pdev, - "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", - vendor, - pdev.device_id() - ); - - pdev.enable_device_mem()?; - pdev.set_master(); - - Ok(try_pin_init!(Self { - bar <- pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_driver_pci"), - index: *info, - _: { - let bar = bar.access(pdev.as_ref())?; - - dev_info!( - pdev, - "pci-testdev data-match count: {}\n", - Self::testdev(info, bar)? - ); - Self::config_space(pdev); - }, - pdev: pdev.into(), - })) + fn probe<'bound>( + pdev: &'bound pci::Device<Core<'_>>, + info: &'bound Self::IdInfo, + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { + let vendor = pdev.vendor_id(); + dev_dbg!( + pdev, + "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", + vendor, + pdev.device_id() + ); + + pdev.enable_device_mem()?; + pdev.set_master(); + + let bar = pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_driver_pci")?; + + dev_info!( + pdev, + "pci-testdev data-match count: {}\n", + SampleDriverData::testdev(info, &bar)? + ); + SampleDriverData::config_space(pdev); + + Ok(SampleDriverData { + pdev, + bar, + index: *info, }) } - fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) { - if let Ok(bar) = this.bar.access(pdev.as_ref()) { - // Reset pci-testdev by writing a new test index. - bar.write_reg(regs::TEST::zeroed().with_index(this.index)); - } + fn unbind<'bound>(_pdev: &'bound pci::Device<Core<'_>>, this: Pin<&Self::Data<'bound>>) { + this.bar + .write_reg(regs::TEST::zeroed().with_index(this.index)); } } -#[pinned_drop] -impl PinnedDrop for SampleDriver { - fn drop(self: Pin<&mut Self>) { +impl Drop for SampleDriverData<'_> { + fn drop(&mut self) { dev_dbg!(self.pdev, "Remove Rust PCI driver sample.\n"); } } diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index f2229d176fb9..ec0d6cac4f57 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -101,13 +101,14 @@ kernel::acpi_device_table!( impl platform::Driver for SampleDriver { type IdInfo = Info; + type Data<'bound> = Self; const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); - fn probe( - pdev: &platform::Device<Core>, - info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + fn probe<'bound>( + pdev: &'bound platform::Device<Core<'_>>, + info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { let dev = pdev.as_ref(); dev_dbg!(dev, "Probe Rust Platform driver sample.\n"); diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb.rs index ab72e99e1274..02bd5085f9bc 100644 --- a/samples/rust/rust_driver_usb.rs +++ b/samples/rust/rust_driver_usb.rs @@ -26,21 +26,22 @@ kernel::usb_device_table!( impl usb::Driver for SampleDriver { type IdInfo = (); + type Data<'bound> = Self; const ID_TABLE: usb::IdTable<Self::IdInfo> = &USB_TABLE; - fn probe( - intf: &usb::Interface<Core>, + fn probe<'bound>( + intf: &'bound usb::Interface<Core<'_>>, _id: &usb::DeviceId, - _info: &Self::IdInfo, - ) -> impl PinInit<Self, Error> { - let dev: &device::Device<Core> = intf.as_ref(); + _info: &'bound Self::IdInfo, + ) -> impl PinInit<Self, Error> + 'bound { + let dev: &device::Device<Core<'_>> = intf.as_ref(); dev_info!(dev, "Rust USB driver sample probed\n"); Ok(Self { _intf: intf.into() }) } - fn disconnect(intf: &usb::Interface<Core>, _data: Pin<&Self>) { - let dev: &device::Device<Core> = intf.as_ref(); + fn disconnect<'bound>(intf: &'bound usb::Interface<Core<'_>>, _data: Pin<&Self>) { + let dev: &device::Device<Core<'_>> = intf.as_ref(); dev_info!(dev, "Rust USB driver sample disconnected\n"); } } diff --git a/samples/rust/rust_i2c_client.rs b/samples/rust/rust_i2c_client.rs index 8d2c12e535b0..2d876f4e3ee0 100644 --- a/samples/rust/rust_i2c_client.rs +++ b/samples/rust/rust_i2c_client.rs @@ -106,13 +106,14 @@ const BOARD_INFO: i2c::I2cBoardInfo = impl platform::Driver for SampleDriver { type IdInfo = (); + type Data<'bound> = Self; const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); - fn probe( - pdev: &platform::Device<device::Core>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + fn probe<'bound>( + pdev: &'bound platform::Device<device::Core<'_>>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { dev_info!( pdev.as_ref(), "Probe Rust I2C Client registration sample.\n" @@ -129,7 +130,10 @@ impl platform::Driver for SampleDriver { }) } - fn unbind(pdev: &platform::Device<device::Core>, _this: Pin<&Self>) { + fn unbind<'bound>( + pdev: &'bound platform::Device<device::Core<'_>>, + _this: Pin<&Self::Data<'bound>>, + ) { dev_info!( pdev.as_ref(), "Unbind Rust I2C Client registration sample.\n" diff --git a/samples/rust/rust_soc.rs b/samples/rust/rust_soc.rs index 8079c1c48416..808d58200eb6 100644 --- a/samples/rust/rust_soc.rs +++ b/samples/rust/rust_soc.rs @@ -37,13 +37,14 @@ kernel::acpi_device_table!( impl platform::Driver for SampleSocDriver { type IdInfo = (); + type Data<'bound> = Self; const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); - fn probe( - pdev: &platform::Device<Core>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + fn probe<'bound>( + pdev: &'bound platform::Device<Core<'_>>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { dev_dbg!(pdev, "Probe Rust SoC driver sample.\n"); let pdev = pdev.into(); |
