Pull driver core updates from Danilo Krummrich: "Deferred probe: - Fix race where deferred probe timeout work could be permanently canceled by using mod_delayed_work() - Fix missing jiffies conversion in deferred_probe_extend_timeout() - Guard timeout extension with delayed_work_pending() to prevent premature firing - Use system_percpu_wq instead of the deprecated system_wq - Update deferred_probe_timeout documentation device: - Replace direct struct device bitfield access (can_match, dma_iommu, dma_skip_sync, dma_ops_bypass, state_synced, dma_coherent, of_node_reused, offline, offline_disabled) with flag-based accessors using bit operations - Reject devices with unregistered buses - Delete unused DEVICE_ATTR_PREALLOC() - Add low-level device attribute macros with const show/store callbacks, allowing device attributes to reside in read-only memory - Move core device attributes to read-only memory - Constify group array pointers in driver_add_groups() / driver_remove_groups(), struct bus_type, and struct device_driver device property: - Fix fwnode reference leak in fwnode_graph_get_endpoint_by_id() - Initialize all fields of fwnode_handle in fwnode_init() - Provide swnode_get()/swnode_put() wrappers around kobject_get/put() - Allow passing struct software_node_ref_args pointers directly to PROPERTY_ENTRY_REF() driver_override: - Migrate amba, cdx, vmbus, and rpmsg to the generic driver_override infrastructure, fixing a UAF from unsynchronized access to driver_override in bus match() callbacks - Remove the now-unused driver_set_override() firmware loader: - Fix recursive lock deadlock in device_cache_fw_images() when async work falls back to synchronous execution - Fix device reference leak in firmware_upload_register() platform: - Pass KBUILD_MODNAME through the platform driver registration macro to create module symlinks in sysfs for built-in drivers; move module_kset initialization to a pure_initcall and tegra cbb registration to core_initcall to ensure correct ordering - Pass THIS_MODULE implicitly through a coresight_init_driver() macro sysfs: - Upgrade OOB write detection in sysfs_kf_seq_show() from printk to WARN - Add return value clamping to sysfs_kf_read() Rust: - ACPI: Fix missing match data for PRP0001 by exporting acpi_of_match_device() - Auxiliary: Replace drvdata() with dedicated registration data on auxiliary_device. drvdata() exposed the driver's bus device private data beyond the driver's own scope, creating ordering constraints and forcing the data to outlive all registrations that access it. Registration data is instead scoped structurally to the Registration object, making lifecycle ordering enforced by construction rather than convention. - Rust-native device driver lifetimes (HRT): Allow Rust device drivers to carry a lifetime parameter on their bus device private data, tied to the device binding scope -- the interval during which a bus device is bound to a driver. Device resources like pci::Bar<'a> and IoMem<'a> can be stored directly in the driver's bus device private data with a lifetime bounded by the binding scope, so the compiler enforces at build time that they do not outlive the binding. This removes Devres indirection from every access site and eliminates try_access() failure paths in destructors. Bus driver traits use a Generic Associated Type (GAT) Data<'bound> to introduce the lifetime on the private data, rather than parameterizing the Driver trait itself. Auxiliary registration data, where the lifetime is not introduced by a trait callback but must be threaded through Registration, uses the ForLt trait (a type-level abstraction for types generic over a lifetime). Misc: - Fix DT overlayed devices not probing by reverting the broken treewide overlay fix and re-running fw_devlink consumer pickup when an overlay is applied to a bound device - Use root_device_register() for faux bus root device; add sanity check for failed bus init - Fix dev_has_sync_state() data race with READ_ONCE() and move it to base.h - Avoid spurious device_links warning when removing a device while its supplier is unbinding - Switch ISA bus to dynamic root device - Fix suspicious RCU usage in kernfs_put() - Remove devcoredump exit callback - Constify devfreq_event_class" * tag 'driver-core-7.2-rc1' of gitolite.kernel.org:pub/scm/linux/kernel/git/driver-core/driver-core: (81 commits) software node: allow passing reference args to PROPERTY_ENTRY_REF() driver core: platform: set mod_name in driver registration coresight: pass THIS_MODULE implicitly through a macro kernel: param: initialize module_kset in a pure_initcall soc/tegra: cbb: Move driver registration from pure_initcall to core_initcall firmware_loader: Fix recursive lock in device_cache_fw_images() driver core: Use system_percpu_wq instead of system_wq driver core: remove driver_set_override() rpmsg: use generic driver_override infrastructure Drivers: hv: vmbus: use generic driver_override infrastructure cdx: use generic driver_override infrastructure amba: use generic driver_override infrastructure rust: devres: add 'static bound to Devres<T> samples: rust: rust_driver_auxiliary: showcase lifetime-bound registration data rust: auxiliary: generalize Registration over ForLt rust: types: add `ForLt` trait for higher-ranked lifetime support gpu: nova-core: separate driver type from driver data samples: rust: rust_driver_pci: use HRT lifetime for Bar rust: io: make IoMem and ExclusiveIoMem lifetime-parameterized rust: pci: make Bar lifetime-parameterized ...
Unified · Split
| @@ -1228,8 +1228,9 @@ Kernel parameters · 1227 unmodified lines | ||
| 1228 | 1228 | deferred probe to give up waiting on dependencies to |
| 1229 | 1229 | probe. Only specific dependencies (subsystems or |
| 1230 | 1230 | drivers) that have opted in will be ignored. A timeout |
| 1231 | − of 0 will timeout at the end of initcalls. If the time | |
| 1232 | − out hasn't expired, it'll be restarted by each | |
| 1231 | + of 0 will timeout at the end of initcalls; a negative | |
| 1232 | + value is treated as an infinite timeout value. If the | |
| 1233 | + timeout hasn't expired, it'll be restarted by each | |
| 1233 | 1234 | successful driver registration. This option will also |
| 1234 | 1235 | dump out devices still on the deferred probe list after |
| 1235 | 1236 | retrying. |
| @@ -70,7 +70,8 @@ Kernel modules can be composed of several platform drivers. The platform core · 69 unmodified lines | ||
| 70 | 70 | provides helpers to register and unregister an array of drivers:: |
| 71 | 71 | |
| 72 | 72 | int __platform_register_drivers(struct platform_driver * const *drivers, |
| 73 | − unsigned int count, struct module *owner); | |
| 73 | + unsigned int count, struct module *owner, | |
| 74 | + const char *mod_name); | |
| 74 | 75 | void platform_unregister_drivers(struct platform_driver * const *drivers, |
| 75 | 76 | unsigned int count); |
| 76 | 77 | |
| @@ -297,6 +297,7 @@ F: include/linux/acpi.h · 296 unmodified lines | ||
| 297 | 297 | F: include/linux/fwnode.h |
| 298 | 298 | F: include/linux/fw_table.h |
| 299 | 299 | F: lib/fw_table.c |
| 300 | +F: rust/helpers/acpi.c | |
| 300 | 301 | F: rust/kernel/acpi.rs |
| 301 | 302 | F: tools/power/acpi/ |
| 302 | 303 | |
| @@ -98,8 +98,8 @@ void arch_setup_dma_ops(struct device *dev, bool coherent) · 97 unmodified lines | ||
| 98 | 98 | * DMA buffers. |
| 99 | 99 | */ |
| 100 | 100 | if (is_isa_arcv2() && ioc_enable && coherent) |
| 101 | − dev->dma_coherent = true; | |
| 101 | + dev_set_dma_coherent(dev); | |
| 102 | 102 | |
| 103 | 103 | dev_info(dev, "use %scoherent DMA ops\n", |
| 104 | − dev->dma_coherent ? "" : "non"); | |
| 104 | + dev_dma_coherent(dev) ? "" : "non"); | |
| 105 | 105 | } |
| @@ -98,7 +98,7 @@ static int highbank_platform_notifier(struct notifier_block *nb, · 97 unmodified lines | ||
| 98 | 98 | if (of_property_read_bool(dev->of_node, "dma-coherent")) { |
| 99 | 99 | val = readl(sregs_base + reg); |
| 100 | 100 | writel(val | 0xff01, sregs_base + reg); |
| 101 | − dev->dma_coherent = true; | |
| 101 | + dev_set_dma_coherent(dev); | |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | 104 | return NOTIFY_OK; |
| @@ -95,7 +95,7 @@ static int mvebu_hwcc_notifier(struct notifier_block *nb, · 94 unmodified lines | ||
| 95 | 95 | |
| 96 | 96 | if (event != BUS_NOTIFY_ADD_DEVICE) |
| 97 | 97 | return NOTIFY_DONE; |
| 98 | − dev->dma_coherent = true; | |
| 98 | + dev_set_dma_coherent(dev); | |
| 99 | 99 | |
| 100 | 100 | return NOTIFY_OK; |
| 101 | 101 | } |
| @@ -42,11 +42,11 @@ void arch_setup_dma_ops(struct device *dev, bool coherent) · 41 unmodified lines | ||
| 42 | 42 | * enough to check if MPU is in use or not since in absence of |
| 43 | 43 | * MPU system memory map is used. |
| 44 | 44 | */ |
| 45 | − dev->dma_coherent = cacheid ? coherent : true; | |
| 45 | + dev_assign_dma_coherent(dev, cacheid ? coherent : true); | |
| 46 | 46 | } else { |
| 47 | 47 | /* |
| 48 | 48 | * Assume coherent DMA in case MMU/MPU has not been set up. |
| 49 | 49 | */ |
| 50 | − dev->dma_coherent = (get_cr() & CR_M) ? coherent : true; | |
| 50 | + dev_assign_dma_coherent(dev, (get_cr() & CR_M) ? coherent : true); | |
| 51 | 51 | } |
| 52 | 52 | } |
| @@ -1076,7 +1076,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, · 1075 unmodified lines | ||
| 1076 | 1076 | pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL); |
| 1077 | 1077 | struct page **pages; |
| 1078 | 1078 | void *addr = NULL; |
| 1079 | − int coherent_flag = dev->dma_coherent ? COHERENT : NORMAL; | |
| 1079 | + int coherent_flag = dev_dma_coherent(dev) ? COHERENT : NORMAL; | |
| 1080 | 1080 | |
| 1081 | 1081 | *handle = DMA_MAPPING_ERROR; |
| 1082 | 1082 | size = PAGE_ALIGN(size); |
| @@ -1124,7 +1124,7 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, · 41 unmodified lines | ||
| 1124 | 1124 | if (vma->vm_pgoff >= nr_pages) |
| 1125 | 1125 | return -ENXIO; |
| 1126 | 1126 | |
| 1127 | − if (!dev->dma_coherent) | |
| 1127 | + if (!dev_dma_coherent(dev)) | |
| 1128 | 1128 | vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); |
| 1129 | 1129 | |
| 1130 | 1130 | 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, · 10 unmodified lines | ||
| 1141 | 1141 | static void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, |
| 1142 | 1142 | dma_addr_t handle, unsigned long attrs) |
| 1143 | 1143 | { |
| 1144 | − int coherent_flag = dev->dma_coherent ? COHERENT : NORMAL; | |
| 1144 | + int coherent_flag = dev_dma_coherent(dev) ? COHERENT : NORMAL; | |
| 1145 | 1145 | struct page **pages; |
| 1146 | 1146 | size = PAGE_ALIGN(size); |
| 1147 | 1147 | |
| @@ -1202,7 +1202,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, · 54 unmodified lines | ||
| 1202 | 1202 | phys_addr_t phys = page_to_phys(sg_page(s)); |
| 1203 | 1203 | unsigned int len = PAGE_ALIGN(s->offset + s->length); |
| 1204 | 1204 | |
| 1205 | − if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) | |
| 1205 | + if (!dev_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) | |
| 1206 | 1206 | arch_sync_dma_for_device(sg_phys(s), s->length, dir); |
| 1207 | 1207 | |
| 1208 | 1208 | prot = __dma_info_to_prot(dir, attrs); |
| @@ -1304,7 +1304,7 @@ static void arm_iommu_unmap_sg(struct device *dev, · 95 unmodified lines | ||
| 1304 | 1304 | if (sg_dma_len(s)) |
| 1305 | 1305 | __iommu_remove_mapping(dev, sg_dma_address(s), |
| 1306 | 1306 | sg_dma_len(s)); |
| 1307 | − if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) | |
| 1307 | + if (!dev_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) | |
| 1308 | 1308 | arch_sync_dma_for_cpu(sg_phys(s), s->length, dir); |
| 1309 | 1309 | } |
| 1310 | 1310 | } |
| @@ -1323,7 +1323,7 @@ static void arm_iommu_sync_sg_for_cpu(struct device *dev, · 12 unmodified lines | ||
| 1323 | 1323 | struct scatterlist *s; |
| 1324 | 1324 | int i; |
| 1325 | 1325 | |
| 1326 | − if (dev->dma_coherent) | |
| 1326 | + if (dev_dma_coherent(dev)) | |
| 1327 | 1327 | return; |
| 1328 | 1328 | |
| 1329 | 1329 | for_each_sg(sg, s, nents, i) |
| @@ -1345,7 +1345,7 @@ static void arm_iommu_sync_sg_for_device(struct device *dev, · 15 unmodified lines | ||
| 1345 | 1345 | struct scatterlist *s; |
| 1346 | 1346 | int i; |
| 1347 | 1347 | |
| 1348 | − if (dev->dma_coherent) | |
| 1348 | + if (dev_dma_coherent(dev)) | |
| 1349 | 1349 | return; |
| 1350 | 1350 | |
| 1351 | 1351 | 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, · 19 unmodified lines | ||
| 1371 | 1371 | dma_addr_t dma_addr; |
| 1372 | 1372 | int ret, prot; |
| 1373 | 1373 | |
| 1374 | − if (!dev->dma_coherent && | |
| 1374 | + if (!dev_dma_coherent(dev) && | |
| 1375 | 1375 | !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) |
| 1376 | 1376 | arch_sync_dma_for_device(phys, size, dir); |
| 1377 | 1377 | |
| @@ -1412,7 +1412,7 @@ static void arm_iommu_unmap_phys(struct device *dev, dma_addr_t handle, · 34 unmodified lines | ||
| 1412 | 1412 | if (!iova) |
| 1413 | 1413 | return; |
| 1414 | 1414 | |
| 1415 | − if (!dev->dma_coherent && | |
| 1415 | + if (!dev_dma_coherent(dev) && | |
| 1416 | 1416 | !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) { |
| 1417 | 1417 | phys_addr_t phys = iommu_iova_to_phys(mapping->domain, iova); |
| 1418 | 1418 | |
| @@ -1431,7 +1431,7 @@ static void arm_iommu_sync_single_for_cpu(struct device *dev, · 12 unmodified lines | ||
| 1431 | 1431 | unsigned int offset = handle & ~PAGE_MASK; |
| 1432 | 1432 | phys_addr_t phys; |
| 1433 | 1433 | |
| 1434 | − if (dev->dma_coherent || !iova) | |
| 1434 | + if (dev_dma_coherent(dev) || !iova) | |
| 1435 | 1435 | return; |
| 1436 | 1436 | |
| 1437 | 1437 | phys = iommu_iova_to_phys(mapping->domain, iova); |
| @@ -1446,7 +1446,7 @@ static void arm_iommu_sync_single_for_device(struct device *dev, · 8 unmodified lines | ||
| 1446 | 1446 | unsigned int offset = handle & ~PAGE_MASK; |
| 1447 | 1447 | phys_addr_t phys; |
| 1448 | 1448 | |
| 1449 | − if (dev->dma_coherent || !iova) | |
| 1449 | + if (dev_dma_coherent(dev) || !iova) | |
| 1450 | 1450 | return; |
| 1451 | 1451 | |
| 1452 | 1452 | phys = iommu_iova_to_phys(mapping->domain, iova); |
| @@ -1701,13 +1701,13 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) { } · 248 unmodified lines | ||
| 1701 | 1701 | void arch_setup_dma_ops(struct device *dev, bool coherent) |
| 1702 | 1702 | { |
| 1703 | 1703 | /* |
| 1704 | − * Due to legacy code that sets the ->dma_coherent flag from a bus | |
| 1705 | − * notifier we can't just assign coherent to the ->dma_coherent flag | |
| 1704 | + * Due to legacy code that sets the dma_coherent flag from a bus | |
| 1705 | + * notifier we can't just assign coherent to the dma_coherent flag | |
| 1706 | 1706 | * here, but instead have to make sure we only set but never clear it |
| 1707 | 1707 | * for now. |
| 1708 | 1708 | */ |
| 1709 | 1709 | if (coherent) |
| 1710 | − dev->dma_coherent = true; | |
| 1710 | + dev_set_dma_coherent(dev); | |
| 1711 | 1711 | |
| 1712 | 1712 | /* |
| 1713 | 1713 | * Don't override the dma_ops if they have already been set. Ideally |
| @@ -4052,7 +4052,7 @@ static int enable_mismatched_32bit_el0(unsigned int cpu) · 4051 unmodified lines | ||
| 4052 | 4052 | */ |
| 4053 | 4053 | lucky_winner = cpu_32bit ? cpu : cpumask_any_and(cpu_32bit_el0_mask, |
| 4054 | 4054 | cpu_active_mask); |
| 4055 | − get_cpu_device(lucky_winner)->offline_disabled = true; | |
| 4055 | + dev_set_offline_disabled(get_cpu_device(lucky_winner)); | |
| 4056 | 4056 | setup_elf_hwcaps(compat_elf_hwcaps); |
| 4057 | 4057 | elf_hwcap_fixup(); |
| 4058 | 4058 | pr_info("Asymmetric 32-bit EL0 support detected on CPU %u; CPU hot-unplug disabled on CPU %u\n", |
| @@ -48,7 +48,7 @@ void arch_setup_dma_ops(struct device *dev, bool coherent) · 47 unmodified lines | ||
| 48 | 48 | dev_driver_string(dev), dev_name(dev), |
| 49 | 49 | ARCH_DMA_MINALIGN, cls); |
| 50 | 50 | |
| 51 | − dev->dma_coherent = coherent; | |
| 51 | + dev_assign_dma_coherent(dev, coherent); | |
| 52 | 52 | |
| 53 | 53 | xen_setup_dma_ops(dev); |
| 54 | 54 | } |
| @@ -23,7 +23,6 @@ extern void mips_mt_set_cpuoptions(void); · 22 unmodified lines | ||
| 23 | 23 | static inline void mips_mt_set_cpuoptions(void) { } |
| 24 | 24 | #endif |
| 25 | 25 | |
| 26 | −struct class; | |
| 27 | 26 | extern const struct class mt_class; |
| 28 | 27 | |
| 29 | 28 | #endif /* __ASM_MIPS_MT_H */ |
| @@ -139,6 +139,6 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, · 138 unmodified lines | ||
| 139 | 139 | #ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS |
| 140 | 140 | void arch_setup_dma_ops(struct device *dev, bool coherent) |
| 141 | 141 | { |
| 142 | − dev->dma_coherent = coherent; | |
| 142 | + dev_assign_dma_coherent(dev, coherent); | |
| 143 | 143 | } |
| 144 | 144 | #endif |
| @@ -67,7 +67,7 @@ bool arch_dma_unmap_sg_direct(struct device *dev, struct scatterlist *sg, · 66 unmodified lines | ||
| 67 | 67 | } |
| 68 | 68 | bool arch_dma_alloc_direct(struct device *dev) |
| 69 | 69 | { |
| 70 | − if (dev->dma_ops_bypass && dev->bus_dma_limit) | |
| 70 | + if (dev_dma_ops_bypass(dev) && dev->bus_dma_limit) | |
| 71 | 71 | return true; |
| 72 | 72 | |
| 73 | 73 | return false; |
| @@ -75,7 +75,7 @@ bool arch_dma_alloc_direct(struct device *dev) · 1 unmodified line | ||
| 75 | 75 | |
| 76 | 76 | bool arch_dma_free_direct(struct device *dev, dma_addr_t dma_handle) |
| 77 | 77 | { |
| 78 | − if (!dev->dma_ops_bypass || !dev->bus_dma_limit) | |
| 78 | + if (!dev_dma_ops_bypass(dev) || !dev->bus_dma_limit) | |
| 79 | 79 | return false; |
| 80 | 80 | |
| 81 | 81 | return is_direct_handle(dev, dma_handle); |
| @@ -164,7 +164,7 @@ int dma_iommu_dma_supported(struct device *dev, u64 mask) · 82 unmodified lines | ||
| 164 | 164 | * fixed ops will be used for RAM. This is limited by |
| 165 | 165 | * bus_dma_limit which is set when RAM is pre-mapped. |
| 166 | 166 | */ |
| 167 | − dev->dma_ops_bypass = true; | |
| 167 | + dev_set_dma_ops_bypass(dev); | |
| 168 | 168 | dev_info(dev, "iommu: 64-bit OK but direct DMA is limited by %llx\n", |
| 169 | 169 | dev->bus_dma_limit); |
| 170 | 170 | return 1; |
| @@ -185,7 +185,7 @@ int dma_iommu_dma_supported(struct device *dev, u64 mask) · 14 unmodified lines | ||
| 185 | 185 | } |
| 186 | 186 | |
| 187 | 187 | dev_dbg(dev, "iommu: not 64-bit, using default ops\n"); |
| 188 | − dev->dma_ops_bypass = false; | |
| 188 | + dev_clear_dma_ops_bypass(dev); | |
| 189 | 189 | return 1; |
| 190 | 190 | } |
| 191 | 191 | |
| @@ -213,9 +213,9 @@ static int dlpar_change_lmb_state(struct drmem_lmb *lmb, bool online) · 212 unmodified lines | ||
| 213 | 213 | return -EINVAL; |
| 214 | 214 | } |
| 215 | 215 | |
| 216 | − if (online && mem_block->dev.offline) | |
| 216 | + if (online && dev_offline(&mem_block->dev)) | |
| 217 | 217 | rc = device_online(&mem_block->dev); |
| 218 | − else if (!online && !mem_block->dev.offline) | |
| 218 | + else if (!online && !dev_offline(&mem_block->dev)) | |
| 219 | 219 | rc = device_offline(&mem_block->dev); |
| 220 | 220 | else |
| 221 | 221 | rc = 0; |
| @@ -140,7 +140,7 @@ void arch_setup_dma_ops(struct device *dev, bool coherent) · 139 unmodified lines | ||
| 140 | 140 | "%s %s: device non-coherent but no non-coherent operations supported", |
| 141 | 141 | dev_driver_string(dev), dev_name(dev)); |
| 142 | 142 | |
| 143 | − dev->dma_coherent = coherent; | |
| 143 | + dev_assign_dma_coherent(dev, coherent); | |
| 144 | 144 | } |
| 145 | 145 | |
| 146 | 146 | void riscv_noncoherent_supported(void) |
| @@ -898,9 +898,9 @@ const struct acpi_device *acpi_companion_match(const struct device *dev) · 897 unmodified lines | ||
| 898 | 898 | * identifiers and a _DSD object with the "compatible" property, use that |
| 899 | 899 | * property to match against the given list of identifiers. |
| 900 | 900 | */ |
| 901 | −static bool acpi_of_match_device(const struct acpi_device *adev, | |
| 902 | − const struct of_device_id *of_match_table, | |
| 903 | − const struct of_device_id **of_id) | |
| 901 | +bool acpi_of_match_device(const struct acpi_device *adev, | |
| 902 | + const struct of_device_id *of_match_table, | |
| 903 | + const struct of_device_id **of_id) | |
| 904 | 904 | { |
| 905 | 905 | const union acpi_object *of_compatible, *obj; |
| 906 | 906 | int i, nval; |
| @@ -122,7 +122,7 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) · 121 unmodified lines | ||
| 122 | 122 | mutex_lock_nested(&adev->physical_node_lock, SINGLE_DEPTH_NESTING); |
| 123 | 123 | |
| 124 | 124 | list_for_each_entry(pn, &adev->physical_node_list, node) |
| 125 | − if (device_supports_offline(pn->dev) && !pn->dev->offline) { | |
| 125 | + if (device_supports_offline(pn->dev) && !dev_offline(pn->dev)) { | |
| 126 | 126 | if (uevent) |
| 127 | 127 | kobject_uevent_env(&pn->dev->kobj, KOBJ_CHANGE, envp); |
| 128 | 128 | |
| @@ -82,33 +82,6 @@ static void amba_put_disable_pclk(struct amba_device *pcdev) · 81 unmodified lines | ||
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | |
| 85 | −static ssize_t driver_override_show(struct device *_dev, | |
| 86 | − struct device_attribute *attr, char *buf) | |
| 87 | −{ | |
| 88 | − struct amba_device *dev = to_amba_device(_dev); | |
| 89 | − ssize_t len; | |
| 90 | − | |
| 91 | − device_lock(_dev); | |
| 92 | − len = sprintf(buf, "%s\n", dev->driver_override); | |
| 93 | − device_unlock(_dev); | |
| 94 | − return len; | |
| 95 | −} | |
| 96 | − | |
| 97 | −static ssize_t driver_override_store(struct device *_dev, | |
| 98 | − struct device_attribute *attr, | |
| 99 | − const char *buf, size_t count) | |
| 100 | −{ | |
| 101 | − struct amba_device *dev = to_amba_device(_dev); | |
| 102 | − int ret; | |
| 103 | − | |
| 104 | − ret = driver_set_override(_dev, &dev->driver_override, buf, count); | |
| 105 | − if (ret) | |
| 106 | − return ret; | |
| 107 | − | |
| 108 | − return count; | |
| 109 | −} | |
| 110 | −static DEVICE_ATTR_RW(driver_override); | |
| 111 | − | |
| 112 | 85 | #define amba_attr_func(name,fmt,arg...) \ |
| 113 | 86 | static ssize_t name##_show(struct device *_dev, \ |
| 114 | 87 | struct device_attribute *attr, char *buf) \ |
| @@ -126,7 +99,6 @@ amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n", · 11 unmodified lines | ||
| 126 | 99 | static struct attribute *amba_dev_attrs[] = { |
| 127 | 100 | &dev_attr_id.attr, |
| 128 | 101 | &dev_attr_resource.attr, |
| 129 | − &dev_attr_driver_override.attr, | |
| 130 | 102 | NULL, |
| 131 | 103 | }; |
| 132 | 104 | ATTRIBUTE_GROUPS(amba_dev); |
| @@ -209,10 +181,11 @@ static int amba_match(struct device *dev, const struct device_driver *drv) · 76 unmodified lines | ||
| 209 | 181 | { |
| 210 | 182 | struct amba_device *pcdev = to_amba_device(dev); |
| 211 | 183 | const struct amba_driver *pcdrv = to_amba_driver(drv); |
| 184 | + int ret; | |
| 212 | 185 | |
| 213 | 186 | mutex_lock(&pcdev->periphid_lock); |
| 214 | 187 | if (!pcdev->periphid) { |
| 215 | − int ret = amba_read_periphid(pcdev); | |
| 188 | + ret = amba_read_periphid(pcdev); | |
| 216 | 189 | |
| 217 | 190 | /* |
| 218 | 191 | * 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) · 11 unmodified lines | ||
| 230 | 203 | mutex_unlock(&pcdev->periphid_lock); |
| 231 | 204 | |
| 232 | 205 | /* When driver_override is set, only bind to the matching driver */ |
| 233 | − if (pcdev->driver_override) | |
| 234 | − return !strcmp(pcdev->driver_override, drv->name); | |
| 206 | + ret = device_match_driver_override(dev, drv); | |
| 207 | + if (ret >= 0) | |
| 208 | + return ret; | |
| 235 | 209 | |
| 236 | 210 | return amba_lookup(pcdrv->id_table, pcdev) != NULL; |
| 237 | 211 | } |
| @@ -436,6 +410,7 @@ static const struct dev_pm_ops amba_pm = { · 198 unmodified lines | ||
| 436 | 410 | const struct bus_type amba_bustype = { |
| 437 | 411 | .name = "amba", |
| 438 | 412 | .dev_groups = amba_dev_groups, |
| 413 | + .driver_override = true, | |
| 439 | 414 | .match = amba_match, |
| 440 | 415 | .uevent = amba_uevent, |
| 441 | 416 | .probe = amba_probe, |
| @@ -86,18 +86,6 @@ struct driver_private { · 85 unmodified lines | ||
| 86 | 86 | }; |
| 87 | 87 | #define to_driver(obj) container_of(obj, struct driver_private, kobj) |
| 88 | 88 | |
| 89 | −#ifdef CONFIG_RUST | |
| 90 | −/** | |
| 91 | − * struct driver_type - Representation of a Rust driver type. | |
| 92 | − */ | |
| 93 | −struct driver_type { | |
| 94 | − /** | |
| 95 | − * @id: Representation of core::any::TypeId. | |
| 96 | − */ | |
| 97 | − u8 id[16]; | |
| 98 | −} __packed; | |
| 99 | −#endif | |
| 100 | − | |
| 101 | 89 | /** |
| 102 | 90 | * struct device_private - structure to hold the private to the driver core |
| 103 | 91 | * portions of the device structure. |
| @@ -115,7 +103,6 @@ struct driver_type { · 11 unmodified lines | ||
| 115 | 103 | * dev_err_probe() for later retrieval via debugfs |
| 116 | 104 | * @device: pointer back to the struct device that this structure is |
| 117 | 105 | * associated with. |
| 118 | − * @driver_type: The type of the bound Rust driver. | |
| 119 | 106 | * @dead: This device is currently either in the process of or has been |
| 120 | 107 | * removed from the system. Any asynchronous events scheduled for this |
| 121 | 108 | * device should exit without taking any action. |
| @@ -132,9 +119,6 @@ struct device_private { · 10 unmodified lines | ||
| 132 | 119 | const struct device_driver *async_driver; |
| 133 | 120 | char *deferred_probe_reason; |
| 134 | 121 | struct device *device; |
| 135 | −#ifdef CONFIG_RUST | |
| 136 | − struct driver_type driver_type; | |
| 137 | −#endif | |
| 138 | 122 | u8 dead:1; |
| 139 | 123 | }; |
| 140 | 124 | #define to_device_private_parent(obj) \ |
| @@ -188,6 +172,20 @@ static inline int driver_match_device(const struct device_driver *drv, · 47 unmodified lines | ||
| 188 | 172 | return drv->bus->match ? drv->bus->match(dev, drv) : 1; |
| 189 | 173 | } |
| 190 | 174 | |
| 175 | +static inline bool dev_has_sync_state(struct device *dev) | |
| 176 | +{ | |
| 177 | + struct device_driver *drv; | |
| 178 | + | |
| 179 | + if (!dev) | |
| 180 | + return false; | |
| 181 | + drv = READ_ONCE(dev->driver); | |
| 182 | + if (drv && drv->sync_state) | |
| 183 | + return true; | |
| 184 | + if (dev->bus && dev->bus->sync_state) | |
| 185 | + return true; | |
| 186 | + return false; | |
| 187 | +} | |
| 188 | + | |
| 191 | 189 | static inline void dev_sync_state(struct device *dev) |
| 192 | 190 | { |
| 193 | 191 | if (dev->bus->sync_state) |
| @@ -196,8 +194,10 @@ static inline void dev_sync_state(struct device *dev) · 2 unmodified lines | ||
| 196 | 194 | dev->driver->sync_state(dev); |
| 197 | 195 | } |
| 198 | 196 | |
| 199 | −int driver_add_groups(const struct device_driver *drv, const struct attribute_group **groups); | |
| 200 | −void driver_remove_groups(const struct device_driver *drv, const struct attribute_group **groups); | |
| 197 | +int driver_add_groups(const struct device_driver *drv, | |
| 198 | + const struct attribute_group *const *groups); | |
| 199 | +void driver_remove_groups(const struct device_driver *drv, | |
| 200 | + const struct attribute_group *const *groups); | |
| 201 | 201 | void device_driver_detach(struct device *dev); |
| 202 | 202 | |
| 203 | 203 | static inline void device_set_driver(struct device *dev, const struct device_driver *drv) |
| @@ -544,10 +544,10 @@ static const struct attribute_group driver_override_dev_group = { · 543 unmodified lines | ||
| 544 | 544 | */ |
| 545 | 545 | int bus_add_device(struct device *dev) |
| 546 | 546 | { |
| 547 | − struct subsys_private *sp = bus_to_subsys(dev->bus); | |
| 547 | + struct subsys_private *sp; | |
| 548 | 548 | int error; |
| 549 | 549 | |
| 550 | − if (!sp) { | |
| 550 | + if (!dev->bus) { | |
| 551 | 551 | /* |
| 552 | 552 | * This is a normal operation for many devices that do not |
| 553 | 553 | * have a bus assigned to them, just say that all went |
| @@ -556,6 +556,13 @@ int bus_add_device(struct device *dev) · 2 unmodified lines | ||
| 556 | 556 | return 0; |
| 557 | 557 | } |
| 558 | 558 | |
| 559 | + sp = bus_to_subsys(dev->bus); | |
| 560 | + if (!sp) { | |
| 561 | + pr_err("%s: cannot add device '%s' to unregistered bus '%s'\n", | |
| 562 | + __func__, dev_name(dev), dev->bus->name); | |
| 563 | + return -EINVAL; | |
| 564 | + } | |
| 565 | + | |
| 559 | 566 | /* |
| 560 | 567 | * Reference in sp is now incremented and will be dropped when |
| 561 | 568 | * the device is removed from the bus |
| @@ -235,6 +235,79 @@ static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode, · 234 unmodified lines | ||
| 235 | 235 | __fw_devlink_pickup_dangling_consumers(child, new_sup); |
| 236 | 236 | } |
| 237 | 237 | |
| 238 | +static void fw_devlink_pickup_dangling_consumers(struct device *dev) | |
| 239 | +{ | |
| 240 | + struct fwnode_handle *child; | |
| 241 | + | |
| 242 | + guard(mutex)(&fwnode_link_lock); | |
| 243 | + | |
| 244 | + fwnode_for_each_available_child_node(dev->fwnode, child) | |
| 245 | + __fw_devlink_pickup_dangling_consumers(child, dev->fwnode); | |
| 246 | + __fw_devlink_link_to_consumers(dev); | |
| 247 | +} | |
| 248 | + | |
| 249 | +/** | |
| 250 | + * fw_devlink_refresh_fwnode - Recheck the tree under this firmware node | |
| 251 | + * @fwnode: The fwnode under which the fwnode tree has changed | |
| 252 | + * | |
| 253 | + * This function is mainly meant to adjust the supplier/consumer dependencies | |
| 254 | + * after a fwnode tree overlay has occurred. | |
| 255 | + */ | |
| 256 | +void fw_devlink_refresh_fwnode(struct fwnode_handle *fwnode) | |
| 257 | +{ | |
| 258 | + struct device *dev; | |
| 259 | + | |
| 260 | + /* | |
| 261 | + * Find the closest ancestor fwnode that has been converted to a device | |
| 262 | + * that can bind to a driver (bus device). | |
| 263 | + */ | |
| 264 | + fwnode_handle_get(fwnode); | |
| 265 | + do { | |
| 266 | + if (fwnode_test_flag(fwnode, FWNODE_FLAG_NOT_DEVICE)) | |
| 267 | + continue; | |
| 268 | + | |
| 269 | + dev = get_dev_from_fwnode(fwnode); | |
| 270 | + if (!dev) | |
| 271 | + continue; | |
| 272 | + | |
| 273 | + if (dev->bus) | |
| 274 | + break; | |
| 275 | + | |
| 276 | + put_device(dev); | |
| 277 | + } while ((fwnode = fwnode_get_next_parent(fwnode))); | |
| 278 | + | |
| 279 | + /* | |
| 280 | + * If none of the ancestor fwnodes have (yet) been converted to a device | |
| 281 | + * that can bind to a driver, there's nothing to fix up. | |
| 282 | + */ | |
| 283 | + if (!fwnode) | |
| 284 | + return; | |
| 285 | + | |
| 286 | + WARN(device_is_bound(dev) && dev->links.status != DL_DEV_DRIVER_BOUND, | |
| 287 | + "Don't multithread overlaying and probing the same device!\n"); | |
| 288 | + | |
| 289 | + /* | |
| 290 | + * If the device has already bound to a driver, then we need to redo | |
| 291 | + * some of the work that was done after the device was bound to a | |
| 292 | + * driver. If the device hasn't bound to a driver, running things too | |
| 293 | + * soon would incorrectly pick up consumers that it shouldn't. | |
| 294 | + */ | |
| 295 | + if (dev->links.status == DL_DEV_DRIVER_BOUND) { | |
| 296 | + fw_devlink_pickup_dangling_consumers(dev); | |
| 297 | + /* | |
| 298 | + * Some of dangling consumers could have been put previously in | |
| 299 | + * the deferred probe list due to the unavailability of their | |
| 300 | + * suppliers. Those consumers have been picked up and some of | |
| 301 | + * their suppliers links have been updated. Time to re-try their | |
| 302 | + * probe sequence. | |
| 303 | + */ | |
| 304 | + driver_deferred_probe_trigger(); | |
| 305 | + } | |
| 306 | + | |
| 307 | + put_device(dev); | |
| 308 | + fwnode_handle_put(fwnode); | |
| 309 | +} | |
| 310 | + | |
| 238 | 311 | static DEFINE_MUTEX(device_links_lock); |
| 239 | 312 | DEFINE_STATIC_SRCU(device_links_srcu); |
| 240 | 313 | |
| @@ -422,7 +495,7 @@ void device_pm_move_to_tail(struct device *dev) · 181 unmodified lines | ||
| 422 | 495 | #define to_devlink(dev) container_of((dev), struct device_link, link_dev) |
| 423 | 496 | |
| 424 | 497 | static ssize_t status_show(struct device *dev, |
| 425 | − struct device_attribute *attr, char *buf) | |
| 498 | + const struct device_attribute *attr, char *buf) | |
| 426 | 499 | { |
| 427 | 500 | const char *output; |
| 428 | 501 | |
| @@ -452,10 +525,10 @@ static ssize_t status_show(struct device *dev, · 23 unmodified lines | ||
| 452 | 525 | |
| 453 | 526 | return sysfs_emit(buf, "%s\n", output); |
| 454 | 527 | } |
| 455 | −static DEVICE_ATTR_RO(status); | |
| 528 | +static const DEVICE_ATTR_RO(status); | |
| 456 | 529 | |
| 457 | 530 | static ssize_t auto_remove_on_show(struct device *dev, |
| 458 | − struct device_attribute *attr, char *buf) | |
| 531 | + const struct device_attribute *attr, char *buf) | |
| 459 | 532 | { |
| 460 | 533 | struct device_link *link = to_devlink(dev); |
| 461 | 534 | const char *output; |
| @@ -469,27 +542,27 @@ static ssize_t auto_remove_on_show(struct device *dev, · 7 unmodified lines | ||
| 469 | 542 | |
| 470 | 543 | return sysfs_emit(buf, "%s\n", output); |
| 471 | 544 | } |
| 472 | −static DEVICE_ATTR_RO(auto_remove_on); | |
| 545 | +static const DEVICE_ATTR_RO(auto_remove_on); | |
| 473 | 546 | |
| 474 | 547 | static ssize_t runtime_pm_show(struct device *dev, |
| 475 | − struct device_attribute *attr, char *buf) | |
| 548 | + const struct device_attribute *attr, char *buf) | |
| 476 | 549 | { |
| 477 | 550 | struct device_link *link = to_devlink(dev); |
| 478 | 551 | |
| 479 | 552 | return sysfs_emit(buf, "%d\n", device_link_test(link, DL_FLAG_PM_RUNTIME)); |
| 480 | 553 | } |
| 481 | −static DEVICE_ATTR_RO(runtime_pm); | |
| 554 | +static const DEVICE_ATTR_RO(runtime_pm); | |
| 482 | 555 | |
| 483 | 556 | static ssize_t sync_state_only_show(struct device *dev, |
| 484 | − struct device_attribute *attr, char *buf) | |
| 557 | + const struct device_attribute *attr, char *buf) | |
| 485 | 558 | { |
| 486 | 559 | struct device_link *link = to_devlink(dev); |
| 487 | 560 | |
| 488 | 561 | return sysfs_emit(buf, "%d\n", device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); |
| 489 | 562 | } |
| 490 | −static DEVICE_ATTR_RO(sync_state_only); | |
| 563 | +static const DEVICE_ATTR_RO(sync_state_only); | |
| 491 | 564 | |
| 492 | −static struct attribute *devlink_attrs[] = { | |
| 565 | +static const struct attribute *const devlink_attrs[] = { | |
| 493 | 566 | &dev_attr_status.attr, |
| 494 | 567 | &dev_attr_auto_remove_on.attr, |
| 495 | 568 | &dev_attr_runtime_pm.attr, |
| @@ -1011,7 +1084,7 @@ static void device_links_missing_supplier(struct device *dev) · 515 unmodified lines | ||
| 1011 | 1084 | |
| 1012 | 1085 | static bool dev_is_best_effort(struct device *dev) |
| 1013 | 1086 | { |
| 1014 | − return (fw_devlink_best_effort && dev->can_match) || | |
| 1087 | + return (fw_devlink_best_effort && dev_can_match(dev)) || | |
| 1015 | 1088 | (dev->fwnode && fwnode_test_flag(dev->fwnode, FWNODE_FLAG_BEST_EFFORT)); |
| 1016 | 1089 | } |
| 1017 | 1090 | |
| @@ -1079,7 +1152,7 @@ int device_links_check_suppliers(struct device *dev) · 61 unmodified lines | ||
| 1079 | 1152 | |
| 1080 | 1153 | if (dev_is_best_effort(dev) && |
| 1081 | 1154 | device_link_test(link, DL_FLAG_INFERRED) && |
| 1082 | − !link->supplier->can_match) { | |
| 1155 | + !dev_can_match(link->supplier)) { | |
| 1083 | 1156 | ret = -EAGAIN; |
| 1084 | 1157 | continue; |
| 1085 | 1158 | } |
| @@ -1123,7 +1196,7 @@ static void __device_links_queue_sync_state(struct device *dev, · 37 unmodified lines | ||
| 1123 | 1196 | |
| 1124 | 1197 | if (!dev_has_sync_state(dev)) |
| 1125 | 1198 | return; |
| 1126 | − if (dev->state_synced) | |
| 1199 | + if (dev_state_synced(dev)) | |
| 1127 | 1200 | return; |
| 1128 | 1201 | |
| 1129 | 1202 | list_for_each_entry(link, &dev->links.consumers, s_node) { |
| @@ -1138,7 +1211,7 @@ static void __device_links_queue_sync_state(struct device *dev, · 8 unmodified lines | ||
| 1138 | 1211 | * than once. This can happen if new consumers get added to the device |
| 1139 | 1212 | * and probed before the list is flushed. |
| 1140 | 1213 | */ |
| 1141 | − dev->state_synced = true; | |
| 1214 | + dev_set_state_synced(dev); | |
| 1142 | 1215 | |
| 1143 | 1216 | if (WARN_ON(!list_empty(&dev->links.defer_sync))) |
| 1144 | 1217 | return; |
| @@ -1233,7 +1306,7 @@ static void device_link_drop_managed(struct device_link *link) · 88 unmodified lines | ||
| 1233 | 1306 | } |
| 1234 | 1307 | |
| 1235 | 1308 | static ssize_t waiting_for_supplier_show(struct device *dev, |
| 1236 | − struct device_attribute *attr, | |
| 1309 | + const struct device_attribute *attr, | |
| 1237 | 1310 | char *buf) |
| 1238 | 1311 | { |
| 1239 | 1312 | bool val; |
| @@ -1244,7 +1317,7 @@ static ssize_t waiting_for_supplier_show(struct device *dev, · 4 unmodified lines | ||
| 1244 | 1317 | device_unlock(dev); |
| 1245 | 1318 | return sysfs_emit(buf, "%u\n", val); |
| 1246 | 1319 | } |
| 1247 | −static DEVICE_ATTR_RO(waiting_for_supplier); | |
| 1320 | +static const DEVICE_ATTR_RO(waiting_for_supplier); | |
| 1248 | 1321 | |
| 1249 | 1322 | /** |
| 1250 | 1323 | * device_links_force_bind - Prepares device to be force bound |
| @@ -1312,16 +1385,8 @@ void device_links_driver_bound(struct device *dev) · 61 unmodified lines | ||
| 1312 | 1385 | * child firmware node. |
| 1313 | 1386 | */ |
| 1314 | 1387 | if (dev->fwnode && dev->fwnode->dev == dev) { |
| 1315 | − struct fwnode_handle *child; | |
| 1316 | − | |
| 1317 | 1388 | fwnode_links_purge_suppliers(dev->fwnode); |
| 1318 | − | |
| 1319 | − guard(mutex)(&fwnode_link_lock); | |
| 1320 | − | |
| 1321 | − fwnode_for_each_available_child_node(dev->fwnode, child) | |
| 1322 | − __fw_devlink_pickup_dangling_consumers(child, | |
| 1323 | − dev->fwnode); | |
| 1324 | − __fw_devlink_link_to_consumers(dev); | |
| 1389 | + fw_devlink_pickup_dangling_consumers(dev); | |
| 1325 | 1390 | } |
| 1326 | 1391 | device_remove_file(dev, &dev_attr_waiting_for_supplier); |
| 1327 | 1392 | |
| @@ -1370,7 +1435,7 @@ void device_links_driver_bound(struct device *dev) · 42 unmodified lines | ||
| 1370 | 1435 | } else if (dev_is_best_effort(dev) && |
| 1371 | 1436 | device_link_test(link, DL_FLAG_INFERRED) && |
| 1372 | 1437 | link->status != DL_STATE_CONSUMER_PROBE && |
| 1373 | − !link->supplier->can_match) { | |
| 1438 | + !dev_can_match(link->supplier)) { | |
| 1374 | 1439 | /* |
| 1375 | 1440 | * When dev_is_best_effort() is true, we ignore device |
| 1376 | 1441 | * links to suppliers that don't have a driver. If the |
| @@ -1435,7 +1500,8 @@ static void __device_links_no_driver(struct device *dev) · 58 unmodified lines | ||
| 1435 | 1500 | if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) { |
| 1436 | 1501 | WRITE_ONCE(link->status, DL_STATE_AVAILABLE); |
| 1437 | 1502 | } else { |
| 1438 | − WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); | |
| 1503 | + WARN_ON(link->supplier->links.status != DL_DEV_UNBINDING && | |
| 1504 | + !device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); | |
| 1439 | 1505 | WRITE_ONCE(link->status, DL_STATE_DORMANT); |
| 1440 | 1506 | } |
| 1441 | 1507 | } |
| @@ -1758,7 +1824,7 @@ static int fw_devlink_no_driver(struct device *dev, void *data) · 316 unmodified lines | ||
| 1758 | 1824 | { |
| 1759 | 1825 | struct device_link *link = to_devlink(dev); |
| 1760 | 1826 | |
| 1761 | − if (!link->supplier->can_match) | |
| 1827 | + if (!dev_can_match(link->supplier)) | |
| 1762 | 1828 | fw_devlink_relax_link(link); |
| 1763 | 1829 | |
| 1764 | 1830 | return 0; |
| @@ -1779,7 +1845,7 @@ static int fw_devlink_dev_sync_state(struct device *dev, void *data) · 14 unmodified lines | ||
| 1779 | 1845 | struct device *sup = link->supplier; |
| 1780 | 1846 | |
| 1781 | 1847 | if (!device_link_test(link, DL_FLAG_MANAGED) || |
| 1782 | − link->status == DL_STATE_ACTIVE || sup->state_synced || | |
| 1848 | + link->status == DL_STATE_ACTIVE || dev_state_synced(sup) || | |
| 1783 | 1849 | !dev_has_sync_state(sup)) |
| 1784 | 1850 | return 0; |
| 1785 | 1851 | |
| @@ -1793,7 +1859,7 @@ static int fw_devlink_dev_sync_state(struct device *dev, void *data) · 7 unmodified lines | ||
| 1793 | 1859 | return 0; |
| 1794 | 1860 | |
| 1795 | 1861 | dev_warn(sup, "Timed out. Forcing sync_state()\n"); |
| 1796 | − sup->state_synced = true; | |
| 1862 | + dev_set_state_synced(sup); | |
| 1797 | 1863 | get_device(sup); |
| 1798 | 1864 | list_add_tail(&sup->links.defer_sync, data); |
| 1799 | 1865 | |
| @@ -2419,9 +2485,11 @@ static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, · 619 unmodified lines | ||
| 2419 | 2485 | |
| 2420 | 2486 | if (dev_attr->show) |
| 2421 | 2487 | ret = dev_attr->show(dev, dev_attr, buf); |
| 2488 | + else if (dev_attr->show_const) | |
| 2489 | + ret = dev_attr->show_const(dev, dev_attr, buf); | |
| 2422 | 2490 | if (ret >= (ssize_t)PAGE_SIZE) { |
| 2423 | − printk("dev_attr_show: %pS returned bad count\n", | |
| 2424 | − dev_attr->show); | |
| 2491 | + printk("dev_attr_show: %pS/%pS returned bad count\n", | |
| 2492 | + dev_attr->show, dev_attr->show_const); | |
| 2425 | 2493 | } |
| 2426 | 2494 | return ret; |
| 2427 | 2495 | } |
| @@ -2435,6 +2503,8 @@ static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, · 7 unmodified lines | ||
| 2435 | 2503 | |
| 2436 | 2504 | if (dev_attr->store) |
| 2437 | 2505 | ret = dev_attr->store(dev, dev_attr, buf, count); |
| 2506 | + else if (dev_attr->store_const) | |
| 2507 | + ret = dev_attr->store_const(dev, dev_attr, buf, count); | |
| 2438 | 2508 | return ret; |
| 2439 | 2509 | } |
| 2440 | 2510 | |
| @@ -2722,7 +2792,7 @@ static const struct kset_uevent_ops device_uevent_ops = { · 281 unmodified lines | ||
| 2722 | 2792 | .uevent = dev_uevent, |
| 2723 | 2793 | }; |
| 2724 | 2794 | |
| 2725 | −static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, | |
| 2795 | +static ssize_t uevent_show(struct device *dev, const struct device_attribute *attr, | |
| 2726 | 2796 | char *buf) |
| 2727 | 2797 | { |
| 2728 | 2798 | struct kobject *top_kobj; |
| @@ -2765,7 +2835,7 @@ out: · 36 unmodified lines | ||
| 2765 | 2835 | return len; |
| 2766 | 2836 | } |
| 2767 | 2837 | |
| 2768 | −static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, | |
| 2838 | +static ssize_t uevent_store(struct device *dev, const struct device_attribute *attr, | |
| 2769 | 2839 | const char *buf, size_t count) |
| 2770 | 2840 | { |
| 2771 | 2841 | int rc; |
| @@ -2779,20 +2849,20 @@ static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, · 7 unmodified lines | ||
| 2779 | 2849 | |
| 2780 | 2850 | return count; |
| 2781 | 2851 | } |
| 2782 | −static DEVICE_ATTR_RW(uevent); | |
| 2852 | +static const DEVICE_ATTR_RW(uevent); | |
| 2783 | 2853 | |
| 2784 | −static ssize_t online_show(struct device *dev, struct device_attribute *attr, | |
| 2854 | +static ssize_t online_show(struct device *dev, const struct device_attribute *attr, | |
| 2785 | 2855 | char *buf) |
| 2786 | 2856 | { |
| 2787 | 2857 | bool val; |
| 2788 | 2858 | |
| 2789 | 2859 | device_lock(dev); |
| 2790 | − val = !dev->offline; | |
| 2860 | + val = !dev_offline(dev); | |
| 2791 | 2861 | device_unlock(dev); |
| 2792 | 2862 | return sysfs_emit(buf, "%u\n", val); |
| 2793 | 2863 | } |
| 2794 | 2864 | |
| 2795 | −static ssize_t online_store(struct device *dev, struct device_attribute *attr, | |
| 2865 | +static ssize_t online_store(struct device *dev, const struct device_attribute *attr, | |
| 2796 | 2866 | const char *buf, size_t count) |
| 2797 | 2867 | { |
| 2798 | 2868 | bool val; |
| @@ -2810,9 +2880,9 @@ static ssize_t online_store(struct device *dev, struct device_attribute *attr, · 11 unmodified lines | ||
| 2810 | 2880 | unlock_device_hotplug(); |
| 2811 | 2881 | return ret < 0 ? ret : count; |
| 2812 | 2882 | } |
| 2813 | −static DEVICE_ATTR_RW(online); | |
| 2883 | +static const DEVICE_ATTR_RW(online); | |
| 2814 | 2884 | |
| 2815 | −static ssize_t removable_show(struct device *dev, struct device_attribute *attr, | |
| 2885 | +static ssize_t removable_show(struct device *dev, const struct device_attribute *attr, | |
| 2816 | 2886 | char *buf) |
| 2817 | 2887 | { |
| 2818 | 2888 | const char *loc; |
| @@ -2829,7 +2899,7 @@ static ssize_t removable_show(struct device *dev, struct device_attribute *attr, · 10 unmodified lines | ||
| 2829 | 2899 | } |
| 2830 | 2900 | return sysfs_emit(buf, "%s\n", loc); |
| 2831 | 2901 | } |
| 2832 | −static DEVICE_ATTR_RO(removable); | |
| 2902 | +static const DEVICE_ATTR_RO(removable); | |
| 2833 | 2903 | |
| 2834 | 2904 | int device_add_groups(struct device *dev, |
| 2835 | 2905 | const struct attribute_group *const *groups) |
| @@ -2913,7 +2983,7 @@ static int device_add_attrs(struct device *dev) · 77 unmodified lines | ||
| 2913 | 2983 | if (error) |
| 2914 | 2984 | goto err_remove_type_groups; |
| 2915 | 2985 | |
| 2916 | − if (device_supports_offline(dev) && !dev->offline_disabled) { | |
| 2986 | + if (device_supports_offline(dev) && !dev_offline_disabled(dev)) { | |
| 2917 | 2987 | error = device_create_file(dev, &dev_attr_online); |
| 2918 | 2988 | if (error) |
| 2919 | 2989 | goto err_remove_dev_groups; |
| @@ -2980,12 +3050,12 @@ static void device_remove_attrs(struct device *dev) · 60 unmodified lines | ||
| 2980 | 3050 | device_remove_groups(dev, class->dev_groups); |
| 2981 | 3051 | } |
| 2982 | 3052 | |
| 2983 | −static ssize_t dev_show(struct device *dev, struct device_attribute *attr, | |
| 3053 | +static ssize_t dev_show(struct device *dev, const struct device_attribute *attr, | |
| 2984 | 3054 | char *buf) |
| 2985 | 3055 | { |
| 2986 | 3056 | return print_dev_t(buf, dev->devt); |
| 2987 | 3057 | } |
| 2988 | −static DEVICE_ATTR_RO(dev); | |
| 3058 | +static const DEVICE_ATTR_RO(dev); | |
| 2989 | 3059 | |
| 2990 | 3060 | /* /sys/devices/ */ |
| 2991 | 3061 | struct kset *devices_kset; |
| @@ -3047,10 +3117,10 @@ int device_create_file(struct device *dev, · 55 unmodified lines | ||
| 3047 | 3117 | int error = 0; |
| 3048 | 3118 | |
| 3049 | 3119 | if (dev) { |
| 3050 | − WARN(((attr->attr.mode & S_IWUGO) && !attr->store), | |
| 3120 | + WARN(((attr->attr.mode & S_IWUGO) && !(attr->store || attr->store_const)), | |
| 3051 | 3121 | "Attribute %s: write permission without 'store'\n", |
| 3052 | 3122 | attr->attr.name); |
| 3053 | − WARN(((attr->attr.mode & S_IRUGO) && !attr->show), | |
| 3123 | + WARN(((attr->attr.mode & S_IRUGO) && !(attr->show || attr->show_const)), | |
| 3054 | 3124 | "Attribute %s: read permission without 'show'\n", |
| 3055 | 3125 | attr->attr.name); |
| 3056 | 3126 | error = sysfs_create_file(&dev->kobj, &attr->attr); |
| @@ -3170,11 +3240,7 @@ void device_initialize(struct device *dev) · 113 unmodified lines | ||
| 3170 | 3240 | INIT_LIST_HEAD(&dev->links.suppliers); |
| 3171 | 3241 | INIT_LIST_HEAD(&dev->links.defer_sync); |
| 3172 | 3242 | dev->links.status = DL_DEV_NO_DRIVER; |
| 3173 | −#if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ | |
| 3174 | − defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \ | |
| 3175 | − defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) | |
| 3176 | − dev->dma_coherent = dma_default_coherent; | |
| 3177 | −#endif | |
| 3243 | + dev_assign_dma_coherent(dev, dma_default_coherent); | |
| 3178 | 3244 | swiotlb_dev_init(dev); |
| 3179 | 3245 | } |
| 3180 | 3246 | EXPORT_SYMBOL_GPL(device_initialize); |
| @@ -3710,7 +3776,7 @@ int device_add(struct device *dev) · 529 unmodified lines | ||
| 3710 | 3776 | * match with any driver, don't block its consumers from probing in |
| 3711 | 3777 | * case the consumer device is able to operate without this supplier. |
| 3712 | 3778 | */ |
| 3713 | − if (dev->fwnode && fw_devlink_drv_reg_done && !dev->can_match) | |
| 3779 | + if (dev->fwnode && fw_devlink_drv_reg_done && !dev_can_match(dev)) | |
| 3714 | 3780 | fw_devlink_unblock_consumers(dev); |
| 3715 | 3781 | |
| 3716 | 3782 | if (parent) |
| @@ -4180,7 +4246,7 @@ static int device_check_offline(struct device *dev, void *not_used) · 463 unmodified lines | ||
| 4180 | 4246 | if (ret) |
| 4181 | 4247 | return ret; |
| 4182 | 4248 | |
| 4183 | − return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0; | |
| 4249 | + return device_supports_offline(dev) && !dev_offline(dev) ? -EBUSY : 0; | |
| 4184 | 4250 | } |
| 4185 | 4251 | |
| 4186 | 4252 | /** |
| @@ -4198,7 +4264,7 @@ int device_offline(struct device *dev) · 11 unmodified lines | ||
| 4198 | 4264 | { |
| 4199 | 4265 | int ret; |
| 4200 | 4266 | |
| 4201 | − if (dev->offline_disabled) | |
| 4267 | + if (dev_offline_disabled(dev)) | |
| 4202 | 4268 | return -EPERM; |
| 4203 | 4269 | |
| 4204 | 4270 | ret = device_for_each_child(dev, NULL, device_check_offline); |
| @@ -4207,13 +4273,13 @@ int device_offline(struct device *dev) · 2 unmodified lines | ||
| 4207 | 4273 | |
| 4208 | 4274 | device_lock(dev); |
| 4209 | 4275 | if (device_supports_offline(dev)) { |
| 4210 | − if (dev->offline) { | |
| 4276 | + if (dev_offline(dev)) { | |
| 4211 | 4277 | ret = 1; |
| 4212 | 4278 | } else { |
| 4213 | 4279 | ret = dev->bus->offline(dev); |
| 4214 | 4280 | if (!ret) { |
| 4215 | 4281 | kobject_uevent(&dev->kobj, KOBJ_OFFLINE); |
| 4216 | − dev->offline = true; | |
| 4282 | + dev_set_offline(dev); | |
| 4217 | 4283 | } |
| 4218 | 4284 | } |
| 4219 | 4285 | } |
| @@ -4238,11 +4304,11 @@ int device_online(struct device *dev) · 18 unmodified lines | ||
| 4238 | 4304 | |
| 4239 | 4305 | device_lock(dev); |
| 4240 | 4306 | if (device_supports_offline(dev)) { |
| 4241 | − if (dev->offline) { | |
| 4307 | + if (dev_offline(dev)) { | |
| 4242 | 4308 | ret = dev->bus->online(dev); |
| 4243 | 4309 | if (!ret) { |
| 4244 | 4310 | kobject_uevent(&dev->kobj, KOBJ_ONLINE); |
| 4245 | − dev->offline = false; | |
| 4311 | + dev_clear_offline(dev); | |
| 4246 | 4312 | } |
| 4247 | 4313 | } else { |
| 4248 | 4314 | ret = 1; |
| @@ -4716,7 +4782,7 @@ static int device_attrs_change_owner(struct device *dev, kuid_t kuid, · 467 unmodified lines | ||
| 4716 | 4782 | if (error) |
| 4717 | 4783 | return error; |
| 4718 | 4784 | |
| 4719 | − if (device_supports_offline(dev) && !dev->offline_disabled) { | |
| 4785 | + if (device_supports_offline(dev) && !dev_offline_disabled(dev)) { | |
| 4720 | 4786 | /* Change online device attributes of @dev to @kuid/@kgid. */ |
| 4721 | 4787 | error = sysfs_file_change_owner(kobj, dev_attr_online.attr.name, |
| 4722 | 4788 | kuid, kgid); |
| @@ -5283,7 +5349,7 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2) · 560 unmodified lines | ||
| 5283 | 5349 | { |
| 5284 | 5350 | of_node_put(dev->of_node); |
| 5285 | 5351 | dev->of_node = of_node_get(dev2->of_node); |
| 5286 | − dev->of_node_reused = true; | |
| 5352 | + dev_set_of_node_reused(dev); | |
| 5287 | 5353 | } |
| 5288 | 5354 | EXPORT_SYMBOL_GPL(device_set_of_node_from_dev); |
| 5289 | 5355 | |
| @@ -422,8 +422,8 @@ int register_cpu(struct cpu *cpu, int num) · 421 unmodified lines | ||
| 422 | 422 | cpu->dev.id = num; |
| 423 | 423 | cpu->dev.bus = &cpu_subsys; |
| 424 | 424 | cpu->dev.release = cpu_device_release; |
| 425 | − cpu->dev.offline_disabled = !cpu->hotpluggable; | |
| 426 | − cpu->dev.offline = !cpu_online(num); | |
| 425 | + dev_assign_offline_disabled(&cpu->dev, !cpu->hotpluggable); | |
| 426 | + dev_assign_offline(&cpu->dev, !cpu_online(num)); | |
| 427 | 427 | cpu->dev.of_node = of_get_cpu_node(num, NULL); |
| 428 | 428 | cpu->dev.groups = common_cpu_attr_groups; |
| 429 | 429 | if (cpu->hotpluggable) |
| @@ -132,7 +132,7 @@ static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func); · 131 unmodified lines | ||
| 132 | 132 | |
| 133 | 133 | void driver_deferred_probe_add(struct device *dev) |
| 134 | 134 | { |
| 135 | − if (!dev->can_match) | |
| 135 | + if (!dev_can_match(dev)) | |
| 136 | 136 | return; |
| 137 | 137 | |
| 138 | 138 | mutex_lock(&deferred_probe_mutex); |
| @@ -323,12 +323,11 @@ void deferred_probe_extend_timeout(void) · 184 unmodified lines | ||
| 323 | 323 | * If the work hasn't been queued yet or if the work expired, don't |
| 324 | 324 | * start a new one. |
| 325 | 325 | */ |
| 326 | − if (cancel_delayed_work(&deferred_probe_timeout_work)) { | |
| 327 | − schedule_delayed_work(&deferred_probe_timeout_work, | |
| 328 | − driver_deferred_probe_timeout * HZ); | |
| 326 | + if (delayed_work_pending(&deferred_probe_timeout_work) && | |
| 327 | + mod_delayed_work(system_percpu_wq, &deferred_probe_timeout_work, | |
| 328 | + secs_to_jiffies(driver_deferred_probe_timeout))) | |
| 329 | 329 | pr_debug("Extended deferred probe timeout by %d secs\n", |
| 330 | 330 | driver_deferred_probe_timeout); |
| 331 | − } | |
| 332 | 331 | } |
| 333 | 332 | |
| 334 | 333 | /** |
| @@ -569,12 +568,10 @@ static ssize_t state_synced_store(struct device *dev, · 234 unmodified lines | ||
| 569 | 568 | return -EINVAL; |
| 570 | 569 | |
| 571 | 570 | device_lock(dev); |
| 572 | − if (!dev->state_synced) { | |
| 573 | − dev->state_synced = true; | |
| 571 | + if (!dev_test_and_set_state_synced(dev)) | |
| 574 | 572 | dev_sync_state(dev); |
| 575 | − } else { | |
| 573 | + else | |
| 576 | 574 | ret = -EINVAL; |
| 577 | − } | |
| 578 | 575 | device_unlock(dev); |
| 579 | 576 | |
| 580 | 577 | return ret ? ret : count; |
| @@ -586,7 +583,7 @@ static ssize_t state_synced_show(struct device *dev, · 5 unmodified lines | ||
| 586 | 583 | bool val; |
| 587 | 584 | |
| 588 | 585 | device_lock(dev); |
| 589 | − val = dev->state_synced; | |
| 586 | + val = dev_state_synced(dev); | |
| 590 | 587 | device_unlock(dev); |
| 591 | 588 | |
| 592 | 589 | return sysfs_emit(buf, "%u\n", val); |
| @@ -595,9 +592,9 @@ static DEVICE_ATTR_RW(state_synced); · 2 unmodified lines | ||
| 595 | 592 | |
| 596 | 593 | static void device_unbind_cleanup(struct device *dev) |
| 597 | 594 | { |
| 598 | − devres_release_all(dev); | |
| 599 | 595 | if (dev->driver->p_cb.post_unbind_rust) |
| 600 | 596 | dev->driver->p_cb.post_unbind_rust(dev); |
| 597 | + devres_release_all(dev); | |
| 601 | 598 | arch_teardown_dma_ops(dev); |
| 602 | 599 | kfree(dev->dma_range_map); |
| 603 | 600 | dev->dma_range_map = NULL; |
| @@ -849,14 +846,14 @@ static int __driver_probe_device(const struct device_driver *drv, struct device · 245 unmodified lines | ||
| 849 | 846 | return dev_err_probe(dev, -EPROBE_DEFER, "Device not ready to probe\n"); |
| 850 | 847 | |
| 851 | 848 | /* |
| 852 | − * Set can_match = true after calling dev_ready_to_probe(), so | |
| 849 | + * Call dev_set_can_match() after calling dev_ready_to_probe(), so | |
| 853 | 850 | * driver_deferred_probe_add() won't actually add the device to the |
| 854 | 851 | * deferred probe list when dev_ready_to_probe() returns false. |
| 855 | 852 | * |
| 856 | 853 | * When dev_ready_to_probe() returns false, it means that device_add() |
| 857 | 854 | * will do another probe() attempt for us. |
| 858 | 855 | */ |
| 859 | − dev->can_match = true; | |
| 856 | + dev_set_can_match(dev); | |
| 860 | 857 | dev_dbg(dev, "bus: '%s': %s: matched device with driver %s\n", |
| 861 | 858 | drv->bus->name, __func__, drv->name); |
| 862 | 859 | |
| @@ -1002,7 +999,7 @@ static int __device_attach_driver(struct device_driver *drv, void *_data) · 139 unmodified lines | ||
| 1002 | 999 | return 0; |
| 1003 | 1000 | } else if (ret == -EPROBE_DEFER) { |
| 1004 | 1001 | dev_dbg(dev, "Device match requests probe deferral\n"); |
| 1005 | − dev->can_match = true; | |
| 1002 | + dev_set_can_match(dev); | |
| 1006 | 1003 | driver_deferred_probe_add(dev); |
| 1007 | 1004 | /* |
| 1008 | 1005 | * 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) · 245 unmodified lines | ||
| 1254 | 1251 | return 0; |
| 1255 | 1252 | } else if (ret == -EPROBE_DEFER) { |
| 1256 | 1253 | dev_dbg(dev, "Device match requests probe deferral\n"); |
| 1257 | − dev->can_match = true; | |
| 1254 | + dev_set_can_match(dev); | |
| 1258 | 1255 | driver_deferred_probe_add(dev); |
| 1259 | 1256 | /* |
| 1260 | 1257 | * Driver could not match with device, but may match with |
| @@ -471,10 +471,3 @@ static int __init devcoredump_init(void) · 470 unmodified lines | ||
| 471 | 471 | return class_register(&devcd_class); |
| 472 | 472 | } |
| 473 | 473 | __initcall(devcoredump_init); |
| 474 | − | |
| 475 | −static void __exit devcoredump_exit(void) | |
| 476 | −{ | |
| 477 | − class_for_each_device(&devcd_class, NULL, NULL, devcd_free); | |
| 478 | − class_unregister(&devcd_class); | |
| 479 | −} | |
| 480 | −__exitcall(devcoredump_exit); | |
| @@ -30,81 +30,6 @@ static struct device *next_device(struct klist_iter *i) · 29 unmodified lines | ||
| 30 | 30 | return dev; |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | −/** | |
| 34 | − * driver_set_override() - Helper to set or clear driver override. | |
| 35 | − * @dev: Device to change | |
| 36 | − * @override: Address of string to change (e.g. &device->driver_override); | |
| 37 | − * The contents will be freed and hold newly allocated override. | |
| 38 | − * @s: NUL-terminated string, new driver name to force a match, pass empty | |
| 39 | − * string to clear it ("" or "\n", where the latter is only for sysfs | |
| 40 | − * interface). | |
| 41 | − * @len: length of @s | |
| 42 | − * | |
| 43 | − * Helper to set or clear driver override in a device, intended for the cases | |
| 44 | − * when the driver_override field is allocated by driver/bus code. | |
| 45 | − * | |
| 46 | − * Returns: 0 on success or a negative error code on failure. | |
| 47 | − */ | |
| 48 | −int driver_set_override(struct device *dev, const char **override, | |
| 49 | − const char *s, size_t len) | |
| 50 | −{ | |
| 51 | − const char *new, *old; | |
| 52 | − char *cp; | |
| 53 | − | |
| 54 | − if (!override || !s) | |
| 55 | − return -EINVAL; | |
| 56 | − | |
| 57 | − /* | |
| 58 | − * The stored value will be used in sysfs show callback (sysfs_emit()), | |
| 59 | − * which has a length limit of PAGE_SIZE and adds a trailing newline. | |
| 60 | − * Thus we can store one character less to avoid truncation during sysfs | |
| 61 | − * show. | |
| 62 | − */ | |
| 63 | − if (len >= (PAGE_SIZE - 1)) | |
| 64 | − return -EINVAL; | |
| 65 | − | |
| 66 | − /* | |
| 67 | − * Compute the real length of the string in case userspace sends us a | |
| 68 | − * bunch of \0 characters like python likes to do. | |
| 69 | − */ | |
| 70 | − len = strlen(s); | |
| 71 | − | |
| 72 | − if (!len) { | |
| 73 | − /* Empty string passed - clear override */ | |
| 74 | − device_lock(dev); | |
| 75 | − old = *override; | |
| 76 | − *override = NULL; | |
| 77 | − device_unlock(dev); | |
| 78 | − kfree(old); | |
| 79 | − | |
| 80 | − return 0; | |
| 81 | − } | |
| 82 | − | |
| 83 | − cp = strnchr(s, len, '\n'); | |
| 84 | − if (cp) | |
| 85 | − len = cp - s; | |
| 86 | − | |
| 87 | − new = kstrndup(s, len, GFP_KERNEL); | |
| 88 | − if (!new) | |
| 89 | − return -ENOMEM; | |
| 90 | − | |
| 91 | − device_lock(dev); | |
| 92 | − old = *override; | |
| 93 | − if (cp != s) { | |
| 94 | − *override = new; | |
| 95 | − } else { | |
| 96 | − /* "\n" passed - clear override */ | |
| 97 | − kfree(new); | |
| 98 | − *override = NULL; | |
| 99 | − } | |
| 100 | − device_unlock(dev); | |
| 101 | − | |
| 102 | − kfree(old); | |
| 103 | − | |
| 104 | − return 0; | |
| 105 | −} | |
| 106 | −EXPORT_SYMBOL_GPL(driver_set_override); | |
| 107 | − | |
| 108 | 33 | /** |
| 109 | 34 | * driver_for_each_device - Iterator for devices bound to a driver. |
| 110 | 35 | * @drv: Driver we're iterating. |
| @@ -203,13 +128,13 @@ void driver_remove_file(const struct device_driver *drv, · 92 unmodified lines | ||
| 203 | 128 | EXPORT_SYMBOL_GPL(driver_remove_file); |
| 204 | 129 | |
| 205 | 130 | int driver_add_groups(const struct device_driver *drv, |
| 206 | − const struct attribute_group **groups) | |
| 131 | + const struct attribute_group *const *groups) | |
| 207 | 132 | { |
| 208 | 133 | return sysfs_create_groups(&drv->p->kobj, groups); |
| 209 | 134 | } |
| 210 | 135 | |
| 211 | 136 | void driver_remove_groups(const struct device_driver *drv, |
| 212 | − const struct attribute_group **groups) | |
| 137 | + const struct attribute_group *const *groups) | |
| 213 | 138 | { |
| 214 | 139 | sysfs_remove_groups(&drv->p->kobj, groups); |
| 215 | 140 | } |
| @@ -133,6 +133,9 @@ struct faux_device *faux_device_create_with_groups(const char *name, · 132 unmodified lines | ||
| 133 | 133 | struct device *dev; |
| 134 | 134 | int ret; |
| 135 | 135 | |
| 136 | + if (!faux_bus_root) | |
| 137 | + return NULL; | |
| 138 | + | |
| 136 | 139 | faux_obj = kzalloc_obj(*faux_obj); |
| 137 | 140 | if (!faux_obj) |
| 138 | 141 | return NULL; |
| @@ -232,34 +235,29 @@ EXPORT_SYMBOL_GPL(faux_device_destroy); · 93 unmodified lines | ||
| 232 | 235 | |
| 233 | 236 | int __init faux_bus_init(void) |
| 234 | 237 | { |
| 238 | + struct device *root; | |
| 235 | 239 | int ret; |
| 236 | 240 | |
| 237 | − faux_bus_root = kzalloc_obj(*faux_bus_root); | |
| 238 | − if (!faux_bus_root) | |
| 239 | − return -ENOMEM; | |
| 240 | − | |
| 241 | − dev_set_name(faux_bus_root, "faux"); | |
| 242 | − | |
| 243 | − ret = device_register(faux_bus_root); | |
| 244 | − if (ret) { | |
| 245 | − put_device(faux_bus_root); | |
| 246 | − return ret; | |
| 247 | − } | |
| 241 | + root = root_device_register("faux"); | |
| 242 | + if (IS_ERR(root)) | |
| 243 | + return PTR_ERR(root); | |
| 248 | 244 | |
| 249 | 245 | ret = bus_register(&faux_bus_type); |
| 250 | 246 | if (ret) |
| 251 | − goto error_bus; | |
| 247 | + goto err_deregister_root; | |
| 252 | 248 | |
| 253 | 249 | ret = driver_register(&faux_driver); |
| 254 | 250 | if (ret) |
| 255 | − goto error_driver; | |
| 251 | + goto err_deregister_bus; | |
| 256 | 252 | |
| 257 | − return ret; | |
| 253 | + faux_bus_root = root; | |
| 254 | + | |
| 255 | + return 0; | |
| 258 | 256 | |
| 259 | −error_driver: | |
| 257 | +err_deregister_bus: | |
| 260 | 258 | bus_unregister(&faux_bus_type); |
| 259 | +err_deregister_root: | |
| 260 | + root_device_unregister(root); | |
| 261 | 261 | |
| 262 | −error_bus: | |
| 263 | − device_unregister(faux_bus_root); | |
| 264 | 262 | return ret; |
| 265 | 263 | } |
| @@ -1503,9 +1503,10 @@ static void device_cache_fw_images(void) · 1502 unmodified lines | ||
| 1503 | 1503 | |
| 1504 | 1504 | mutex_lock(&fw_lock); |
| 1505 | 1505 | fwc->state = FW_LOADER_START_CACHE; |
| 1506 | − dpm_for_each_dev(NULL, dev_cache_fw_image); | |
| 1507 | 1506 | mutex_unlock(&fw_lock); |
| 1508 | 1507 | |
| 1508 | + dpm_for_each_dev(NULL, dev_cache_fw_image); | |
| 1509 | + | |
| 1509 | 1510 | /* wait for completion of caching firmware for all devices */ |
| 1510 | 1511 | async_synchronize_full_domain(&fw_cache_domain); |
| 1511 | 1512 | |
| @@ -343,7 +343,6 @@ firmware_upload_register(struct module *module, struct device *parent, · 342 unmodified lines | ||
| 343 | 343 | goto free_fw_upload_priv; |
| 344 | 344 | } |
| 345 | 345 | fw_upload->priv = fw_sysfs; |
| 346 | − fw_sysfs->fw_upload_priv = fw_upload_priv; | |
| 347 | 346 | fw_dev = &fw_sysfs->dev; |
| 348 | 347 | |
| 349 | 348 | 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, · 1 unmodified line | ||
| 351 | 350 | if (ret != 0) { |
| 352 | 351 | if (ret > 0) |
| 353 | 352 | ret = -EINVAL; |
| 354 | − goto free_fw_sysfs; | |
| 353 | + put_device(fw_dev); | |
| 354 | + goto free_fw_upload_priv; | |
| 355 | 355 | } |
| 356 | 356 | fw_priv->is_paged_buf = true; |
| 357 | 357 | fw_sysfs->fw_priv = fw_priv; |
| 358 | + fw_sysfs->fw_upload_priv = fw_upload_priv; | |
| 358 | 359 | |
| 359 | 360 | ret = device_add(fw_dev); |
| 360 | 361 | if (ret) { |
| @@ -365,9 +366,6 @@ firmware_upload_register(struct module *module, struct device *parent, · 4 unmodified lines | ||
| 365 | 366 | |
| 366 | 367 | return fw_upload; |
| 367 | 368 | |
| 368 | −free_fw_sysfs: | |
| 369 | − kfree(fw_sysfs); | |
| 370 | − | |
| 371 | 369 | free_fw_upload_priv: |
| 372 | 370 | kfree(fw_upload_priv); |
| 373 | 371 | |
| @@ -11,9 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <linux/dma-mapping.h> |
| 12 | 12 | #include <linux/isa.h> |
| 13 | 13 | |
| 14 | −static struct device isa_bus = { | |
| 15 | − .init_name = "isa" | |
| 16 | −}; | |
| 14 | +static struct device *isa_bus; | |
| 17 | 15 | |
| 18 | 16 | struct isa_dev { |
| 19 | 17 | struct device dev; |
| @@ -131,7 +129,7 @@ int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) · 111 unmodified lines | ||
| 131 | 129 | break; |
| 132 | 130 | } |
| 133 | 131 | |
| 134 | − isa_dev->dev.parent = &isa_bus; | |
| 132 | + isa_dev->dev.parent = isa_bus; | |
| 135 | 133 | isa_dev->dev.bus = &isa_bus_type; |
| 136 | 134 | |
| 137 | 135 | dev_set_name(&isa_dev->dev, "%s.%u", |
| @@ -169,9 +167,11 @@ static int __init isa_bus_init(void) · 31 unmodified lines | ||
| 169 | 167 | |
| 170 | 168 | error = bus_register(&isa_bus_type); |
| 171 | 169 | if (!error) { |
| 172 | − error = device_register(&isa_bus); | |
| 173 | − if (error) | |
| 170 | + isa_bus = root_device_register("isa"); | |
| 171 | + if (IS_ERR(isa_bus)) { | |
| 172 | + error = PTR_ERR(isa_bus); | |
| 174 | 173 | bus_unregister(&isa_bus_type); |
| 174 | + } | |
| 175 | 175 | } |
| 176 | 176 | return error; |
| 177 | 177 | } |
| @@ -697,7 +697,7 @@ static int __add_memory_block(struct memory_block *memory) · 696 unmodified lines | ||
| 697 | 697 | memory->dev.id = memory->start_section_nr / sections_per_block; |
| 698 | 698 | memory->dev.release = memory_block_release; |
| 699 | 699 | memory->dev.groups = memory_memblk_attr_groups; |
| 700 | − memory->dev.offline = memory->state == MEM_OFFLINE; | |
| 700 | + dev_assign_offline(&memory->dev, memory->state == MEM_OFFLINE); | |
| 701 | 701 | |
| 702 | 702 | ret = device_register(&memory->dev); |
| 703 | 703 | if (ret) { |
| @@ -24,7 +24,7 @@ int pinctrl_bind_pins(struct device *dev) · 23 unmodified lines | ||
| 24 | 24 | { |
| 25 | 25 | int ret; |
| 26 | 26 | |
| 27 | − if (dev->of_node_reused) | |
| 27 | + if (dev_of_node_reused(dev)) | |
| 28 | 28 | return 0; |
| 29 | 29 | |
| 30 | 30 | dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL); |
| @@ -870,7 +870,7 @@ struct platform_device *platform_device_register_full(const struct platform_devi · 869 unmodified lines | ||
| 870 | 870 | pdev->dev.parent = pdevinfo->parent; |
| 871 | 871 | pdev->dev.fwnode = pdevinfo->fwnode; |
| 872 | 872 | pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode)); |
| 873 | − pdev->dev.of_node_reused = pdevinfo->of_node_reused; | |
| 873 | + dev_assign_of_node_reused(&pdev->dev, pdevinfo->of_node_reused); | |
| 874 | 874 | |
| 875 | 875 | if (pdevinfo->dma_mask) { |
| 876 | 876 | pdev->platform_dma_mask = pdevinfo->dma_mask; |
| @@ -915,11 +915,14 @@ EXPORT_SYMBOL_GPL(platform_device_register_full); · 38 unmodified lines | ||
| 915 | 915 | * __platform_driver_register - register a driver for platform-level devices |
| 916 | 916 | * @drv: platform driver structure |
| 917 | 917 | * @owner: owning module/driver |
| 918 | + * @mod_name: module name string | |
| 918 | 919 | */ |
| 919 | −int __platform_driver_register(struct platform_driver *drv, struct module *owner) | |
| 920 | +int __platform_driver_register(struct platform_driver *drv, struct module *owner, | |
| 921 | + const char *mod_name) | |
| 920 | 922 | { |
| 921 | 923 | drv->driver.owner = owner; |
| 922 | 924 | drv->driver.bus = &platform_bus_type; |
| 925 | + drv->driver.mod_name = mod_name; | |
| 923 | 926 | |
| 924 | 927 | return driver_register(&drv->driver); |
| 925 | 928 | } |
| @@ -952,6 +955,7 @@ static int is_bound_to_driver(struct device *dev, void *driver) · 26 unmodified lines | ||
| 952 | 955 | * @drv: platform driver structure |
| 953 | 956 | * @probe: the driver probe routine, probably from an __init section |
| 954 | 957 | * @module: module which will be the owner of the driver |
| 958 | + * @mod_name: module name string | |
| 955 | 959 | * |
| 956 | 960 | * Use this instead of platform_driver_register() when you know the device |
| 957 | 961 | * 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) · 11 unmodified lines | ||
| 969 | 973 | */ |
| 970 | 974 | int __init_or_module __platform_driver_probe(struct platform_driver *drv, |
| 971 | 975 | int (*probe)(struct platform_device *), |
| 972 | − struct module *module) | |
| 976 | + struct module *module, | |
| 977 | + const char *mod_name) | |
| 973 | 978 | { |
| 974 | 979 | int retval; |
| 975 | 980 | |
| @@ -997,7 +1002,7 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv, · 21 unmodified lines | ||
| 997 | 1002 | |
| 998 | 1003 | /* temporary section violation during probe() */ |
| 999 | 1004 | drv->probe = probe; |
| 1000 | − retval = __platform_driver_register(drv, module); | |
| 1005 | + retval = __platform_driver_register(drv, module, mod_name); | |
| 1001 | 1006 | if (retval) |
| 1002 | 1007 | return retval; |
| 1003 | 1008 | |
| @@ -1025,6 +1030,7 @@ EXPORT_SYMBOL_GPL(__platform_driver_probe); · 21 unmodified lines | ||
| 1025 | 1030 | * @data: platform specific data for this platform device |
| 1026 | 1031 | * @size: size of platform specific data |
| 1027 | 1032 | * @module: module which will be the owner of the driver |
| 1033 | + * @mod_name: module name string | |
| 1028 | 1034 | * |
| 1029 | 1035 | * Use this in legacy-style modules that probe hardware directly and |
| 1030 | 1036 | * register a single platform device and corresponding platform driver. |
| @@ -1035,7 +1041,7 @@ struct platform_device * __init_or_module · 4 unmodified lines | ||
| 1035 | 1041 | __platform_create_bundle(struct platform_driver *driver, |
| 1036 | 1042 | int (*probe)(struct platform_device *), |
| 1037 | 1043 | struct resource *res, unsigned int n_res, |
| 1038 | − const void *data, size_t size, struct module *module) | |
| 1044 | + const void *data, size_t size, struct module *module, const char *mod_name) | |
| 1039 | 1045 | { |
| 1040 | 1046 | struct platform_device *pdev; |
| 1041 | 1047 | int error; |
| @@ -1058,7 +1064,7 @@ __platform_create_bundle(struct platform_driver *driver, · 16 unmodified lines | ||
| 1058 | 1064 | if (error) |
| 1059 | 1065 | goto err_pdev_put; |
| 1060 | 1066 | |
| 1061 | − error = __platform_driver_probe(driver, probe, module); | |
| 1067 | + error = __platform_driver_probe(driver, probe, module, mod_name); | |
| 1062 | 1068 | if (error) |
| 1063 | 1069 | goto err_pdev_del; |
| 1064 | 1070 | |
| @@ -1078,6 +1084,7 @@ EXPORT_SYMBOL_GPL(__platform_create_bundle); · 13 unmodified lines | ||
| 1078 | 1084 | * @drivers: an array of drivers to register |
| 1079 | 1085 | * @count: the number of drivers to register |
| 1080 | 1086 | * @owner: module owning the drivers |
| 1087 | + * @mod_name: module name string | |
| 1081 | 1088 | * |
| 1082 | 1089 | * Registers platform drivers specified by an array. On failure to register a |
| 1083 | 1090 | * driver, all previously registered drivers will be unregistered. Callers of |
| @@ -1087,7 +1094,7 @@ EXPORT_SYMBOL_GPL(__platform_create_bundle); · 3 unmodified lines | ||
| 1087 | 1094 | * Returns: 0 on success or a negative error code on failure. |
| 1088 | 1095 | */ |
| 1089 | 1096 | int __platform_register_drivers(struct platform_driver * const *drivers, |
| 1090 | − unsigned int count, struct module *owner) | |
| 1097 | + unsigned int count, struct module *owner, const char *mod_name) | |
| 1091 | 1098 | { |
| 1092 | 1099 | unsigned int i; |
| 1093 | 1100 | int err; |
| @@ -1095,7 +1102,7 @@ int __platform_register_drivers(struct platform_driver * const *drivers, · 1 unmodified line | ||
| 1095 | 1102 | for (i = 0; i < count; i++) { |
| 1096 | 1103 | pr_debug("registering platform driver %ps\n", drivers[i]); |
| 1097 | 1104 | |
| 1098 | − err = __platform_driver_register(drivers[i], owner); | |
| 1105 | + err = __platform_driver_register(drivers[i], owner, mod_name); | |
| 1099 | 1106 | if (err < 0) { |
| 1100 | 1107 | pr_err("failed to register platform driver %ps: %d\n", |
| 1101 | 1108 | drivers[i], err); |
| @@ -1277,8 +1277,10 @@ fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode, · 1276 unmodified lines | ||
| 1277 | 1277 | if (fwnode_ep.port != port) |
| 1278 | 1278 | continue; |
| 1279 | 1279 | |
| 1280 | − if (fwnode_ep.id == endpoint) | |
| 1280 | + if (fwnode_ep.id == endpoint) { | |
| 1281 | + fwnode_handle_put(best_ep); | |
| 1281 | 1282 | return ep; |
| 1283 | + } | |
| 1282 | 1284 | |
| 1283 | 1285 | if (!endpoint_next) |
| 1284 | 1286 | continue; |
| @@ -374,20 +374,28 @@ EXPORT_SYMBOL_GPL(property_entries_free); · 373 unmodified lines | ||
| 374 | 374 | /* -------------------------------------------------------------------------- */ |
| 375 | 375 | /* fwnode operations */ |
| 376 | 376 | |
| 377 | −static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode) | |
| 377 | +static struct swnode *swnode_get(struct swnode *swnode) | |
| 378 | 378 | { |
| 379 | − struct swnode *swnode = to_swnode(fwnode); | |
| 380 | − | |
| 381 | 379 | kobject_get(&swnode->kobj); |
| 382 | 380 | |
| 381 | + return swnode; | |
| 382 | +} | |
| 383 | + | |
| 384 | +static void swnode_put(struct swnode *swnode) | |
| 385 | +{ | |
| 386 | + kobject_put(&swnode->kobj); | |
| 387 | +} | |
| 388 | + | |
| 389 | +static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode) | |
| 390 | +{ | |
| 391 | + struct swnode *swnode = swnode_get(to_swnode(fwnode)); | |
| 392 | + | |
| 383 | 393 | return &swnode->fwnode; |
| 384 | 394 | } |
| 385 | 395 | |
| 386 | 396 | static void software_node_put(struct fwnode_handle *fwnode) |
| 387 | 397 | { |
| 388 | − struct swnode *swnode = to_swnode(fwnode); | |
| 389 | − | |
| 390 | − kobject_put(&swnode->kobj); | |
| 398 | + swnode_put(to_swnode(fwnode)); | |
| 391 | 399 | } |
| 392 | 400 | |
| 393 | 401 | 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, · 99 unmodified lines | ||
| 493 | 501 | |
| 494 | 502 | list_for_each_entry(child, &swnode->children, entry) { |
| 495 | 503 | if (!strcmp(childname, kobject_name(&child->kobj))) { |
| 496 | − kobject_get(&child->kobj); | |
| 504 | + swnode_get(child); | |
| 497 | 505 | return &child->fwnode; |
| 498 | 506 | } |
| 499 | 507 | } |
| @@ -737,7 +745,7 @@ software_node_find_by_name(const struct software_node *parent, const char *name) · 237 unmodified lines | ||
| 737 | 745 | swnode = kobj_to_swnode(k); |
| 738 | 746 | if (parent == swnode->node->parent && swnode->node->name && |
| 739 | 747 | !strcmp(name, swnode->node->name)) { |
| 740 | − kobject_get(&swnode->kobj); | |
| 748 | + swnode_get(swnode); | |
| 741 | 749 | break; |
| 742 | 750 | } |
| 743 | 751 | swnode = NULL; |
| @@ -835,13 +843,13 @@ swnode_register(const struct software_node *node, struct swnode *parent, · 91 unmodified lines | ||
| 835 | 843 | parent ? &parent->kobj : NULL, |
| 836 | 844 | "node%d", swnode->id); |
| 837 | 845 | if (ret) { |
| 838 | − kobject_put(&swnode->kobj); | |
| 846 | + swnode_put(swnode); | |
| 839 | 847 | return ERR_PTR(ret); |
| 840 | 848 | } |
| 841 | 849 | |
| 842 | 850 | /* |
| 843 | 851 | * Assign the flag only in the successful case, so |
| 844 | − * the above kobject_put() won't mess up with properties. | |
| 852 | + * the above swnode_put() won't mess up with properties. | |
| 845 | 853 | */ |
| 846 | 854 | swnode->allocated = allocated; |
| 847 | 855 | |
| @@ -978,7 +986,7 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode) · 130 unmodified lines | ||
| 978 | 986 | if (!swnode) |
| 979 | 987 | return; |
| 980 | 988 | |
| 981 | − kobject_put(&swnode->kobj); | |
| 989 | + swnode_put(swnode); | |
| 982 | 990 | } |
| 983 | 991 | EXPORT_SYMBOL_GPL(fwnode_remove_software_node); |
| 984 | 992 | |
| @@ -1002,7 +1010,7 @@ int device_add_software_node(struct device *dev, const struct software_node *nod · 17 unmodified lines | ||
| 1002 | 1010 | |
| 1003 | 1011 | swnode = software_node_to_swnode(node); |
| 1004 | 1012 | if (swnode) { |
| 1005 | − kobject_get(&swnode->kobj); | |
| 1013 | + swnode_get(swnode); | |
| 1006 | 1014 | } else { |
| 1007 | 1015 | ret = software_node_register(node); |
| 1008 | 1016 | if (ret) |
| @@ -1044,7 +1052,7 @@ void device_remove_software_node(struct device *dev) · 35 unmodified lines | ||
| 1044 | 1052 | software_node_notify_remove(dev); |
| 1045 | 1053 | |
| 1046 | 1054 | set_secondary_fwnode(dev, NULL); |
| 1047 | − kobject_put(&swnode->kobj); | |
| 1055 | + swnode_put(swnode); | |
| 1048 | 1056 | } |
| 1049 | 1057 | EXPORT_SYMBOL_GPL(device_remove_software_node); |
| 1050 | 1058 | |
| @@ -1097,7 +1105,7 @@ void software_node_notify(struct device *dev) · 46 unmodified lines | ||
| 1097 | 1105 | if (!swnode) |
| 1098 | 1106 | return; |
| 1099 | 1107 | |
| 1100 | − kobject_get(&swnode->kobj); | |
| 1108 | + swnode_get(swnode); | |
| 1101 | 1109 | ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node"); |
| 1102 | 1110 | if (ret) |
| 1103 | 1111 | return; |
| @@ -1119,11 +1127,11 @@ void software_node_notify_remove(struct device *dev) · 15 unmodified lines | ||
| 1119 | 1127 | |
| 1120 | 1128 | sysfs_remove_link(&swnode->kobj, dev_name(dev)); |
| 1121 | 1129 | sysfs_remove_link(&dev->kobj, "software_node"); |
| 1122 | − kobject_put(&swnode->kobj); | |
| 1130 | + swnode_put(swnode); | |
| 1123 | 1131 | |
| 1124 | 1132 | if (swnode->managed) { |
| 1125 | 1133 | set_secondary_fwnode(dev, NULL); |
| 1126 | − kobject_put(&swnode->kobj); | |
| 1134 | + swnode_put(swnode); | |
| 1127 | 1135 | } |
| 1128 | 1136 | } |
| 1129 | 1137 | |
| @@ -327,12 +327,6 @@ static int of_weim_notify(struct notifier_block *nb, unsigned long action, · 326 unmodified lines | ||
| 327 | 327 | "Failed to setup timing for '%pOF'\n", rd->dn); |
| 328 | 328 | |
| 329 | 329 | if (!of_node_check_flag(rd->dn, OF_POPULATED)) { |
| 330 | − /* | |
| 331 | − * Clear the flag before adding the device so that | |
| 332 | − * fw_devlink doesn't skip adding consumers to this | |
| 333 | − * device. | |
| 334 | − */ | |
| 335 | − fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE); | |
| 336 | 330 | if (!of_platform_device_create(rd->dn, NULL, &pdev->dev)) { |
| 337 | 331 | dev_err(&pdev->dev, |
| 338 | 332 | "Failed to create child device '%pOF'\n", |
| @@ -156,8 +156,6 @@ static int cdx_unregister_device(struct device *dev, · 155 unmodified lines | ||
| 156 | 156 | } else { |
| 157 | 157 | cdx_destroy_res_attr(cdx_dev, MAX_CDX_DEV_RESOURCES); |
| 158 | 158 | debugfs_remove_recursive(cdx_dev->debugfs_dir); |
| 159 | − kfree(cdx_dev->driver_override); | |
| 160 | − cdx_dev->driver_override = NULL; | |
| 161 | 159 | } |
| 162 | 160 | |
| 163 | 161 | /* |
| @@ -268,6 +266,7 @@ static int cdx_bus_match(struct device *dev, const struct device_driver *drv) · 104 unmodified lines | ||
| 268 | 266 | const struct cdx_driver *cdx_drv = to_cdx_driver(drv); |
| 269 | 267 | const struct cdx_device_id *found_id = NULL; |
| 270 | 268 | const struct cdx_device_id *ids; |
| 269 | + int ret; | |
| 271 | 270 | |
| 272 | 271 | if (cdx_dev->is_bus) |
| 273 | 272 | return false; |
| @@ -275,7 +274,8 @@ static int cdx_bus_match(struct device *dev, const struct device_driver *drv) · 1 unmodified line | ||
| 275 | 274 | ids = cdx_drv->match_id_table; |
| 276 | 275 | |
| 277 | 276 | /* When driver_override is set, only bind to the matching driver */ |
| 278 | − if (cdx_dev->driver_override && strcmp(cdx_dev->driver_override, drv->name)) | |
| 277 | + ret = device_match_driver_override(dev, drv); | |
| 278 | + if (ret == 0) | |
| 279 | 279 | return false; |
| 280 | 280 | |
| 281 | 281 | 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) · 7 unmodified lines | ||
| 289 | 289 | */ |
| 290 | 290 | if (!found_id->override_only) |
| 291 | 291 | return true; |
| 292 | − if (cdx_dev->driver_override) | |
| 292 | + if (ret > 0) | |
| 293 | 293 | return true; |
| 294 | 294 | |
| 295 | 295 | ids = found_id + 1; |
| @@ -453,36 +453,6 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, · 157 unmodified lines | ||
| 453 | 453 | } |
| 454 | 454 | static DEVICE_ATTR_RO(modalias); |
| 455 | 455 | |
| 456 | −static ssize_t driver_override_store(struct device *dev, | |
| 457 | − struct device_attribute *attr, | |
| 458 | − const char *buf, size_t count) | |
| 459 | −{ | |
| 460 | − struct cdx_device *cdx_dev = to_cdx_device(dev); | |
| 461 | − int ret; | |
| 462 | − | |
| 463 | − if (WARN_ON(dev->bus != &cdx_bus_type)) | |
| 464 | − return -EINVAL; | |
| 465 | − | |
| 466 | − ret = driver_set_override(dev, &cdx_dev->driver_override, buf, count); | |
| 467 | − if (ret) | |
| 468 | − return ret; | |
| 469 | − | |
| 470 | − return count; | |
| 471 | −} | |
| 472 | − | |
| 473 | −static ssize_t driver_override_show(struct device *dev, | |
| 474 | − struct device_attribute *attr, char *buf) | |
| 475 | −{ | |
| 476 | − struct cdx_device *cdx_dev = to_cdx_device(dev); | |
| 477 | − ssize_t len; | |
| 478 | − | |
| 479 | − device_lock(dev); | |
| 480 | − len = sysfs_emit(buf, "%s\n", cdx_dev->driver_override); | |
| 481 | − device_unlock(dev); | |
| 482 | − return len; | |
| 483 | −} | |
| 484 | −static DEVICE_ATTR_RW(driver_override); | |
| 485 | − | |
| 486 | 456 | static ssize_t enable_store(struct device *dev, struct device_attribute *attr, |
| 487 | 457 | const char *buf, size_t count) |
| 488 | 458 | { |
| @@ -552,7 +522,6 @@ static struct attribute *cdx_dev_attrs[] = { · 63 unmodified lines | ||
| 552 | 522 | &dev_attr_class.attr, |
| 553 | 523 | &dev_attr_revision.attr, |
| 554 | 524 | &dev_attr_modalias.attr, |
| 555 | − &dev_attr_driver_override.attr, | |
| 556 | 525 | NULL, |
| 557 | 526 | }; |
| 558 | 527 | |
| @@ -646,6 +615,7 @@ ATTRIBUTE_GROUPS(cdx_bus); · 87 unmodified lines | ||
| 646 | 615 | |
| 647 | 616 | const struct bus_type cdx_bus_type = { |
| 648 | 617 | .name = "cdx", |
| 618 | + .driver_override = true, | |
| 649 | 619 | .match = cdx_bus_match, |
| 650 | 620 | .probe = cdx_probe, |
| 651 | 621 | .remove = cdx_remove, |
| @@ -201,12 +201,13 @@ kernel::of_device_table!( · 200 unmodified lines | ||
| 201 | 201 | |
| 202 | 202 | impl platform::Driver for CPUFreqDTDriver { |
| 203 | 203 | type IdInfo = (); |
| 204 | + type Data<'bound> = Self; | |
| 204 | 205 | const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); |
| 205 | 206 | |
| 206 | − fn probe( | |
| 207 | − pdev: &platform::Device<Core>, | |
| 208 | − _id_info: Option<&Self::IdInfo>, | |
| 209 | − ) -> impl PinInit<Self, Error> { | |
| 207 | + fn probe<'bound>( | |
| 208 | + pdev: &'bound platform::Device<Core<'_>>, | |
| 209 | + _id_info: Option<&'bound Self::IdInfo>, | |
| 210 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 210 | 211 | cpufreq::Registration::<CPUFreqDTDriver>::new_foreign_owned(pdev.as_ref())?; |
| 211 | 212 | Ok(Self {}) |
| 212 | 213 | } |
| @@ -17,7 +17,13 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/list.h> |
| 18 | 18 | #include <linux/of.h> |
| 19 | 19 | |
| 20 | −static struct class *devfreq_event_class; | |
| 20 | +static struct attribute *devfreq_event_attrs[]; | |
| 21 | +ATTRIBUTE_GROUPS(devfreq_event); | |
| 22 | + | |
| 23 | +static const struct class devfreq_event_class = { | |
| 24 | + .name = "devfreq-event", | |
| 25 | + .dev_groups = devfreq_event_groups | |
| 26 | +}; | |
| 21 | 27 | |
| 22 | 28 | /* The list of all devfreq event list */ |
| 23 | 29 | static LIST_HEAD(devfreq_event_list); |
| @@ -321,7 +327,7 @@ struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, · 297 unmodified lines | ||
| 321 | 327 | edev->desc = desc; |
| 322 | 328 | edev->enable_count = 0; |
| 323 | 329 | edev->dev.parent = dev; |
| 324 | − edev->dev.class = devfreq_event_class; | |
| 330 | + edev->dev.class = &devfreq_event_class; | |
| 325 | 331 | edev->dev.release = devfreq_event_release_edev; |
| 326 | 332 | |
| 327 | 333 | dev_set_name(&edev->dev, "event%d", atomic_inc_return(&event_no)); |
| @@ -461,18 +467,15 @@ static struct attribute *devfreq_event_attrs[] = { · 133 unmodified lines | ||
| 461 | 467 | &dev_attr_enable_count.attr, |
| 462 | 468 | NULL, |
| 463 | 469 | }; |
| 464 | −ATTRIBUTE_GROUPS(devfreq_event); | |
| 465 | 470 | |
| 466 | 471 | static int __init devfreq_event_init(void) |
| 467 | 472 | { |
| 468 | − devfreq_event_class = class_create("devfreq-event"); | |
| 469 | − if (IS_ERR(devfreq_event_class)) { | |
| 470 | − pr_err("%s: couldn't create class\n", __FILE__); | |
| 471 | − return PTR_ERR(devfreq_event_class); | |
| 472 | − } | |
| 473 | + int err; | |
| 473 | 474 | |
| 474 | − devfreq_event_class->dev_groups = devfreq_event_groups; | |
| 475 | + err = class_register(&devfreq_event_class); | |
| 476 | + if (err) | |
| 477 | + pr_err("%s: couldn't create class\n", __FILE__); | |
| 475 | 478 | |
| 476 | − return 0; | |
| 479 | + return err; | |
| 477 | 480 | } |
| 478 | 481 | subsys_initcall(devfreq_event_init); |
| @@ -312,7 +312,7 @@ k3_udma_glue_request_tx_chn_common(struct device *dev, · 311 unmodified lines | ||
| 312 | 312 | |
| 313 | 313 | if (xudma_is_pktdma(tx_chn->common.udmax)) { |
| 314 | 314 | /* prepare the channel device as coherent */ |
| 315 | − tx_chn->common.chan_dev.dma_coherent = true; | |
| 315 | + dev_set_dma_coherent(&tx_chn->common.chan_dev); | |
| 316 | 316 | dma_coerce_mask_and_coherent(&tx_chn->common.chan_dev, |
| 317 | 317 | DMA_BIT_MASK(48)); |
| 318 | 318 | } |
| @@ -1003,7 +1003,7 @@ k3_udma_glue_request_rx_chn_priv(struct device *dev, const char *name, · 684 unmodified lines | ||
| 1003 | 1003 | |
| 1004 | 1004 | if (xudma_is_pktdma(rx_chn->common.udmax)) { |
| 1005 | 1005 | /* prepare the channel device as coherent */ |
| 1006 | − rx_chn->common.chan_dev.dma_coherent = true; | |
| 1006 | + dev_set_dma_coherent(&rx_chn->common.chan_dev); | |
| 1007 | 1007 | dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev, |
| 1008 | 1008 | DMA_BIT_MASK(48)); |
| 1009 | 1009 | } |
| @@ -1104,7 +1104,7 @@ k3_udma_glue_request_remote_rx_chn_common(struct k3_udma_glue_rx_channel *rx_chn · 94 unmodified lines | ||
| 1104 | 1104 | |
| 1105 | 1105 | if (xudma_is_pktdma(rx_chn->common.udmax)) { |
| 1106 | 1106 | /* prepare the channel device as coherent */ |
| 1107 | − rx_chn->common.chan_dev.dma_coherent = true; | |
| 1107 | + dev_set_dma_coherent(&rx_chn->common.chan_dev); | |
| 1108 | 1108 | dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev, |
| 1109 | 1109 | DMA_BIT_MASK(48)); |
| 1110 | 1110 | rx_chn->single_fdq = false; |
| @@ -428,18 +428,18 @@ static void k3_configure_chan_coherency(struct dma_chan *chan, u32 asel) · 427 unmodified lines | ||
| 428 | 428 | /* No special handling for the channel */ |
| 429 | 429 | chan->dev->chan_dma_dev = false; |
| 430 | 430 | |
| 431 | − chan_dev->dma_coherent = false; | |
| 431 | + dev_clear_dma_coherent(chan_dev); | |
| 432 | 432 | chan_dev->dma_parms = NULL; |
| 433 | 433 | } else if (asel == 14 || asel == 15) { |
| 434 | 434 | chan->dev->chan_dma_dev = true; |
| 435 | 435 | |
| 436 | − chan_dev->dma_coherent = true; | |
| 436 | + dev_set_dma_coherent(chan_dev); | |
| 437 | 437 | dma_coerce_mask_and_coherent(chan_dev, DMA_BIT_MASK(48)); |
| 438 | 438 | chan_dev->dma_parms = chan_dev->parent->dma_parms; |
| 439 | 439 | } else { |
| 440 | 440 | dev_warn(chan->device->dev, "Invalid ASEL value: %u\n", asel); |
| 441 | 441 | |
| 442 | − chan_dev->dma_coherent = false; | |
| 442 | + dev_clear_dma_coherent(chan_dev); | |
| 443 | 443 | chan_dev->dma_parms = NULL; |
| 444 | 444 | } |
| 445 | 445 | } |
| @@ -51,9 +51,13 @@ kernel::auxiliary_device_table!( · 50 unmodified lines | ||
| 51 | 51 | |
| 52 | 52 | impl auxiliary::Driver for NovaDriver { |
| 53 | 53 | type IdInfo = (); |
| 54 | + type Data<'bound> = Self; | |
| 54 | 55 | const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE; |
| 55 | 56 | |
| 56 | − fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { | |
| 57 | + fn probe<'bound>( | |
| 58 | + adev: &'bound auxiliary::Device<Core<'_>>, | |
| 59 | + _info: &'bound Self::IdInfo, | |
| 60 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 57 | 61 | let data = try_pin_init!(NovaData { adev: adev.into() }); |
| 58 | 62 | |
| 59 | 63 | let drm = drm::Device::<Self>::new(adev.as_ref(), data)?; |
| @@ -37,7 +37,7 @@ use crate::{ · 36 unmodified lines | ||
| 37 | 37 | regs, // |
| 38 | 38 | }; |
| 39 | 39 | |
| 40 | −pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>; | |
| 40 | +pub(crate) type IoMem = kernel::io::mem::IoMem<'static, SZ_2M>; | |
| 41 | 41 | |
| 42 | 42 | pub(crate) struct TyrDrmDriver; |
| 43 | 43 | |
| @@ -91,12 +91,13 @@ kernel::of_device_table!( · 47 unmodified lines | ||
| 91 | 91 | |
| 92 | 92 | impl platform::Driver for TyrPlatformDriverData { |
| 93 | 93 | type IdInfo = (); |
| 94 | + type Data<'bound> = Self; | |
| 94 | 95 | const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); |
| 95 | 96 | |
| 96 | − fn probe( | |
| 97 | − pdev: &platform::Device<Core>, | |
| 98 | − _info: Option<&Self::IdInfo>, | |
| 99 | − ) -> impl PinInit<Self, Error> { | |
| 97 | + fn probe<'bound>( | |
| 98 | + pdev: &'bound platform::Device<Core<'_>>, | |
| 99 | + _info: Option<&'bound Self::IdInfo>, | |
| 100 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 100 | 101 | let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?; |
| 101 | 102 | let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?; |
| 102 | 103 | let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?; |
| @@ -109,7 +110,7 @@ impl platform::Driver for TyrPlatformDriverData { · 6 unmodified lines | ||
| 109 | 110 | let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?; |
| 110 | 111 | |
| 111 | 112 | let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; |
| 112 | − let iomem = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?; | |
| 113 | + let iomem = Arc::new(request.iomap_sized::<SZ_2M>()?.into_devres()?, GFP_KERNEL)?; | |
| 113 | 114 | |
| 114 | 115 | issue_soft_reset(pdev.as_ref(), &iomem)?; |
| 115 | 116 | gpu::l2_power_on(pdev.as_ref(), &iomem)?; |
| @@ -3,7 +3,6 @@ · 2 unmodified lines | ||
| 3 | 3 | use kernel::{ |
| 4 | 4 | auxiliary, |
| 5 | 5 | device::Core, |
| 6 | − devres::Devres, | |
| 7 | 6 | dma::Device, |
| 8 | 7 | dma::DmaMask, |
| 9 | 8 | pci, |
| @@ -21,6 +20,7 @@ use kernel::{ · 11 unmodified lines | ||
| 21 | 20 | }, |
| 22 | 21 | Arc, |
| 23 | 22 | }, |
| 23 | + types::ForLt, | |
| 24 | 24 | }; |
| 25 | 25 | |
| 26 | 26 | use crate::gpu::Gpu; |
| @@ -29,13 +29,15 @@ use crate::gpu::Gpu; · 2 unmodified lines | ||
| 29 | 29 | static AUXILIARY_ID_COUNTER: Atomic<u32> = Atomic::new(0); |
| 30 | 30 | |
| 31 | 31 | #[pin_data] |
| 32 | −pub(crate) struct NovaCore { | |
| 32 | +pub(crate) struct NovaCore<'bound> { | |
| 33 | 33 | #[pin] |
| 34 | 34 | pub(crate) gpu: Gpu, |
| 35 | − #[pin] | |
| 36 | − _reg: Devres<auxiliary::Registration>, | |
| 35 | + #[allow(clippy::type_complexity)] | |
| 36 | + _reg: auxiliary::Registration<'bound, ForLt!(())>, | |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | +pub(crate) struct NovaCoreDriver; | |
| 40 | + | |
| 39 | 41 | const BAR0_SIZE: usize = SZ_16M; |
| 40 | 42 | |
| 41 | 43 | // 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; · 4 unmodified lines | ||
| 46 | 48 | // DMA addresses. These systems should be quite rare. |
| 47 | 49 | const GPU_DMA_BITS: u32 = 47; |
| 48 | 50 | |
| 49 | −pub(crate) type Bar0 = pci::Bar<BAR0_SIZE>; | |
| 51 | +pub(crate) type Bar0 = pci::Bar<'static, BAR0_SIZE>; | |
| 50 | 52 | |
| 51 | 53 | kernel::pci_device_table!( |
| 52 | 54 | PCI_TABLE, |
| 53 | 55 | MODULE_PCI_TABLE, |
| 54 | − <NovaCore as pci::Driver>::IdInfo, | |
| 56 | + <NovaCoreDriver as pci::Driver>::IdInfo, | |
| 55 | 57 | [ |
| 56 | 58 | // Modern NVIDIA GPUs will show up as either VGA or 3D controllers. |
| 57 | 59 | ( |
| @@ -73,11 +75,15 @@ kernel::pci_device_table!( · 15 unmodified lines | ||
| 73 | 75 | ] |
| 74 | 76 | ); |
| 75 | 77 | |
| 76 | −impl pci::Driver for NovaCore { | |
| 78 | +impl pci::Driver for NovaCoreDriver { | |
| 77 | 79 | type IdInfo = (); |
| 80 | + type Data<'bound> = NovaCore<'bound>; | |
| 78 | 81 | const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; |
| 79 | 82 | |
| 80 | − fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { | |
| 83 | + fn probe<'bound>( | |
| 84 | + pdev: &'bound pci::Device<Core<'_>>, | |
| 85 | + _info: &'bound Self::IdInfo, | |
| 86 | + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { | |
| 81 | 87 | pin_init::pin_init_scope(move || { |
| 82 | 88 | dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); |
| 83 | 89 | |
| @@ -89,26 +95,28 @@ impl pci::Driver for NovaCore { · 5 unmodified lines | ||
| 89 | 95 | // other threads of execution. |
| 90 | 96 | unsafe { pdev.dma_set_mask_and_coherent(DmaMask::new::<GPU_DMA_BITS>())? }; |
| 91 | 97 | |
| 92 | − let bar = Arc::pin_init( | |
| 93 | − pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0"), | |
| 98 | + let bar = Arc::new( | |
| 99 | + pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0")? | |
| 100 | + .into_devres()?, | |
| 94 | 101 | GFP_KERNEL, |
| 95 | 102 | )?; |
| 96 | 103 | |
| 97 | − Ok(try_pin_init!(Self { | |
| 104 | + Ok(try_pin_init!(NovaCore { | |
| 98 | 105 | gpu <- Gpu::new(pdev, bar.clone(), bar.access(pdev.as_ref())?), |
| 99 | − _reg <- auxiliary::Registration::new( | |
| 106 | + _reg: auxiliary::Registration::new( | |
| 100 | 107 | pdev.as_ref(), |
| 101 | 108 | c"nova-drm", |
| 102 | 109 | // TODO[XARR]: Use XArray or perhaps IDA for proper ID allocation/recycling. For |
| 103 | 110 | // now, use a simple atomic counter that never recycles IDs. |
| 104 | 111 | AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed), |
| 105 | − crate::MODULE_NAME | |
| 106 | − ), | |
| 112 | + crate::MODULE_NAME, | |
| 113 | + (), | |
| 114 | + )?, | |
| 107 | 115 | })) |
| 108 | 116 | }) |
| 109 | 117 | } |
| 110 | 118 | |
| 111 | − fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) { | |
| 119 | + fn unbind<'bound>(pdev: &'bound pci::Device<Core<'_>>, this: Pin<&Self::Data<'bound>>) { | |
| 112 | 120 | this.gpu.unbind(pdev.as_ref()); |
| 113 | 121 | } |
| 114 | 122 | } |
| @@ -278,7 +278,7 @@ impl Gpu { · 277 unmodified lines | ||
| 278 | 278 | /// Called when the corresponding [`Device`](device::Device) is unbound. |
| 279 | 279 | /// |
| 280 | 280 | /// Note: This method must only be called from `Driver::unbind`. |
| 281 | − pub(crate) fn unbind(&self, dev: &device::Device<device::Core>) { | |
| 281 | + pub(crate) fn unbind(&self, dev: &device::Device<device::Core<'_>>) { | |
| 282 | 282 | kernel::warn_on!(self |
| 283 | 283 | .bar |
| 284 | 284 | .access(dev) |
| @@ -47,7 +47,7 @@ struct NovaCoreModule { · 46 unmodified lines | ||
| 47 | 47 | // Fields are dropped in declaration order, so `_driver` is dropped first, |
| 48 | 48 | // then `_debugfs_guard` clears `DEBUGFS_ROOT`. |
| 49 | 49 | #[pin] |
| 50 | − _driver: Registration<pci::Adapter<driver::NovaCore>>, | |
| 50 | + _driver: Registration<pci::Adapter<driver::NovaCoreDriver>>, | |
| 51 | 51 | _debugfs_guard: DebugfsRootGuard, |
| 52 | 52 | } |
| 53 | 53 | |
| @@ -548,34 +548,6 @@ static ssize_t device_show(struct device *dev, · 547 unmodified lines | ||
| 548 | 548 | } |
| 549 | 549 | static DEVICE_ATTR_RO(device); |
| 550 | 550 | |
| 551 | −static ssize_t driver_override_store(struct device *dev, | |
| 552 | − struct device_attribute *attr, | |
| 553 | − const char *buf, size_t count) | |
| 554 | −{ | |
| 555 | − struct hv_device *hv_dev = device_to_hv_device(dev); | |
| 556 | − int ret; | |
| 557 | − | |
| 558 | − ret = driver_set_override(dev, &hv_dev->driver_override, buf, count); | |
| 559 | − if (ret) | |
| 560 | − return ret; | |
| 561 | − | |
| 562 | − return count; | |
| 563 | −} | |
| 564 | − | |
| 565 | −static ssize_t driver_override_show(struct device *dev, | |
| 566 | − struct device_attribute *attr, char *buf) | |
| 567 | −{ | |
| 568 | − struct hv_device *hv_dev = device_to_hv_device(dev); | |
| 569 | − ssize_t len; | |
| 570 | − | |
| 571 | − device_lock(dev); | |
| 572 | − len = sysfs_emit(buf, "%s\n", hv_dev->driver_override); | |
| 573 | − device_unlock(dev); | |
| 574 | − | |
| 575 | − return len; | |
| 576 | −} | |
| 577 | −static DEVICE_ATTR_RW(driver_override); | |
| 578 | − | |
| 579 | 551 | /* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */ |
| 580 | 552 | static struct attribute *vmbus_dev_attrs[] = { |
| 581 | 553 | &dev_attr_id.attr, |
| @@ -606,7 +578,6 @@ static struct attribute *vmbus_dev_attrs[] = { · 24 unmodified lines | ||
| 606 | 578 | &dev_attr_channel_vp_mapping.attr, |
| 607 | 579 | &dev_attr_vendor.attr, |
| 608 | 580 | &dev_attr_device.attr, |
| 609 | − &dev_attr_driver_override.attr, | |
| 610 | 581 | NULL, |
| 611 | 582 | }; |
| 612 | 583 | |
| @@ -718,9 +689,11 @@ static const struct hv_vmbus_device_id *hv_vmbus_get_id(const struct hv_driver * · 105 unmodified lines | ||
| 718 | 689 | { |
| 719 | 690 | const guid_t *guid = &dev->dev_type; |
| 720 | 691 | const struct hv_vmbus_device_id *id; |
| 692 | + int ret; | |
| 721 | 693 | |
| 722 | − /* When driver_override is set, only bind to the matching driver */ | |
| 723 | − if (dev->driver_override && strcmp(dev->driver_override, drv->name)) | |
| 694 | + /* If a driver override is set, only bind to the matching driver */ | |
| 695 | + ret = device_match_driver_override(&dev->device, &drv->driver); | |
| 696 | + if (ret == 0) | |
| 724 | 697 | return NULL; |
| 725 | 698 | |
| 726 | 699 | /* 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 * · 1 unmodified line | ||
| 728 | 701 | if (!id) |
| 729 | 702 | id = hv_vmbus_dev_match(drv->id_table, guid); |
| 730 | 703 | |
| 731 | − /* driver_override will always match, send a dummy id */ | |
| 732 | − if (!id && dev->driver_override) | |
| 704 | + /* | |
| 705 | + * If there's a matching driver override, this function should succeed, | |
| 706 | + * thus return a dummy device ID if no matching ID is found. | |
| 707 | + */ | |
| 708 | + if (!id && ret > 0) | |
| 733 | 709 | id = &vmbus_device_null; |
| 734 | 710 | |
| 735 | 711 | return id; |
| @@ -1031,6 +1007,7 @@ static const struct dev_pm_ops vmbus_pm = { · 295 unmodified lines | ||
| 1031 | 1007 | /* The one and only one */ |
| 1032 | 1008 | static const struct bus_type hv_bus = { |
| 1033 | 1009 | .name = "vmbus", |
| 1010 | + .driver_override = true, | |
| 1034 | 1011 | .match = vmbus_match, |
| 1035 | 1012 | .shutdown = vmbus_shutdown, |
| 1036 | 1013 | .remove = vmbus_remove, |
| @@ -706,7 +706,7 @@ static int __init catu_init(void) · 705 unmodified lines | ||
| 706 | 706 | { |
| 707 | 707 | int ret; |
| 708 | 708 | |
| 709 | − ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver, THIS_MODULE); | |
| 709 | + ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver); | |
| 710 | 710 | tmc_etr_set_catu_ops(&etr_catu_buf_ops); |
| 711 | 711 | return ret; |
| 712 | 712 | } |
| @@ -1694,8 +1694,9 @@ static void __exit coresight_exit(void) · 1693 unmodified lines | ||
| 1694 | 1694 | module_init(coresight_init); |
| 1695 | 1695 | module_exit(coresight_exit); |
| 1696 | 1696 | |
| 1697 | −int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, | |
| 1698 | − struct platform_driver *pdev_drv, struct module *owner) | |
| 1697 | +int coresight_init_driver_with_owner(const char *drv, struct amba_driver *amba_drv, | |
| 1698 | + struct platform_driver *pdev_drv, struct module *owner, | |
| 1699 | + const char *mod_name) | |
| 1699 | 1700 | { |
| 1700 | 1701 | int ret; |
| 1701 | 1702 | |
| @@ -1705,7 +1706,7 @@ int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, · 3 unmodified lines | ||
| 1705 | 1706 | return ret; |
| 1706 | 1707 | } |
| 1707 | 1708 | |
| 1708 | − ret = __platform_driver_register(pdev_drv, owner); | |
| 1709 | + ret = __platform_driver_register(pdev_drv, owner, mod_name); | |
| 1709 | 1710 | if (!ret) |
| 1710 | 1711 | return 0; |
| 1711 | 1712 | |
| @@ -1713,7 +1714,7 @@ int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, · 1 unmodified line | ||
| 1713 | 1714 | amba_driver_unregister(amba_drv); |
| 1714 | 1715 | return ret; |
| 1715 | 1716 | } |
| 1716 | −EXPORT_SYMBOL_GPL(coresight_init_driver); | |
| 1717 | +EXPORT_SYMBOL_GPL(coresight_init_driver_with_owner); | |
| 1717 | 1718 | |
| 1718 | 1719 | void coresight_remove_driver(struct amba_driver *amba_drv, |
| 1719 | 1720 | struct platform_driver *pdev_drv) |
| @@ -757,8 +757,7 @@ static struct platform_driver debug_platform_driver = { · 756 unmodified lines | ||
| 757 | 757 | |
| 758 | 758 | static int __init debug_init(void) |
| 759 | 759 | { |
| 760 | − return coresight_init_driver("debug", &debug_driver, &debug_platform_driver, | |
| 761 | − THIS_MODULE); | |
| 760 | + return coresight_init_driver("debug", &debug_driver, &debug_platform_driver); | |
| 762 | 761 | } |
| 763 | 762 | |
| 764 | 763 | static void __exit debug_exit(void) |
| @@ -412,8 +412,7 @@ static struct amba_driver dynamic_funnel_driver = { · 411 unmodified lines | ||
| 412 | 412 | |
| 413 | 413 | static int __init funnel_init(void) |
| 414 | 414 | { |
| 415 | − return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver, | |
| 416 | − THIS_MODULE); | |
| 415 | + return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver); | |
| 417 | 416 | } |
| 418 | 417 | |
| 419 | 418 | static void __exit funnel_exit(void) |
| @@ -418,8 +418,7 @@ static struct amba_driver dynamic_replicator_driver = { · 417 unmodified lines | ||
| 418 | 418 | |
| 419 | 419 | static int __init replicator_init(void) |
| 420 | 420 | { |
| 421 | − return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver, | |
| 422 | − THIS_MODULE); | |
| 421 | + return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver); | |
| 423 | 422 | } |
| 424 | 423 | |
| 425 | 424 | static void __exit replicator_exit(void) |
| @@ -1050,7 +1050,7 @@ static struct platform_driver stm_platform_driver = { · 1049 unmodified lines | ||
| 1050 | 1050 | |
| 1051 | 1051 | static int __init stm_init(void) |
| 1052 | 1052 | { |
| 1053 | − return coresight_init_driver("stm", &stm_driver, &stm_platform_driver, THIS_MODULE); | |
| 1053 | + return coresight_init_driver("stm", &stm_driver, &stm_platform_driver); | |
| 1054 | 1054 | } |
| 1055 | 1055 | |
| 1056 | 1056 | static void __exit stm_exit(void) |
| @@ -1046,7 +1046,7 @@ static struct platform_driver tmc_platform_driver = { · 1045 unmodified lines | ||
| 1046 | 1046 | |
| 1047 | 1047 | static int __init tmc_init(void) |
| 1048 | 1048 | { |
| 1049 | − return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver, THIS_MODULE); | |
| 1049 | + return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver); | |
| 1050 | 1050 | } |
| 1051 | 1051 | |
| 1052 | 1052 | static void __exit tmc_exit(void) |
| @@ -344,7 +344,7 @@ static struct platform_driver itnoc_driver = { · 343 unmodified lines | ||
| 344 | 344 | |
| 345 | 345 | static int __init tnoc_init(void) |
| 346 | 346 | { |
| 347 | − return coresight_init_driver("tnoc", &trace_noc_driver, &itnoc_driver, THIS_MODULE); | |
| 347 | + return coresight_init_driver("tnoc", &trace_noc_driver, &itnoc_driver); | |
| 348 | 348 | } |
| 349 | 349 | |
| 350 | 350 | static void __exit tnoc_exit(void) |
| @@ -1563,8 +1563,7 @@ static struct platform_driver static_tpdm_driver = { · 1562 unmodified lines | ||
| 1563 | 1563 | |
| 1564 | 1564 | static int __init tpdm_init(void) |
| 1565 | 1565 | { |
| 1566 | − return coresight_init_driver("tpdm", &dynamic_tpdm_driver, &static_tpdm_driver, | |
| 1567 | − THIS_MODULE); | |
| 1566 | + return coresight_init_driver("tpdm", &dynamic_tpdm_driver, &static_tpdm_driver); | |
| 1568 | 1567 | } |
| 1569 | 1568 | |
| 1570 | 1569 | static void __exit tpdm_exit(void) |
| @@ -310,7 +310,7 @@ static struct platform_driver tpiu_platform_driver = { · 309 unmodified lines | ||
| 310 | 310 | |
| 311 | 311 | static int __init tpiu_init(void) |
| 312 | 312 | { |
| 313 | − return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver, THIS_MODULE); | |
| 313 | + return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver); | |
| 314 | 314 | } |
| 315 | 315 | |
| 316 | 316 | static void __exit tpiu_exit(void) |
| @@ -176,11 +176,6 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, · 175 unmodified lines | ||
| 176 | 176 | return NOTIFY_OK; |
| 177 | 177 | } |
| 178 | 178 | |
| 179 | − /* | |
| 180 | − * Clear the flag before adding the device so that fw_devlink | |
| 181 | − * doesn't skip adding consumers to this device. | |
| 182 | − */ | |
| 183 | − fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE); | |
| 184 | 179 | client = of_i2c_register_device(adap, rd->dn); |
| 185 | 180 | if (IS_ERR(client)) { |
| 186 | 181 | dev_err(&adap->dev, "failed to create client for '%pOF'\n", |
| @@ -2149,18 +2149,21 @@ EXPORT_SYMBOL_GPL(dma_iova_destroy); · 2148 unmodified lines | ||
| 2149 | 2149 | |
| 2150 | 2150 | void iommu_setup_dma_ops(struct device *dev, struct iommu_domain *domain) |
| 2151 | 2151 | { |
| 2152 | + bool dma_iommu; | |
| 2153 | + | |
| 2152 | 2154 | if (dev_is_pci(dev)) |
| 2153 | 2155 | dev->iommu->pci_32bit_workaround = !iommu_dma_forcedac; |
| 2154 | 2156 | |
| 2155 | − dev->dma_iommu = iommu_is_dma_domain(domain); | |
| 2156 | − if (dev->dma_iommu && iommu_dma_init_domain(domain, dev)) | |
| 2157 | + dma_iommu = iommu_is_dma_domain(domain); | |
| 2158 | + dev_assign_dma_iommu(dev, dma_iommu); | |
| 2159 | + if (dma_iommu && iommu_dma_init_domain(domain, dev)) | |
| 2157 | 2160 | goto out_err; |
| 2158 | 2161 | |
| 2159 | 2162 | return; |
| 2160 | 2163 | out_err: |
| 2161 | 2164 | pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n", |
| 2162 | 2165 | dev_name(dev)); |
| 2163 | − dev->dma_iommu = false; | |
| 2166 | + dev_clear_dma_iommu(dev); | |
| 2164 | 2167 | } |
| 2165 | 2168 | |
| 2166 | 2169 | static bool has_msi_cookie(const struct iommu_domain *domain) |
| @@ -611,9 +611,8 @@ static void iommu_deinit_device(struct device *dev) · 610 unmodified lines | ||
| 611 | 611 | dev->iommu_group = NULL; |
| 612 | 612 | module_put(ops->owner); |
| 613 | 613 | dev_iommu_free(dev); |
| 614 | −#ifdef CONFIG_IOMMU_DMA | |
| 615 | − dev->dma_iommu = false; | |
| 616 | −#endif | |
| 614 | + if (IS_ENABLED(CONFIG_IOMMU_DMA)) | |
| 615 | + dev_clear_dma_iommu(dev); | |
| 617 | 616 | } |
| 618 | 617 | |
| 619 | 618 | static struct iommu_domain *pasid_array_entry_to_domain(void *entry) |
| @@ -349,7 +349,7 @@ static int xpcs_plat_init_dev(struct dw_xpcs_plat *pxpcs) · 348 unmodified lines | ||
| 349 | 349 | * up later. Make sure DD-core is aware of the OF-node being re-used. |
| 350 | 350 | */ |
| 351 | 351 | device_set_node(&mdiodev->dev, fwnode_handle_get(dev_fwnode(dev))); |
| 352 | − mdiodev->dev.of_node_reused = true; | |
| 352 | + dev_set_of_node_reused(&mdiodev->dev); | |
| 353 | 353 | |
| 354 | 354 | /* Pass the data further so the DW XPCS driver core could use it */ |
| 355 | 355 | mdiodev->dev.platform_data = (void *)device_get_match_data(dev); |
| @@ -26,7 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | const struct of_device_id *of_match_device(const struct of_device_id *matches, |
| 27 | 27 | const struct device *dev) |
| 28 | 28 | { |
| 29 | − if (!matches || !dev->of_node || dev->of_node_reused) | |
| 29 | + if (!matches || !dev->of_node || dev_of_node_reused(dev)) | |
| 30 | 30 | return NULL; |
| 31 | 31 | return of_match_node(matches, dev->of_node); |
| 32 | 32 | } |
| @@ -192,7 +192,7 @@ ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len) · 159 unmodified lines | ||
| 192 | 192 | { |
| 193 | 193 | ssize_t sl; |
| 194 | 194 | |
| 195 | − if (!dev || !dev->of_node || dev->of_node_reused) | |
| 195 | + if (!dev || !dev->of_node || dev_of_node_reused(dev)) | |
| 196 | 196 | return -ENODEV; |
| 197 | 197 | |
| 198 | 198 | 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 * · 55 unmodified lines | ||
| 254 | 254 | { |
| 255 | 255 | int sl; |
| 256 | 256 | |
| 257 | − if ((!dev) || (!dev->of_node) || dev->of_node_reused) | |
| 257 | + if ((!dev) || (!dev->of_node) || dev_of_node_reused(dev)) | |
| 258 | 258 | return -ENODEV; |
| 259 | 259 | |
| 260 | 260 | /* Devicetree modalias is tricky, we add it in 2 steps */ |
| @@ -225,7 +225,6 @@ static void __of_attach_node(struct device_node *np) · 224 unmodified lines | ||
| 225 | 225 | np->sibling = np->parent->child; |
| 226 | 226 | np->parent->child = np; |
| 227 | 227 | of_node_clear_flag(np, OF_DETACHED); |
| 228 | − fwnode_set_flag(&np->fwnode, FWNODE_FLAG_NOT_DEVICE); | |
| 229 | 228 | |
| 230 | 229 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 231 | 230 | |
| @@ -185,6 +185,15 @@ static int overlay_notify(struct overlay_changeset *ovcs, · 184 unmodified lines | ||
| 185 | 185 | return 0; |
| 186 | 186 | } |
| 187 | 187 | |
| 188 | +static void overlay_fw_devlink_refresh(struct overlay_changeset *ovcs) | |
| 189 | +{ | |
| 190 | + for (int i = 0; i < ovcs->count; i++) { | |
| 191 | + struct device_node *np = ovcs->fragments[i].target; | |
| 192 | + | |
| 193 | + fw_devlink_refresh_fwnode(of_fwnode_handle(np)); | |
| 194 | + } | |
| 195 | +} | |
| 196 | + | |
| 188 | 197 | /* |
| 189 | 198 | * The values of properties in the "/__symbols__" node are paths in |
| 190 | 199 | * the ovcs->overlay_root. When duplicating the properties, the paths |
| @@ -951,6 +960,12 @@ static int of_overlay_apply(struct overlay_changeset *ovcs, · 760 unmodified lines | ||
| 951 | 960 | pr_err("overlay apply changeset entry notify error %d\n", ret); |
| 952 | 961 | /* notify failure is not fatal, continue */ |
| 953 | 962 | |
| 963 | + /* | |
| 964 | + * Needs to happen after changeset notify to give the listeners a chance | |
| 965 | + * to finish creating all the devices they need to create. | |
| 966 | + */ | |
| 967 | + overlay_fw_devlink_refresh(ovcs); | |
| 968 | + | |
| 954 | 969 | ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_APPLY); |
| 955 | 970 | if (ret_tmp) |
| 956 | 971 | if (!ret) |
| @@ -744,11 +744,6 @@ static int of_platform_notify(struct notifier_block *nb, · 743 unmodified lines | ||
| 744 | 744 | if (of_node_check_flag(rd->dn, OF_POPULATED)) |
| 745 | 745 | return NOTIFY_OK; |
| 746 | 746 | |
| 747 | − /* | |
| 748 | − * Clear the flag before adding the device so that fw_devlink | |
| 749 | − * doesn't skip adding consumers to this device. | |
| 750 | − */ | |
| 751 | − fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE); | |
| 752 | 747 | /* pdev_parent may be NULL when no bus platform device */ |
| 753 | 748 | pdev_parent = of_find_device_by_node(parent); |
| 754 | 749 | pdev = of_platform_device_create(rd->dn, NULL, |
| @@ -38,7 +38,7 @@ int pci_set_of_node(struct pci_dev *dev) · 37 unmodified lines | ||
| 38 | 38 | struct device *pdev __free(put_device) = |
| 39 | 39 | bus_find_device_by_of_node(&platform_bus_type, node); |
| 40 | 40 | if (pdev) |
| 41 | − dev->bus->dev.of_node_reused = true; | |
| 41 | + dev_set_of_node_reused(&dev->bus->dev); | |
| 42 | 42 | |
| 43 | 43 | device_set_node(&dev->dev, of_fwnode_handle(no_free_ptr(node))); |
| 44 | 44 | return 0; |
| @@ -39,7 +39,7 @@ static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action, · 38 unmodified lines | ||
| 39 | 39 | * If we got here then the PCI device is the second after the |
| 40 | 40 | * power control platform device. Mark its OF node as reused. |
| 41 | 41 | */ |
| 42 | − dev->of_node_reused = true; | |
| 42 | + dev_set_of_node_reused(dev); | |
| 43 | 43 | break; |
| 44 | 44 | } |
| 45 | 45 | |
| @@ -92,7 +92,7 @@ struct Th1520WfHw { · 91 unmodified lines | ||
| 92 | 92 | #[pin_data(PinnedDrop)] |
| 93 | 93 | struct Th1520PwmDriverData { |
| 94 | 94 | #[pin] |
| 95 | − iomem: devres::Devres<IoMem<TH1520_PWM_REG_SIZE>>, | |
| 95 | + iomem: devres::Devres<IoMem<'static, TH1520_PWM_REG_SIZE>>, | |
| 96 | 96 | clk: Clk, |
| 97 | 97 | } |
| 98 | 98 | |
| @@ -316,12 +316,13 @@ kernel::of_device_table!( · 217 unmodified lines | ||
| 316 | 316 | |
| 317 | 317 | impl platform::Driver for Th1520PwmPlatformDriver { |
| 318 | 318 | type IdInfo = (); |
| 319 | + type Data<'bound> = Self; | |
| 319 | 320 | const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); |
| 320 | 321 | |
| 321 | − fn probe( | |
| 322 | − pdev: &platform::Device<Core>, | |
| 323 | − _id_info: Option<&Self::IdInfo>, | |
| 324 | − ) -> impl PinInit<Self, Error> { | |
| 322 | + fn probe<'bound>( | |
| 323 | + pdev: &'bound platform::Device<Core<'_>>, | |
| 324 | + _id_info: Option<&'bound Self::IdInfo>, | |
| 325 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 325 | 326 | let dev = pdev.as_ref(); |
| 326 | 327 | let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; |
| 327 | 328 | |
| @@ -351,7 +352,7 @@ impl platform::Driver for Th1520PwmPlatformDriver { · 23 unmodified lines | ||
| 351 | 352 | dev, |
| 352 | 353 | TH1520_MAX_PWM_NUM, |
| 353 | 354 | try_pin_init!(Th1520PwmDriverData { |
| 354 | − iomem <- request.iomap_sized::<TH1520_PWM_REG_SIZE>(), | |
| 355 | + iomem <- request.iomap_sized::<TH1520_PWM_REG_SIZE>()?.into_devres(), | |
| 355 | 356 | clk <- clk, |
| 356 | 357 | }), |
| 357 | 358 | )?; |
| @@ -1626,7 +1626,6 @@ static void qcom_glink_rpdev_release(struct device *dev) · 1625 unmodified lines | ||
| 1626 | 1626 | { |
| 1627 | 1627 | struct rpmsg_device *rpdev = to_rpmsg_device(dev); |
| 1628 | 1628 | |
| 1629 | − kfree(rpdev->driver_override); | |
| 1630 | 1629 | kfree(rpdev); |
| 1631 | 1630 | } |
| 1632 | 1631 | |
| @@ -1862,7 +1861,6 @@ static void qcom_glink_device_release(struct device *dev) · 229 unmodified lines | ||
| 1862 | 1861 | |
| 1863 | 1862 | /* Release qcom_glink_alloc_channel() reference */ |
| 1864 | 1863 | kref_put(&channel->refcount, qcom_glink_channel_release); |
| 1865 | − kfree(rpdev->driver_override); | |
| 1866 | 1864 | kfree(rpdev); |
| 1867 | 1865 | } |
| 1868 | 1866 | |
| @@ -358,33 +358,6 @@ rpmsg_show_attr(src, src, "0x%x\n"); · 357 unmodified lines | ||
| 358 | 358 | rpmsg_show_attr(dst, dst, "0x%x\n"); |
| 359 | 359 | rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n"); |
| 360 | 360 | |
| 361 | −static ssize_t driver_override_store(struct device *dev, | |
| 362 | − struct device_attribute *attr, | |
| 363 | − const char *buf, size_t count) | |
| 364 | −{ | |
| 365 | − struct rpmsg_device *rpdev = to_rpmsg_device(dev); | |
| 366 | − int ret; | |
| 367 | − | |
| 368 | − ret = driver_set_override(dev, &rpdev->driver_override, buf, count); | |
| 369 | − if (ret) | |
| 370 | − return ret; | |
| 371 | − | |
| 372 | − return count; | |
| 373 | −} | |
| 374 | − | |
| 375 | −static ssize_t driver_override_show(struct device *dev, | |
| 376 | − struct device_attribute *attr, char *buf) | |
| 377 | −{ | |
| 378 | − struct rpmsg_device *rpdev = to_rpmsg_device(dev); | |
| 379 | − ssize_t len; | |
| 380 | − | |
| 381 | − device_lock(dev); | |
| 382 | − len = sysfs_emit(buf, "%s\n", rpdev->driver_override); | |
| 383 | − device_unlock(dev); | |
| 384 | − return len; | |
| 385 | −} | |
| 386 | −static DEVICE_ATTR_RW(driver_override); | |
| 387 | − | |
| 388 | 361 | static ssize_t modalias_show(struct device *dev, |
| 389 | 362 | struct device_attribute *attr, char *buf) |
| 390 | 363 | { |
| @@ -405,7 +378,6 @@ static struct attribute *rpmsg_dev_attrs[] = { · 14 unmodified lines | ||
| 405 | 378 | &dev_attr_dst.attr, |
| 406 | 379 | &dev_attr_src.attr, |
| 407 | 380 | &dev_attr_announce.attr, |
| 408 | − &dev_attr_driver_override.attr, | |
| 409 | 381 | NULL, |
| 410 | 382 | }; |
| 411 | 383 | ATTRIBUTE_GROUPS(rpmsg_dev); |
| @@ -424,9 +396,11 @@ static int rpmsg_dev_match(struct device *dev, const struct device_driver *drv) · 12 unmodified lines | ||
| 424 | 396 | const struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv); |
| 425 | 397 | const struct rpmsg_device_id *ids = rpdrv->id_table; |
| 426 | 398 | unsigned int i; |
| 399 | + int ret; | |
| 427 | 400 | |
| 428 | − if (rpdev->driver_override) | |
| 429 | − return !strcmp(rpdev->driver_override, drv->name); | |
| 401 | + ret = device_match_driver_override(dev, drv); | |
| 402 | + if (ret >= 0) | |
| 403 | + return ret; | |
| 430 | 404 | |
| 431 | 405 | if (ids) |
| 432 | 406 | for (i = 0; ids[i].name[0]; i++) |
| @@ -535,6 +509,7 @@ static const struct bus_type rpmsg_bus = { · 102 unmodified lines | ||
| 535 | 509 | .name = "rpmsg", |
| 536 | 510 | .match = rpmsg_dev_match, |
| 537 | 511 | .dev_groups = rpmsg_dev_groups, |
| 512 | + .driver_override = true, | |
| 538 | 513 | .uevent = rpmsg_uevent, |
| 539 | 514 | .probe = rpmsg_dev_probe, |
| 540 | 515 | .remove = rpmsg_dev_remove, |
| @@ -560,11 +535,9 @@ int rpmsg_register_device_override(struct rpmsg_device *rpdev, · 19 unmodified lines | ||
| 560 | 535 | |
| 561 | 536 | device_initialize(dev); |
| 562 | 537 | if (driver_override) { |
| 563 | − ret = driver_set_override(dev, &rpdev->driver_override, | |
| 564 | − driver_override, | |
| 565 | − strlen(driver_override)); | |
| 538 | + ret = device_set_driver_override(dev, driver_override); | |
| 566 | 539 | if (ret) { |
| 567 | − dev_err(dev, "device_set_override failed: %d\n", ret); | |
| 540 | + dev_err(dev, "device_set_driver_override() failed: %d\n", ret); | |
| 568 | 541 | put_device(dev); |
| 569 | 542 | return ret; |
| 570 | 543 | } |
| @@ -573,8 +546,6 @@ int rpmsg_register_device_override(struct rpmsg_device *rpdev, · 2 unmodified lines | ||
| 573 | 546 | ret = device_add(dev); |
| 574 | 547 | if (ret) { |
| 575 | 548 | dev_err(dev, "device_add failed: %d\n", ret); |
| 576 | − kfree(rpdev->driver_override); | |
| 577 | − rpdev->driver_override = NULL; | |
| 578 | 549 | put_device(dev); |
| 579 | 550 | } |
| 580 | 551 | |
| @@ -374,7 +374,6 @@ static void virtio_rpmsg_release_device(struct device *dev) · 373 unmodified lines | ||
| 374 | 374 | struct rpmsg_device *rpdev = to_rpmsg_device(dev); |
| 375 | 375 | struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev); |
| 376 | 376 | |
| 377 | − kfree(rpdev->driver_override); | |
| 378 | 377 | kfree(vch); |
| 379 | 378 | } |
| 380 | 379 | |
| @@ -2342,7 +2342,7 @@ static int __init tegra194_cbb_init(void) · 2341 unmodified lines | ||
| 2342 | 2342 | { |
| 2343 | 2343 | return platform_driver_register(&tegra194_cbb_driver); |
| 2344 | 2344 | } |
| 2345 | −pure_initcall(tegra194_cbb_init); | |
| 2345 | +core_initcall(tegra194_cbb_init); | |
| 2346 | 2346 | |
| 2347 | 2347 | static void __exit tegra194_cbb_exit(void) |
| 2348 | 2348 | { |
| @@ -1774,7 +1774,7 @@ static int __init tegra234_cbb_init(void) · 1773 unmodified lines | ||
| 1774 | 1774 | { |
| 1775 | 1775 | return platform_driver_register(&tegra234_cbb_driver); |
| 1776 | 1776 | } |
| 1777 | −pure_initcall(tegra234_cbb_init); | |
| 1777 | +core_initcall(tegra234_cbb_init); | |
| 1778 | 1778 | |
| 1779 | 1779 | static void __exit tegra234_cbb_exit(void) |
| 1780 | 1780 | { |
| @@ -5003,11 +5003,6 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action, · 5002 unmodified lines | ||
| 5003 | 5003 | return NOTIFY_OK; |
| 5004 | 5004 | } |
| 5005 | 5005 | |
| 5006 | − /* | |
| 5007 | − * Clear the flag before adding the device so that fw_devlink | |
| 5008 | − * doesn't skip adding consumers to this device. | |
| 5009 | − */ | |
| 5010 | − fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE); | |
| 5011 | 5006 | spi = of_register_spi_device(ctlr, rd->dn); |
| 5012 | 5007 | put_device(&ctlr->dev); |
| 5013 | 5008 | |
| @@ -74,7 +74,7 @@ static int serial_base_device_init(struct uart_port *port, · 73 unmodified lines | ||
| 74 | 74 | dev->parent = parent_dev; |
| 75 | 75 | dev->bus = &serial_base_bus_type; |
| 76 | 76 | dev->release = release; |
| 77 | − dev->of_node_reused = true; | |
| 77 | + dev_set_of_node_reused(dev); | |
| 78 | 78 | |
| 79 | 79 | device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev))); |
| 80 | 80 | |
| @@ -593,7 +593,7 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx) · 592 unmodified lines | ||
| 593 | 593 | d->gadget.max_speed = USB_SPEED_HIGH; |
| 594 | 594 | d->gadget.speed = USB_SPEED_UNKNOWN; |
| 595 | 595 | d->gadget.dev.of_node = vhub->pdev->dev.of_node; |
| 596 | − d->gadget.dev.of_node_reused = true; | |
| 596 | + dev_set_of_node_reused(&d->gadget.dev); | |
| 597 | 597 | |
| 598 | 598 | rc = usb_add_gadget_udc(d->port_dev, &d->gadget); |
| 599 | 599 | if (rc != 0) |
| @@ -597,10 +597,13 @@ void kernfs_put(struct kernfs_node *kn) · 596 unmodified lines | ||
| 597 | 597 | */ |
| 598 | 598 | parent = kernfs_parent(kn); |
| 599 | 599 | |
| 600 | − WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS, | |
| 601 | − "kernfs_put: %s/%s: released with incorrect active_ref %d\n", | |
| 602 | − parent ? rcu_dereference(parent->name) : "", | |
| 603 | − rcu_dereference(kn->name), atomic_read(&kn->active)); | |
| 600 | + if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS) { | |
| 601 | + guard(rcu)(); | |
| 602 | + WARN_ONCE(1, | |
| 603 | + "kernfs_put: %s/%s: released with incorrect active_ref %d\n", | |
| 604 | + parent ? rcu_dereference(parent->name) : "", | |
| 605 | + rcu_dereference(kn->name), atomic_read(&kn->active)); | |
| 606 | + } | |
| 604 | 607 | |
| 605 | 608 | if (kernfs_type(kn) == KERNFS_LINK) |
| 606 | 609 | kernfs_put(kn->symlink.target_kn); |
| @@ -70,9 +70,8 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v) · 69 unmodified lines | ||
| 70 | 70 | * The code works fine with PAGE_SIZE return but it's likely to |
| 71 | 71 | * indicate truncated result or overflow in normal use cases. |
| 72 | 72 | */ |
| 73 | − if (count >= (ssize_t)PAGE_SIZE) { | |
| 74 | − printk("fill_read_buffer: %pS returned bad count\n", | |
| 75 | − ops->show); | |
| 73 | + if (count >= PAGE_SIZE) { | |
| 74 | + WARN(1, "OOB write or bad count %zd at %pS\n", count, ops->show); | |
| 76 | 75 | /* Try to struggle along */ |
| 77 | 76 | count = PAGE_SIZE - 1; |
| 78 | 77 | } |
| @@ -120,6 +119,10 @@ static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf, · 41 unmodified lines | ||
| 120 | 119 | len = ops->show(kobj, of->kn->priv, buf); |
| 121 | 120 | if (len < 0) |
| 122 | 121 | return len; |
| 122 | + if (len >= (ssize_t)PAGE_SIZE) { | |
| 123 | + printk("fill_read_buffer: %pS returned bad count\n", ops->show); | |
| 124 | + len = PAGE_SIZE - 1; | |
| 125 | + } | |
| 123 | 126 | if (pos) { |
| 124 | 127 | if (len <= pos) |
| 125 | 128 | return 0; |
| @@ -189,6 +189,10 @@ struct acpi_driver { · 188 unmodified lines | ||
| 189 | 189 | * ----------- |
| 190 | 190 | */ |
| 191 | 191 | |
| 192 | +bool acpi_of_match_device(const struct acpi_device *adev, | |
| 193 | + const struct of_device_id *of_match_table, | |
| 194 | + const struct of_device_id **of_id); | |
| 195 | + | |
| 192 | 196 | /* Status (_STA) */ |
| 193 | 197 | |
| 194 | 198 | struct acpi_device_status { |
| @@ -996,6 +1000,13 @@ int acpi_scan_add_dep(acpi_handle handle, struct acpi_handle_list *dep_devices); · 801 unmodified lines | ||
| 996 | 1000 | u32 arch_acpi_add_auto_dep(acpi_handle handle); |
| 997 | 1001 | #else /* CONFIG_ACPI */ |
| 998 | 1002 | |
| 1003 | +static inline bool acpi_of_match_device(const struct acpi_device *adev, | |
| 1004 | + const struct of_device_id *of_match_table, | |
| 1005 | + const struct of_device_id **of_id) | |
| 1006 | +{ | |
| 1007 | + return false; | |
| 1008 | +} | |
| 1009 | + | |
| 999 | 1010 | static inline int register_acpi_bus_type(void *bus) { return 0; } |
| 1000 | 1011 | static inline int unregister_acpi_bus_type(void *bus) { return 0; } |
| 1001 | 1012 | |
| @@ -71,11 +71,6 @@ struct amba_device { · 70 unmodified lines | ||
| 71 | 71 | unsigned int cid; |
| 72 | 72 | struct amba_cs_uci_id uci; |
| 73 | 73 | unsigned int irq[AMBA_NR_IRQS]; |
| 74 | − /* | |
| 75 | − * Driver name to force a match. Do not set directly, because core | |
| 76 | − * frees it. Use driver_set_override() to set or clear it. | |
| 77 | − */ | |
| 78 | − const char *driver_override; | |
| 79 | 74 | }; |
| 80 | 75 | |
| 81 | 76 | struct amba_driver { |
| @@ -62,6 +62,9 @@ · 61 unmodified lines | ||
| 62 | 62 | * @sysfs.irqs: irqs xarray contains irq indices which are used by the device, |
| 63 | 63 | * @sysfs.lock: Synchronize irq sysfs creation, |
| 64 | 64 | * @sysfs.irq_dir_exists: whether "irqs" directory exists, |
| 65 | + * @registration_data_rust: private data owned by the registering (parent) | |
| 66 | + * driver; valid for as long as the device is | |
| 67 | + * registered with the driver core, | |
| 65 | 68 | * |
| 66 | 69 | * An auxiliary_device represents a part of its parent device's functionality. |
| 67 | 70 | * It is given a name that, combined with the registering drivers |
| @@ -148,6 +151,7 @@ struct auxiliary_device { · 80 unmodified lines | ||
| 148 | 151 | struct mutex lock; /* Synchronize irq sysfs creation */ |
| 149 | 152 | bool irq_dir_exists; |
| 150 | 153 | } sysfs; |
| 154 | + void *registration_data_rust; | |
| 151 | 155 | }; |
| 152 | 156 | |
| 153 | 157 | /** |
| @@ -137,9 +137,6 @@ struct cdx_controller { · 136 unmodified lines | ||
| 137 | 137 | * @enabled: is this bus enabled |
| 138 | 138 | * @msi_dev_id: MSI Device ID associated with CDX device |
| 139 | 139 | * @num_msi: Number of MSI's supported by the device |
| 140 | − * @driver_override: driver name to force a match; do not set directly, | |
| 141 | − * because core frees it; use driver_set_override() to | |
| 142 | − * set or clear it. | |
| 143 | 140 | * @irqchip_lock: lock to synchronize irq/msi configuration |
| 144 | 141 | * @msi_write_pending: MSI write pending for this device |
| 145 | 142 | */ |
| @@ -165,7 +162,6 @@ struct cdx_device { · 19 unmodified lines | ||
| 165 | 162 | bool enabled; |
| 166 | 163 | u32 msi_dev_id; |
| 167 | 164 | u32 num_msi; |
| 168 | − const char *driver_override; | |
| 169 | 165 | struct mutex irqchip_lock; |
| 170 | 166 | bool msi_write_pending; |
| 171 | 167 | }; |
| @@ -691,8 +691,11 @@ coresight_find_output_type(struct coresight_platform_data *pdata, · 690 unmodified lines | ||
| 691 | 691 | enum coresight_dev_type type, |
| 692 | 692 | union coresight_dev_subtype subtype); |
| 693 | 693 | |
| 694 | −int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, | |
| 695 | − struct platform_driver *pdev_drv, struct module *owner); | |
| 694 | +int coresight_init_driver_with_owner(const char *drv, struct amba_driver *amba_drv, | |
| 695 | + struct platform_driver *pdev_drv, struct module *owner, | |
| 696 | + const char *mod_name); | |
| 697 | +#define coresight_init_driver(drv, amba_drv, pdev_drv) \ | |
| 698 | + coresight_init_driver_with_owner(drv, amba_drv, pdev_drv, THIS_MODULE, KBUILD_MODNAME) | |
| 696 | 699 | |
| 697 | 700 | void coresight_remove_driver(struct amba_driver *amba_drv, |
| 698 | 701 | struct platform_driver *pdev_drv); |
| @@ -38,7 +38,6 @@ struct device_private; · 37 unmodified lines | ||
| 38 | 38 | struct device_driver; |
| 39 | 39 | struct driver_private; |
| 40 | 40 | struct module; |
| 41 | −struct class; | |
| 42 | 41 | struct subsys_private; |
| 43 | 42 | struct device_node; |
| 44 | 43 | struct fwnode_handle; |
| @@ -104,10 +103,18 @@ struct device_type { · 59 unmodified lines | ||
| 104 | 103 | */ |
| 105 | 104 | struct device_attribute { |
| 106 | 105 | struct attribute attr; |
| 107 | − ssize_t (*show)(struct device *dev, struct device_attribute *attr, | |
| 108 | − char *buf); | |
| 109 | − ssize_t (*store)(struct device *dev, struct device_attribute *attr, | |
| 110 | − const char *buf, size_t count); | |
| 106 | + __SYSFS_FUNCTION_ALTERNATIVE( | |
| 107 | + ssize_t (*show)(struct device *dev, struct device_attribute *attr, | |
| 108 | + char *buf); | |
| 109 | + ssize_t (*show_const)(struct device *dev, const struct device_attribute *attr, | |
| 110 | + char *buf); | |
| 111 | + ); | |
| 112 | + __SYSFS_FUNCTION_ALTERNATIVE( | |
| 113 | + ssize_t (*store)(struct device *dev, struct device_attribute *attr, | |
| 114 | + const char *buf, size_t count); | |
| 115 | + ssize_t (*store_const)(struct device *dev, const struct device_attribute *attr, | |
| 116 | + const char *buf, size_t count); | |
| 117 | + ); | |
| 111 | 118 | }; |
| 112 | 119 | |
| 113 | 120 | /** |
| @@ -135,6 +142,77 @@ ssize_t device_store_bool(struct device *dev, struct device_attribute *attr, · 21 unmodified lines | ||
| 135 | 142 | ssize_t device_show_string(struct device *dev, struct device_attribute *attr, |
| 136 | 143 | char *buf); |
| 137 | 144 | |
| 145 | +typedef ssize_t __device_show_handler_const(struct device *dev, const struct device_attribute *attr, | |
| 146 | + char *buf); | |
| 147 | +typedef ssize_t __device_store_handler_const(struct device *dev, const struct device_attribute *attr, | |
| 148 | + const char *buf, size_t count); | |
| 149 | + | |
| 150 | +#ifdef CONFIG_CFI | |
| 151 | + | |
| 152 | +#define __DEVICE_ATTR_SHOW_STORE(_show, _store) \ | |
| 153 | + .show = _Generic(_show, \ | |
| 154 | + __device_show_handler_const * : NULL, \ | |
| 155 | + default : _show \ | |
| 156 | + ), \ | |
| 157 | + .show_const = _Generic(_show, \ | |
| 158 | + __device_show_handler_const * : _show, \ | |
| 159 | + default : NULL \ | |
| 160 | + ), \ | |
| 161 | + .store = _Generic(_store, \ | |
| 162 | + __device_store_handler_const * : NULL, \ | |
| 163 | + default : _store \ | |
| 164 | + ), \ | |
| 165 | + .store_const = _Generic(_store, \ | |
| 166 | + __device_store_handler_const * : _store, \ | |
| 167 | + default : NULL \ | |
| 168 | + ), | |
| 169 | + | |
| 170 | +#else | |
| 171 | + | |
| 172 | +#define __DEVICE_ATTR_SHOW_STORE(_show, _store) \ | |
| 173 | + .show = _Generic(_show, \ | |
| 174 | + __device_show_handler_const * : (void *)_show, \ | |
| 175 | + default : _show \ | |
| 176 | + ), \ | |
| 177 | + .store = _Generic(_store, \ | |
| 178 | + __device_store_handler_const * : (void *)_store, \ | |
| 179 | + default : _store \ | |
| 180 | + ), \ | |
| 181 | + | |
| 182 | +#endif | |
| 183 | + | |
| 184 | + | |
| 185 | +#define __DEVICE_ATTR(_name, _mode, _show, _store) { \ | |
| 186 | + .attr = {.name = __stringify(_name), \ | |
| 187 | + .mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \ | |
| 188 | + __DEVICE_ATTR_SHOW_STORE(_show, _store) \ | |
| 189 | +} | |
| 190 | + | |
| 191 | +#define __DEVICE_ATTR_RO_MODE(_name, _mode) \ | |
| 192 | + __DEVICE_ATTR(_name, _mode, _name##_show, NULL) | |
| 193 | + | |
| 194 | +#define __DEVICE_ATTR_RO(_name) \ | |
| 195 | + __DEVICE_ATTR_RO_MODE(_name, 0444) | |
| 196 | + | |
| 197 | +#define __DEVICE_ATTR_WO(_name) \ | |
| 198 | + __DEVICE_ATTR(_name, 0200, NULL, _name##_store) | |
| 199 | + | |
| 200 | +#define __DEVICE_ATTR_RW_MODE(_name, _mode) \ | |
| 201 | + __DEVICE_ATTR(_name, _mode, _name##_show, _name##_store) | |
| 202 | + | |
| 203 | +#define __DEVICE_ATTR_RW(_name) \ | |
| 204 | + __DEVICE_ATTR_RW_MODE(_name, 0644) | |
| 205 | + | |
| 206 | +#ifdef CONFIG_DEBUG_LOCK_ALLOC | |
| 207 | +#define __DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) { \ | |
| 208 | + .attr = {.name = __stringify(_name), .mode = _mode, \ | |
| 209 | + .ignore_lockdep = true }, \ | |
| 210 | + __DEVICE_ATTR_SHOW_STORE(_show, _store) \ | |
| 211 | +} | |
| 212 | +#else | |
| 213 | +#define __DEVICE_ATTR_IGNORE_LOCKDEP __DEVICE_ATTR | |
| 214 | +#endif | |
| 215 | + | |
| 138 | 216 | /** |
| 139 | 217 | * DEVICE_ATTR - Define a device attribute. |
| 140 | 218 | * @_name: Attribute name. |
| @@ -155,20 +233,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, · 14 unmodified lines | ||
| 155 | 233 | * }; |
| 156 | 234 | */ |
| 157 | 235 | #define DEVICE_ATTR(_name, _mode, _show, _store) \ |
| 158 | − struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) | |
| 159 | − | |
| 160 | −/** | |
| 161 | − * DEVICE_ATTR_PREALLOC - Define a preallocated device attribute. | |
| 162 | − * @_name: Attribute name. | |
| 163 | − * @_mode: File mode. | |
| 164 | − * @_show: Show handler. Optional, but mandatory if attribute is readable. | |
| 165 | − * @_store: Store handler. Optional, but mandatory if attribute is writable. | |
| 166 | − * | |
| 167 | − * Like DEVICE_ATTR(), but ``SYSFS_PREALLOC`` is set on @_mode. | |
| 168 | − */ | |
| 169 | −#define DEVICE_ATTR_PREALLOC(_name, _mode, _show, _store) \ | |
| 170 | − struct device_attribute dev_attr_##_name = \ | |
| 171 | − __ATTR_PREALLOC(_name, _mode, _show, _store) | |
| 236 | + struct device_attribute dev_attr_##_name = __DEVICE_ATTR(_name, _mode, _show, _store) | |
| 172 | 237 | |
| 173 | 238 | /** |
| 174 | 239 | * 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, · 3 unmodified lines | ||
| 178 | 243 | * and @_store is <_name>_store. |
| 179 | 244 | */ |
| 180 | 245 | #define DEVICE_ATTR_RW(_name) \ |
| 181 | − struct device_attribute dev_attr_##_name = __ATTR_RW(_name) | |
| 246 | + struct device_attribute dev_attr_##_name = __DEVICE_ATTR_RW(_name) | |
| 182 | 247 | |
| 183 | 248 | /** |
| 184 | 249 | * 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, · 2 unmodified lines | ||
| 187 | 252 | * Like DEVICE_ATTR_RW(), but @_mode is 0600. |
| 188 | 253 | */ |
| 189 | 254 | #define DEVICE_ATTR_ADMIN_RW(_name) \ |
| 190 | − struct device_attribute dev_attr_##_name = __ATTR_RW_MODE(_name, 0600) | |
| 255 | + struct device_attribute dev_attr_##_name = __DEVICE_ATTR_RW_MODE(_name, 0600) | |
| 191 | 256 | |
| 192 | 257 | /** |
| 193 | 258 | * 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, · 7 unmodified lines | ||
| 201 | 266 | #define DEVICE_ATTR_RW_NAMED(_name, _attrname) \ |
| 202 | 267 | struct device_attribute dev_attr_##_name = { \ |
| 203 | 268 | .attr = { .name = _attrname, .mode = 0644 }, \ |
| 204 | − .show = _name##_show, \ | |
| 205 | − .store = _name##_store, \ | |
| 269 | + __DEVICE_ATTR_SHOW_STORE(_name##_show, _name##_store) \ | |
| 206 | 270 | } |
| 207 | 271 | |
| 208 | 272 | /** |
| @@ -212,7 +276,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, · 3 unmodified lines | ||
| 212 | 276 | * Like DEVICE_ATTR(), but @_mode is 0444 and @_show is <_name>_show. |
| 213 | 277 | */ |
| 214 | 278 | #define DEVICE_ATTR_RO(_name) \ |
| 215 | − struct device_attribute dev_attr_##_name = __ATTR_RO(_name) | |
| 279 | + struct device_attribute dev_attr_##_name = __DEVICE_ATTR_RO(_name) | |
| 216 | 280 | |
| 217 | 281 | /** |
| 218 | 282 | * 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, · 2 unmodified lines | ||
| 221 | 285 | * Like DEVICE_ATTR_RO(), but @_mode is 0400. |
| 222 | 286 | */ |
| 223 | 287 | #define DEVICE_ATTR_ADMIN_RO(_name) \ |
| 224 | − struct device_attribute dev_attr_##_name = __ATTR_RO_MODE(_name, 0400) | |
| 288 | + struct device_attribute dev_attr_##_name = __DEVICE_ATTR_RO_MODE(_name, 0400) | |
| 225 | 289 | |
| 226 | 290 | /** |
| 227 | 291 | * 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, · 7 unmodified lines | ||
| 235 | 299 | #define DEVICE_ATTR_RO_NAMED(_name, _attrname) \ |
| 236 | 300 | struct device_attribute dev_attr_##_name = { \ |
| 237 | 301 | .attr = { .name = _attrname, .mode = 0444 }, \ |
| 238 | − .show = _name##_show, \ | |
| 302 | + __DEVICE_ATTR_SHOW_STORE(_name##_show, NULL) \ | |
| 239 | 303 | } |
| 240 | 304 | |
| 241 | 305 | /** |
| @@ -245,7 +309,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, · 3 unmodified lines | ||
| 245 | 309 | * Like DEVICE_ATTR(), but @_mode is 0200 and @_store is <_name>_store. |
| 246 | 310 | */ |
| 247 | 311 | #define DEVICE_ATTR_WO(_name) \ |
| 248 | − struct device_attribute dev_attr_##_name = __ATTR_WO(_name) | |
| 312 | + struct device_attribute dev_attr_##_name = __DEVICE_ATTR_WO(_name) | |
| 249 | 313 | |
| 250 | 314 | /** |
| 251 | 315 | * 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, · 7 unmodified lines | ||
| 259 | 323 | #define DEVICE_ATTR_WO_NAMED(_name, _attrname) \ |
| 260 | 324 | struct device_attribute dev_attr_##_name = { \ |
| 261 | 325 | .attr = { .name = _attrname, .mode = 0200 }, \ |
| 262 | − .store = _name##_store, \ | |
| 326 | + __DEVICE_ATTR_SHOW_STORE(NULL, _name##_store) \ | |
| 263 | 327 | } |
| 264 | 328 | |
| 265 | 329 | /** |
| @@ -273,7 +337,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr, · 7 unmodified lines | ||
| 273 | 337 | */ |
| 274 | 338 | #define DEVICE_ULONG_ATTR(_name, _mode, _var) \ |
| 275 | 339 | struct dev_ext_attribute dev_attr_##_name = \ |
| 276 | − { __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) } | |
| 340 | + { __DEVICE_ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) } | |
| 277 | 341 | |
| 278 | 342 | /** |
| 279 | 343 | * 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, · 5 unmodified lines | ||
| 285 | 349 | */ |
| 286 | 350 | #define DEVICE_INT_ATTR(_name, _mode, _var) \ |
| 287 | 351 | struct dev_ext_attribute dev_attr_##_name = \ |
| 288 | − { __ATTR(_name, _mode, device_show_int, device_store_int), &(_var) } | |
| 352 | + { __DEVICE_ATTR(_name, _mode, device_show_int, device_store_int), &(_var) } | |
| 289 | 353 | |
| 290 | 354 | /** |
| 291 | 355 | * 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, · 5 unmodified lines | ||
| 297 | 361 | */ |
| 298 | 362 | #define DEVICE_BOOL_ATTR(_name, _mode, _var) \ |
| 299 | 363 | struct dev_ext_attribute dev_attr_##_name = \ |
| 300 | − { __ATTR(_name, _mode, device_show_bool, device_store_bool), &(_var) } | |
| 364 | + { __DEVICE_ATTR(_name, _mode, device_show_bool, device_store_bool), &(_var) } | |
| 301 | 365 | |
| 302 | 366 | /** |
| 303 | 367 | * 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, · 6 unmodified lines | ||
| 310 | 374 | */ |
| 311 | 375 | #define DEVICE_STRING_ATTR_RO(_name, _mode, _var) \ |
| 312 | 376 | struct dev_ext_attribute dev_attr_##_name = \ |
| 313 | − { __ATTR(_name, (_mode) & ~0222, device_show_string, NULL), (_var) } | |
| 377 | + { __DEVICE_ATTR(_name, (_mode) & ~0222, device_show_string, NULL), (_var) } | |
| 314 | 378 | |
| 315 | 379 | #define DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \ |
| 316 | 380 | struct device_attribute dev_attr_##_name = \ |
| 317 | − __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) | |
| 381 | + __DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) | |
| 318 | 382 | |
| 319 | 383 | int device_create_file(struct device *device, |
| 320 | 384 | const struct device_attribute *entry); |
| @@ -512,10 +576,40 @@ struct device_physical_location { · 191 unmodified lines | ||
| 512 | 576 | * |
| 513 | 577 | * @DEV_FLAG_READY_TO_PROBE: If set then device_add() has finished enough |
| 514 | 578 | * initialization that probe could be called. |
| 579 | + * @DEV_FLAG_CAN_MATCH: The device has matched with a driver at least once or it | |
| 580 | + * is in a bus (like AMBA) which can't check for matching drivers | |
| 581 | + * until other devices probe successfully. | |
| 582 | + * @DEV_FLAG_DMA_IOMMU: Device is using default IOMMU implementation for DMA and | |
| 583 | + * doesn't rely on dma_ops structure. | |
| 584 | + * @DEV_FLAG_DMA_SKIP_SYNC: DMA sync operations can be skipped for coherent | |
| 585 | + * buffers. | |
| 586 | + * @DEV_FLAG_DMA_OPS_BYPASS: If set then the dma_ops are bypassed for the | |
| 587 | + * streaming DMA operations (->map_* / ->unmap_* / ->sync_*), and | |
| 588 | + * optional (if the coherent mask is large enough) also for dma | |
| 589 | + * allocations. This flag is managed by the dma ops instance from | |
| 590 | + * ->dma_supported. | |
| 591 | + * @DEV_FLAG_STATE_SYNCED: The hardware state of this device has been synced to | |
| 592 | + * match the software state of this device by calling the | |
| 593 | + * driver/bus sync_state() callback. | |
| 594 | + * @DEV_FLAG_DMA_COHERENT: This particular device is dma coherent, even if the | |
| 595 | + * architecture supports non-coherent devices. | |
| 596 | + * @DEV_FLAG_OF_NODE_REUSED: Set if the device-tree node is shared with an | |
| 597 | + * ancestor device. | |
| 598 | + * @DEV_FLAG_OFFLINE_DISABLED: If set, the device is permanently online. | |
| 599 | + * @DEV_FLAG_OFFLINE: Set after successful invocation of bus type's .offline(). | |
| 515 | 600 | * @DEV_FLAG_COUNT: Number of defined struct_device_flags. |
| 516 | 601 | */ |
| 517 | 602 | enum struct_device_flags { |
| 518 | 603 | DEV_FLAG_READY_TO_PROBE = 0, |
| 604 | + DEV_FLAG_CAN_MATCH = 1, | |
| 605 | + DEV_FLAG_DMA_IOMMU = 2, | |
| 606 | + DEV_FLAG_DMA_SKIP_SYNC = 3, | |
| 607 | + DEV_FLAG_DMA_OPS_BYPASS = 4, | |
| 608 | + DEV_FLAG_STATE_SYNCED = 5, | |
| 609 | + DEV_FLAG_DMA_COHERENT = 6, | |
| 610 | + DEV_FLAG_OF_NODE_REUSED = 7, | |
| 611 | + DEV_FLAG_OFFLINE_DISABLED = 8, | |
| 612 | + DEV_FLAG_OFFLINE = 9, | |
| 519 | 613 | |
| 520 | 614 | DEV_FLAG_COUNT |
| 521 | 615 | }; |
| @@ -594,27 +688,6 @@ enum struct_device_flags { · 72 unmodified lines | ||
| 594 | 688 | * @removable: Whether the device can be removed from the system. This |
| 595 | 689 | * should be set by the subsystem / bus driver that discovered |
| 596 | 690 | * the device. |
| 597 | − * | |
| 598 | − * @offline_disabled: If set, the device is permanently online. | |
| 599 | − * @offline: Set after successful invocation of bus type's .offline(). | |
| 600 | − * @of_node_reused: Set if the device-tree node is shared with an ancestor | |
| 601 | − * device. | |
| 602 | − * @state_synced: The hardware state of this device has been synced to match | |
| 603 | − * the software state of this device by calling the driver/bus | |
| 604 | − * sync_state() callback. | |
| 605 | − * @can_match: The device has matched with a driver at least once or it is in | |
| 606 | − * a bus (like AMBA) which can't check for matching drivers until | |
| 607 | − * other devices probe successfully. | |
| 608 | − * @dma_coherent: this particular device is dma coherent, even if the | |
| 609 | − * architecture supports non-coherent devices. | |
| 610 | − * @dma_ops_bypass: If set to %true then the dma_ops are bypassed for the | |
| 611 | − * streaming DMA operations (->map_* / ->unmap_* / ->sync_*), | |
| 612 | − * and optionall (if the coherent mask is large enough) also | |
| 613 | − * for dma allocations. This flag is managed by the dma ops | |
| 614 | − * instance from ->dma_supported. | |
| 615 | − * @dma_skip_sync: DMA sync operations can be skipped for coherent buffers. | |
| 616 | − * @dma_iommu: Device is using default IOMMU implementation for DMA and | |
| 617 | − * doesn't rely on dma_ops structure. | |
| 618 | 691 | * @flags: DEV_FLAG_XXX flags. Use atomic bitfield operations to modify. |
| 619 | 692 | * |
| 620 | 693 | * At the lowest level, every device in a Linux system is represented by an |
| @@ -719,26 +792,6 @@ struct device { · 98 unmodified lines | ||
| 719 | 792 | |
| 720 | 793 | enum device_removable removable; |
| 721 | 794 | |
| 722 | − bool offline_disabled:1; | |
| 723 | − bool offline:1; | |
| 724 | − bool of_node_reused:1; | |
| 725 | − bool state_synced:1; | |
| 726 | − bool can_match:1; | |
| 727 | −#if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ | |
| 728 | − defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \ | |
| 729 | − defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) | |
| 730 | − bool dma_coherent:1; | |
| 731 | −#endif | |
| 732 | −#ifdef CONFIG_DMA_OPS_BYPASS | |
| 733 | − bool dma_ops_bypass : 1; | |
| 734 | −#endif | |
| 735 | −#ifdef CONFIG_DMA_NEED_SYNC | |
| 736 | − bool dma_skip_sync:1; | |
| 737 | −#endif | |
| 738 | −#ifdef CONFIG_IOMMU_DMA | |
| 739 | − bool dma_iommu:1; | |
| 740 | −#endif | |
| 741 | − | |
| 742 | 795 | DECLARE_BITMAP(flags, DEV_FLAG_COUNT); |
| 743 | 796 | }; |
| 744 | 797 | |
| @@ -765,6 +818,15 @@ static inline bool dev_test_and_set_##accessor_name(struct device *dev) \ · 20 unmodified lines | ||
| 765 | 818 | } |
| 766 | 819 | |
| 767 | 820 | __create_dev_flag_accessors(ready_to_probe, DEV_FLAG_READY_TO_PROBE); |
| 821 | +__create_dev_flag_accessors(can_match, DEV_FLAG_CAN_MATCH); | |
| 822 | +__create_dev_flag_accessors(dma_iommu, DEV_FLAG_DMA_IOMMU); | |
| 823 | +__create_dev_flag_accessors(dma_skip_sync, DEV_FLAG_DMA_SKIP_SYNC); | |
| 824 | +__create_dev_flag_accessors(dma_ops_bypass, DEV_FLAG_DMA_OPS_BYPASS); | |
| 825 | +__create_dev_flag_accessors(state_synced, DEV_FLAG_STATE_SYNCED); | |
| 826 | +__create_dev_flag_accessors(dma_coherent, DEV_FLAG_DMA_COHERENT); | |
| 827 | +__create_dev_flag_accessors(of_node_reused, DEV_FLAG_OF_NODE_REUSED); | |
| 828 | +__create_dev_flag_accessors(offline_disabled, DEV_FLAG_OFFLINE_DISABLED); | |
| 829 | +__create_dev_flag_accessors(offline, DEV_FLAG_OFFLINE); | |
| 768 | 830 | |
| 769 | 831 | #undef __create_dev_flag_accessors |
| 770 | 832 | |
| @@ -1063,17 +1125,6 @@ static inline void device_lock_assert(struct device *dev) · 292 unmodified lines | ||
| 1063 | 1125 | lockdep_assert_held(&dev->mutex); |
| 1064 | 1126 | } |
| 1065 | 1127 | |
| 1066 | −static inline bool dev_has_sync_state(struct device *dev) | |
| 1067 | −{ | |
| 1068 | − if (!dev) | |
| 1069 | − return false; | |
| 1070 | − if (dev->driver && dev->driver->sync_state) | |
| 1071 | − return true; | |
| 1072 | − if (dev->bus && dev->bus->sync_state) | |
| 1073 | − return true; | |
| 1074 | − return false; | |
| 1075 | −} | |
| 1076 | − | |
| 1077 | 1128 | static inline int dev_set_drv_sync_state(struct device *dev, |
| 1078 | 1129 | void (*fn)(struct device *dev)) |
| 1079 | 1130 | { |
| @@ -83,9 +83,9 @@ struct fwnode_handle; · 82 unmodified lines | ||
| 83 | 83 | struct bus_type { |
| 84 | 84 | const char *name; |
| 85 | 85 | const char *dev_name; |
| 86 | − const struct attribute_group **bus_groups; | |
| 87 | − const struct attribute_group **dev_groups; | |
| 88 | − const struct attribute_group **drv_groups; | |
| 86 | + const struct attribute_group *const *bus_groups; | |
| 87 | + const struct attribute_group *const *dev_groups; | |
| 88 | + const struct attribute_group *const *drv_groups; | |
| 89 | 89 | |
| 90 | 90 | int (*match)(struct device *dev, const struct device_driver *drv); |
| 91 | 91 | int (*uevent)(const struct device *dev, struct kobj_uevent_env *env); |
| @@ -34,7 +34,7 @@ struct fwnode_handle; · 33 unmodified lines | ||
| 34 | 34 | * @class_release: Called to release this class. |
| 35 | 35 | * @dev_release: Called to release the device. |
| 36 | 36 | * @shutdown_pre: Called at shut-down time before driver shutdown. |
| 37 | − * @ns_type: Callbacks so sysfs can detemine namespaces. | |
| 37 | + * @ns_type: Callbacks so sysfs can determine namespaces. | |
| 38 | 38 | * @namespace: Namespace of the device belongs to this class. |
| 39 | 39 | * @get_ownership: Allows class to specify uid/gid of the sysfs directories |
| 40 | 40 | * for the devices belonging to the class. Usually tied to |
| @@ -114,8 +114,8 @@ struct device_driver { · 113 unmodified lines | ||
| 114 | 114 | void (*shutdown) (struct device *dev); |
| 115 | 115 | int (*suspend) (struct device *dev, pm_message_t state); |
| 116 | 116 | int (*resume) (struct device *dev); |
| 117 | − const struct attribute_group **groups; | |
| 118 | − const struct attribute_group **dev_groups; | |
| 117 | + const struct attribute_group *const *groups; | |
| 118 | + const struct attribute_group *const *dev_groups; | |
| 119 | 119 | |
| 120 | 120 | const struct dev_pm_ops *pm; |
| 121 | 121 | void (*coredump) (struct device *dev); |
| @@ -123,8 +123,8 @@ struct device_driver { · 1 unmodified line | ||
| 123 | 123 | struct driver_private *p; |
| 124 | 124 | struct { |
| 125 | 125 | /* |
| 126 | − * Called after remove() and after all devres entries have been | |
| 127 | − * processed. This is a Rust only callback. | |
| 126 | + * Called after remove() but before devres entries are released. | |
| 127 | + * This is a Rust only callback. | |
| 128 | 128 | */ |
| 129 | 129 | void (*post_unbind_rust)(struct device *dev); |
| 130 | 130 | } p_cb; |
| @@ -160,8 +160,6 @@ int __must_check driver_create_file(const struct device_driver *driver, · 29 unmodified lines | ||
| 160 | 160 | void driver_remove_file(const struct device_driver *driver, |
| 161 | 161 | const struct driver_attribute *attr); |
| 162 | 162 | |
| 163 | −int driver_set_override(struct device *dev, const char **override, | |
| 164 | − const char *s, size_t len); | |
| 165 | 163 | int __must_check driver_for_each_device(struct device_driver *drv, struct device *start, |
| 166 | 164 | void *data, device_iter_t fn); |
| 167 | 165 | struct device *driver_find_device(const struct device_driver *drv, |
| @@ -225,7 +225,7 @@ int dma_direct_set_offset(struct device *dev, phys_addr_t cpu_start, · 224 unmodified lines | ||
| 225 | 225 | extern bool dma_default_coherent; |
| 226 | 226 | static inline bool dev_is_dma_coherent(struct device *dev) |
| 227 | 227 | { |
| 228 | − return dev->dma_coherent; | |
| 228 | + return dev_dma_coherent(dev); | |
| 229 | 229 | } |
| 230 | 230 | #else |
| 231 | 231 | #define dma_default_coherent true |
| @@ -240,8 +240,8 @@ static inline void dma_reset_need_sync(struct device *dev) · 8 unmodified lines | ||
| 240 | 240 | { |
| 241 | 241 | #ifdef CONFIG_DMA_NEED_SYNC |
| 242 | 242 | /* Reset it only once so that the function can be called on hotpath */ |
| 243 | − if (unlikely(dev->dma_skip_sync)) | |
| 244 | − dev->dma_skip_sync = false; | |
| 243 | + if (unlikely(dev_dma_skip_sync(dev))) | |
| 244 | + dev_clear_dma_skip_sync(dev); | |
| 245 | 245 | #endif |
| 246 | 246 | } |
| 247 | 247 | |
| @@ -429,7 +429,7 @@ bool __dma_need_sync(struct device *dev, dma_addr_t dma_addr); · 428 unmodified lines | ||
| 429 | 429 | static inline bool dma_dev_need_sync(const struct device *dev) |
| 430 | 430 | { |
| 431 | 431 | /* Always call DMA sync operations when debugging is enabled */ |
| 432 | − return !dev->dma_skip_sync || IS_ENABLED(CONFIG_DMA_API_DEBUG); | |
| 432 | + return !dev_dma_skip_sync(dev) || IS_ENABLED(CONFIG_DMA_API_DEBUG); | |
| 433 | 433 | } |
| 434 | 434 | |
| 435 | 435 | static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, |
| @@ -210,8 +210,10 @@ static inline void fwnode_init(struct fwnode_handle *fwnode, · 209 unmodified lines | ||
| 210 | 210 | { |
| 211 | 211 | fwnode->secondary = NULL; |
| 212 | 212 | fwnode->ops = ops; |
| 213 | + fwnode->dev = NULL; | |
| 213 | 214 | INIT_LIST_HEAD(&fwnode->consumers); |
| 214 | 215 | INIT_LIST_HEAD(&fwnode->suppliers); |
| 216 | + fwnode->flags = 0; | |
| 215 | 217 | } |
| 216 | 218 | |
| 217 | 219 | 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, · 33 unmodified lines | ||
| 251 | 253 | u8 flags); |
| 252 | 254 | void fwnode_links_purge(struct fwnode_handle *fwnode); |
| 253 | 255 | void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode); |
| 256 | +void fw_devlink_refresh_fwnode(struct fwnode_handle *fwnode); | |
| 254 | 257 | bool fw_devlink_is_strict(void); |
| 255 | 258 | |
| 256 | 259 | #endif |
| @@ -1272,11 +1272,6 @@ struct hv_device { · 1271 unmodified lines | ||
| 1272 | 1272 | u16 device_id; |
| 1273 | 1273 | |
| 1274 | 1274 | struct device device; |
| 1275 | − /* | |
| 1276 | − * Driver name to force a match. Do not set directly, because core | |
| 1277 | − * frees it. Use driver_set_override() to set or clear it. | |
| 1278 | − */ | |
| 1279 | − const char *driver_override; | |
| 1280 | 1275 | |
| 1281 | 1276 | struct vmbus_channel *channel; |
| 1282 | 1277 | struct kset *channels_kset; |
| @@ -7,12 +7,13 @@ · 6 unmodified lines | ||
| 7 | 7 | #ifndef _LINUX_IOMMU_DMA_H |
| 8 | 8 | #define _LINUX_IOMMU_DMA_H |
| 9 | 9 | |
| 10 | +#include <linux/device.h> | |
| 10 | 11 | #include <linux/dma-direction.h> |
| 11 | 12 | |
| 12 | 13 | #ifdef CONFIG_IOMMU_DMA |
| 13 | 14 | static inline bool use_dma_iommu(struct device *dev) |
| 14 | 15 | { |
| 15 | − return dev->dma_iommu; | |
| 16 | + return dev_dma_iommu(dev); | |
| 16 | 17 | } |
| 17 | 18 | #else |
| 18 | 19 | static inline bool use_dma_iommu(struct device *dev) |
| @@ -293,18 +293,19 @@ struct platform_driver { · 292 unmodified lines | ||
| 293 | 293 | * use a macro to avoid include chaining to get THIS_MODULE |
| 294 | 294 | */ |
| 295 | 295 | #define platform_driver_register(drv) \ |
| 296 | − __platform_driver_register(drv, THIS_MODULE) | |
| 296 | + __platform_driver_register(drv, THIS_MODULE, KBUILD_MODNAME) | |
| 297 | 297 | extern int __platform_driver_register(struct platform_driver *, |
| 298 | − struct module *); | |
| 298 | + struct module *, const char *mod_name); | |
| 299 | 299 | extern void platform_driver_unregister(struct platform_driver *); |
| 300 | 300 | |
| 301 | 301 | /* non-hotpluggable platform devices may use this so that probe() and |
| 302 | 302 | * its support may live in __init sections, conserving runtime memory. |
| 303 | 303 | */ |
| 304 | 304 | #define platform_driver_probe(drv, probe) \ |
| 305 | − __platform_driver_probe(drv, probe, THIS_MODULE) | |
| 305 | + __platform_driver_probe(drv, probe, THIS_MODULE, KBUILD_MODNAME) | |
| 306 | 306 | extern int __platform_driver_probe(struct platform_driver *driver, |
| 307 | − int (*probe)(struct platform_device *), struct module *module); | |
| 307 | + int (*probe)(struct platform_device *), struct module *module, | |
| 308 | + const char *mod_name); | |
| 308 | 309 | |
| 309 | 310 | static inline void *platform_get_drvdata(const struct platform_device *pdev) |
| 310 | 311 | { |
| @@ -368,19 +369,19 @@ static int __init __platform_driver##_init(void) \ · 57 unmodified lines | ||
| 368 | 369 | device_initcall(__platform_driver##_init); \ |
| 369 | 370 | |
| 370 | 371 | #define platform_create_bundle(driver, probe, res, n_res, data, size) \ |
| 371 | − __platform_create_bundle(driver, probe, res, n_res, data, size, THIS_MODULE) | |
| 372 | + __platform_create_bundle(driver, probe, res, n_res, data, size, THIS_MODULE, KBUILD_MODNAME) | |
| 372 | 373 | extern struct platform_device *__platform_create_bundle( |
| 373 | 374 | struct platform_driver *driver, int (*probe)(struct platform_device *), |
| 374 | 375 | struct resource *res, unsigned int n_res, |
| 375 | − const void *data, size_t size, struct module *module); | |
| 376 | + const void *data, size_t size, struct module *module, const char *mod_name); | |
| 376 | 377 | |
| 377 | 378 | int __platform_register_drivers(struct platform_driver * const *drivers, |
| 378 | − unsigned int count, struct module *owner); | |
| 379 | + unsigned int count, struct module *owner, const char *mod_name); | |
| 379 | 380 | void platform_unregister_drivers(struct platform_driver * const *drivers, |
| 380 | 381 | unsigned int count); |
| 381 | 382 | |
| 382 | 383 | #define platform_register_drivers(drivers, count) \ |
| 383 | − __platform_register_drivers(drivers, count, THIS_MODULE) | |
| 384 | + __platform_register_drivers(drivers, count, THIS_MODULE, KBUILD_MODNAME) | |
| 384 | 385 | |
| 385 | 386 | #ifdef CONFIG_SUSPEND |
| 386 | 387 | extern int platform_pm_suspend(struct device *dev); |
| @@ -471,12 +471,18 @@ struct property_entry { · 470 unmodified lines | ||
| 471 | 471 | #define PROPERTY_ENTRY_STRING(_name_, _val_) \ |
| 472 | 472 | __PROPERTY_ENTRY_ELEMENT(_name_, str, STRING, _val_) |
| 473 | 473 | |
| 474 | +#define __PROPERTY_ENTRY_REF_ARGS(_ref_, ...) \ | |
| 475 | + _Generic(_ref_, \ | |
| 476 | + const struct software_node_ref_args *: _ref_, \ | |
| 477 | + struct software_node_ref_args *: _ref_, \ | |
| 478 | + default: &SOFTWARE_NODE_REFERENCE(_ref_, ##__VA_ARGS__)) | |
| 479 | + | |
| 474 | 480 | #define PROPERTY_ENTRY_REF(_name_, _ref_, ...) \ |
| 475 | 481 | (struct property_entry) { \ |
| 476 | 482 | .name = _name_, \ |
| 477 | 483 | .length = sizeof(struct software_node_ref_args), \ |
| 478 | 484 | .type = DEV_PROP_REF, \ |
| 479 | − { .pointer = &SOFTWARE_NODE_REFERENCE(_ref_, ##__VA_ARGS__), }, \ | |
| 485 | + { .pointer = __PROPERTY_ENTRY_REF_ARGS(_ref_, ##__VA_ARGS__) }, \ | |
| 480 | 486 | } |
| 481 | 487 | |
| 482 | 488 | #define PROPERTY_ENTRY_BOOL(_name_) \ |
| @@ -41,9 +41,6 @@ struct rpmsg_channel_info { · 40 unmodified lines | ||
| 41 | 41 | * rpmsg_device - device that belong to the rpmsg bus |
| 42 | 42 | * @dev: the device struct |
| 43 | 43 | * @id: device id (used to match between rpmsg drivers and devices) |
| 44 | − * @driver_override: driver name to force a match; do not set directly, | |
| 45 | − * because core frees it; use driver_set_override() to | |
| 46 | − * set or clear it. | |
| 47 | 44 | * @src: local address |
| 48 | 45 | * @dst: destination address |
| 49 | 46 | * @ept: the rpmsg endpoint of this channel |
| @@ -53,7 +50,6 @@ struct rpmsg_channel_info { · 3 unmodified lines | ||
| 53 | 50 | struct rpmsg_device { |
| 54 | 51 | struct device dev; |
| 55 | 52 | struct rpmsg_device_id id; |
| 56 | − const char *driver_override; | |
| 57 | 53 | u32 src; |
| 58 | 54 | u32 dst; |
| 59 | 55 | struct rpmsg_endpoint *ept; |
| @@ -2639,7 +2639,7 @@ static void cpuhp_offline_cpu_device(unsigned int cpu) · 2638 unmodified lines | ||
| 2639 | 2639 | { |
| 2640 | 2640 | struct device *dev = get_cpu_device(cpu); |
| 2641 | 2641 | |
| 2642 | − dev->offline = true; | |
| 2642 | + dev_set_offline(dev); | |
| 2643 | 2643 | /* Tell user space about the state change */ |
| 2644 | 2644 | kobject_uevent(&dev->kobj, KOBJ_OFFLINE); |
| 2645 | 2645 | } |
| @@ -2648,7 +2648,7 @@ static void cpuhp_online_cpu_device(unsigned int cpu) · 2 unmodified lines | ||
| 2648 | 2648 | { |
| 2649 | 2649 | struct device *dev = get_cpu_device(cpu); |
| 2650 | 2650 | |
| 2651 | − dev->offline = false; | |
| 2651 | + dev_clear_offline(dev); | |
| 2652 | 2652 | /* Tell user space about the state change */ |
| 2653 | 2653 | kobject_uevent(&dev->kobj, KOBJ_ONLINE); |
| 2654 | 2654 | } |
| @@ -126,11 +126,9 @@ static bool dma_go_direct(struct device *dev, dma_addr_t mask, · 125 unmodified lines | ||
| 126 | 126 | if (likely(!ops)) |
| 127 | 127 | return true; |
| 128 | 128 | |
| 129 | −#ifdef CONFIG_DMA_OPS_BYPASS | |
| 130 | − if (dev->dma_ops_bypass) | |
| 129 | + if (IS_ENABLED(CONFIG_DMA_OPS_BYPASS) && dev_dma_ops_bypass(dev)) | |
| 131 | 130 | return min_not_zero(mask, dev->bus_dma_limit) >= |
| 132 | 131 | dma_direct_get_required_mask(dev); |
| 133 | −#endif | |
| 134 | 132 | return false; |
| 135 | 133 | } |
| 136 | 134 | |
| @@ -472,7 +470,7 @@ bool dma_need_unmap(struct device *dev) · 335 unmodified lines | ||
| 472 | 470 | { |
| 473 | 471 | if (!dma_map_direct(dev, get_dma_ops(dev))) |
| 474 | 472 | return true; |
| 475 | − if (!dev->dma_skip_sync) | |
| 473 | + if (!dev_dma_skip_sync(dev)) | |
| 476 | 474 | return true; |
| 477 | 475 | return IS_ENABLED(CONFIG_DMA_API_DEBUG); |
| 478 | 476 | } |
| @@ -488,16 +486,16 @@ static void dma_setup_need_sync(struct device *dev) · 9 unmodified lines | ||
| 488 | 486 | * mapping, if any. During the device initialization, it's |
| 489 | 487 | * enough to check only for the DMA coherence. |
| 490 | 488 | */ |
| 491 | − dev->dma_skip_sync = dev_is_dma_coherent(dev); | |
| 489 | + dev_assign_dma_skip_sync(dev, dev_is_dma_coherent(dev)); | |
| 492 | 490 | else if (!ops->sync_single_for_device && !ops->sync_single_for_cpu && |
| 493 | 491 | !ops->sync_sg_for_device && !ops->sync_sg_for_cpu) |
| 494 | 492 | /* |
| 495 | 493 | * Synchronization is not possible when none of DMA sync ops |
| 496 | 494 | * is set. |
| 497 | 495 | */ |
| 498 | − dev->dma_skip_sync = true; | |
| 496 | + dev_set_dma_skip_sync(dev); | |
| 499 | 497 | else |
| 500 | − dev->dma_skip_sync = false; | |
| 498 | + dev_clear_dma_skip_sync(dev); | |
| 501 | 499 | } |
| 502 | 500 | #else /* !CONFIG_DMA_NEED_SYNC */ |
| 503 | 501 | static inline void dma_setup_need_sync(struct device *dev) { } |
| @@ -942,9 +942,9 @@ const struct kobj_type module_ktype = { · 941 unmodified lines | ||
| 942 | 942 | /* |
| 943 | 943 | * param_sysfs_init - create "module" kset |
| 944 | 944 | * |
| 945 | − * This must be done before the initramfs is unpacked and | |
| 946 | − * request_module() thus becomes possible, because otherwise the | |
| 947 | − * module load would fail in mod_sysfs_init. | |
| 945 | + * This must be done before any driver registration so that when a driver comes | |
| 946 | + * from a built-in module, the driver core can add the module under /sys/module | |
| 947 | + * and create the associated driver symlinks. | |
| 948 | 948 | */ |
| 949 | 949 | static int __init param_sysfs_init(void) |
| 950 | 950 | { |
| @@ -957,7 +957,7 @@ static int __init param_sysfs_init(void) · 6 unmodified lines | ||
| 957 | 957 | |
| 958 | 958 | return 0; |
| 959 | 959 | } |
| 960 | −subsys_initcall(param_sysfs_init); | |
| 960 | +pure_initcall(param_sysfs_init); | |
| 961 | 961 | |
| 962 | 962 | /* |
| 963 | 963 | * 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, · 708 unmodified lines | ||
| 709 | 709 | * best approximation to ensure no swiotlb buffering happens. |
| 710 | 710 | */ |
| 711 | 711 | #ifdef CONFIG_DMA_NEED_SYNC |
| 712 | − dma_need_sync = !dev->dma_skip_sync; | |
| 712 | + dma_need_sync = !dev_dma_skip_sync(dev); | |
| 713 | 713 | #endif /* CONFIG_DMA_NEED_SYNC */ |
| 714 | 714 | if (dma_need_sync || dma_addressing_limited(dev)) |
| 715 | 715 | return -EOPNOTSUPP; |
| @@ -119,6 +119,7 @@ syn-cfgs := \ · 118 unmodified lines | ||
| 119 | 119 | feature="parsing" \ |
| 120 | 120 | feature="printing" \ |
| 121 | 121 | feature="proc-macro" \ |
| 122 | + feature="visit" \ | |
| 122 | 123 | feature="visit-mut" |
| 123 | 124 | |
| 124 | 125 | syn-flags := \ |
| @@ -0,0 +1,16 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +#include <linux/acpi.h> | |
| 4 | +#include <acpi/acpi_bus.h> | |
| 5 | + | |
| 6 | +__rust_helper bool rust_helper_acpi_of_match_device(const struct acpi_device *adev, | |
| 7 | + const struct of_device_id *of_match_table, | |
| 8 | + const struct of_device_id **of_id) | |
| 9 | +{ | |
| 10 | + return acpi_of_match_device(adev, of_match_table, of_id); | |
| 11 | +} | |
| 12 | + | |
| 13 | +__rust_helper struct acpi_device *rust_helper_to_acpi_device_node(struct fwnode_handle *fwnode) | |
| 14 | +{ | |
| 15 | + return to_acpi_device_node(fwnode); | |
| 16 | +} | |
| @@ -38,6 +38,7 @@ · 37 unmodified lines | ||
| 38 | 38 | #define __rust_helper __always_inline |
| 39 | 39 | #endif |
| 40 | 40 | |
| 41 | +#include "acpi.c" | |
| 41 | 42 | #include "atomic.c" |
| 42 | 43 | #include "atomic_ext.c" |
| 43 | 44 | #include "auxiliary.c" |
| @@ -279,6 +279,27 @@ where · 278 unmodified lines | ||
| 279 | 279 | Ok(Box(ptr.cast(), PhantomData)) |
| 280 | 280 | } |
| 281 | 281 | |
| 282 | + /// Creates a new zero-initialized `Box<T, A>`. | |
| 283 | + /// | |
| 284 | + /// New memory is allocated with `A` and the [`__GFP_ZERO`] flag. The allocation may fail, in | |
| 285 | + /// which case an error is returned. For ZSTs no memory is allocated. | |
| 286 | + /// | |
| 287 | + /// # Examples | |
| 288 | + /// | |
| 289 | + /// ``` | |
| 290 | + /// let b = KBox::<[u8; 128]>::zeroed(GFP_KERNEL)?; | |
| 291 | + /// assert_eq!(*b, [0; 128]); | |
| 292 | + /// # Ok::<(), Error>(()) | |
| 293 | + /// ``` | |
| 294 | + pub fn zeroed(flags: Flags) -> Result<Self, AllocError> | |
| 295 | + where | |
| 296 | + T: Zeroable, | |
| 297 | + { | |
| 298 | + // SAFETY: `__GFP_ZERO` guarantees the memory is zeroed; `T: Zeroable` guarantees that | |
| 299 | + // all-zeroes is a valid bit pattern for `T`. | |
| 300 | + Ok(unsafe { Self::new_uninit(flags | __GFP_ZERO)?.assume_init() }) | |
| 301 | + } | |
| 302 | + | |
| 282 | 303 | /// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement [`Unpin`], then `x` will be |
| 283 | 304 | /// pinned in memory and can't be moved. |
| 284 | 305 | #[inline] |
| @@ -483,7 +504,7 @@ where · 198 unmodified lines | ||
| 483 | 504 | |
| 484 | 505 | // SAFETY: The pointer returned by `into_foreign` comes from a well aligned |
| 485 | 506 | // pointer to `T` allocated by `A`. |
| 486 | −unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A> | |
| 507 | +unsafe impl<T, A> ForeignOwnable for Box<T, A> | |
| 487 | 508 | where |
| 488 | 509 | A: Allocator, |
| 489 | 510 | { |
| @@ -493,8 +514,14 @@ where · 3 unmodified lines | ||
| 493 | 514 | core::mem::align_of::<T>() |
| 494 | 515 | }; |
| 495 | 516 | |
| 496 | − type Borrowed<'a> = &'a T; | |
| 497 | − type BorrowedMut<'a> = &'a mut T; | |
| 517 | + type Borrowed<'a> | |
| 518 | + = &'a T | |
| 519 | + where | |
| 520 | + Self: 'a; | |
| 521 | + type BorrowedMut<'a> | |
| 522 | + = &'a mut T | |
| 523 | + where | |
| 524 | + Self: 'a; | |
| 498 | 525 | |
| 499 | 526 | fn into_foreign(self) -> *mut c_void { |
| 500 | 527 | Box::into_raw(self).cast() |
| @@ -522,13 +549,19 @@ where · 21 unmodified lines | ||
| 522 | 549 | |
| 523 | 550 | // SAFETY: The pointer returned by `into_foreign` comes from a well aligned |
| 524 | 551 | // pointer to `T` allocated by `A`. |
| 525 | −unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>> | |
| 552 | +unsafe impl<T, A> ForeignOwnable for Pin<Box<T, A>> | |
| 526 | 553 | where |
| 527 | 554 | A: Allocator, |
| 528 | 555 | { |
| 529 | 556 | const FOREIGN_ALIGN: usize = <Box<T, A> as ForeignOwnable>::FOREIGN_ALIGN; |
| 530 | − type Borrowed<'a> = Pin<&'a T>; | |
| 531 | − type BorrowedMut<'a> = Pin<&'a mut T>; | |
| 557 | + type Borrowed<'a> | |
| 558 | + = Pin<&'a T> | |
| 559 | + where | |
| 560 | + Self: 'a; | |
| 561 | + type BorrowedMut<'a> | |
| 562 | + = Pin<&'a mut T> | |
| 563 | + where | |
| 564 | + Self: 'a; | |
| 532 | 565 | |
| 533 | 566 | fn into_foreign(self) -> *mut c_void { |
| 534 | 567 | // SAFETY: We are still treating the box as pinned. |
| @@ -12,19 +12,25 @@ use crate::{ · 11 unmodified lines | ||
| 12 | 12 | RawDeviceId, |
| 13 | 13 | RawDeviceIdIndex, // |
| 14 | 14 | }, |
| 15 | − devres::Devres, | |
| 15 | + | |
| 16 | 16 | driver, |
| 17 | 17 | error::{ |
| 18 | 18 | from_result, |
| 19 | 19 | to_result, // |
| 20 | 20 | }, |
| 21 | 21 | prelude::*, |
| 22 | − types::Opaque, | |
| 22 | + types::{ | |
| 23 | + ForLt, | |
| 24 | + ForeignOwnable, | |
| 25 | + Opaque, // | |
| 26 | + }, | |
| 23 | 27 | ThisModule, // |
| 24 | 28 | }; |
| 25 | 29 | use core::{ |
| 30 | + any::TypeId, | |
| 26 | 31 | marker::PhantomData, |
| 27 | 32 | mem::offset_of, |
| 33 | + pin::Pin, | |
| 28 | 34 | ptr::{ |
| 29 | 35 | addr_of_mut, |
| 30 | 36 | NonNull, // |
| @@ -36,18 +42,18 @@ pub struct Adapter<T: Driver>(T); · 5 unmodified lines | ||
| 36 | 42 | |
| 37 | 43 | // SAFETY: |
| 38 | 44 | // - `bindings::auxiliary_driver` is a C type declared as `repr(C)`. |
| 39 | −// - `T` is the type of the driver's device private data. | |
| 45 | +// - `T::Data` is the type of the driver's device private data. | |
| 40 | 46 | // - `struct auxiliary_driver` embeds a `struct device_driver`. |
| 41 | 47 | // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. |
| 42 | −unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> { | |
| 48 | +unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> { | |
| 43 | 49 | type DriverType = bindings::auxiliary_driver; |
| 44 | − type DriverData = T; | |
| 50 | + type DriverData<'bound> = T::Data<'bound>; | |
| 45 | 51 | const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); |
| 46 | 52 | } |
| 47 | 53 | |
| 48 | 54 | // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if |
| 49 | 55 | // a preceding call to `register` has been successful. |
| 50 | −unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { | |
| 56 | +unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> { | |
| 51 | 57 | unsafe fn register( |
| 52 | 58 | adrv: &Opaque<Self::DriverType>, |
| 53 | 59 | name: &'static CStr, |
| @@ -73,7 +79,7 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { · 19 unmodified lines | ||
| 73 | 79 | } |
| 74 | 80 | } |
| 75 | 81 | |
| 76 | −impl<T: Driver + 'static> Adapter<T> { | |
| 82 | +impl<T: Driver> Adapter<T> { | |
| 77 | 83 | extern "C" fn probe_callback( |
| 78 | 84 | adev: *mut bindings::auxiliary_device, |
| 79 | 85 | id: *const bindings::auxiliary_device_id, |
| @@ -82,7 +88,7 @@ impl<T: Driver + 'static> Adapter<T> { · 2 unmodified lines | ||
| 82 | 88 | // `struct auxiliary_device`. |
| 83 | 89 | // |
| 84 | 90 | // INVARIANT: `adev` is valid for the duration of `probe_callback()`. |
| 85 | − let adev = unsafe { &*adev.cast::<Device<device::CoreInternal>>() }; | |
| 91 | + let adev = unsafe { &*adev.cast::<Device<device::CoreInternal<'_>>>() }; | |
| 86 | 92 | |
| 87 | 93 | // SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id` |
| 88 | 94 | // and does not add additional invariants, so it's safe to transmute. |
| @@ -102,12 +108,12 @@ impl<T: Driver + 'static> Adapter<T> { · 13 unmodified lines | ||
| 102 | 108 | // `struct auxiliary_device`. |
| 103 | 109 | // |
| 104 | 110 | // INVARIANT: `adev` is valid for the duration of `remove_callback()`. |
| 105 | − let adev = unsafe { &*adev.cast::<Device<device::CoreInternal>>() }; | |
| 111 | + let adev = unsafe { &*adev.cast::<Device<device::CoreInternal<'_>>>() }; | |
| 106 | 112 | |
| 107 | 113 | // SAFETY: `remove_callback` is only ever called after a successful call to |
| 108 | 114 | // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called |
| 109 | − // and stored a `Pin<KBox<T>>`. | |
| 110 | − let data = unsafe { adev.as_ref().drvdata_borrow::<T>() }; | |
| 115 | + // and stored a `Pin<KBox<T::Data<'_>>>`. | |
| 116 | + let data = unsafe { adev.as_ref().drvdata_borrow::<T::Data<'_>>() }; | |
| 111 | 117 | |
| 112 | 118 | T::unbind(adev, data); |
| 113 | 119 | } |
| @@ -197,13 +203,19 @@ pub trait Driver { · 83 unmodified lines | ||
| 197 | 203 | /// type IdInfo: 'static = (); |
| 198 | 204 | type IdInfo: 'static; |
| 199 | 205 | |
| 206 | + /// The type of the driver's bus device private data. | |
| 207 | + type Data<'bound>: Send + 'bound; | |
| 208 | + | |
| 200 | 209 | /// The table of device ids supported by the driver. |
| 201 | 210 | const ID_TABLE: IdTable<Self::IdInfo>; |
| 202 | 211 | |
| 203 | 212 | /// Auxiliary driver probe. |
| 204 | 213 | /// |
| 205 | 214 | /// Called when an auxiliary device is matches a corresponding driver. |
| 206 | − fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>; | |
| 215 | + fn probe<'bound>( | |
| 216 | + dev: &'bound Device<device::Core<'_>>, | |
| 217 | + id_info: &'bound Self::IdInfo, | |
| 218 | + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; | |
| 207 | 219 | |
| 208 | 220 | /// Auxiliary driver unbind. |
| 209 | 221 | /// |
| @@ -214,8 +226,8 @@ pub trait Driver { · 4 unmodified lines | ||
| 214 | 226 | /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O |
| 215 | 227 | /// operations to gracefully tear down the device. |
| 216 | 228 | /// |
| 217 | − /// Otherwise, release operations for driver resources should be performed in `Self::drop`. | |
| 218 | − fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { | |
| 229 | + /// Otherwise, release operations for driver resources should be performed in `Drop`. | |
| 230 | + fn unbind<'bound>(dev: &'bound Device<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) { | |
| 219 | 231 | let _ = (dev, this); |
| 220 | 232 | } |
| 221 | 233 | } |
| @@ -257,6 +269,49 @@ impl Device<device::Bound> { · 35 unmodified lines | ||
| 257 | 269 | // SAFETY: A bound auxiliary device always has a bound parent device. |
| 258 | 270 | unsafe { parent.as_bound() } |
| 259 | 271 | } |
| 272 | + | |
| 273 | + /// Returns a pinned reference to the registration data set by the registering (parent) driver. | |
| 274 | + /// | |
| 275 | + /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The returned | |
| 276 | + /// reference has its lifetime shortened from `'static` to `&self`'s borrow lifetime via | |
| 277 | + /// [`ForLt::cast_ref`]. | |
| 278 | + /// | |
| 279 | + /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling | |
| 280 | + /// [`Registration::new()`]. | |
| 281 | + /// | |
| 282 | + /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was | |
| 283 | + /// registered by a C driver. | |
| 284 | + pub fn registration_data<F: ForLt + 'static>(&self) -> Result<Pin<&F::Of<'_>>> { | |
| 285 | + // SAFETY: By the type invariant, `self.as_raw()` is a valid `struct auxiliary_device`. | |
| 286 | + let ptr = unsafe { (*self.as_raw()).registration_data_rust }; | |
| 287 | + if ptr.is_null() { | |
| 288 | + dev_warn!( | |
| 289 | + self.as_ref(), | |
| 290 | + "No registration data set; parent is not a Rust driver.\n" | |
| 291 | + ); | |
| 292 | + return Err(ENOENT); | |
| 293 | + } | |
| 294 | + | |
| 295 | + // SAFETY: `ptr` is non-null and was set via `into_foreign()` in `Registration::new()`; | |
| 296 | + // `RegistrationData` is `#[repr(C)]` with `type_id` at offset 0, so reading a `TypeId` | |
| 297 | + // at the start of the allocation is valid regardless of `F`. | |
| 298 | + let type_id = unsafe { ptr.cast::<TypeId>().read() }; | |
| 299 | + if type_id != TypeId::of::<F>() { | |
| 300 | + return Err(EINVAL); | |
| 301 | + } | |
| 302 | + | |
| 303 | + // SAFETY: The `TypeId` check above confirms that the stored type matches | |
| 304 | + // `F::Of<'static>`; `ptr` remains valid until `Registration::drop()` calls | |
| 305 | + // `from_foreign()`. | |
| 306 | + let wrapper = unsafe { Pin::<KBox<RegistrationData<F::Of<'static>>>>::borrow(ptr) }; | |
| 307 | + | |
| 308 | + // SAFETY: `data` is a structurally pinned field of `RegistrationData`. | |
| 309 | + let pinned: Pin<&F::Of<'_>> = unsafe { wrapper.map_unchecked(|w| &w.data) }; | |
| 310 | + | |
| 311 | + // SAFETY: The data was pinned when stored; `cast_ref` only shortens | |
| 312 | + // the lifetime, so the pinning guarantee is preserved. | |
| 313 | + Ok(unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) }) | |
| 314 | + } | |
| 260 | 315 | } |
| 261 | 316 | |
| 262 | 317 | impl Device { |
| @@ -326,87 +381,173 @@ unsafe impl Send for Device {} · 63 unmodified lines | ||
| 326 | 381 | // (i.e. `Device<Normal>) are thread safe. |
| 327 | 382 | unsafe impl Sync for Device {} |
| 328 | 383 | |
| 384 | +// SAFETY: Same as `Device<Normal>` -- the underlying `struct auxiliary_device` is the same; | |
| 385 | +// `Bound` is a zero-sized type-state marker that does not affect thread safety. | |
| 386 | +unsafe impl Sync for Device<device::Bound> {} | |
| 387 | + | |
| 388 | +/// Wrapper that stores a [`TypeId`] alongside the registration data for runtime type checking. | |
| 389 | +#[repr(C)] | |
| 390 | +#[pin_data] | |
| 391 | +struct RegistrationData<T> { | |
| 392 | + type_id: TypeId, | |
| 393 | + #[pin] | |
| 394 | + data: T, | |
| 395 | +} | |
| 396 | + | |
| 329 | 397 | /// The registration of an auxiliary device. |
| 330 | 398 | /// |
| 331 | 399 | /// This type represents the registration of a [`struct auxiliary_device`]. When its parent device |
| 332 | 400 | /// is unbound, the corresponding auxiliary device will be unregistered from the system. |
| 333 | 401 | /// |
| 402 | +/// The type parameter `F` is a [`ForLt`](trait@ForLt) encoding of the registration | |
| 403 | +/// data type. For non-lifetime-parameterized types, use [`ForLt!(T)`](macro@ForLt). | |
| 404 | +/// The data can be accessed by the auxiliary driver through [`Device::registration_data()`]. | |
| 405 | +/// | |
| 334 | 406 | /// # Invariants |
| 335 | 407 | /// |
| 336 | −/// `self.0` always holds a valid pointer to an initialized and registered | |
| 337 | −/// [`struct auxiliary_device`]. | |
| 338 | −pub struct Registration(NonNull<bindings::auxiliary_device>); | |
| 408 | +/// `self.adev` always holds a valid pointer to an initialized and registered | |
| 409 | +/// [`struct auxiliary_device`] whose `registration_data_rust` field points to a | |
| 410 | +/// valid `Pin<KBox<RegistrationData<F::Of<'static>>>>`. | |
| 411 | +pub struct Registration<'a, F: ForLt + 'static> { | |
| 412 | + adev: NonNull<bindings::auxiliary_device>, | |
| 413 | + _phantom: PhantomData<F::Of<'a>>, | |
| 414 | +} | |
| 339 | 415 | |
| 340 | −impl Registration { | |
| 341 | − /// Create and register a new auxiliary device. | |
| 342 | − pub fn new<'a>( | |
| 416 | +impl<'a, F: ForLt> Registration<'a, F> | |
| 417 | +where | |
| 418 | + for<'b> F::Of<'b>: Send + Sync, | |
| 419 | +{ | |
| 420 | + /// Create and register a new auxiliary device with the given registration data. | |
| 421 | + /// | |
| 422 | + /// The `data` is owned by the registration and can be accessed through the auxiliary device | |
| 423 | + /// via [`Device::registration_data()`]. | |
| 424 | + /// | |
| 425 | + /// # Safety | |
| 426 | + /// | |
| 427 | + /// The caller must not `mem::forget()` the returned [`Registration`] or otherwise prevent its | |
| 428 | + /// [`Drop`] implementation from running, since the registration data may contain borrowed | |
| 429 | + /// references that become invalid after `'a` ends. | |
| 430 | + /// | |
| 431 | + /// If the registration data is `'static`, use the safe [`Registration::new()`] instead. | |
| 432 | + pub unsafe fn new_with_lt<E>( | |
| 343 | 433 | parent: &'a device::Device<device::Bound>, |
| 344 | − name: &'a CStr, | |
| 434 | + name: &CStr, | |
| 345 | 435 | id: u32, |
| 346 | − modname: &'a CStr, | |
| 347 | − ) -> impl PinInit<Devres<Self>, Error> + 'a { | |
| 348 | − pin_init::pin_init_scope(move || { | |
| 349 | − let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?; | |
| 350 | − let adev = boxed.get(); | |
| 351 | − | |
| 352 | − // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. | |
| 353 | − unsafe { | |
| 354 | − (*adev).dev.parent = parent.as_raw(); | |
| 355 | − (*adev).dev.release = Some(Device::release); | |
| 356 | − (*adev).name = name.as_char_ptr(); | |
| 357 | − (*adev).id = id; | |
| 358 | − } | |
| 359 | − | |
| 360 | − // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, | |
| 361 | − // which has not been initialized yet. | |
| 362 | − unsafe { bindings::auxiliary_device_init(adev) }; | |
| 363 | − | |
| 364 | − // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be | |
| 365 | − // freed by `Device::release` when the last reference to the `struct auxiliary_device` | |
| 366 | − // is dropped. | |
| 367 | − let _ = KBox::into_raw(boxed); | |
| 368 | − | |
| 369 | − // SAFETY: | |
| 370 | − // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which | |
| 371 | − // has been initialized, | |
| 372 | − // - `modname.as_char_ptr()` is a NULL terminated string. | |
| 373 | − let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; | |
| 374 | − if ret != 0 { | |
| 375 | − // SAFETY: `adev` is guaranteed to be a valid pointer to a | |
| 376 | − // `struct auxiliary_device`, which has been initialized. | |
| 377 | − unsafe { bindings::auxiliary_device_uninit(adev) }; | |
| 378 | − | |
| 379 | − return Err(Error::from_errno(ret)); | |
| 380 | − } | |
| 381 | − | |
| 382 | − // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is | |
| 383 | − // called, which happens in `Self::drop()`. | |
| 384 | − Ok(Devres::new( | |
| 385 | − parent, | |
| 386 | − // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated | |
| 387 | − // successfully. | |
| 388 | − Self(unsafe { NonNull::new_unchecked(adev) }), | |
| 389 | − )) | |
| 436 | + modname: &CStr, | |
| 437 | + data: impl PinInit<F::Of<'a>, E>, | |
| 438 | + ) -> Result<Self> | |
| 439 | + where | |
| 440 | + Error: From<E>, | |
| 441 | + { | |
| 442 | + let data = KBox::pin_init::<Error>( | |
| 443 | + try_pin_init!(RegistrationData { | |
| 444 | + type_id: TypeId::of::<F>(), | |
| 445 | + data <- data, | |
| 446 | + }), | |
| 447 | + GFP_KERNEL, | |
| 448 | + )?; | |
| 449 | + | |
| 450 | + // SAFETY: `'a` is invariant (via `Registration`'s `PhantomData`). Lifetimes do not | |
| 451 | + // affect layout, so RegistrationData<F::Of<'a>> and RegistrationData<F::Of<'static>> | |
| 452 | + // have identical representation. | |
| 453 | + let data: Pin<KBox<RegistrationData<F::Of<'static>>>> = | |
| 454 | + unsafe { core::mem::transmute(data) }; | |
| 455 | + | |
| 456 | + let boxed: KBox<Opaque<bindings::auxiliary_device>> = KBox::zeroed(GFP_KERNEL)?; | |
| 457 | + let adev = boxed.get(); | |
| 458 | + | |
| 459 | + // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. | |
| 460 | + unsafe { | |
| 461 | + (*adev).dev.parent = parent.as_raw(); | |
| 462 | + (*adev).dev.release = Some(Device::release); | |
| 463 | + (*adev).name = name.as_char_ptr(); | |
| 464 | + (*adev).id = id; | |
| 465 | + (*adev).registration_data_rust = data.into_foreign(); | |
| 466 | + } | |
| 467 | + | |
| 468 | + // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, | |
| 469 | + // which has not been initialized yet. | |
| 470 | + unsafe { bindings::auxiliary_device_init(adev) }; | |
| 471 | + | |
| 472 | + // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be | |
| 473 | + // freed by `Device::release` when the last reference to the `struct auxiliary_device` | |
| 474 | + // is dropped. | |
| 475 | + let _ = KBox::into_raw(boxed); | |
| 476 | + | |
| 477 | + // SAFETY: | |
| 478 | + // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which | |
| 479 | + // has been initialized, | |
| 480 | + // - `modname.as_char_ptr()` is a NULL terminated string. | |
| 481 | + let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; | |
| 482 | + if ret != 0 { | |
| 483 | + // SAFETY: `registration_data` was set above via `into_foreign()`. | |
| 484 | + drop(unsafe { | |
| 485 | + Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign( | |
| 486 | + (*adev).registration_data_rust, | |
| 487 | + ) | |
| 488 | + }); | |
| 489 | + | |
| 490 | + // SAFETY: `adev` is guaranteed to be a valid pointer to a | |
| 491 | + // `struct auxiliary_device`, which has been initialized. | |
| 492 | + unsafe { bindings::auxiliary_device_uninit(adev) }; | |
| 493 | + | |
| 494 | + return Err(Error::from_errno(ret)); | |
| 495 | + } | |
| 496 | + | |
| 497 | + // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is | |
| 498 | + // called, which happens in `Self::drop()`. | |
| 499 | + Ok(Self { | |
| 500 | + // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated | |
| 501 | + // successfully. | |
| 502 | + adev: unsafe { NonNull::new_unchecked(adev) }, | |
| 503 | + _phantom: PhantomData, | |
| 390 | 504 | }) |
| 391 | 505 | } |
| 506 | + | |
| 507 | + /// Create and register a new auxiliary device with `'static` registration data. | |
| 508 | + /// | |
| 509 | + /// Safe variant of [`Registration::new_with_lt()`] for registration data that does not contain | |
| 510 | + /// borrowed references. | |
| 511 | + pub fn new<E>( | |
| 512 | + parent: &'a device::Device<device::Bound>, | |
| 513 | + name: &CStr, | |
| 514 | + id: u32, | |
| 515 | + modname: &CStr, | |
| 516 | + data: impl PinInit<F::Of<'a>, E>, | |
| 517 | + ) -> Result<Self> | |
| 518 | + where | |
| 519 | + F::Of<'a>: 'static, | |
| 520 | + Error: From<E>, | |
| 521 | + { | |
| 522 | + // SAFETY: `F::Of<'a>: 'static` guarantees the data contains no borrowed references, | |
| 523 | + // so forgetting the `Registration` cannot cause use-after-free. | |
| 524 | + unsafe { Self::new_with_lt(parent, name, id, modname, data) } | |
| 525 | + } | |
| 392 | 526 | } |
| 393 | 527 | |
| 394 | −impl Drop for Registration { | |
| 528 | +impl<F: ForLt> Drop for Registration<'_, F> { | |
| 395 | 529 | fn drop(&mut self) { |
| 396 | − // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered | |
| 530 | + // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` is a valid registered | |
| 397 | 531 | // `struct auxiliary_device`. |
| 398 | − unsafe { bindings::auxiliary_device_delete(self.0.as_ptr()) }; | |
| 532 | + unsafe { bindings::auxiliary_device_delete(self.adev.as_ptr()) }; | |
| 533 | + | |
| 534 | + // SAFETY: `registration_data` was set in `new()` via `into_foreign()`. | |
| 535 | + drop(unsafe { | |
| 536 | + Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign( | |
| 537 | + (*self.adev.as_ptr()).registration_data_rust, | |
| 538 | + ) | |
| 539 | + }); | |
| 399 | 540 | |
| 400 | 541 | // This drops the reference we acquired through `auxiliary_device_init()`. |
| 401 | 542 | // |
| 402 | − // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered | |
| 543 | + // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` is a valid registered | |
| 403 | 544 | // `struct auxiliary_device`. |
| 404 | − unsafe { bindings::auxiliary_device_uninit(self.0.as_ptr()) }; | |
| 545 | + unsafe { bindings::auxiliary_device_uninit(self.adev.as_ptr()) }; | |
| 405 | 546 | } |
| 406 | 547 | } |
| 407 | 548 | |
| 408 | 549 | // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread. |
| 409 | −unsafe impl Send for Registration {} | |
| 550 | +unsafe impl<F: ForLt> Send for Registration<'_, F> where for<'a> F::Of<'a>: Send {} | |
| 410 | 551 | |
| 411 | 552 | // SAFETY: `Registration` does not expose any methods or fields that need synchronization. |
| 412 | −unsafe impl Sync for Registration {} | |
| 553 | +unsafe impl<F: ForLt> Sync for Registration<'_, F> where for<'a> F::Of<'a>: Send {} | |
| @@ -888,12 +888,13 @@ pub trait Driver { · 887 unmodified lines | ||
| 888 | 888 | /// |
| 889 | 889 | /// impl platform::Driver for SampleDriver { |
| 890 | 890 | /// type IdInfo = (); |
| 891 | +/// type Data<'bound> = Self; | |
| 891 | 892 | /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; |
| 892 | 893 | /// |
| 893 | −/// fn probe( | |
| 894 | −/// pdev: &platform::Device<Core>, | |
| 895 | −/// _id_info: Option<&Self::IdInfo>, | |
| 896 | −/// ) -> impl PinInit<Self, Error> { | |
| 894 | +/// fn probe<'bound>( | |
| 895 | +/// pdev: &'bound platform::Device<Core<'_>>, | |
| 896 | +/// _id_info: Option<&'bound Self::IdInfo>, | |
| 897 | +/// ) -> impl PinInit<Self, Error> + 'bound { | |
| 897 | 898 | /// cpufreq::Registration::<SampleDriver>::new_foreign_owned(pdev.as_ref())?; |
| 898 | 899 | /// Ok(Self {}) |
| 899 | 900 | /// } |
| @@ -15,16 +15,12 @@ use crate::{ · 14 unmodified lines | ||
| 15 | 15 | }, // |
| 16 | 16 | }; |
| 17 | 17 | use core::{ |
| 18 | − any::TypeId, | |
| 19 | 18 | marker::PhantomData, |
| 20 | 19 | ptr, // |
| 21 | 20 | }; |
| 22 | 21 | |
| 23 | 22 | pub mod property; |
| 24 | 23 | |
| 25 | −// Assert that we can `read()` / `write()` a `TypeId` instance from / into `struct driver_type`. | |
| 26 | −static_assert!(core::mem::size_of::<bindings::driver_type>() >= core::mem::size_of::<TypeId>()); | |
| 27 | − | |
| 28 | 24 | /// The core representation of a device in the kernel's driver model. |
| 29 | 25 | /// |
| 30 | 26 | /// This structure represents the Rust abstraction for a C `struct device`. A [`Device`] can either |
| @@ -205,30 +201,13 @@ impl Device { · 174 unmodified lines | ||
| 205 | 201 | } |
| 206 | 202 | } |
| 207 | 203 | |
| 208 | −impl Device<CoreInternal> { | |
| 209 | − fn set_type_id<T: 'static>(&self) { | |
| 210 | − // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. | |
| 211 | − let private = unsafe { (*self.as_raw()).p }; | |
| 212 | − | |
| 213 | − // SAFETY: For a bound device (implied by the `CoreInternal` device context), `private` is | |
| 214 | − // guaranteed to be a valid pointer to a `struct device_private`. | |
| 215 | − let driver_type = unsafe { &raw mut (*private).driver_type }; | |
| 216 | − | |
| 217 | − // SAFETY: `driver_type` is valid for (unaligned) writes of a `TypeId`. | |
| 218 | − unsafe { | |
| 219 | − driver_type | |
| 220 | − .cast::<TypeId>() | |
| 221 | − .write_unaligned(TypeId::of::<T>()) | |
| 222 | − }; | |
| 223 | − } | |
| 224 | − | |
| 204 | +impl<'a> Device<CoreInternal<'a>> { | |
| 225 | 205 | /// Store a pointer to the bound driver's private data. |
| 226 | − pub fn set_drvdata<T: 'static>(&self, data: impl PinInit<T, Error>) -> Result { | |
| 206 | + pub fn set_drvdata<T>(&self, data: impl PinInit<T, Error>) -> Result { | |
| 227 | 207 | let data = KBox::pin_init(data, GFP_KERNEL)?; |
| 228 | 208 | |
| 229 | 209 | // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. |
| 230 | 210 | unsafe { bindings::dev_set_drvdata(self.as_raw(), data.into_foreign().cast()) }; |
| 231 | − self.set_type_id::<T>(); | |
| 232 | 211 | |
| 233 | 212 | Ok(()) |
| 234 | 213 | } |
| @@ -239,7 +218,7 @@ impl Device<CoreInternal> { · 4 unmodified lines | ||
| 239 | 218 | /// |
| 240 | 219 | /// - The type `T` must match the type of the `ForeignOwnable` previously stored by |
| 241 | 220 | /// [`Device::set_drvdata`]. |
| 242 | − pub(crate) unsafe fn drvdata_obtain<T: 'static>(&self) -> Option<Pin<KBox<T>>> { | |
| 221 | + pub(crate) unsafe fn drvdata_obtain<T>(&self) -> Option<Pin<KBox<T>>> { | |
| 243 | 222 | // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. |
| 244 | 223 | let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) }; |
| 245 | 224 | |
| @@ -265,7 +244,7 @@ impl Device<CoreInternal> { · 19 unmodified lines | ||
| 265 | 244 | /// device is fully unbound. |
| 266 | 245 | /// - The type `T` must match the type of the `ForeignOwnable` previously stored by |
| 267 | 246 | /// [`Device::set_drvdata`]. |
| 268 | − pub unsafe fn drvdata_borrow<T: 'static>(&self) -> Pin<&T> { | |
| 247 | + pub unsafe fn drvdata_borrow<T>(&self) -> Pin<&T> { | |
| 269 | 248 | // SAFETY: `drvdata_unchecked()` has the exact same safety requirements as the ones |
| 270 | 249 | // required by this method. |
| 271 | 250 | unsafe { self.drvdata_unchecked() } |
| @@ -281,7 +260,7 @@ impl Device<Bound> { · 9 unmodified lines | ||
| 281 | 260 | /// the device is fully unbound. |
| 282 | 261 | /// - The type `T` must match the type of the `ForeignOwnable` previously stored by |
| 283 | 262 | /// [`Device::set_drvdata`]. |
| 284 | − unsafe fn drvdata_unchecked<T: 'static>(&self) -> Pin<&T> { | |
| 263 | + unsafe fn drvdata_unchecked<T>(&self) -> Pin<&T> { | |
| 285 | 264 | // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. |
| 286 | 265 | let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) }; |
| 287 | 266 | |
| @@ -292,45 +271,6 @@ impl Device<Bound> { · 4 unmodified lines | ||
| 292 | 271 | // in `into_foreign()`. |
| 293 | 272 | unsafe { Pin::<KBox<T>>::borrow(ptr.cast()) } |
| 294 | 273 | } |
| 295 | − | |
| 296 | − fn match_type_id<T: 'static>(&self) -> Result { | |
| 297 | − // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. | |
| 298 | − let private = unsafe { (*self.as_raw()).p }; | |
| 299 | − | |
| 300 | − // SAFETY: For a bound device, `private` is guaranteed to be a valid pointer to a | |
| 301 | − // `struct device_private`. | |
| 302 | − let driver_type = unsafe { &raw mut (*private).driver_type }; | |
| 303 | − | |
| 304 | − // SAFETY: | |
| 305 | − // - `driver_type` is valid for (unaligned) reads of a `TypeId`. | |
| 306 | − // - A bound device guarantees that `driver_type` contains a valid `TypeId` value. | |
| 307 | − let type_id = unsafe { driver_type.cast::<TypeId>().read_unaligned() }; | |
| 308 | − | |
| 309 | − if type_id != TypeId::of::<T>() { | |
| 310 | − return Err(EINVAL); | |
| 311 | − } | |
| 312 | − | |
| 313 | − Ok(()) | |
| 314 | − } | |
| 315 | − | |
| 316 | − /// Access a driver's private data. | |
| 317 | − /// | |
| 318 | − /// Returns a pinned reference to the driver's private data or [`EINVAL`] if it doesn't match | |
| 319 | − /// the asserted type `T`. | |
| 320 | − pub fn drvdata<T: 'static>(&self) -> Result<Pin<&T>> { | |
| 321 | − // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. | |
| 322 | − if unsafe { bindings::dev_get_drvdata(self.as_raw()) }.is_null() { | |
| 323 | − return Err(ENOENT); | |
| 324 | − } | |
| 325 | − | |
| 326 | − self.match_type_id::<T>()?; | |
| 327 | − | |
| 328 | − // SAFETY: | |
| 329 | − // - The above check of `dev_get_drvdata()` guarantees that we are called after | |
| 330 | − // `set_drvdata()`. | |
| 331 | − // - We've just checked that the type of the driver's private data is in fact `T`. | |
| 332 | − Ok(unsafe { self.drvdata_unchecked() }) | |
| 333 | − } | |
| 334 | 274 | } |
| 335 | 275 | |
| 336 | 276 | impl<Ctx: DeviceContext> Device<Ctx> { |
| @@ -527,6 +467,10 @@ unsafe impl Send for Device {} · 190 unmodified lines | ||
| 527 | 467 | // synchronization in `struct device`. |
| 528 | 468 | unsafe impl Sync for Device {} |
| 529 | 469 | |
| 470 | +// SAFETY: Same as `Device<Normal>` -- the underlying `struct device` is the same; `Bound` is a | |
| 471 | +// zero-sized type-state marker that does not affect thread safety. | |
| 472 | +unsafe impl Sync for Device<Bound> {} | |
| 473 | + | |
| 530 | 474 | /// Marker trait for the context or scope of a bus specific device. |
| 531 | 475 | /// |
| 532 | 476 | /// [`DeviceContext`] is a marker trait for types representing the context of a bus specific |
| @@ -567,7 +511,7 @@ pub struct Normal; · 34 unmodified lines | ||
| 567 | 511 | /// callback it appears in. It is intended to be used for synchronization purposes. Bus device |
| 568 | 512 | /// implementations can implement methods for [`Device<Core>`], such that they can only be called |
| 569 | 513 | /// from bus callbacks. |
| 570 | −pub struct Core; | |
| 514 | +pub struct Core<'a>(PhantomData<&'a ()>); | |
| 571 | 515 | |
| 572 | 516 | /// Semantically the same as [`Core`], but reserved for internal usage of the corresponding bus |
| 573 | 517 | /// abstraction. |
| @@ -578,7 +522,7 @@ pub struct Core; · 4 unmodified lines | ||
| 578 | 522 | /// |
| 579 | 523 | /// This context mainly exists to share generic [`Device`] infrastructure that should only be called |
| 580 | 524 | /// from bus callbacks with bus abstractions, but without making them accessible for drivers. |
| 581 | −pub struct CoreInternal; | |
| 525 | +pub struct CoreInternal<'a>(PhantomData<&'a ()>); | |
| 582 | 526 | |
| 583 | 527 | /// The [`Bound`] context is the [`DeviceContext`] of a bus specific device when it is guaranteed to |
| 584 | 528 | /// be bound to a driver. |
| @@ -602,14 +546,14 @@ mod private { · 17 unmodified lines | ||
| 602 | 546 | pub trait Sealed {} |
| 603 | 547 | |
| 604 | 548 | impl Sealed for super::Bound {} |
| 605 | − impl Sealed for super::Core {} | |
| 606 | − impl Sealed for super::CoreInternal {} | |
| 549 | + impl<'a> Sealed for super::Core<'a> {} | |
| 550 | + impl<'a> Sealed for super::CoreInternal<'a> {} | |
| 607 | 551 | impl Sealed for super::Normal {} |
| 608 | 552 | } |
| 609 | 553 | |
| 610 | 554 | impl DeviceContext for Bound {} |
| 611 | −impl DeviceContext for Core {} | |
| 612 | −impl DeviceContext for CoreInternal {} | |
| 555 | +impl<'a> DeviceContext for Core<'a> {} | |
| 556 | +impl<'a> DeviceContext for CoreInternal<'a> {} | |
| 613 | 557 | impl DeviceContext for Normal {} |
| 614 | 558 | |
| 615 | 559 | impl<Ctx: DeviceContext> AsRef<Device<Ctx>> for Device<Ctx> { |
| @@ -659,6 +603,22 @@ pub unsafe trait AsBusDevice<Ctx: DeviceContext>: AsRef<Device<Ctx>> { · 43 unmodified lines | ||
| 659 | 603 | #[doc(hidden)] |
| 660 | 604 | #[macro_export] |
| 661 | 605 | macro_rules! __impl_device_context_deref { |
| 606 | + (unsafe { $device:ident, <$lt:lifetime> $src:ty => $dst:ty }) => { | |
| 607 | + impl<$lt> ::core::ops::Deref for $device<$src> { | |
| 608 | + type Target = $device<$dst>; | |
| 609 | + | |
| 610 | + fn deref(&self) -> &Self::Target { | |
| 611 | + let ptr: *const Self = self; | |
| 612 | + | |
| 613 | + // CAST: `$device<$src>` and `$device<$dst>` transparently wrap the same type by the | |
| 614 | + // safety requirement of the macro. | |
| 615 | + let ptr = ptr.cast::<Self::Target>(); | |
| 616 | + | |
| 617 | + // SAFETY: `ptr` was derived from `&self`. | |
| 618 | + unsafe { &*ptr } | |
| 619 | + } | |
| 620 | + } | |
| 621 | + }; | |
| 662 | 622 | (unsafe { $device:ident, $src:ty => $dst:ty }) => { |
| 663 | 623 | impl ::core::ops::Deref for $device<$src> { |
| 664 | 624 | type Target = $device<$dst>; |
| @@ -691,14 +651,14 @@ macro_rules! impl_device_context_deref { · 26 unmodified lines | ||
| 691 | 651 | // `__impl_device_context_deref!`. |
| 692 | 652 | ::kernel::__impl_device_context_deref!(unsafe { |
| 693 | 653 | $device, |
| 694 | − $crate::device::CoreInternal => $crate::device::Core | |
| 654 | + <'a> $crate::device::CoreInternal<'a> => $crate::device::Core<'a> | |
| 695 | 655 | }); |
| 696 | 656 | |
| 697 | 657 | // SAFETY: This macro has the exact same safety requirement as |
| 698 | 658 | // `__impl_device_context_deref!`. |
| 699 | 659 | ::kernel::__impl_device_context_deref!(unsafe { |
| 700 | 660 | $device, |
| 701 | − $crate::device::Core => $crate::device::Bound | |
| 661 | + <'a> $crate::device::Core<'a> => $crate::device::Bound | |
| 702 | 662 | }); |
| 703 | 663 | |
| 704 | 664 | // SAFETY: This macro has the exact same safety requirement as |
| @@ -713,6 +673,13 @@ macro_rules! impl_device_context_deref { · 8 unmodified lines | ||
| 713 | 673 | #[doc(hidden)] |
| 714 | 674 | #[macro_export] |
| 715 | 675 | macro_rules! __impl_device_context_into_aref { |
| 676 | + (<$lt:lifetime> $src:ty, $device:tt) => { | |
| 677 | + impl<$lt> ::core::convert::From<&$device<$src>> for $crate::sync::aref::ARef<$device> { | |
| 678 | + fn from(dev: &$device<$src>) -> Self { | |
| 679 | + (&**dev).into() | |
| 680 | + } | |
| 681 | + } | |
| 682 | + }; | |
| 716 | 683 | ($src:ty, $device:tt) => { |
| 717 | 684 | impl ::core::convert::From<&$device<$src>> for $crate::sync::aref::ARef<$device> { |
| 718 | 685 | fn from(dev: &$device<$src>) -> Self { |
| @@ -727,8 +694,12 @@ macro_rules! __impl_device_context_into_aref { · 8 unmodified lines | ||
| 727 | 694 | #[macro_export] |
| 728 | 695 | macro_rules! impl_device_context_into_aref { |
| 729 | 696 | ($device:tt) => { |
| 730 | − ::kernel::__impl_device_context_into_aref!($crate::device::CoreInternal, $device); | |
| 731 | − ::kernel::__impl_device_context_into_aref!($crate::device::Core, $device); | |
| 697 | + ::kernel::__impl_device_context_into_aref!( | |
| 698 | + <'a> $crate::device::CoreInternal<'a>, $device | |
| 699 | + ); | |
| 700 | + ::kernel::__impl_device_context_into_aref!( | |
| 701 | + <'a> $crate::device::Core<'a>, $device | |
| 702 | + ); | |
| 732 | 703 | ::kernel::__impl_device_context_into_aref!($crate::device::Bound, $device); |
| 733 | 704 | }; |
| 734 | 705 | } |
| @@ -122,7 +122,7 @@ struct Inner<T> { · 121 unmodified lines | ||
| 122 | 122 | /// # Ok(()) |
| 123 | 123 | /// # } |
| 124 | 124 | /// ``` |
| 125 | −pub struct Devres<T: Send> { | |
| 125 | +pub struct Devres<T: Send + 'static> { | |
| 126 | 126 | dev: ARef<Device>, |
| 127 | 127 | inner: Arc<Inner<T>>, |
| 128 | 128 | } |
| @@ -184,7 +184,7 @@ mod base { · 55 unmodified lines | ||
| 184 | 184 | } |
| 185 | 185 | } |
| 186 | 186 | |
| 187 | −impl<T: Send> Devres<T> { | |
| 187 | +impl<T: Send + 'static> Devres<T> { | |
| 188 | 188 | /// Creates a new [`Devres`] instance of the given `data`. |
| 189 | 189 | /// |
| 190 | 190 | /// The `data` encapsulated within the returned `Devres` instance' `data` will be |
| @@ -304,7 +304,7 @@ impl<T: Send> Devres<T> { · 113 unmodified lines | ||
| 304 | 304 | /// pci, // |
| 305 | 305 | /// }; |
| 306 | 306 | /// |
| 307 | − /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result { | |
| 307 | + /// fn from_core(dev: &pci::Device<Core<'_>>, devres: Devres<pci::Bar<'_, 0x4>>) -> Result { | |
| 308 | 308 | /// let bar = devres.access(dev.as_ref())?; |
| 309 | 309 | /// |
| 310 | 310 | /// let _ = bar.read32(0x0); |
| @@ -349,7 +349,7 @@ unsafe impl<T: Send> Send for Devres<T> {} · 38 unmodified lines | ||
| 349 | 349 | // SAFETY: `Devres` can be shared with any task, if `T: Sync`. |
| 350 | 350 | unsafe impl<T: Send + Sync> Sync for Devres<T> {} |
| 351 | 351 | |
| 352 | −impl<T: Send> Drop for Devres<T> { | |
| 352 | +impl<T: Send + 'static> Drop for Devres<T> { | |
| 353 | 353 | fn drop(&mut self) { |
| 354 | 354 | // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data |
| 355 | 355 | // anymore, hence it is safe not to wait for the grace period to finish. |
| @@ -47,7 +47,7 @@ pub type DmaAddress = bindings::dma_addr_t; · 46 unmodified lines | ||
| 47 | 47 | /// where the underlying bus is DMA capable, such as: |
| 48 | 48 | #[cfg_attr(CONFIG_PCI, doc = "* [`pci::Device`](kernel::pci::Device)")] |
| 49 | 49 | /// * [`platform::Device`](::kernel::platform::Device) |
| 50 | −pub trait Device: AsRef<device::Device<Core>> { | |
| 50 | +pub trait Device<'a>: AsRef<device::Device<Core<'a>>> { | |
| 51 | 51 | /// Set up the device's DMA streaming addressing capabilities. |
| 52 | 52 | /// |
| 53 | 53 | /// This method is usually called once from `probe()` as soon as the device capabilities are |
| @@ -13,10 +13,13 @@ · 12 unmodified lines | ||
| 13 | 13 | //! The main driver interface is defined by a bus specific driver trait. For instance: |
| 14 | 14 | //! |
| 15 | 15 | //! ```ignore |
| 16 | −//! pub trait Driver: Send { | |
| 16 | +//! pub trait Driver { | |
| 17 | 17 | //! /// The type holding information about each device ID supported by the driver. |
| 18 | 18 | //! type IdInfo: 'static; |
| 19 | 19 | //! |
| 20 | +//! /// The type of the driver's bus device private data. | |
| 21 | +//! type Data<'bound>: Send + 'bound; | |
| 22 | +//! | |
| 20 | 23 | //! /// The table of OF device ids supported by the driver. |
| 21 | 24 | //! const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; |
| 22 | 25 | //! |
| @@ -24,10 +27,16 @@ · 1 unmodified line | ||
| 24 | 27 | //! const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None; |
| 25 | 28 | //! |
| 26 | 29 | //! /// Driver probe. |
| 27 | −//! fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>; | |
| 30 | +//! fn probe<'bound>( | |
| 31 | +//! dev: &'bound Device<device::Core<'_>>, | |
| 32 | +//! id_info: &'bound Self::IdInfo, | |
| 33 | +//! ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; | |
| 28 | 34 | //! |
| 29 | 35 | //! /// Driver unbind (optional). |
| 30 | −//! fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { | |
| 36 | +//! fn unbind<'bound>( | |
| 37 | +//! dev: &'bound Device<device::Core<'_>>, | |
| 38 | +//! this: Pin<&Self::Data<'bound>>, | |
| 39 | +//! ) { | |
| 31 | 40 | //! let _ = (dev, this); |
| 32 | 41 | //! } |
| 33 | 42 | //! } |
| @@ -42,8 +51,9 @@ · 8 unmodified lines | ||
| 42 | 51 | )] |
| 43 | 52 | #")] |
| 44 | 53 | //! |
| 45 | −//! The `probe()` callback should return a `impl PinInit<Self, Error>`, i.e. the driver's private | |
| 46 | −//! data. The bus abstraction should store the pointer in the corresponding bus device. The generic | |
| 54 | +//! The `probe()` callback should return a | |
| 55 | +//! `impl PinInit<Self::Data<'bound>, Error>`, i.e. the driver's private data. The bus | |
| 56 | +//! abstraction should store the pointer in the corresponding bus device. The generic | |
| 47 | 57 | //! [`Device`] infrastructure provides common helpers for this purpose on its |
| 48 | 58 | //! [`Device<CoreInternal>`] implementation. |
| 49 | 59 | //! |
| @@ -118,8 +128,8 @@ pub unsafe trait DriverLayout { · 68 unmodified lines | ||
| 118 | 128 | /// The specific driver type embedding a `struct device_driver`. |
| 119 | 129 | type DriverType: Default; |
| 120 | 130 | |
| 121 | − /// The type of the driver's device private data. | |
| 122 | − type DriverData; | |
| 131 | + /// The type of the driver's bus device private data. | |
| 132 | + type DriverData<'bound>; | |
| 123 | 133 | |
| 124 | 134 | /// Byte offset of the embedded `struct device_driver` within `DriverType`. |
| 125 | 135 | /// |
| @@ -181,20 +191,20 @@ unsafe impl<T: RegistrationOps> Sync for Registration<T> {} · 55 unmodified lines | ||
| 181 | 191 | // any thread, so `Registration` is `Send`. |
| 182 | 192 | unsafe impl<T: RegistrationOps> Send for Registration<T> {} |
| 183 | 193 | |
| 184 | −impl<T: RegistrationOps + 'static> Registration<T> { | |
| 194 | +impl<T: RegistrationOps> Registration<T> { | |
| 185 | 195 | extern "C" fn post_unbind_callback(dev: *mut bindings::device) { |
| 186 | 196 | // SAFETY: The driver core only ever calls the post unbind callback with a valid pointer to |
| 187 | 197 | // a `struct device`. |
| 188 | 198 | // |
| 189 | 199 | // INVARIANT: `dev` is valid for the duration of the `post_unbind_callback()`. |
| 190 | − let dev = unsafe { &*dev.cast::<device::Device<device::CoreInternal>>() }; | |
| 200 | + let dev = unsafe { &*dev.cast::<device::Device<device::CoreInternal<'_>>>() }; | |
| 191 | 201 | |
| 192 | − // `remove()` and all devres callbacks have been completed at this point, hence drop the | |
| 193 | − // driver's device private data. | |
| 202 | + // `remove()` has been completed at this point; devres resources are still valid and will | |
| 203 | + // be released after the driver's bus device private data is dropped. | |
| 194 | 204 | // |
| 195 | 205 | // SAFETY: By the safety requirements of the `Driver` trait, `T::DriverData` is the |
| 196 | − // driver's device private data type. | |
| 197 | − drop(unsafe { dev.drvdata_obtain::<T::DriverData>() }); | |
| 206 | + // driver's bus device private data type. | |
| 207 | + drop(unsafe { dev.drvdata_obtain::<T::DriverData<'_>>() }); | |
| 198 | 208 | } |
| 199 | 209 | |
| 200 | 210 | /// Attach generic `struct device_driver` callbacks. |
| @@ -215,7 +225,10 @@ impl<T: RegistrationOps + 'static> Registration<T> { · 14 unmodified lines | ||
| 215 | 225 | } |
| 216 | 226 | |
| 217 | 227 | /// Creates a new instance of the registration object. |
| 218 | − pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { | |
| 228 | + pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> | |
| 229 | + where | |
| 230 | + T: 'static, | |
| 231 | + { | |
| 219 | 232 | try_pin_init!(Self { |
| 220 | 233 | reg <- Opaque::try_ffi_init(|ptr: *mut T::DriverType| { |
| 221 | 234 | // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write. |
| @@ -278,6 +291,26 @@ macro_rules! module_driver { · 56 unmodified lines | ||
| 278 | 291 | } |
| 279 | 292 | } |
| 280 | 293 | |
| 294 | +// Calling the FFI function directly from the `Adapter` impl may result in it being called | |
| 295 | +// directly from driver modules. This happens since the Rust compiler will use monomorphisation, so | |
| 296 | +// it might happen that functions are instantiated within the calling driver module. For now, work | |
| 297 | +// around this with `#[inline(never)]` helpers. | |
| 298 | +// | |
| 299 | +// TODO: Remove once a more generic solution has been implemented. For instance, we may be able to | |
| 300 | +// leverage `bindgen` to take care of this depending on whether a symbol is (already) exported. | |
| 301 | +#[inline(never)] | |
| 302 | +#[allow(clippy::missing_safety_doc)] | |
| 303 | +#[allow(dead_code)] | |
| 304 | +#[must_use] | |
| 305 | +unsafe fn acpi_of_match_device( | |
| 306 | + adev: *const bindings::acpi_device, | |
| 307 | + of_match_table: *const bindings::of_device_id, | |
| 308 | + of_id: *mut *const bindings::of_device_id, | |
| 309 | +) -> bool { | |
| 310 | + // SAFETY: Safety requirements are the same as `bindings::acpi_of_match_device`. | |
| 311 | + unsafe { bindings::acpi_of_match_device(adev, of_match_table, of_id) } | |
| 312 | +} | |
| 313 | + | |
| 281 | 314 | /// The bus independent adapter to match a drivers and a devices. |
| 282 | 315 | /// |
| 283 | 316 | /// This trait should be implemented by the bus specific adapter, which represents the connection |
| @@ -329,35 +362,63 @@ pub trait Adapter { · 45 unmodified lines | ||
| 329 | 362 | /// |
| 330 | 363 | /// If this returns `None`, it means there is no match with an entry in the [`of::IdTable`]. |
| 331 | 364 | fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { |
| 332 | − #[cfg(not(CONFIG_OF))] | |
| 365 | + let table = Self::of_id_table()?; | |
| 366 | + | |
| 367 | + #[cfg(not(any(CONFIG_OF, CONFIG_ACPI)))] | |
| 333 | 368 | { |
| 334 | − let _ = dev; | |
| 335 | − None | |
| 369 | + let _ = (dev, table); | |
| 336 | 370 | } |
| 337 | 371 | |
| 338 | 372 | #[cfg(CONFIG_OF)] |
| 339 | 373 | { |
| 340 | − let table = Self::of_id_table()?; | |
| 341 | − | |
| 342 | 374 | // SAFETY: |
| 343 | 375 | // - `table` has static lifetime, hence it's valid for read, |
| 344 | 376 | // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`. |
| 345 | 377 | let raw_id = unsafe { bindings::of_match_device(table.as_ptr(), dev.as_raw()) }; |
| 346 | 378 | |
| 347 | − if raw_id.is_null() { | |
| 348 | − None | |
| 349 | − } else { | |
| 379 | + if !raw_id.is_null() { | |
| 350 | 380 | // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id` |
| 351 | 381 | // and does not add additional invariants, so it's safe to transmute. |
| 352 | 382 | let id = unsafe { &*raw_id.cast::<of::DeviceId>() }; |
| 353 | 383 | |
| 354 | − Some( | |
| 355 | − table.info(<of::DeviceId as crate::device_id::RawDeviceIdIndex>::index( | |
| 356 | − id, | |
| 357 | − )), | |
| 358 | − ) | |
| 384 | + return Some(table.info( | |
| 385 | + <of::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id), | |
| 386 | + )); | |
| 387 | + } | |
| 388 | + } | |
| 389 | + | |
| 390 | + #[cfg(CONFIG_ACPI)] | |
| 391 | + { | |
| 392 | + use core::ptr; | |
| 393 | + use device::property::FwNode; | |
| 394 | + | |
| 395 | + let mut raw_id = ptr::null(); | |
| 396 | + | |
| 397 | + let fwnode = dev.fwnode().map_or(ptr::null_mut(), FwNode::as_raw); | |
| 398 | + | |
| 399 | + // SAFETY: `fwnode` is a pointer to a valid `fwnode_handle`. A null pointer will be | |
| 400 | + // passed through the function. | |
| 401 | + let adev = unsafe { bindings::to_acpi_device_node(fwnode) }; | |
| 402 | + | |
| 403 | + // SAFETY: | |
| 404 | + // - `adev` is a valid pointer to `acpi_device` or is null. It is guaranteed to be | |
| 405 | + // valid as long as `dev` is alive. | |
| 406 | + // - `table` has static lifetime, hence it's valid for read. | |
| 407 | + if unsafe { acpi_of_match_device(adev, table.as_ptr(), &raw mut raw_id) } { | |
| 408 | + // SAFETY: | |
| 409 | + // - the function returns true, therefore `raw_id` has been set to a pointer to a | |
| 410 | + // valid `of_device_id`. | |
| 411 | + // - `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id` | |
| 412 | + // and does not add additional invariants, so it's safe to transmute. | |
| 413 | + let id = unsafe { &*raw_id.cast::<of::DeviceId>() }; | |
| 414 | + | |
| 415 | + return Some(table.info( | |
| 416 | + <of::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id), | |
| 417 | + )); | |
| 359 | 418 | } |
| 360 | 419 | } |
| 420 | + | |
| 421 | + None | |
| 361 | 422 | } |
| 362 | 423 | |
| 363 | 424 | /// Returns the driver's private data from the matching entry of any of the ID tables, if any. |
| @@ -93,18 +93,18 @@ pub struct Adapter<T: Driver>(T); · 92 unmodified lines | ||
| 93 | 93 | |
| 94 | 94 | // SAFETY: |
| 95 | 95 | // - `bindings::i2c_driver` is a C type declared as `repr(C)`. |
| 96 | −// - `T` is the type of the driver's device private data. | |
| 96 | +// - `T::Data` is the type of the driver's device private data. | |
| 97 | 97 | // - `struct i2c_driver` embeds a `struct device_driver`. |
| 98 | 98 | // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. |
| 99 | −unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> { | |
| 99 | +unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> { | |
| 100 | 100 | type DriverType = bindings::i2c_driver; |
| 101 | − type DriverData = T; | |
| 101 | + type DriverData<'bound> = T::Data<'bound>; | |
| 102 | 102 | const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | 105 | // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if |
| 106 | 106 | // a preceding call to `register` has been successful. |
| 107 | −unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { | |
| 107 | +unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> { | |
| 108 | 108 | unsafe fn register( |
| 109 | 109 | idrv: &Opaque<Self::DriverType>, |
| 110 | 110 | name: &'static CStr, |
| @@ -151,13 +151,13 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { · 40 unmodified lines | ||
| 151 | 151 | } |
| 152 | 152 | } |
| 153 | 153 | |
| 154 | −impl<T: Driver + 'static> Adapter<T> { | |
| 154 | +impl<T: Driver> Adapter<T> { | |
| 155 | 155 | extern "C" fn probe_callback(idev: *mut bindings::i2c_client) -> kernel::ffi::c_int { |
| 156 | 156 | // SAFETY: The I2C bus only ever calls the probe callback with a valid pointer to a |
| 157 | 157 | // `struct i2c_client`. |
| 158 | 158 | // |
| 159 | 159 | // INVARIANT: `idev` is valid for the duration of `probe_callback()`. |
| 160 | − let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() }; | |
| 160 | + let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal<'_>>>() }; | |
| 161 | 161 | |
| 162 | 162 | let info = |
| 163 | 163 | 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> { · 8 unmodified lines | ||
| 172 | 172 | |
| 173 | 173 | extern "C" fn remove_callback(idev: *mut bindings::i2c_client) { |
| 174 | 174 | // SAFETY: `idev` is a valid pointer to a `struct i2c_client`. |
| 175 | − let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() }; | |
| 175 | + let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal<'_>>>() }; | |
| 176 | 176 | |
| 177 | 177 | // SAFETY: `remove_callback` is only ever called after a successful call to |
| 178 | 178 | // `probe_callback`, hence it's guaranteed that `I2cClient::set_drvdata()` has been called |
| 179 | − // and stored a `Pin<KBox<T>>`. | |
| 180 | − let data = unsafe { idev.as_ref().drvdata_borrow::<T>() }; | |
| 179 | + // and stored a `Pin<KBox<T::Data<'_>>>`. | |
| 180 | + let data = unsafe { idev.as_ref().drvdata_borrow::<T::Data<'_>>() }; | |
| 181 | 181 | |
| 182 | 182 | T::unbind(idev, data); |
| 183 | 183 | } |
| 184 | 184 | |
| 185 | 185 | extern "C" fn shutdown_callback(idev: *mut bindings::i2c_client) { |
| 186 | 186 | // SAFETY: `shutdown_callback` is only ever called for a valid `idev` |
| 187 | − let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() }; | |
| 187 | + let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal<'_>>>() }; | |
| 188 | 188 | |
| 189 | 189 | // SAFETY: `shutdown_callback` is only ever called after a successful call to |
| 190 | 190 | // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called |
| 191 | − // and stored a `Pin<KBox<T>>`. | |
| 192 | − let data = unsafe { idev.as_ref().drvdata_borrow::<T>() }; | |
| 191 | + // and stored a `Pin<KBox<T::Data<'_>>>`. | |
| 192 | + let data = unsafe { idev.as_ref().drvdata_borrow::<T::Data<'_>>() }; | |
| 193 | 193 | |
| 194 | 194 | T::shutdown(idev, data); |
| 195 | 195 | } |
| @@ -222,7 +222,7 @@ impl<T: Driver + 'static> Adapter<T> { · 26 unmodified lines | ||
| 222 | 222 | } |
| 223 | 223 | } |
| 224 | 224 | |
| 225 | −impl<T: Driver + 'static> driver::Adapter for Adapter<T> { | |
| 225 | +impl<T: Driver> driver::Adapter for Adapter<T> { | |
| 226 | 226 | type IdInfo = T::IdInfo; |
| 227 | 227 | |
| 228 | 228 | fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> { |
| @@ -294,22 +294,26 @@ macro_rules! module_i2c_driver { · 65 unmodified lines | ||
| 294 | 294 | /// |
| 295 | 295 | /// impl i2c::Driver for MyDriver { |
| 296 | 296 | /// type IdInfo = (); |
| 297 | +/// type Data<'bound> = Self; | |
| 297 | 298 | /// const I2C_ID_TABLE: Option<i2c::IdTable<Self::IdInfo>> = Some(&I2C_TABLE); |
| 298 | 299 | /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); |
| 299 | 300 | /// const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); |
| 300 | 301 | /// |
| 301 | −/// fn probe( | |
| 302 | −/// _idev: &i2c::I2cClient<Core>, | |
| 303 | −/// _id_info: Option<&Self::IdInfo>, | |
| 304 | −/// ) -> impl PinInit<Self, Error> { | |
| 302 | +/// fn probe<'bound>( | |
| 303 | +/// _idev: &'bound i2c::I2cClient<Core<'_>>, | |
| 304 | +/// _id_info: Option<&'bound Self::IdInfo>, | |
| 305 | +/// ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { | |
| 305 | 306 | /// Err(ENODEV) |
| 306 | 307 | /// } |
| 307 | 308 | /// |
| 308 | −/// fn shutdown(_idev: &i2c::I2cClient<Core>, this: Pin<&Self>) { | |
| 309 | +/// fn shutdown<'bound>( | |
| 310 | +/// _idev: &'bound i2c::I2cClient<Core<'_>>, | |
| 311 | +/// this: Pin<&Self::Data<'bound>>, | |
| 312 | +/// ) { | |
| 309 | 313 | /// } |
| 310 | 314 | /// } |
| 311 | 315 | ///``` |
| 312 | −pub trait Driver: Send { | |
| 316 | +pub trait Driver { | |
| 313 | 317 | /// The type holding information about each device id supported by the driver. |
| 314 | 318 | // TODO: Use `associated_type_defaults` once stabilized: |
| 315 | 319 | // |
| @@ -318,6 +322,9 @@ pub trait Driver: Send { · 2 unmodified lines | ||
| 318 | 322 | // ``` |
| 319 | 323 | type IdInfo: 'static; |
| 320 | 324 | |
| 325 | + /// The type of the driver's bus device private data. | |
| 326 | + type Data<'bound>: Send + 'bound; | |
| 327 | + | |
| 321 | 328 | /// The table of device ids supported by the driver. |
| 322 | 329 | const I2C_ID_TABLE: Option<IdTable<Self::IdInfo>> = None; |
| 323 | 330 | |
| @@ -331,10 +338,10 @@ pub trait Driver: Send { · 7 unmodified lines | ||
| 331 | 338 | /// |
| 332 | 339 | /// Called when a new i2c client is added or discovered. |
| 333 | 340 | /// Implementers should attempt to initialize the client here. |
| 334 | − fn probe( | |
| 335 | − dev: &I2cClient<device::Core>, | |
| 336 | − id_info: Option<&Self::IdInfo>, | |
| 337 | − ) -> impl PinInit<Self, Error>; | |
| 341 | + fn probe<'bound>( | |
| 342 | + dev: &'bound I2cClient<device::Core<'_>>, | |
| 343 | + id_info: Option<&'bound Self::IdInfo>, | |
| 344 | + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; | |
| 338 | 345 | |
| 339 | 346 | /// I2C driver shutdown. |
| 340 | 347 | /// |
| @@ -346,8 +353,8 @@ pub trait Driver: Send { · 5 unmodified lines | ||
| 346 | 353 | /// |
| 347 | 354 | /// This callback is distinct from final resource cleanup, as the driver instance remains valid |
| 348 | 355 | /// after it returns. Any deallocation or teardown of driver-owned resources should instead be |
| 349 | − /// handled in `Self::drop`. | |
| 350 | − fn shutdown(dev: &I2cClient<device::Core>, this: Pin<&Self>) { | |
| 356 | + /// handled in `Drop`. | |
| 357 | + fn shutdown<'bound>(dev: &'bound I2cClient<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) { | |
| 351 | 358 | let _ = (dev, this); |
| 352 | 359 | } |
| 353 | 360 | |
| @@ -360,8 +367,8 @@ pub trait Driver: Send { · 6 unmodified lines | ||
| 360 | 367 | /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O |
| 361 | 368 | /// operations to gracefully tear down the device. |
| 362 | 369 | /// |
| 363 | − /// Otherwise, release operations for driver resources should be performed in `Self::drop`. | |
| 364 | − fn unbind(dev: &I2cClient<device::Core>, this: Pin<&Self>) { | |
| 370 | + /// Otherwise, release operations for driver resources should be performed in `Drop`. | |
| 371 | + fn unbind<'bound>(dev: &'bound I2cClient<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) { | |
| 365 | 372 | let _ = (dev, this); |
| 366 | 373 | } |
| 367 | 374 | } |
| @@ -62,33 +62,31 @@ impl<'a> IoRequest<'a> { · 61 unmodified lines | ||
| 62 | 62 | /// |
| 63 | 63 | /// impl platform::Driver for SampleDriver { |
| 64 | 64 | /// # type IdInfo = (); |
| 65 | + /// # type Data<'bound> = Self; | |
| 65 | 66 | /// |
| 66 | − /// fn probe( | |
| 67 | − /// pdev: &platform::Device<Core>, | |
| 68 | − /// info: Option<&Self::IdInfo>, | |
| 69 | − /// ) -> impl PinInit<Self, Error> { | |
| 67 | + /// fn probe<'bound>( | |
| 68 | + /// pdev: &'bound platform::Device<Core<'_>>, | |
| 69 | + /// info: Option<&'bound Self::IdInfo>, | |
| 70 | + /// ) -> impl PinInit<Self, Error> + 'bound { | |
| 70 | 71 | /// let offset = 0; // Some offset. |
| 71 | 72 | /// |
| 72 | 73 | /// // If the size is known at compile time, use [`Self::iomap_sized`]. |
| 73 | 74 | /// // |
| 74 | 75 | /// // No runtime checks will apply when reading and writing. |
| 75 | 76 | /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; |
| 76 | − /// let iomem = request.iomap_sized::<42>(); | |
| 77 | − /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?; | |
| 78 | − /// | |
| 79 | − /// let io = iomem.access(pdev.as_ref())?; | |
| 77 | + /// let iomem = request.iomap_sized::<42>()?; | |
| 80 | 78 | /// |
| 81 | 79 | /// // Read and write a 32-bit value at `offset`. |
| 82 | − /// let data = io.read32(offset); | |
| 80 | + /// let data = iomem.read32(offset); | |
| 83 | 81 | /// |
| 84 | − /// io.write32(data, offset); | |
| 82 | + /// iomem.write32(data, offset); | |
| 85 | 83 | /// |
| 86 | 84 | /// # Ok(SampleDriver) |
| 87 | 85 | /// } |
| 88 | 86 | /// } |
| 89 | 87 | /// ``` |
| 90 | − pub fn iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a { | |
| 91 | − IoMem::new(self) | |
| 88 | + pub fn iomap_sized<const SIZE: usize>(self) -> Result<IoMem<'a, SIZE>> { | |
| 89 | + IoMem::ioremap(self.device, self.resource) | |
| 92 | 90 | } |
| 93 | 91 | |
| 94 | 92 | /// Same as [`Self::iomap_sized`] but with exclusive access to the |
| @@ -97,10 +95,8 @@ impl<'a> IoRequest<'a> { · 2 unmodified lines | ||
| 97 | 95 | /// This uses the [`ioremap()`] C API. |
| 98 | 96 | /// |
| 99 | 97 | /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device |
| 100 | − pub fn iomap_exclusive_sized<const SIZE: usize>( | |
| 101 | − self, | |
| 102 | − ) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a { | |
| 103 | − ExclusiveIoMem::new(self) | |
| 98 | + pub fn iomap_exclusive_sized<const SIZE: usize>(self) -> Result<ExclusiveIoMem<'a, SIZE>> { | |
| 99 | + ExclusiveIoMem::ioremap(self.device, self.resource) | |
| 104 | 100 | } |
| 105 | 101 | |
| 106 | 102 | /// Maps an [`IoRequest`] where the size is not known at compile time, |
| @@ -126,11 +122,12 @@ impl<'a> IoRequest<'a> { · 19 unmodified lines | ||
| 126 | 122 | /// |
| 127 | 123 | /// impl platform::Driver for SampleDriver { |
| 128 | 124 | /// # type IdInfo = (); |
| 125 | + /// # type Data<'bound> = Self; | |
| 129 | 126 | /// |
| 130 | − /// fn probe( | |
| 131 | − /// pdev: &platform::Device<Core>, | |
| 132 | − /// info: Option<&Self::IdInfo>, | |
| 133 | − /// ) -> impl PinInit<Self, Error> { | |
| 127 | + /// fn probe<'bound>( | |
| 128 | + /// pdev: &'bound platform::Device<Core<'_>>, | |
| 129 | + /// info: Option<&'bound Self::IdInfo>, | |
| 130 | + /// ) -> impl PinInit<Self, Error> + 'bound { | |
| 134 | 131 | /// let offset = 0; // Some offset. |
| 135 | 132 | /// |
| 136 | 133 | /// // Unlike [`Self::iomap_sized`], here the size of the memory region |
| @@ -138,27 +135,24 @@ impl<'a> IoRequest<'a> { · 1 unmodified line | ||
| 138 | 135 | /// // family of functions should be used, leading to runtime checks on every |
| 139 | 136 | /// // access. |
| 140 | 137 | /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; |
| 141 | − /// let iomem = request.iomap(); | |
| 142 | − /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?; | |
| 143 | − /// | |
| 144 | − /// let io = iomem.access(pdev.as_ref())?; | |
| 138 | + /// let iomem = request.iomap()?; | |
| 145 | 139 | /// |
| 146 | − /// let data = io.try_read32(offset)?; | |
| 140 | + /// let data = iomem.try_read32(offset)?; | |
| 147 | 141 | /// |
| 148 | − /// io.try_write32(data, offset)?; | |
| 142 | + /// iomem.try_write32(data, offset)?; | |
| 149 | 143 | /// |
| 150 | 144 | /// # Ok(SampleDriver) |
| 151 | 145 | /// } |
| 152 | 146 | /// } |
| 153 | 147 | /// ``` |
| 154 | − pub fn iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a { | |
| 155 | − Self::iomap_sized::<0>(self) | |
| 148 | + pub fn iomap(self) -> Result<IoMem<'a>> { | |
| 149 | + self.iomap_sized::<0>() | |
| 156 | 150 | } |
| 157 | 151 | |
| 158 | 152 | /// Same as [`Self::iomap`] but with exclusive access to the underlying |
| 159 | 153 | /// region. |
| 160 | − pub fn iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a { | |
| 161 | − Self::iomap_exclusive_sized::<0>(self) | |
| 154 | + pub fn iomap_exclusive(self) -> Result<ExclusiveIoMem<'a, 0>> { | |
| 155 | + self.iomap_exclusive_sized::<0>() | |
| 162 | 156 | } |
| 163 | 157 | } |
| 164 | 158 | |
| @@ -167,9 +161,9 @@ impl<'a> IoRequest<'a> { · 2 unmodified lines | ||
| 167 | 161 | /// # Invariants |
| 168 | 162 | /// |
| 169 | 163 | /// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`]. |
| 170 | −pub struct ExclusiveIoMem<const SIZE: usize> { | |
| 164 | +pub struct ExclusiveIoMem<'a, const SIZE: usize> { | |
| 171 | 165 | /// The underlying `IoMem` instance. |
| 172 | − iomem: IoMem<SIZE>, | |
| 166 | + iomem: IoMem<'a, SIZE>, | |
| 173 | 167 | |
| 174 | 168 | /// The region abstraction. This represents exclusive access to the |
| 175 | 169 | /// range represented by the underlying `iomem`. |
| @@ -178,9 +172,9 @@ pub struct ExclusiveIoMem<const SIZE: usize> { · 2 unmodified lines | ||
| 178 | 172 | _region: Region, |
| 179 | 173 | } |
| 180 | 174 | |
| 181 | −impl<const SIZE: usize> ExclusiveIoMem<SIZE> { | |
| 175 | +impl<'a, const SIZE: usize> ExclusiveIoMem<'a, SIZE> { | |
| 182 | 176 | /// Creates a new `ExclusiveIoMem` instance. |
| 183 | − fn ioremap(resource: &Resource) -> Result<Self> { | |
| 177 | + fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> { | |
| 184 | 178 | let start = resource.start(); |
| 185 | 179 | let size = resource.size(); |
| 186 | 180 | let name = resource.name().unwrap_or_default(); |
| @@ -194,26 +188,29 @@ impl<const SIZE: usize> ExclusiveIoMem<SIZE> { · 7 unmodified lines | ||
| 194 | 188 | ) |
| 195 | 189 | .ok_or(EBUSY)?; |
| 196 | 190 | |
| 197 | − let iomem = IoMem::ioremap(resource)?; | |
| 191 | + let iomem = IoMem::ioremap(dev, resource)?; | |
| 198 | 192 | |
| 199 | − let iomem = ExclusiveIoMem { | |
| 193 | + Ok(ExclusiveIoMem { | |
| 200 | 194 | iomem, |
| 201 | 195 | _region: region, |
| 202 | − }; | |
| 203 | − | |
| 204 | − Ok(iomem) | |
| 196 | + }) | |
| 205 | 197 | } |
| 206 | 198 | |
| 207 | − /// Creates a new `ExclusiveIoMem` instance from a previously acquired [`IoRequest`]. | |
| 208 | − pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a { | |
| 209 | − let dev = io_request.device; | |
| 210 | − let res = io_request.resource; | |
| 211 | − | |
| 212 | − Devres::new(dev, Self::ioremap(res)) | |
| 199 | + /// Consume the `ExclusiveIoMem` and register it as a device-managed resource. | |
| 200 | + /// | |
| 201 | + /// The returned `Devres<ExclusiveIoMem<'static, SIZE>>` can outlive the original lifetime | |
| 202 | + /// `'a`. Access to the I/O memory is revoked when the device is unbound. | |
| 203 | + pub fn into_devres(self) -> Result<Devres<ExclusiveIoMem<'static, SIZE>>> { | |
| 204 | + // SAFETY: Casting to `'static` is sound because `Devres` guarantees the | |
| 205 | + // `ExclusiveIoMem` does not actually outlive the device -- access is revoked and the | |
| 206 | + // resource is released when the device is unbound. | |
| 207 | + let iomem: ExclusiveIoMem<'static, SIZE> = unsafe { core::mem::transmute(self) }; | |
| 208 | + let dev = iomem.iomem.dev; | |
| 209 | + Devres::new(dev, iomem) | |
| 213 | 210 | } |
| 214 | 211 | } |
| 215 | 212 | |
| 216 | −impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { | |
| 213 | +impl<const SIZE: usize> Deref for ExclusiveIoMem<'_, SIZE> { | |
| 217 | 214 | type Target = Mmio<SIZE>; |
| 218 | 215 | |
| 219 | 216 | fn deref(&self) -> &Self::Target { |
| @@ -230,12 +227,13 @@ impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { · 10 unmodified lines | ||
| 230 | 227 | /// |
| 231 | 228 | /// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid pointer to the |
| 232 | 229 | /// start of the I/O memory mapped region. |
| 233 | −pub struct IoMem<const SIZE: usize = 0> { | |
| 230 | +pub struct IoMem<'a, const SIZE: usize = 0> { | |
| 231 | + dev: &'a Device<Bound>, | |
| 234 | 232 | io: MmioRaw<SIZE>, |
| 235 | 233 | } |
| 236 | 234 | |
| 237 | −impl<const SIZE: usize> IoMem<SIZE> { | |
| 238 | − fn ioremap(resource: &Resource) -> Result<Self> { | |
| 235 | +impl<'a, const SIZE: usize> IoMem<'a, SIZE> { | |
| 236 | + fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> { | |
| 239 | 237 | // Note: Some ioremap() implementations use types that depend on the CPU |
| 240 | 238 | // word width rather than the bus address width. |
| 241 | 239 | // |
| @@ -267,28 +265,33 @@ impl<const SIZE: usize> IoMem<SIZE> { · 25 unmodified lines | ||
| 267 | 265 | } |
| 268 | 266 | |
| 269 | 267 | let io = MmioRaw::new(addr as usize, size)?; |
| 270 | − let io = IoMem { io }; | |
| 271 | 268 | |
| 272 | − Ok(io) | |
| 269 | + Ok(IoMem { dev, io }) | |
| 273 | 270 | } |
| 274 | 271 | |
| 275 | − /// Creates a new `IoMem` instance from a previously acquired [`IoRequest`]. | |
| 276 | − pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a { | |
| 277 | − let dev = io_request.device; | |
| 278 | − let res = io_request.resource; | |
| 279 | − | |
| 280 | − Devres::new(dev, Self::ioremap(res)) | |
| 272 | + /// Consume the `IoMem` and register it as a device-managed resource. | |
| 273 | + /// | |
| 274 | + /// The returned `Devres<IoMem<'static, SIZE>>` can outlive the original | |
| 275 | + /// lifetime `'a`. Access to the I/O memory is revoked when the device | |
| 276 | + /// is unbound. | |
| 277 | + pub fn into_devres(self) -> Result<Devres<IoMem<'static, SIZE>>> { | |
| 278 | + // SAFETY: Casting to `'static` is sound because `Devres` guarantees the `IoMem` does not | |
| 279 | + // actually outlive the device -- access is revoked and the resource is released when the | |
| 280 | + // device is unbound. | |
| 281 | + let iomem: IoMem<'static, SIZE> = unsafe { core::mem::transmute(self) }; | |
| 282 | + let dev = iomem.dev; | |
| 283 | + Devres::new(dev, iomem) | |
| 281 | 284 | } |
| 282 | 285 | } |
| 283 | 286 | |
| 284 | −impl<const SIZE: usize> Drop for IoMem<SIZE> { | |
| 287 | +impl<const SIZE: usize> Drop for IoMem<'_, SIZE> { | |
| 285 | 288 | fn drop(&mut self) { |
| 286 | 289 | // SAFETY: Safe as by the invariant of `Io`. |
| 287 | 290 | unsafe { bindings::iounmap(self.io.addr() as *mut c_void) } |
| 288 | 291 | } |
| 289 | 292 | } |
| 290 | 293 | |
| 291 | −impl<const SIZE: usize> Deref for IoMem<SIZE> { | |
| 294 | +impl<const SIZE: usize> Deref for IoMem<'_, SIZE> { | |
| 292 | 295 | type Target = Mmio<SIZE>; |
| 293 | 296 | |
| 294 | 297 | fn deref(&self) -> &Self::Target { |
| @@ -59,18 +59,18 @@ pub struct Adapter<T: Driver>(T); · 58 unmodified lines | ||
| 59 | 59 | |
| 60 | 60 | // SAFETY: |
| 61 | 61 | // - `bindings::pci_driver` is a C type declared as `repr(C)`. |
| 62 | −// - `T` is the type of the driver's device private data. | |
| 62 | +// - `T::Data` is the type of the driver's device private data. | |
| 63 | 63 | // - `struct pci_driver` embeds a `struct device_driver`. |
| 64 | 64 | // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. |
| 65 | −unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> { | |
| 65 | +unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> { | |
| 66 | 66 | type DriverType = bindings::pci_driver; |
| 67 | − type DriverData = T; | |
| 67 | + type DriverData<'bound> = T::Data<'bound>; | |
| 68 | 68 | const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | 71 | // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if |
| 72 | 72 | // a preceding call to `register` has been successful. |
| 73 | −unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { | |
| 73 | +unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> { | |
| 74 | 74 | unsafe fn register( |
| 75 | 75 | pdrv: &Opaque<Self::DriverType>, |
| 76 | 76 | name: &'static CStr, |
| @@ -96,7 +96,7 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { · 19 unmodified lines | ||
| 96 | 96 | } |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | −impl<T: Driver + 'static> Adapter<T> { | |
| 99 | +impl<T: Driver> Adapter<T> { | |
| 100 | 100 | extern "C" fn probe_callback( |
| 101 | 101 | pdev: *mut bindings::pci_dev, |
| 102 | 102 | id: *const bindings::pci_device_id, |
| @@ -105,7 +105,7 @@ impl<T: Driver + 'static> Adapter<T> { · 2 unmodified lines | ||
| 105 | 105 | // `struct pci_dev`. |
| 106 | 106 | // |
| 107 | 107 | // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. |
| 108 | − let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; | |
| 108 | + let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() }; | |
| 109 | 109 | |
| 110 | 110 | // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct pci_device_id` and |
| 111 | 111 | // does not add additional invariants, so it's safe to transmute. |
| @@ -125,12 +125,12 @@ impl<T: Driver + 'static> Adapter<T> { · 13 unmodified lines | ||
| 125 | 125 | // `struct pci_dev`. |
| 126 | 126 | // |
| 127 | 127 | // INVARIANT: `pdev` is valid for the duration of `remove_callback()`. |
| 128 | − let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; | |
| 128 | + let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() }; | |
| 129 | 129 | |
| 130 | 130 | // SAFETY: `remove_callback` is only ever called after a successful call to |
| 131 | 131 | // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called |
| 132 | − // and stored a `Pin<KBox<T>>`. | |
| 133 | − let data = unsafe { pdev.as_ref().drvdata_borrow::<T>() }; | |
| 132 | + // and stored a `Pin<KBox<T::Data<'_>>>`. | |
| 133 | + let data = unsafe { pdev.as_ref().drvdata_borrow::<T::Data<'_>>() }; | |
| 134 | 134 | |
| 135 | 135 | T::unbind(pdev, data); |
| 136 | 136 | } |
| @@ -279,19 +279,20 @@ macro_rules! pci_device_table { · 142 unmodified lines | ||
| 279 | 279 | /// |
| 280 | 280 | /// impl pci::Driver for MyDriver { |
| 281 | 281 | /// type IdInfo = (); |
| 282 | +/// type Data<'bound> = Self; | |
| 282 | 283 | /// const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; |
| 283 | 284 | /// |
| 284 | −/// fn probe( | |
| 285 | −/// _pdev: &pci::Device<Core>, | |
| 286 | −/// _id_info: &Self::IdInfo, | |
| 287 | −/// ) -> impl PinInit<Self, Error> { | |
| 285 | +/// fn probe<'bound>( | |
| 286 | +/// _pdev: &'bound pci::Device<Core<'_>>, | |
| 287 | +/// _id_info: &'bound Self::IdInfo, | |
| 288 | +/// ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { | |
| 288 | 289 | /// Err(ENODEV) |
| 289 | 290 | /// } |
| 290 | 291 | /// } |
| 291 | 292 | ///``` |
| 292 | 293 | /// Drivers must implement this trait in order to get a PCI driver registered. Please refer to the |
| 293 | 294 | /// `Adapter` documentation for an example. |
| 294 | −pub trait Driver: Send { | |
| 295 | +pub trait Driver { | |
| 295 | 296 | /// The type holding information about each device id supported by the driver. |
| 296 | 297 | // TODO: Use `associated_type_defaults` once stabilized: |
| 297 | 298 | // |
| @@ -300,6 +301,9 @@ pub trait Driver: Send { · 2 unmodified lines | ||
| 300 | 301 | // ``` |
| 301 | 302 | type IdInfo: 'static; |
| 302 | 303 | |
| 304 | + /// The type of the driver's bus device private data. | |
| 305 | + type Data<'bound>: Send + 'bound; | |
| 306 | + | |
| 303 | 307 | /// The table of device ids supported by the driver. |
| 304 | 308 | const ID_TABLE: IdTable<Self::IdInfo>; |
| 305 | 309 | |
| @@ -307,7 +311,10 @@ pub trait Driver: Send { · 1 unmodified line | ||
| 307 | 311 | /// |
| 308 | 312 | /// Called when a new pci device is added or discovered. Implementers should |
| 309 | 313 | /// attempt to initialize the device here. |
| 310 | − fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>; | |
| 314 | + fn probe<'bound>( | |
| 315 | + dev: &'bound Device<device::Core<'_>>, | |
| 316 | + id_info: &'bound Self::IdInfo, | |
| 317 | + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; | |
| 311 | 318 | |
| 312 | 319 | /// PCI driver unbind. |
| 313 | 320 | /// |
| @@ -318,8 +325,8 @@ pub trait Driver: Send { · 4 unmodified lines | ||
| 318 | 325 | /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O |
| 319 | 326 | /// operations to gracefully tear down the device. |
| 320 | 327 | /// |
| 321 | − /// Otherwise, release operations for driver resources should be performed in `Self::drop`. | |
| 322 | − fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { | |
| 328 | + /// Otherwise, release operations for driver resources should be performed in `Drop`. | |
| 329 | + fn unbind<'bound>(dev: &'bound Device<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) { | |
| 323 | 330 | let _ = (dev, this); |
| 324 | 331 | } |
| 325 | 332 | } |
| @@ -354,7 +361,7 @@ impl Device { · 28 unmodified lines | ||
| 354 | 361 | /// |
| 355 | 362 | /// ``` |
| 356 | 363 | /// # use kernel::{device::Core, pci::{self, Vendor}, prelude::*}; |
| 357 | − /// fn log_device_info(pdev: &pci::Device<Core>) -> Result { | |
| 364 | + /// fn log_device_info(pdev: &pci::Device<Core<'_>>) -> Result { | |
| 358 | 365 | /// // Get an instance of `Vendor`. |
| 359 | 366 | /// let vendor = pdev.vendor_id(); |
| 360 | 367 | /// dev_info!( |
| @@ -445,7 +452,7 @@ impl Device { · 84 unmodified lines | ||
| 445 | 452 | } |
| 446 | 453 | } |
| 447 | 454 | |
| 448 | −impl Device<device::Core> { | |
| 455 | +impl<'a> Device<device::Core<'a>> { | |
| 449 | 456 | /// Enable memory resources for this device. |
| 450 | 457 | pub fn enable_device_mem(&self) -> Result { |
| 451 | 458 | // 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> · 19 unmodified lines | ||
| 471 | 478 | kernel::impl_device_context_deref!(unsafe { Device }); |
| 472 | 479 | kernel::impl_device_context_into_aref!(Device); |
| 473 | 480 | |
| 474 | −impl crate::dma::Device for Device<device::Core> {} | |
| 481 | +impl<'a> crate::dma::Device<'a> for Device<device::Core<'a>> {} | |
| 475 | 482 | |
| 476 | 483 | // SAFETY: Instances of `Device` are always reference-counted. |
| 477 | 484 | unsafe impl crate::sync::aref::AlwaysRefCounted for Device { |
| @@ -523,3 +530,7 @@ unsafe impl Send for Device {} · 45 unmodified lines | ||
| 523 | 530 | // SAFETY: `Device` can be shared among threads because all methods of `Device` |
| 524 | 531 | // (i.e. `Device<Normal>) are thread safe. |
| 525 | 532 | unsafe impl Sync for Device {} |
| 533 | + | |
| 534 | +// SAFETY: Same as `Device<Normal>` -- the underlying `struct pci_dev` is the same; | |
| 535 | +// `Bound` is a zero-sized type-state marker that does not affect thread safety. | |
| 536 | +unsafe impl Sync for Device<device::Bound> {} | |
| @@ -19,7 +19,7 @@ use crate::{ · 18 unmodified lines | ||
| 19 | 19 | /// |
| 20 | 20 | /// ``` |
| 21 | 21 | /// # use kernel::{device::Core, pci::{self, Class}, prelude::*}; |
| 22 | −/// fn probe_device(pdev: &pci::Device<Core>) -> Result { | |
| 22 | +/// fn probe_device(pdev: &pci::Device<Core<'_>>) -> Result { | |
| 23 | 23 | /// let pci_class = pdev.pci_class(); |
| 24 | 24 | /// dev_info!( |
| 25 | 25 | /// pdev, |
| @@ -14,8 +14,7 @@ use crate::{ · 13 unmodified lines | ||
| 14 | 14 | Mmio, |
| 15 | 15 | MmioRaw, // |
| 16 | 16 | }, |
| 17 | − prelude::*, | |
| 18 | − sync::aref::ARef, // | |
| 17 | + prelude::*, // | |
| 19 | 18 | }; |
| 20 | 19 | use core::{ |
| 21 | 20 | marker::PhantomData, |
| @@ -146,14 +145,18 @@ impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'a, S> { · 124 unmodified lines | ||
| 146 | 145 | /// |
| 147 | 146 | /// `Bar` always holds an `IoRaw` instance that holds a valid pointer to the start of the I/O |
| 148 | 147 | /// memory mapped PCI BAR and its size. |
| 149 | −pub struct Bar<const SIZE: usize = 0> { | |
| 150 | − pdev: ARef<Device>, | |
| 148 | +pub struct Bar<'a, const SIZE: usize = 0> { | |
| 149 | + pdev: &'a Device<device::Bound>, | |
| 151 | 150 | io: MmioRaw<SIZE>, |
| 152 | 151 | num: i32, |
| 153 | 152 | } |
| 154 | 153 | |
| 155 | −impl<const SIZE: usize> Bar<SIZE> { | |
| 156 | − pub(super) fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> { | |
| 154 | +impl<'a, const SIZE: usize> Bar<'a, SIZE> { | |
| 155 | + pub(super) fn new( | |
| 156 | + pdev: &'a Device<device::Bound>, | |
| 157 | + num: u32, | |
| 158 | + name: &'static CStr, | |
| 159 | + ) -> Result<Self> { | |
| 157 | 160 | let len = pdev.resource_len(num)?; |
| 158 | 161 | if len == 0 { |
| 159 | 162 | return Err(ENOMEM); |
| @@ -196,11 +199,7 @@ impl<const SIZE: usize> Bar<SIZE> { · 36 unmodified lines | ||
| 196 | 199 | } |
| 197 | 200 | }; |
| 198 | 201 | |
| 199 | − Ok(Bar { | |
| 200 | − pdev: pdev.into(), | |
| 201 | − io, | |
| 202 | − num, | |
| 203 | − }) | |
| 202 | + Ok(Bar { pdev, io, num }) | |
| 204 | 203 | } |
| 205 | 204 | |
| 206 | 205 | /// # Safety |
| @@ -219,11 +218,24 @@ impl<const SIZE: usize> Bar<SIZE> { · 12 unmodified lines | ||
| 219 | 218 | |
| 220 | 219 | fn release(&self) { |
| 221 | 220 | // SAFETY: The safety requirements are guaranteed by the type invariant of `self.pdev`. |
| 222 | − unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) }; | |
| 221 | + unsafe { Self::do_release(self.pdev, self.io.addr(), self.num) }; | |
| 222 | + } | |
| 223 | + | |
| 224 | + /// Consume the `Bar` and register it as a device-managed resource. | |
| 225 | + /// | |
| 226 | + /// The returned `Devres<Bar<'static, SIZE>>` can outlive the original lifetime `'a`. Access | |
| 227 | + /// to the BAR is revoked when the device is unbound. | |
| 228 | + pub fn into_devres(self) -> Result<Devres<Bar<'static, SIZE>>> { | |
| 229 | + // SAFETY: Casting to `'static` is sound because `Devres` guarantees the `Bar` does not | |
| 230 | + // actually outlive the device -- access is revoked and the resource is released when the | |
| 231 | + // device is unbound. | |
| 232 | + let bar: Bar<'static, SIZE> = unsafe { core::mem::transmute(self) }; | |
| 233 | + let pdev = bar.pdev; | |
| 234 | + Devres::new(pdev.as_ref(), bar) | |
| 223 | 235 | } |
| 224 | 236 | } |
| 225 | 237 | |
| 226 | −impl Bar { | |
| 238 | +impl Bar<'_> { | |
| 227 | 239 | #[inline] |
| 228 | 240 | pub(super) fn index_is_valid(index: u32) -> bool { |
| 229 | 241 | // A `struct pci_dev` owns an array of resources with at most `PCI_NUM_RESOURCES` entries. |
| @@ -231,13 +243,13 @@ impl Bar { · 1 unmodified line | ||
| 231 | 243 | } |
| 232 | 244 | } |
| 233 | 245 | |
| 234 | −impl<const SIZE: usize> Drop for Bar<SIZE> { | |
| 246 | +impl<const SIZE: usize> Drop for Bar<'_, SIZE> { | |
| 235 | 247 | fn drop(&mut self) { |
| 236 | 248 | self.release(); |
| 237 | 249 | } |
| 238 | 250 | } |
| 239 | 251 | |
| 240 | −impl<const SIZE: usize> Deref for Bar<SIZE> { | |
| 252 | +impl<const SIZE: usize> Deref for Bar<'_, SIZE> { | |
| 241 | 253 | type Target = Mmio<SIZE>; |
| 242 | 254 | |
| 243 | 255 | fn deref(&self) -> &Self::Target { |
| @@ -252,17 +264,13 @@ impl Device<device::Bound> { · 8 unmodified lines | ||
| 252 | 264 | pub fn iomap_region_sized<'a, const SIZE: usize>( |
| 253 | 265 | &'a self, |
| 254 | 266 | bar: u32, |
| 255 | − name: &'a CStr, | |
| 256 | − ) -> impl PinInit<Devres<Bar<SIZE>>, Error> + 'a { | |
| 257 | − Devres::new(self.as_ref(), Bar::<SIZE>::new(self, bar, name)) | |
| 267 | + name: &'static CStr, | |
| 268 | + ) -> Result<Bar<'a, SIZE>> { | |
| 269 | + Bar::new(self, bar, name) | |
| 258 | 270 | } |
| 259 | 271 | |
| 260 | 272 | /// Maps an entire PCI BAR after performing a region-request on it. |
| 261 | − pub fn iomap_region<'a>( | |
| 262 | − &'a self, | |
| 263 | − bar: u32, | |
| 264 | − name: &'a CStr, | |
| 265 | − ) -> impl PinInit<Devres<Bar>, Error> + 'a { | |
| 273 | + pub fn iomap_region<'a>(&'a self, bar: u32, name: &'static CStr) -> Result<Bar<'a>> { | |
| 266 | 274 | self.iomap_region_sized::<0>(bar, name) |
| 267 | 275 | } |
| 268 | 276 | |
| @@ -45,18 +45,18 @@ pub struct Adapter<T: Driver>(T); · 44 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | // SAFETY: |
| 47 | 47 | // - `bindings::platform_driver` is a C type declared as `repr(C)`. |
| 48 | −// - `T` is the type of the driver's device private data. | |
| 48 | +// - `T::Data` is the type of the driver's device private data. | |
| 49 | 49 | // - `struct platform_driver` embeds a `struct device_driver`. |
| 50 | 50 | // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. |
| 51 | −unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> { | |
| 51 | +unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> { | |
| 52 | 52 | type DriverType = bindings::platform_driver; |
| 53 | − type DriverData = T; | |
| 53 | + type DriverData<'bound> = T::Data<'bound>; | |
| 54 | 54 | const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | 57 | // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if |
| 58 | 58 | // a preceding call to `register` has been successful. |
| 59 | −unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { | |
| 59 | +unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> { | |
| 60 | 60 | unsafe fn register( |
| 61 | 61 | pdrv: &Opaque<Self::DriverType>, |
| 62 | 62 | name: &'static CStr, |
| @@ -82,7 +82,9 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { · 19 unmodified lines | ||
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | // SAFETY: `pdrv` is guaranteed to be a valid `DriverType`. |
| 85 | − to_result(unsafe { bindings::__platform_driver_register(pdrv.get(), module.0) }) | |
| 85 | + to_result(unsafe { | |
| 86 | + bindings::__platform_driver_register(pdrv.get(), module.0, name.as_char_ptr()) | |
| 87 | + }) | |
| 86 | 88 | } |
| 87 | 89 | |
| 88 | 90 | unsafe fn unregister(pdrv: &Opaque<Self::DriverType>) { |
| @@ -91,13 +93,13 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { · 2 unmodified lines | ||
| 91 | 93 | } |
| 92 | 94 | } |
| 93 | 95 | |
| 94 | −impl<T: Driver + 'static> Adapter<T> { | |
| 96 | +impl<T: Driver> Adapter<T> { | |
| 95 | 97 | extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ffi::c_int { |
| 96 | 98 | // SAFETY: The platform bus only ever calls the probe callback with a valid pointer to a |
| 97 | 99 | // `struct platform_device`. |
| 98 | 100 | // |
| 99 | 101 | // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. |
| 100 | − let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; | |
| 102 | + let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() }; | |
| 101 | 103 | let info = <Self as driver::Adapter>::id_info(pdev.as_ref()); |
| 102 | 104 | |
| 103 | 105 | from_result(|| { |
| @@ -113,18 +115,18 @@ impl<T: Driver + 'static> Adapter<T> { · 9 unmodified lines | ||
| 113 | 115 | // `struct platform_device`. |
| 114 | 116 | // |
| 115 | 117 | // INVARIANT: `pdev` is valid for the duration of `remove_callback()`. |
| 116 | − let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; | |
| 118 | + let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() }; | |
| 117 | 119 | |
| 118 | 120 | // SAFETY: `remove_callback` is only ever called after a successful call to |
| 119 | 121 | // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called |
| 120 | − // and stored a `Pin<KBox<T>>`. | |
| 121 | − let data = unsafe { pdev.as_ref().drvdata_borrow::<T>() }; | |
| 122 | + // and stored a `Pin<KBox<T::Data<'_>>>`. | |
| 123 | + let data = unsafe { pdev.as_ref().drvdata_borrow::<T::Data<'_>>() }; | |
| 122 | 124 | |
| 123 | 125 | T::unbind(pdev, data); |
| 124 | 126 | } |
| 125 | 127 | } |
| 126 | 128 | |
| 127 | −impl<T: Driver + 'static> driver::Adapter for Adapter<T> { | |
| 129 | +impl<T: Driver> driver::Adapter for Adapter<T> { | |
| 128 | 130 | type IdInfo = T::IdInfo; |
| 129 | 131 | |
| 130 | 132 | fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> { |
| @@ -192,18 +194,19 @@ macro_rules! module_platform_driver { · 61 unmodified lines | ||
| 192 | 194 | /// |
| 193 | 195 | /// impl platform::Driver for MyDriver { |
| 194 | 196 | /// type IdInfo = (); |
| 197 | +/// type Data<'bound> = Self; | |
| 195 | 198 | /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); |
| 196 | 199 | /// const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); |
| 197 | 200 | /// |
| 198 | −/// fn probe( | |
| 199 | −/// _pdev: &platform::Device<Core>, | |
| 200 | −/// _id_info: Option<&Self::IdInfo>, | |
| 201 | −/// ) -> impl PinInit<Self, Error> { | |
| 201 | +/// fn probe<'bound>( | |
| 202 | +/// _pdev: &'bound platform::Device<Core<'_>>, | |
| 203 | +/// _id_info: Option<&'bound Self::IdInfo>, | |
| 204 | +/// ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { | |
| 202 | 205 | /// Err(ENODEV) |
| 203 | 206 | /// } |
| 204 | 207 | /// } |
| 205 | 208 | ///``` |
| 206 | −pub trait Driver: Send { | |
| 209 | +pub trait Driver { | |
| 207 | 210 | /// The type holding driver private data about each device id supported by the driver. |
| 208 | 211 | // TODO: Use associated_type_defaults once stabilized: |
| 209 | 212 | // |
| @@ -212,6 +215,9 @@ pub trait Driver: Send { · 2 unmodified lines | ||
| 212 | 215 | // ``` |
| 213 | 216 | type IdInfo: 'static; |
| 214 | 217 | |
| 218 | + /// The type of the driver's bus device private data. | |
| 219 | + type Data<'bound>: Send + 'bound; | |
| 220 | + | |
| 215 | 221 | /// The table of OF device ids supported by the driver. |
| 216 | 222 | const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; |
| 217 | 223 | |
| @@ -222,10 +228,10 @@ pub trait Driver: Send { · 4 unmodified lines | ||
| 222 | 228 | /// |
| 223 | 229 | /// Called when a new platform device is added or discovered. |
| 224 | 230 | /// Implementers should attempt to initialize the device here. |
| 225 | − fn probe( | |
| 226 | − dev: &Device<device::Core>, | |
| 227 | − id_info: Option<&Self::IdInfo>, | |
| 228 | − ) -> impl PinInit<Self, Error>; | |
| 231 | + fn probe<'bound>( | |
| 232 | + dev: &'bound Device<device::Core<'_>>, | |
| 233 | + id_info: Option<&'bound Self::IdInfo>, | |
| 234 | + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; | |
| 229 | 235 | |
| 230 | 236 | /// Platform driver unbind. |
| 231 | 237 | /// |
| @@ -236,8 +242,8 @@ pub trait Driver: Send { · 4 unmodified lines | ||
| 236 | 242 | /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O |
| 237 | 243 | /// operations to gracefully tear down the device. |
| 238 | 244 | /// |
| 239 | − /// Otherwise, release operations for driver resources should be performed in `Self::drop`. | |
| 240 | − fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { | |
| 245 | + /// Otherwise, release operations for driver resources should be performed in `Drop`. | |
| 246 | + fn unbind<'bound>(dev: &'bound Device<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) { | |
| 241 | 247 | let _ = (dev, this); |
| 242 | 248 | } |
| 243 | 249 | } |
| @@ -509,7 +515,7 @@ impl Device<Bound> { · 265 unmodified lines | ||
| 509 | 515 | kernel::impl_device_context_deref!(unsafe { Device }); |
| 510 | 516 | kernel::impl_device_context_into_aref!(Device); |
| 511 | 517 | |
| 512 | −impl crate::dma::Device for Device<device::Core> {} | |
| 518 | +impl<'a> crate::dma::Device<'a> for Device<device::Core<'a>> {} | |
| 513 | 519 | |
| 514 | 520 | // SAFETY: Instances of `Device` are always reference-counted. |
| 515 | 521 | unsafe impl crate::sync::aref::AlwaysRefCounted for Device { |
| @@ -561,3 +567,7 @@ unsafe impl Send for Device {} · 45 unmodified lines | ||
| 561 | 567 | // SAFETY: `Device` can be shared among threads because all methods of `Device` |
| 562 | 568 | // (i.e. `Device<Normal>) are thread safe. |
| 563 | 569 | unsafe impl Sync for Device {} |
| 570 | + | |
| 571 | +// SAFETY: Same as `Device<Normal>` -- the underlying `struct platform_device` is the same; | |
| 572 | +// `Bound` is a zero-sized type-state marker that does not affect thread safety. | |
| 573 | +unsafe impl Sync for Device<device::Bound> {} | |
| @@ -11,6 +11,10 @@ use core::{ · 10 unmodified lines | ||
| 11 | 11 | }; |
| 12 | 12 | use pin_init::{PinInit, Wrapper, Zeroable}; |
| 13 | 13 | |
| 14 | +#[doc(hidden)] | |
| 15 | +pub mod for_lt; | |
| 16 | +pub use for_lt::ForLt; | |
| 17 | + | |
| 14 | 18 | /// Used to transfer ownership to and from foreign (non-Rust) languages. |
| 15 | 19 | /// |
| 16 | 20 | /// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and |
| @@ -27,10 +31,14 @@ pub unsafe trait ForeignOwnable: Sized { · 10 unmodified lines | ||
| 27 | 31 | const FOREIGN_ALIGN: usize; |
| 28 | 32 | |
| 29 | 33 | /// Type used to immutably borrow a value that is currently foreign-owned. |
| 30 | − type Borrowed<'a>; | |
| 34 | + type Borrowed<'a> | |
| 35 | + where | |
| 36 | + Self: 'a; | |
| 31 | 37 | |
| 32 | 38 | /// Type used to mutably borrow a value that is currently foreign-owned. |
| 33 | − type BorrowedMut<'a>; | |
| 39 | + type BorrowedMut<'a> | |
| 40 | + where | |
| 41 | + Self: 'a; | |
| 34 | 42 | |
| 35 | 43 | /// Converts a Rust-owned object to a foreign-owned one. |
| 36 | 44 | /// |
| @@ -0,0 +1,122 @@ | ||
| 1 | +// SPDX-License-Identifier: Apache-2.0 OR MIT | |
| 2 | + | |
| 3 | +//! Provide implementation and test of the `ForLt` trait and macro. | |
| 4 | +//! | |
| 5 | +//! This module is hidden and user should just use `ForLt!` directly. | |
| 6 | + | |
| 7 | +use core::marker::PhantomData; | |
| 8 | + | |
| 9 | +/// Representation of types generic over a lifetime. | |
| 10 | +/// | |
| 11 | +/// The type must be covariant over the generic lifetime, i.e. the lifetime parameter | |
| 12 | +/// can be soundly shortened. | |
| 13 | +/// | |
| 14 | +/// The lifetime involved must be covariant. | |
| 15 | +/// | |
| 16 | +/// # Macro | |
| 17 | +/// | |
| 18 | +/// It is not recommended to implement this trait directly. `ForLt!` macro is provided to obtain a | |
| 19 | +/// type that implements this trait. | |
| 20 | +/// | |
| 21 | +/// The full syntax is | |
| 22 | +/// | |
| 23 | +/// ``` | |
| 24 | +/// # use kernel::types::ForLt; | |
| 25 | +/// # fn expect_lt<F: ForLt>() {} | |
| 26 | +/// # struct TypeThatUse<'a>(&'a ()); | |
| 27 | +/// # expect_lt::< | |
| 28 | +/// ForLt!(for<'a> TypeThatUse<'a>) | |
| 29 | +/// # >(); | |
| 30 | +/// ``` | |
| 31 | +/// | |
| 32 | +/// which gives a type so that `<ForLt!(for<'a> TypeThatUse<'a>) as ForLt>::Of<'b>` | |
| 33 | +/// is `TypeThatUse<'b>`. | |
| 34 | +/// | |
| 35 | +/// You may also use a short-hand syntax which works similar to lifetime elision. | |
| 36 | +/// The macro also accepts types that do not involve a lifetime at all. | |
| 37 | +/// | |
| 38 | +/// ``` | |
| 39 | +/// # use kernel::types::ForLt; | |
| 40 | +/// # fn expect_lt<F: ForLt>() {} | |
| 41 | +/// # struct TypeThatUse<'a>(&'a ()); | |
| 42 | +/// # expect_lt::< | |
| 43 | +/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'a>)`. | |
| 44 | +/// # >(); | |
| 45 | +/// # expect_lt::< | |
| 46 | +/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)`. | |
| 47 | +/// # >(); | |
| 48 | +/// # expect_lt::< | |
| 49 | +/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)`. | |
| 50 | +/// # >(); | |
| 51 | +/// ``` | |
| 52 | +/// | |
| 53 | +/// The macro will attempt to prove that the type is indeed covariant over the lifetime supplied. | |
| 54 | +/// When it cannot be syntactically proven, it will emit checks to ask the Rust compiler to prove | |
| 55 | +/// it. | |
| 56 | +/// | |
| 57 | +/// ```ignore,compile_fail | |
| 58 | +/// # use kernel::types::ForLt; | |
| 59 | +/// # fn expect_lt<F: ForLt>() {} | |
| 60 | +/// # expect_lt::< | |
| 61 | +/// ForLt!(fn(&u32)) // Contravariant, will fail compilation. | |
| 62 | +/// # >(); | |
| 63 | +/// ``` | |
| 64 | +/// | |
| 65 | +/// There is a limitation if the type refers to generic parameters; if the macro cannot prove the | |
| 66 | +/// covariance syntactically, the emitted checks will fail the compilation as it needs to refer to | |
| 67 | +/// the generic parameter but is in a separate item. | |
| 68 | +/// | |
| 69 | +/// ``` | |
| 70 | +/// # use kernel::types::ForLt; | |
| 71 | +/// fn expect_lt<F: ForLt>() {} | |
| 72 | +/// # #[allow(clippy::unnecessary_safety_comment, reason = "false positive")] | |
| 73 | +/// fn generic_fn<T: 'static>() { | |
| 74 | +/// // Syntactically proven by the macro | |
| 75 | +/// expect_lt::<ForLt!(&T)>(); | |
| 76 | +/// // Syntactically proven by the macro | |
| 77 | +/// expect_lt::<ForLt!(&KBox<T>)>(); | |
| 78 | +/// // Cannot be syntactically proven, need to check covariance of `KBox` | |
| 79 | +/// // expect_lt::<ForLt!(&KBox<&T>)>(); | |
| 80 | +/// } | |
| 81 | +/// ``` | |
| 82 | +/// | |
| 83 | +/// # Safety | |
| 84 | +/// | |
| 85 | +/// `Self::Of<'a>` must be covariant over the lifetime `'a`. | |
| 86 | +pub unsafe trait ForLt { | |
| 87 | + /// The type parameterized by the lifetime. | |
| 88 | + type Of<'a>: 'a; | |
| 89 | + | |
| 90 | + /// Cast a reference to a shorter lifetime. | |
| 91 | + #[inline(always)] | |
| 92 | + fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Self::Of<'short> { | |
| 93 | + // SAFETY: This is sound as this trait guarantees covariance. | |
| 94 | + unsafe { core::mem::transmute(long) } | |
| 95 | + } | |
| 96 | +} | |
| 97 | +pub use macros::ForLt; | |
| 98 | + | |
| 99 | +/// This is intended to be an "unsafe-to-refer-to" type. | |
| 100 | +/// | |
| 101 | +/// Must only be used by the `ForLt!` macro. | |
| 102 | +/// | |
| 103 | +/// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro. | |
| 104 | +/// | |
| 105 | +/// `WF` is a type that the macro can use to assert some specific type is well-formed. | |
| 106 | +/// | |
| 107 | +/// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove | |
| 108 | +/// additional properties. | |
| 109 | +#[doc(hidden)] | |
| 110 | +pub struct UnsafeForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>); | |
| 111 | + | |
| 112 | +// This is a helper trait for implementation `ForLt` to be able to use HRTB. | |
| 113 | +#[doc(hidden)] | |
| 114 | +pub trait WithLt<'a> { | |
| 115 | + type Of: 'a; | |
| 116 | +} | |
| 117 | + | |
| 118 | +// SAFETY: In `ForLt!` macro, a covariance proof is generated when naming `UnsafeForLtImpl` | |
| 119 | +// and it will fail to evaluate if the type is not covariant. | |
| 120 | +unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for UnsafeForLtImpl<T, WF, 0> { | |
| 121 | + type Of<'a> = <T as WithLt<'a>>::Of; | |
| 122 | +} | |
| @@ -36,18 +36,18 @@ pub struct Adapter<T: Driver>(T); · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | // SAFETY: |
| 38 | 38 | // - `bindings::usb_driver` is a C type declared as `repr(C)`. |
| 39 | −// - `T` is the type of the driver's device private data. | |
| 39 | +// - `T::Data` is the type of the driver's device private data. | |
| 40 | 40 | // - `struct usb_driver` embeds a `struct device_driver`. |
| 41 | 41 | // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. |
| 42 | −unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> { | |
| 42 | +unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> { | |
| 43 | 43 | type DriverType = bindings::usb_driver; |
| 44 | − type DriverData = T; | |
| 44 | + type DriverData<'bound> = T::Data<'bound>; | |
| 45 | 45 | const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | 48 | // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if |
| 49 | 49 | // a preceding call to `register` has been successful. |
| 50 | −unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { | |
| 50 | +unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> { | |
| 51 | 51 | unsafe fn register( |
| 52 | 52 | udrv: &Opaque<Self::DriverType>, |
| 53 | 53 | name: &'static CStr, |
| @@ -73,7 +73,7 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { · 19 unmodified lines | ||
| 73 | 73 | } |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | −impl<T: Driver + 'static> Adapter<T> { | |
| 76 | +impl<T: Driver> Adapter<T> { | |
| 77 | 77 | extern "C" fn probe_callback( |
| 78 | 78 | intf: *mut bindings::usb_interface, |
| 79 | 79 | id: *const bindings::usb_device_id, |
| @@ -82,7 +82,7 @@ impl<T: Driver + 'static> Adapter<T> { · 2 unmodified lines | ||
| 82 | 82 | // `struct usb_interface` and `struct usb_device_id`. |
| 83 | 83 | // |
| 84 | 84 | // INVARIANT: `intf` is valid for the duration of `probe_callback()`. |
| 85 | − let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal>>() }; | |
| 85 | + let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal<'_>>>() }; | |
| 86 | 86 | |
| 87 | 87 | from_result(|| { |
| 88 | 88 | // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct usb_device_id` and |
| @@ -92,7 +92,7 @@ impl<T: Driver + 'static> Adapter<T> { · 3 unmodified lines | ||
| 92 | 92 | let info = T::ID_TABLE.info(id.index()); |
| 93 | 93 | let data = T::probe(intf, id, info); |
| 94 | 94 | |
| 95 | − let dev: &device::Device<device::CoreInternal> = intf.as_ref(); | |
| 95 | + let dev: &device::Device<device::CoreInternal<'_>> = intf.as_ref(); | |
| 96 | 96 | dev.set_drvdata(data)?; |
| 97 | 97 | Ok(0) |
| 98 | 98 | }) |
| @@ -103,14 +103,14 @@ impl<T: Driver + 'static> Adapter<T> { · 4 unmodified lines | ||
| 103 | 103 | // `struct usb_interface`. |
| 104 | 104 | // |
| 105 | 105 | // INVARIANT: `intf` is valid for the duration of `disconnect_callback()`. |
| 106 | − let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal>>() }; | |
| 106 | + let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal<'_>>>() }; | |
| 107 | 107 | |
| 108 | − let dev: &device::Device<device::CoreInternal> = intf.as_ref(); | |
| 108 | + let dev: &device::Device<device::CoreInternal<'_>> = intf.as_ref(); | |
| 109 | 109 | |
| 110 | 110 | // SAFETY: `disconnect_callback` is only ever called after a successful call to |
| 111 | 111 | // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called |
| 112 | − // and stored a `Pin<KBox<T>>`. | |
| 113 | − let data = unsafe { dev.drvdata_borrow::<T>() }; | |
| 112 | + // and stored a `Pin<KBox<T::Data<'_>>>`. | |
| 113 | + let data = unsafe { dev.drvdata_borrow::<T::Data<'_>>() }; | |
| 114 | 114 | |
| 115 | 115 | T::disconnect(intf, data); |
| 116 | 116 | } |
| @@ -287,23 +287,31 @@ macro_rules! usb_device_table { · 170 unmodified lines | ||
| 287 | 287 | /// |
| 288 | 288 | /// impl usb::Driver for MyDriver { |
| 289 | 289 | /// type IdInfo = (); |
| 290 | +/// type Data<'bound> = Self; | |
| 290 | 291 | /// const ID_TABLE: usb::IdTable<Self::IdInfo> = &USB_TABLE; |
| 291 | 292 | /// |
| 292 | −/// fn probe( | |
| 293 | −/// _interface: &usb::Interface<Core>, | |
| 293 | +/// fn probe<'bound>( | |
| 294 | +/// _interface: &'bound usb::Interface<Core<'_>>, | |
| 294 | 295 | /// _id: &usb::DeviceId, |
| 295 | −/// _info: &Self::IdInfo, | |
| 296 | −/// ) -> impl PinInit<Self, Error> { | |
| 296 | +/// _info: &'bound Self::IdInfo, | |
| 297 | +/// ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { | |
| 297 | 298 | /// Err(ENODEV) |
| 298 | 299 | /// } |
| 299 | 300 | /// |
| 300 | −/// fn disconnect(_interface: &usb::Interface<Core>, _data: Pin<&Self>) {} | |
| 301 | +/// fn disconnect<'bound>( | |
| 302 | +/// _interface: &'bound usb::Interface<Core<'_>>, | |
| 303 | +/// _data: Pin<&Self::Data<'bound>>, | |
| 304 | +/// ) { | |
| 305 | +/// } | |
| 301 | 306 | /// } |
| 302 | 307 | ///``` |
| 303 | 308 | pub trait Driver { |
| 304 | 309 | /// The type holding information about each one of the device ids supported by the driver. |
| 305 | 310 | type IdInfo: 'static; |
| 306 | 311 | |
| 312 | + /// The type of the driver's bus device private data. | |
| 313 | + type Data<'bound>: Send + 'bound; | |
| 314 | + | |
| 307 | 315 | /// The table of device ids supported by the driver. |
| 308 | 316 | const ID_TABLE: IdTable<Self::IdInfo>; |
| 309 | 317 | |
| @@ -311,16 +319,19 @@ pub trait Driver { · 1 unmodified line | ||
| 311 | 319 | /// |
| 312 | 320 | /// Called when a new USB interface is bound to this driver. |
| 313 | 321 | /// Implementers should attempt to initialize the interface here. |
| 314 | − fn probe( | |
| 315 | − interface: &Interface<device::Core>, | |
| 322 | + fn probe<'bound>( | |
| 323 | + interface: &'bound Interface<device::Core<'_>>, | |
| 316 | 324 | id: &DeviceId, |
| 317 | − id_info: &Self::IdInfo, | |
| 318 | − ) -> impl PinInit<Self, Error>; | |
| 325 | + id_info: &'bound Self::IdInfo, | |
| 326 | + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound; | |
| 319 | 327 | |
| 320 | 328 | /// USB driver disconnect. |
| 321 | 329 | /// |
| 322 | 330 | /// Called when the USB interface is about to be unbound from this driver. |
| 323 | − fn disconnect(interface: &Interface<device::Core>, data: Pin<&Self>); | |
| 331 | + fn disconnect<'bound>( | |
| 332 | + interface: &'bound Interface<device::Core<'_>>, | |
| 333 | + data: Pin<&Self::Data<'bound>>, | |
| 334 | + ); | |
| 324 | 335 | } |
| 325 | 336 | |
| 326 | 337 | /// A USB interface. |
| @@ -464,6 +475,10 @@ unsafe impl Send for Device {} · 137 unmodified lines | ||
| 464 | 475 | // allow any mutation through a shared reference. |
| 465 | 476 | unsafe impl Sync for Device {} |
| 466 | 477 | |
| 478 | +// SAFETY: Same as `Device<Normal>` -- the underlying `struct usb_device` is the same; | |
| 479 | +// `Bound` is a zero-sized type-state marker that does not affect thread safety. | |
| 480 | +unsafe impl Sync for Device<device::Bound> {} | |
| 481 | + | |
| 467 | 482 | /// Declares a kernel module that exposes a single USB driver. |
| 468 | 483 | /// |
| 469 | 484 | /// # Examples |
| @@ -0,0 +1,248 @@ | ||
| 1 | +// SPDX-License-Identifier: Apache-2.0 OR MIT | |
| 2 | + | |
| 3 | +use proc_macro2::{ | |
| 4 | + Span, | |
| 5 | + TokenStream, // | |
| 6 | +}; | |
| 7 | +use quote::{ | |
| 8 | + format_ident, | |
| 9 | + quote, // | |
| 10 | +}; | |
| 11 | +use syn::{ | |
| 12 | + parse::{ | |
| 13 | + Parse, | |
| 14 | + ParseStream, // | |
| 15 | + }, | |
| 16 | + visit::Visit, | |
| 17 | + visit_mut::VisitMut, | |
| 18 | + Lifetime, | |
| 19 | + Result, | |
| 20 | + Token, | |
| 21 | + Type, // | |
| 22 | +}; | |
| 23 | + | |
| 24 | +pub(crate) enum HigherRankedType { | |
| 25 | + Explicit { | |
| 26 | + _for_token: Token![for], | |
| 27 | + _lt_token: Token![<], | |
| 28 | + lifetime: Lifetime, | |
| 29 | + _gt_token: Token![>], | |
| 30 | + ty: Type, | |
| 31 | + }, | |
| 32 | + Implicit { | |
| 33 | + ty: Type, | |
| 34 | + }, | |
| 35 | +} | |
| 36 | + | |
| 37 | +impl Parse for HigherRankedType { | |
| 38 | + fn parse(input: ParseStream<'_>) -> Result<Self> { | |
| 39 | + if input.peek(Token![for]) { | |
| 40 | + Ok(Self::Explicit { | |
| 41 | + _for_token: input.parse()?, | |
| 42 | + _lt_token: input.parse()?, | |
| 43 | + lifetime: input.parse()?, | |
| 44 | + _gt_token: input.parse()?, | |
| 45 | + ty: input.parse()?, | |
| 46 | + }) | |
| 47 | + } else { | |
| 48 | + Ok(Self::Implicit { ty: input.parse()? }) | |
| 49 | + } | |
| 50 | + } | |
| 51 | +} | |
| 52 | + | |
| 53 | +trait TypeExt { | |
| 54 | + fn expand_elided_lifetime(&self, explicit_lt: &Lifetime) -> Type; | |
| 55 | + fn replace_lifetime(&self, src: &Lifetime, dst: &Lifetime) -> Type; | |
| 56 | + fn has_lifetime(&self, lt: &Lifetime) -> bool; | |
| 57 | +} | |
| 58 | + | |
| 59 | +impl TypeExt for Type { | |
| 60 | + fn expand_elided_lifetime(&self, explicit_lt: &Lifetime) -> Type { | |
| 61 | + struct ElidedLifetimeExpander<'a>(&'a Lifetime); | |
| 62 | + | |
| 63 | + impl VisitMut for ElidedLifetimeExpander<'_> { | |
| 64 | + fn visit_lifetime_mut(&mut self, lifetime: &mut Lifetime) { | |
| 65 | + // Expand explicit `'_` | |
| 66 | + if lifetime.ident == "_" { | |
| 67 | + *lifetime = self.0.clone(); | |
| 68 | + } | |
| 69 | + } | |
| 70 | + | |
| 71 | + fn visit_type_reference_mut(&mut self, reference: &mut syn::TypeReference) { | |
| 72 | + syn::visit_mut::visit_type_reference_mut(self, reference); | |
| 73 | + | |
| 74 | + if reference.lifetime.is_none() { | |
| 75 | + reference.lifetime = Some(self.0.clone()); | |
| 76 | + } | |
| 77 | + } | |
| 78 | + } | |
| 79 | + | |
| 80 | + let mut ret = self.clone(); | |
| 81 | + ElidedLifetimeExpander(explicit_lt).visit_type_mut(&mut ret); | |
| 82 | + ret | |
| 83 | + } | |
| 84 | + | |
| 85 | + fn replace_lifetime(&self, src: &Lifetime, dst: &Lifetime) -> Type { | |
| 86 | + struct LifetimeReplacer<'a>(&'a Lifetime, &'a Lifetime); | |
| 87 | + | |
| 88 | + impl VisitMut for LifetimeReplacer<'_> { | |
| 89 | + fn visit_lifetime_mut(&mut self, lifetime: &mut Lifetime) { | |
| 90 | + if lifetime.ident == self.0.ident { | |
| 91 | + *lifetime = self.1.clone(); | |
| 92 | + } | |
| 93 | + } | |
| 94 | + } | |
| 95 | + | |
| 96 | + let mut ret = self.clone(); | |
| 97 | + LifetimeReplacer(src, dst).visit_type_mut(&mut ret); | |
| 98 | + ret | |
| 99 | + } | |
| 100 | + | |
| 101 | + fn has_lifetime(&self, lt: &Lifetime) -> bool { | |
| 102 | + struct HasLifetime<'a>(&'a Lifetime, bool); | |
| 103 | + | |
| 104 | + impl Visit<'_> for HasLifetime<'_> { | |
| 105 | + fn visit_lifetime(&mut self, lifetime: &Lifetime) { | |
| 106 | + if lifetime.ident == self.0.ident { | |
| 107 | + self.1 = true; | |
| 108 | + } | |
| 109 | + } | |
| 110 | + | |
| 111 | + // Macro invocations are opaque; conservatively assume they may | |
| 112 | + // reference the lifetime. | |
| 113 | + fn visit_macro(&mut self, _: &syn::Macro) { | |
| 114 | + self.1 = true; | |
| 115 | + } | |
| 116 | + } | |
| 117 | + | |
| 118 | + let mut visitor = HasLifetime(lt, false); | |
| 119 | + visitor.visit_type(self); | |
| 120 | + visitor.1 | |
| 121 | + } | |
| 122 | +} | |
| 123 | + | |
| 124 | +struct Prover<'a>(&'a Lifetime, Vec<&'a Type>); | |
| 125 | + | |
| 126 | +impl<'a> Prover<'a> { | |
| 127 | + /// Prove that `ty` is covariant over `'lt`. | |
| 128 | + /// | |
| 129 | + /// This also needs to prove that it'll be wellformed for any instance of `'lt`. | |
| 130 | + /// It can be assumed that `ty` will be wellformed if `'lt` is substituted to `'static`. | |
| 131 | + fn prove(&mut self, ty: &'a Type) { | |
| 132 | + match ty { | |
| 133 | + Type::Paren(ty) => self.prove(&ty.elem), | |
| 134 | + Type::Group(ty) => self.prove(&ty.elem), | |
| 135 | + | |
| 136 | + // No lifetime involved | |
| 137 | + Type::Never(_) => {} | |
| 138 | + | |
| 139 | + // `[T; N]` and `[T]` is covariant over `T`. | |
| 140 | + Type::Array(ty) => self.prove(&ty.elem), | |
| 141 | + Type::Slice(ty) => self.prove(&ty.elem), | |
| 142 | + | |
| 143 | + Type::Tuple(ty) => { | |
| 144 | + for elem in &ty.elems { | |
| 145 | + self.prove(elem); | |
| 146 | + } | |
| 147 | + } | |
| 148 | + | |
| 149 | + // `*const T` is covariant over `T` | |
| 150 | + Type::Ptr(ty) if ty.const_token.is_some() => self.prove(&ty.elem), | |
| 151 | + | |
| 152 | + // `&T` is covariant over `T` and lifetime. | |
| 153 | + // | |
| 154 | + // Note that if we encounter `&'other_lt T`, then we still need to make sure the type | |
| 155 | + // is wellformed if `T` involves `&'lt`, so we defer to the compiler. | |
| 156 | + // | |
| 157 | + // This is to block cases like `ForLt!(for<'a> &'static &'a u32)`, as the presence of | |
| 158 | + // the type implies `'a: 'static` but this is unsound. | |
| 159 | + Type::Reference(ty) | |
| 160 | + if ty.mutability.is_none() && ty.lifetime.as_ref() == Some(self.0) => | |
| 161 | + { | |
| 162 | + self.prove(&ty.elem) | |
| 163 | + } | |
| 164 | + | |
| 165 | + // `&[mut] T` is covariant over lifetime. | |
| 166 | + // In case we have `&[mut] NoLifetime`, we don't need to do additional checks. | |
| 167 | + Type::Reference(ty) if !ty.elem.has_lifetime(self.0) => (), | |
| 168 | + | |
| 169 | + // No mention of lifetime at all, no need to perform compiler check. | |
| 170 | + ty if !ty.has_lifetime(self.0) => (), | |
| 171 | + | |
| 172 | + // Otherwise, we need to emit checks so that compiler can determine if the types are | |
| 173 | + // actually covariant. | |
| 174 | + ty => self.1.push(ty), | |
| 175 | + } | |
| 176 | + } | |
| 177 | +} | |
| 178 | + | |
| 179 | +pub(crate) fn for_lt(input: HigherRankedType) -> TokenStream { | |
| 180 | + let (ty, lifetime) = match input { | |
| 181 | + HigherRankedType::Explicit { lifetime, ty, .. } => (ty, lifetime), | |
| 182 | + HigherRankedType::Implicit { ty } => { | |
| 183 | + // If there's no explicit `for<'a>` binder, inject a synthetic `'__elided` lifetime | |
| 184 | + // and expand elided sites. | |
| 185 | + let lifetime = Lifetime { | |
| 186 | + apostrophe: Span::mixed_site(), | |
| 187 | + ident: format_ident!("__elided", span = Span::mixed_site()), | |
| 188 | + }; | |
| 189 | + (ty.expand_elided_lifetime(&lifetime), lifetime) | |
| 190 | + } | |
| 191 | + }; | |
| 192 | + | |
| 193 | + let mut prover = Prover(&lifetime, Vec::new()); | |
| 194 | + prover.prove(&ty); | |
| 195 | + | |
| 196 | + let mut proof = Vec::new(); | |
| 197 | + | |
| 198 | + // Emit proofs for every type that requires additional compiler help in proving covariance. | |
| 199 | + for (idx, required_proof) in prover.1.into_iter().enumerate() { | |
| 200 | + // Insert a proof that the type is well-formed. | |
| 201 | + // | |
| 202 | + // This is intended to workaround a Rust compiler soundness bug related to HRTB. | |
| 203 | + // https://github.com/rust-lang/rust/issues/152489 | |
| 204 | + // | |
| 205 | + // This needs to be a struct instead of fn to avoid the implied WF bounds. | |
| 206 | + let wf_proof_name = format_ident!("ProveWf{idx}"); | |
| 207 | + proof.push(quote!( | |
| 208 | + struct #wf_proof_name<#lifetime>( | |
| 209 | + ::core::marker::PhantomData<&#lifetime ()>, #required_proof | |
| 210 | + ); | |
| 211 | + )); | |
| 212 | + | |
| 213 | + // Insert a proof that the type is covariant. | |
| 214 | + let cov_proof_name = format_ident!("prove_covariant_{idx}"); | |
| 215 | + proof.push(quote!( | |
| 216 | + fn #cov_proof_name<'__short, '__long: '__short>( | |
| 217 | + long: #wf_proof_name<'__long> | |
| 218 | + ) -> #wf_proof_name<'__short> { | |
| 219 | + long | |
| 220 | + } | |
| 221 | + )); | |
| 222 | + } | |
| 223 | + | |
| 224 | + // Make sure that the type is wellformed when substituting lifetime with `'static`. | |
| 225 | + // | |
| 226 | + // Currently the Rust compiler doesn't check this, see the above `ProveWf` documentation. | |
| 227 | + // | |
| 228 | + // We prefer to use this way of proving WF-ness as it can work when generics are involved. | |
| 229 | + let ty_static = ty.replace_lifetime( | |
| 230 | + &lifetime, | |
| 231 | + &Lifetime { | |
| 232 | + apostrophe: Span::mixed_site(), | |
| 233 | + ident: format_ident!("static"), | |
| 234 | + }, | |
| 235 | + ); | |
| 236 | + | |
| 237 | + quote!( | |
| 238 | + ::kernel::types::for_lt::UnsafeForLtImpl::< | |
| 239 | + dyn for<#lifetime> ::kernel::types::for_lt::WithLt<#lifetime, Of = #ty>, | |
| 240 | + #ty_static, | |
| 241 | + { | |
| 242 | + #(#proof)* | |
| 243 | + | |
| 244 | + 0 | |
| 245 | + } | |
| 246 | + > | |
| 247 | + ) | |
| 248 | +} | |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | mod concat_idents; |
| 18 | 18 | mod export; |
| 19 | 19 | mod fmt; |
| 20 | +mod for_lt; | |
| 20 | 21 | mod helpers; |
| 21 | 22 | mod kunit; |
| 22 | 23 | mod module; |
| @@ -489,3 +490,15 @@ pub fn kunit_tests(attr: TokenStream, input: TokenStream) -> TokenStream { · 466 unmodified lines | ||
| 489 | 490 | .unwrap_or_else(|e| e.into_compile_error()) |
| 490 | 491 | .into() |
| 491 | 492 | } |
| 493 | + | |
| 494 | +/// Obtain a type that implements [`ForLt`] for the given higher-ranked type. | |
| 495 | +/// | |
| 496 | +/// Please refer to the documentation of the [`ForLt`] trait. | |
| 497 | +/// | |
| 498 | +/// [`ForLt`]: trait.ForLt.html | |
| 499 | +#[proc_macro] | |
| 500 | +// The macro shares the name with the trait. | |
| 501 | +#[allow(non_snake_case)] | |
| 502 | +pub fn ForLt(input: TokenStream) -> TokenStream { | |
| 503 | + for_lt::for_lt(parse_macro_input!(input)).into() | |
| 504 | +} | |
| @@ -117,13 +117,14 @@ kernel::acpi_device_table!( · 116 unmodified lines | ||
| 117 | 117 | |
| 118 | 118 | impl platform::Driver for RustDebugFs { |
| 119 | 119 | type IdInfo = (); |
| 120 | + type Data<'bound> = Self; | |
| 120 | 121 | const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; |
| 121 | 122 | const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); |
| 122 | 123 | |
| 123 | − fn probe( | |
| 124 | − pdev: &platform::Device<Core>, | |
| 125 | − _info: Option<&Self::IdInfo>, | |
| 126 | − ) -> impl PinInit<Self, Error> { | |
| 124 | + fn probe<'bound>( | |
| 125 | + pdev: &'bound platform::Device<Core<'_>>, | |
| 126 | + _info: Option<&'bound Self::IdInfo>, | |
| 127 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 127 | 128 | RustDebugFs::new(pdev).pin_chain(|this| { |
| 128 | 129 | this.counter.store(91, Relaxed); |
| 129 | 130 | { |
| @@ -146,7 +147,7 @@ impl RustDebugFs { · 16 unmodified lines | ||
| 146 | 147 | dir.read_write_file(c"pair", new_mutex!(Inner { x: 3, y: 10 })) |
| 147 | 148 | } |
| 148 | 149 | |
| 149 | − fn new(pdev: &platform::Device<Core>) -> impl PinInit<Self, Error> + '_ { | |
| 150 | + fn new<'a>(pdev: &'a platform::Device<Core<'_>>) -> impl PinInit<Self, Error> + 'a { | |
| 150 | 151 | let debugfs = Dir::new(c"sample_debugfs"); |
| 151 | 152 | let dev = pdev.as_ref(); |
| 152 | 153 | |
| @@ -58,9 +58,13 @@ kernel::pci_device_table!( · 57 unmodified lines | ||
| 58 | 58 | |
| 59 | 59 | impl pci::Driver for DmaSampleDriver { |
| 60 | 60 | type IdInfo = (); |
| 61 | + type Data<'bound> = Self; | |
| 61 | 62 | const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; |
| 62 | 63 | |
| 63 | − fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { | |
| 64 | + fn probe<'bound>( | |
| 65 | + pdev: &'bound pci::Device<Core<'_>>, | |
| 66 | + _info: &'bound Self::IdInfo, | |
| 67 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 64 | 68 | pin_init::pin_init_scope(move || { |
| 65 | 69 | dev_info!(pdev, "Probe DMA test driver.\n"); |
| 66 | 70 | |
| @@ -10,15 +10,13 @@ use kernel::{ · 9 unmodified lines | ||
| 10 | 10 | Bound, |
| 11 | 11 | Core, // |
| 12 | 12 | }, |
| 13 | − devres::Devres, | |
| 14 | 13 | driver, |
| 15 | 14 | pci, |
| 16 | 15 | prelude::*, |
| 16 | + types::ForLt, | |
| 17 | 17 | InPlaceModule, // |
| 18 | 18 | }; |
| 19 | 19 | |
| 20 | −use core::any::TypeId; | |
| 21 | − | |
| 22 | 20 | const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME; |
| 23 | 21 | const AUXILIARY_NAME: &CStr = c"auxiliary"; |
| 24 | 22 | |
| @@ -33,10 +31,14 @@ kernel::auxiliary_device_table!( · 8 unmodified lines | ||
| 33 | 31 | |
| 34 | 32 | impl auxiliary::Driver for AuxiliaryDriver { |
| 35 | 33 | type IdInfo = (); |
| 34 | + type Data<'bound> = Self; | |
| 36 | 35 | |
| 37 | 36 | const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE; |
| 38 | 37 | |
| 39 | − fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { | |
| 38 | + fn probe<'bound>( | |
| 39 | + adev: &'bound auxiliary::Device<Core<'_>>, | |
| 40 | + _info: &'bound Self::IdInfo, | |
| 41 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 40 | 42 | dev_info!( |
| 41 | 43 | adev, |
| 42 | 44 | "Probing auxiliary driver for auxiliary device with id={}\n", |
| @@ -49,13 +51,17 @@ impl auxiliary::Driver for AuxiliaryDriver { · 6 unmodified lines | ||
| 49 | 51 | } |
| 50 | 52 | } |
| 51 | 53 | |
| 52 | −#[pin_data] | |
| 53 | −struct ParentDriver { | |
| 54 | − private: TypeId, | |
| 55 | − #[pin] | |
| 56 | − _reg0: Devres<auxiliary::Registration>, | |
| 57 | − #[pin] | |
| 58 | − _reg1: Devres<auxiliary::Registration>, | |
| 54 | +struct Data<'bound> { | |
| 55 | + index: u32, | |
| 56 | + parent: &'bound pci::Device<Bound>, | |
| 57 | +} | |
| 58 | + | |
| 59 | +struct ParentDriver; | |
| 60 | + | |
| 61 | +#[allow(clippy::type_complexity)] | |
| 62 | +struct ParentData<'bound> { | |
| 63 | + _reg0: auxiliary::Registration<'bound, ForLt!(Data<'_>)>, | |
| 64 | + _reg1: auxiliary::Registration<'bound, ForLt!(Data<'_>)>, | |
| 59 | 65 | } |
| 60 | 66 | |
| 61 | 67 | kernel::pci_device_table!( |
| @@ -67,26 +73,53 @@ kernel::pci_device_table!( · 5 unmodified lines | ||
| 67 | 73 | |
| 68 | 74 | impl pci::Driver for ParentDriver { |
| 69 | 75 | type IdInfo = (); |
| 76 | + type Data<'bound> = ParentData<'bound>; | |
| 70 | 77 | |
| 71 | 78 | const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; |
| 72 | 79 | |
| 73 | − fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { | |
| 74 | − try_pin_init!(Self { | |
| 75 | − private: TypeId::of::<Self>(), | |
| 76 | − _reg0 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME), | |
| 77 | − _reg1 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME), | |
| 80 | + fn probe<'bound>( | |
| 81 | + pdev: &'bound pci::Device<Core<'_>>, | |
| 82 | + _info: &'bound Self::IdInfo, | |
| 83 | + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { | |
| 84 | + Ok(ParentData { | |
| 85 | + // SAFETY: `ParentData` is the driver's private data, which is dropped when the | |
| 86 | + // device is unbound; i.e. `mem::forget()` is never called on it. | |
| 87 | + _reg0: unsafe { | |
| 88 | + auxiliary::Registration::new_with_lt( | |
| 89 | + pdev.as_ref(), | |
| 90 | + AUXILIARY_NAME, | |
| 91 | + 0, | |
| 92 | + MODULE_NAME, | |
| 93 | + Data { | |
| 94 | + index: 0, | |
| 95 | + parent: pdev, | |
| 96 | + }, | |
| 97 | + )? | |
| 98 | + }, | |
| 99 | + // SAFETY: See `_reg0` above. | |
| 100 | + _reg1: unsafe { | |
| 101 | + auxiliary::Registration::new_with_lt( | |
| 102 | + pdev.as_ref(), | |
| 103 | + AUXILIARY_NAME, | |
| 104 | + 1, | |
| 105 | + MODULE_NAME, | |
| 106 | + Data { | |
| 107 | + index: 1, | |
| 108 | + parent: pdev, | |
| 109 | + }, | |
| 110 | + )? | |
| 111 | + }, | |
| 78 | 112 | }) |
| 79 | 113 | } |
| 80 | 114 | } |
| 81 | 115 | |
| 82 | 116 | impl ParentDriver { |
| 83 | 117 | fn connect(adev: &auxiliary::Device<Bound>) -> Result { |
| 84 | − let dev = adev.parent(); | |
| 85 | − let pdev: &pci::Device<Bound> = dev.try_into()?; | |
| 86 | − let drvdata = dev.drvdata::<Self>()?; | |
| 118 | + let data = adev.registration_data::<ForLt!(Data<'_>)>()?; | |
| 119 | + let pdev = data.parent; | |
| 87 | 120 | |
| 88 | 121 | dev_info!( |
| 89 | − dev, | |
| 122 | + pdev, | |
| 90 | 123 | "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n", |
| 91 | 124 | adev.id(), |
| 92 | 125 | pdev.vendor_id(), |
| @@ -94,9 +127,9 @@ impl ParentDriver { · 1 unmodified line | ||
| 94 | 127 | ); |
| 95 | 128 | |
| 96 | 129 | dev_info!( |
| 97 | − dev, | |
| 98 | − "We have access to the private data of {:?}.\n", | |
| 99 | − drvdata.private | |
| 130 | + pdev, | |
| 131 | + "Connected to auxiliary device with index {}.\n", | |
| 132 | + data.index | |
| 100 | 133 | ); |
| 101 | 134 | |
| 102 | 135 | Ok(()) |
| @@ -35,15 +35,16 @@ kernel::of_device_table! { · 34 unmodified lines | ||
| 35 | 35 | |
| 36 | 36 | impl i2c::Driver for SampleDriver { |
| 37 | 37 | type IdInfo = u32; |
| 38 | + type Data<'bound> = Self; | |
| 38 | 39 | |
| 39 | 40 | const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); |
| 40 | 41 | const I2C_ID_TABLE: Option<i2c::IdTable<Self::IdInfo>> = Some(&I2C_TABLE); |
| 41 | 42 | const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); |
| 42 | 43 | |
| 43 | − fn probe( | |
| 44 | − idev: &i2c::I2cClient<Core>, | |
| 45 | − info: Option<&Self::IdInfo>, | |
| 46 | − ) -> impl PinInit<Self, Error> { | |
| 44 | + fn probe<'bound>( | |
| 45 | + idev: &'bound i2c::I2cClient<Core<'_>>, | |
| 46 | + info: Option<&'bound Self::IdInfo>, | |
| 47 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 47 | 48 | let dev = idev.as_ref(); |
| 48 | 49 | |
| 49 | 50 | dev_info!(dev, "Probe Rust I2C driver sample.\n"); |
| @@ -55,11 +56,11 @@ impl i2c::Driver for SampleDriver { · 5 unmodified lines | ||
| 55 | 56 | Ok(Self) |
| 56 | 57 | } |
| 57 | 58 | |
| 58 | − fn shutdown(idev: &i2c::I2cClient<Core>, _this: Pin<&Self>) { | |
| 59 | + fn shutdown<'bound>(idev: &'bound i2c::I2cClient<Core<'_>>, _this: Pin<&Self>) { | |
| 59 | 60 | dev_info!(idev.as_ref(), "Shutdown Rust I2C driver sample.\n"); |
| 60 | 61 | } |
| 61 | 62 | |
| 62 | − fn unbind(idev: &i2c::I2cClient<Core>, _this: Pin<&Self>) { | |
| 63 | + fn unbind<'bound>(idev: &'bound i2c::I2cClient<Core<'_>>, _this: Pin<&Self>) { | |
| 63 | 64 | dev_info!(idev.as_ref(), "Unbind Rust I2C driver sample.\n"); |
| 64 | 65 | } |
| 65 | 66 | } |
| @@ -9,7 +9,6 @@ use kernel::{ · 8 unmodified lines | ||
| 9 | 9 | Bound, |
| 10 | 10 | Core, // |
| 11 | 11 | }, |
| 12 | − devres::Devres, | |
| 13 | 12 | io::{ |
| 14 | 13 | register, |
| 15 | 14 | register::Array, |
| @@ -17,8 +16,7 @@ use kernel::{ · 1 unmodified line | ||
| 17 | 16 | }, |
| 18 | 17 | num::Bounded, |
| 19 | 18 | pci, |
| 20 | − prelude::*, | |
| 21 | − sync::aref::ARef, // | |
| 19 | + prelude::*, // | |
| 22 | 20 | }; |
| 23 | 21 | |
| 24 | 22 | mod regs { |
| @@ -45,7 +43,7 @@ mod regs { · 20 unmodified lines | ||
| 45 | 43 | pub(super) const END: usize = 0x10; |
| 46 | 44 | } |
| 47 | 45 | |
| 48 | −type Bar0 = pci::Bar<{ regs::END }>; | |
| 46 | +type Bar0<'bound> = pci::Bar<'bound, { regs::END }>; | |
| 49 | 47 | |
| 50 | 48 | #[derive(Copy, Clone, Debug)] |
| 51 | 49 | struct TestIndex(u8); |
| @@ -66,14 +64,14 @@ impl TestIndex { · 14 unmodified lines | ||
| 66 | 64 | const NO_EVENTFD: Self = Self(0); |
| 67 | 65 | } |
| 68 | 66 | |
| 69 | −#[pin_data(PinnedDrop)] | |
| 70 | −struct SampleDriver { | |
| 71 | − pdev: ARef<pci::Device>, | |
| 72 | − #[pin] | |
| 73 | − bar: Devres<Bar0>, | |
| 67 | +struct SampleDriverData<'bound> { | |
| 68 | + pdev: &'bound pci::Device, | |
| 69 | + bar: Bar0<'bound>, | |
| 74 | 70 | index: TestIndex, |
| 75 | 71 | } |
| 76 | 72 | |
| 73 | +struct SampleDriver; | |
| 74 | + | |
| 77 | 75 | kernel::pci_device_table!( |
| 78 | 76 | PCI_TABLE, |
| 79 | 77 | MODULE_PCI_TABLE, |
| @@ -84,8 +82,8 @@ kernel::pci_device_table!( · 4 unmodified lines | ||
| 84 | 82 | )] |
| 85 | 83 | ); |
| 86 | 84 | |
| 87 | −impl SampleDriver { | |
| 88 | − fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> { | |
| 85 | +impl SampleDriverData<'_> { | |
| 86 | + fn testdev(index: &TestIndex, bar: &Bar0<'_>) -> Result<u32> { | |
| 89 | 87 | // Select the test. |
| 90 | 88 | bar.write_reg(regs::TEST::zeroed().with_index(*index)); |
| 91 | 89 | |
| @@ -140,51 +138,49 @@ impl SampleDriver { · 48 unmodified lines | ||
| 140 | 138 | |
| 141 | 139 | impl pci::Driver for SampleDriver { |
| 142 | 140 | type IdInfo = TestIndex; |
| 141 | + type Data<'bound> = SampleDriverData<'bound>; | |
| 143 | 142 | |
| 144 | 143 | const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; |
| 145 | 144 | |
| 146 | − fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> impl PinInit<Self, Error> { | |
| 147 | − pin_init::pin_init_scope(move || { | |
| 148 | − let vendor = pdev.vendor_id(); | |
| 149 | − dev_dbg!( | |
| 150 | − pdev, | |
| 151 | − "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", | |
| 152 | − vendor, | |
| 153 | − pdev.device_id() | |
| 154 | − ); | |
| 155 | − | |
| 156 | − pdev.enable_device_mem()?; | |
| 157 | − pdev.set_master(); | |
| 158 | − | |
| 159 | − Ok(try_pin_init!(Self { | |
| 160 | − bar <- pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_driver_pci"), | |
| 161 | − index: *info, | |
| 162 | − _: { | |
| 163 | − let bar = bar.access(pdev.as_ref())?; | |
| 164 | − | |
| 165 | − dev_info!( | |
| 166 | − pdev, | |
| 167 | − "pci-testdev data-match count: {}\n", | |
| 168 | − Self::testdev(info, bar)? | |
| 169 | − ); | |
| 170 | − Self::config_space(pdev); | |
| 171 | − }, | |
| 172 | − pdev: pdev.into(), | |
| 173 | − })) | |
| 145 | + fn probe<'bound>( | |
| 146 | + pdev: &'bound pci::Device<Core<'_>>, | |
| 147 | + info: &'bound Self::IdInfo, | |
| 148 | + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { | |
| 149 | + let vendor = pdev.vendor_id(); | |
| 150 | + dev_dbg!( | |
| 151 | + pdev, | |
| 152 | + "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", | |
| 153 | + vendor, | |
| 154 | + pdev.device_id() | |
| 155 | + ); | |
| 156 | + | |
| 157 | + pdev.enable_device_mem()?; | |
| 158 | + pdev.set_master(); | |
| 159 | + | |
| 160 | + let bar = pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_driver_pci")?; | |
| 161 | + | |
| 162 | + dev_info!( | |
| 163 | + pdev, | |
| 164 | + "pci-testdev data-match count: {}\n", | |
| 165 | + SampleDriverData::testdev(info, &bar)? | |
| 166 | + ); | |
| 167 | + SampleDriverData::config_space(pdev); | |
| 168 | + | |
| 169 | + Ok(SampleDriverData { | |
| 170 | + pdev, | |
| 171 | + bar, | |
| 172 | + index: *info, | |
| 174 | 173 | }) |
| 175 | 174 | } |
| 176 | 175 | |
| 177 | − fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) { | |
| 178 | − if let Ok(bar) = this.bar.access(pdev.as_ref()) { | |
| 179 | − // Reset pci-testdev by writing a new test index. | |
| 180 | − bar.write_reg(regs::TEST::zeroed().with_index(this.index)); | |
| 181 | − } | |
| 176 | + fn unbind<'bound>(_pdev: &'bound pci::Device<Core<'_>>, this: Pin<&Self::Data<'bound>>) { | |
| 177 | + this.bar | |
| 178 | + .write_reg(regs::TEST::zeroed().with_index(this.index)); | |
| 182 | 179 | } |
| 183 | 180 | } |
| 184 | 181 | |
| 185 | −#[pinned_drop] | |
| 186 | −impl PinnedDrop for SampleDriver { | |
| 187 | − fn drop(self: Pin<&mut Self>) { | |
| 182 | +impl Drop for SampleDriverData<'_> { | |
| 183 | + fn drop(&mut self) { | |
| 188 | 184 | dev_dbg!(self.pdev, "Remove Rust PCI driver sample.\n"); |
| 189 | 185 | } |
| 190 | 186 | } |
| @@ -101,13 +101,14 @@ kernel::acpi_device_table!( · 100 unmodified lines | ||
| 101 | 101 | |
| 102 | 102 | impl platform::Driver for SampleDriver { |
| 103 | 103 | type IdInfo = Info; |
| 104 | + type Data<'bound> = Self; | |
| 104 | 105 | const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); |
| 105 | 106 | const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); |
| 106 | 107 | |
| 107 | − fn probe( | |
| 108 | − pdev: &platform::Device<Core>, | |
| 109 | − info: Option<&Self::IdInfo>, | |
| 110 | − ) -> impl PinInit<Self, Error> { | |
| 108 | + fn probe<'bound>( | |
| 109 | + pdev: &'bound platform::Device<Core<'_>>, | |
| 110 | + info: Option<&'bound Self::IdInfo>, | |
| 111 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 111 | 112 | let dev = pdev.as_ref(); |
| 112 | 113 | |
| 113 | 114 | dev_dbg!(dev, "Probe Rust Platform driver sample.\n"); |
| @@ -26,21 +26,22 @@ kernel::usb_device_table!( · 25 unmodified lines | ||
| 26 | 26 | |
| 27 | 27 | impl usb::Driver for SampleDriver { |
| 28 | 28 | type IdInfo = (); |
| 29 | + type Data<'bound> = Self; | |
| 29 | 30 | const ID_TABLE: usb::IdTable<Self::IdInfo> = &USB_TABLE; |
| 30 | 31 | |
| 31 | − fn probe( | |
| 32 | − intf: &usb::Interface<Core>, | |
| 32 | + fn probe<'bound>( | |
| 33 | + intf: &'bound usb::Interface<Core<'_>>, | |
| 33 | 34 | _id: &usb::DeviceId, |
| 34 | − _info: &Self::IdInfo, | |
| 35 | − ) -> impl PinInit<Self, Error> { | |
| 36 | − let dev: &device::Device<Core> = intf.as_ref(); | |
| 35 | + _info: &'bound Self::IdInfo, | |
| 36 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 37 | + let dev: &device::Device<Core<'_>> = intf.as_ref(); | |
| 37 | 38 | dev_info!(dev, "Rust USB driver sample probed\n"); |
| 38 | 39 | |
| 39 | 40 | Ok(Self { _intf: intf.into() }) |
| 40 | 41 | } |
| 41 | 42 | |
| 42 | − fn disconnect(intf: &usb::Interface<Core>, _data: Pin<&Self>) { | |
| 43 | − let dev: &device::Device<Core> = intf.as_ref(); | |
| 43 | + fn disconnect<'bound>(intf: &'bound usb::Interface<Core<'_>>, _data: Pin<&Self>) { | |
| 44 | + let dev: &device::Device<Core<'_>> = intf.as_ref(); | |
| 44 | 45 | dev_info!(dev, "Rust USB driver sample disconnected\n"); |
| 45 | 46 | } |
| 46 | 47 | } |
| @@ -106,13 +106,14 @@ const BOARD_INFO: i2c::I2cBoardInfo = · 105 unmodified lines | ||
| 106 | 106 | |
| 107 | 107 | impl platform::Driver for SampleDriver { |
| 108 | 108 | type IdInfo = (); |
| 109 | + type Data<'bound> = Self; | |
| 109 | 110 | const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); |
| 110 | 111 | const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); |
| 111 | 112 | |
| 112 | − fn probe( | |
| 113 | − pdev: &platform::Device<device::Core>, | |
| 114 | − _info: Option<&Self::IdInfo>, | |
| 115 | − ) -> impl PinInit<Self, Error> { | |
| 113 | + fn probe<'bound>( | |
| 114 | + pdev: &'bound platform::Device<device::Core<'_>>, | |
| 115 | + _info: Option<&'bound Self::IdInfo>, | |
| 116 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 116 | 117 | dev_info!( |
| 117 | 118 | pdev.as_ref(), |
| 118 | 119 | "Probe Rust I2C Client registration sample.\n" |
| @@ -129,7 +130,10 @@ impl platform::Driver for SampleDriver { · 10 unmodified lines | ||
| 129 | 130 | }) |
| 130 | 131 | } |
| 131 | 132 | |
| 132 | − fn unbind(pdev: &platform::Device<device::Core>, _this: Pin<&Self>) { | |
| 133 | + fn unbind<'bound>( | |
| 134 | + pdev: &'bound platform::Device<device::Core<'_>>, | |
| 135 | + _this: Pin<&Self::Data<'bound>>, | |
| 136 | + ) { | |
| 133 | 137 | dev_info!( |
| 134 | 138 | pdev.as_ref(), |
| 135 | 139 | "Unbind Rust I2C Client registration sample.\n" |
| @@ -37,13 +37,14 @@ kernel::acpi_device_table!( · 36 unmodified lines | ||
| 37 | 37 | |
| 38 | 38 | impl platform::Driver for SampleSocDriver { |
| 39 | 39 | type IdInfo = (); |
| 40 | + type Data<'bound> = Self; | |
| 40 | 41 | const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); |
| 41 | 42 | const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); |
| 42 | 43 | |
| 43 | − fn probe( | |
| 44 | − pdev: &platform::Device<Core>, | |
| 45 | − _info: Option<&Self::IdInfo>, | |
| 46 | − ) -> impl PinInit<Self, Error> { | |
| 44 | + fn probe<'bound>( | |
| 45 | + pdev: &'bound platform::Device<Core<'_>>, | |
| 46 | + _info: Option<&'bound Self::IdInfo>, | |
| 47 | + ) -> impl PinInit<Self, Error> + 'bound { | |
| 47 | 48 | dev_dbg!(pdev, "Probe Rust SoC driver sample.\n"); |
| 48 | 49 | |
| 49 | 50 | let pdev = pdev.into(); |