diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-19 10:42:18 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-19 10:42:18 -0700 |
| commit | 59e6295fac26b8e85c1ea859cdd89fa1e47519d7 (patch) | |
| tree | 7c071f8bab440eddbb569e84e9f31c80f8a4e529 /drivers | |
| parent | c6cf4441a3a05bb7273ed022f3e56c4fc591da08 (diff) | |
| parent | 3b5ea0f078e1b72276e99c237f3dfc2fd72938bb (diff) | |
| download | linux-stable-59e6295fac26b8e85c1ea859cdd89fa1e47519d7.tar.gz linux-stable-59e6295fac26b8e85c1ea859cdd89fa1e47519d7.zip | |
Merge tag 'driver-core-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core
Pull driver core updates from Danilo Krummrich:
"container_of:
- Apply typeof_member(), remove the local __mptr variable to
eliminate variable shadowing warnings on nested container_of()
calls, and remove unnecessary parentheses
core:
- Add driver name to probe debug print for initcall_debug
- Avoid repeatedly printing the same 'Fixed dependency cycle' log
- Unwind device_add() on attribute creation failure in
attribute_container_add_class_device()
- Remove statistics group if encryption group creation fails in
transport_add_class_device()
debugfs:
- Fix lockdown check for mmap_prepare()
- Warn if file creation failed due to uninitialized debugfs
device property:
- Implement fw_devlink support for software nodes by adding
software_node_add_links(), which creates fwnode links from
DEV_PROP_REF properties to enable automatic probe ordering. Add
kunit-managed fwnode helpers and test coverage
- Fix infinite loop in fwnode_for_each_child_node() when the
secondary fwnode has more than one child. Add test cases
- Fix out-of-bounds access in software_node_get_reference_args() when
called with index -1 (UINT_MAX)
- Refactor to use RAII approach with __free()
- Add Bartosz Golaszewski as software node reviewer
firmware loader:
- Fix race where a sysfs fallback request can complete before being
queued as pending, leading to a use-after-free on the next fallback
request
- Reject 0-size built-in firmware and fail the build on empty
firmware files in CONFIG_EXTRA_FIRMWARE
kobject:
- Provide __KOBJ_ATTR() and __KOBJ_ATTR_RO/WO() initialization macros
and allow the constification of kobject attributes, enabling them
to reside in read-only memory
platform:
- Provide platform_device_set_of_node(), platform_device_set_fwnode(),
and platform_device_set_of_node_from_dev() helpers that encapsulate
firmware node reference counting for dynamically allocated platform
devices
Convert all in-tree users that manually assigned dev.of_node or
dev.fwnode, fixing a pre-existing refcount bug in powermac. Switch
to counting references of all firmware node types, not only OF
nodes
- Unify the release path for dynamically allocated platform devices
by removing platform_device_release_full(). Amend the fwnode setter
API contract to warn if a primary software node is overwritten. Add
KUnit tests for correct software node removal on device
unregistration
Rust:
- Auxiliary:
- Add registration_data_with() closure-based API for invariant
ForLt types
- Debugfs:
- Migrate BinaryWriter and BinaryReaderMut trait requirements
from kernel::transmute traits to zerocopy traits
- Device:
- Add BoundInternal device context and InternalBoundContext trait
for bus abstractions that need internal access to a bound
device.
- Make the lifetime on Core and CoreInternal invariant to prevent
coercion to shorter lifetimes
- Devres:
- Fix race between concurrent revokers where the losing revoker
could return before the winning revoker finished dropping the
inner data, causing use-after-free.
- Ensure revocation is complete before the device finishes
unbinding by making the synchronization bidirectional.
- Add DevresLt<F: ForLt>, a wrapper around Devres that shortens
'static back to the caller's borrow scope. Implement ForLt and
CovariantForLt for Bar, IoMem, and ExclusiveIoMem
- Driver:
- Switch from index-based to pointer-based device ID info lookup,
storing static references in driver_data. Centralize device ID
handling in device_id.rs, removing the open-coded ACPI/OF
matching logic and duplicate ID table from driver.rs
- I/O:
- Make I/O regions typed (with a dynamically-sized Region type
for the existing untyped case), create view types representing
subregions of a mapped I/O region, and add io_project!() for
safely creating subviews.
- Split Io into a base trait (IoBase) and an extension trait (Io)
with a blanket implementation, preventing implementers from
overriding provided methods that unsafe code relies on.
- Add a SysMem backend for shared system memory with volatile
access, and make Coherent implement Io via an I/O view type.
Add IoSysMap as sum type of Mmio and SysMem. Add copying
methods (memcpy_{from,to}io()) and read_val()/write_val() for
typed access.
- Replace dma_read!()/dma_write!() with io_read!()/io_write!()
for primitives and copying methods for aggregates; drop the old
macros. Convert nova-core to use I/O projection.
- Fix internal shortcut rule dispatch in the register!() macro,
remove unused rule arguments, and use path fragments for alias
destinations
- IRQ:
- Make irq::Registration compatible with lifetime-bound drivers
by removing the 'static bound on Handler/ThreadedHandler and
replacing Devres<RegistrationInner> with direct
request_irq()/free_irq() calls. Handlers can now directly own
lifetime-bound device resources
- PCI:
- Convert IrqVectorRegistration to a lifetime-annotated owning
type, giving drivers explicit control over the allocation
lifetime. IrqVector embeds a resolved IrqRequest, making the
conversion infallible. Remove the redundant
request_irq()/request_threaded_irq() wrappers from pci::Device.
- Add pci_irq_type() C helper and expose it via irq_type() on
IrqVectorRegistration and IrqVector, returning PCI_IRQ_MSIX,
PCI_IRQ_MSI, or PCI_IRQ_INTX.
- Mark pci::Device refcount methods inline
- Serdev:
- Add Rust abstractions for the serial device bus, including
serdev::Driver trait, serdev::Device wrapping struct
serdev_device, and serdev::Adapter implementing
RegistrationOps. Includes a sample driver. Markus Probst takes
over as serdev maintainer for both C and Rust code
- Misc:
- Split ForLt into a base trait (providing the Of<'a> GAT) and an
unsafe CovariantForLt subtrait guaranteeing covariance,
enabling invariant types (e.g. those containing Mutex<&'bound T>)
to participate in the ForLt abstraction.
- Fix Coherent read past EOF returning -ERANGE instead of zero.
- Fix firmware example UB by avoiding null-pointer ARef
misc:
- Avoid iattr allocation in kernfs listxattr by using
kernfs_iattrs_noalloc().
- Unregister SoC bus on early device registration failure.
- Remove unused DMA_FENCE_TRACE Kconfig symbol.
- Fix /sys/module path in comment.
- Refactor ISA bus init to remove nested blocks.
- Remove redundant nodemask clears in numa_init().
- Add kernel-doc for fwnode_operations and sys_soc.h, mark
internal property data as private for kernel-doc, and add
property.h/fwnode.h to driver-api infrastructure docs.
- Add MAINTAINERS entry for sys_soc.h"
* tag 'driver-core-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: (129 commits)
rust: pci: expose the allocated interrupt type
PCI: Add pci_irq_type() to query the allocated interrupt type
rust: pci: remove request_irq() and request_threaded_irq() from Device
rust: pci: resolve IRQ in index() and embed IrqRequest in IrqVector
rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type
kernfs: avoid iattr allocation in listxattr
rust: serdev: use ThisModule::as_ptr() instead of field access
ACPI/IORT: use platform_device_set_fwnode()
ACPI/APMT: use platform_device_set_fwnode()
firmware_loader: do not queue completed sysfs fallback requests
rust: pci: Mark Device refcount methods inline
rust: irq: make Registration compatible with lifetime-bound drivers
rust: net/phy: remove expansion from doc
rust: dma: return zero for Coherent reads past EOF
rust: io: register: use path fragment for alias destination
rust: io: register: remove unused rule arguments
rust: io: register: dispatch shortcut rules internally
MAINTAINERS: add sys_soc.h to DRIVER CORE
rust: debugfs: remove unsafe blocks from traits impl for Vec
rust: debugfs: migrate debugfs traits requirements to zerocopy
...
Diffstat (limited to 'drivers')
46 files changed, 645 insertions, 270 deletions
diff --git a/drivers/acpi/arm64/apmt.c b/drivers/acpi/arm64/apmt.c index 91fcdd289..8ad049f81 100644 --- a/drivers/acpi/arm64/apmt.c +++ b/drivers/acpi/arm64/apmt.c @@ -101,7 +101,7 @@ static int __init apmt_add_platform_device(struct acpi_apmt_node *node, if (ret) goto dev_put; - pdev->dev.fwnode = fwnode; + platform_device_set_fwnode(pdev, fwnode); ret = platform_device_add(pdev); diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 34412cd69..1020ac953 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -1992,7 +1992,7 @@ static int __init iort_add_platform_device(struct acpi_iort_node *node, goto dev_put; } - pdev->dev.fwnode = fwnode; + platform_device_set_fwnode(pdev, fwnode); if (ops->dev_dma_configure) ops->dev_dma_configure(&pdev->dev, node); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index c1876f145..beb51151a 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -871,9 +871,9 @@ const struct acpi_device *acpi_companion_match(const struct device *dev) * identifiers and a _DSD object with the "compatible" property, use that * property to match against the given list of identifiers. */ -bool acpi_of_match_device(const struct acpi_device *adev, - const struct of_device_id *of_match_table, - const struct of_device_id **of_id) +static bool acpi_of_match_device(const struct acpi_device *adev, + const struct of_device_id *of_match_table, + const struct of_device_id **of_id) { const union acpi_object *of_compatible, *obj; int i, nval; diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index f7d385cbd..43f20ca95 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -222,15 +222,6 @@ config DMA_SHARED_BUFFER APIs extension; the file's descriptor can then be passed on to other driver. -config DMA_FENCE_TRACE - bool "Enable verbose DMA_FENCE_TRACE messages" - depends on DMA_SHARED_BUFFER - help - Enable the DMA_FENCE_TRACE printks. This will add extra - spam to the console log, but will make it easier to diagnose - lockup related problems for dma-buffers shared across multiple - devices. - config GENERIC_ARCH_TOPOLOGY bool help diff --git a/drivers/base/arch_numa.c b/drivers/base/arch_numa.c index d4e426aa5..6476227b7 100644 --- a/drivers/base/arch_numa.c +++ b/drivers/base/arch_numa.c @@ -228,10 +228,6 @@ static int __init numa_init(int (*init_func)(void)) { int ret; - nodes_clear(numa_nodes_parsed); - nodes_clear(node_possible_map); - nodes_clear(node_online_map); - ret = numa_memblks_init(init_func, /* memblock_force_top_down */ false); if (ret < 0) goto out_free_distance; diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 4ad26b8dd..3c4563742 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -425,7 +425,12 @@ attribute_container_add_class_device(struct device *classdev) if (error) return error; - return attribute_container_add_attrs(classdev); + + error = attribute_container_add_attrs(classdev); + if (error) + device_del(classdev); + + return error; } /** diff --git a/drivers/base/core.c b/drivers/base/core.c index 4d0266829..4c0c37399 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -127,7 +127,13 @@ static void __fwnode_link_cycle(struct fwnode_link *link) { pr_debug("%pfwf: cycle: depends on %pfwf\n", link->consumer, link->supplier); + + if (link->flags & FWLINK_FLAG_CYCLE) + return; + link->flags |= FWLINK_FLAG_CYCLE; + pr_info("%pfwf: Fixed dependency cycle(s) with %pfwf\n", + link->consumer, link->supplier); } /** @@ -2206,8 +2212,6 @@ static int fw_devlink_create_devlink(struct device *con, if (__fw_devlink_relax_cycles(link->consumer, sup_handle)) { __fwnode_link_cycle(link); pr_debug("----- cycle: end -----\n"); - pr_info("%pfwf: Fixed dependency cycle(s) with %pfwf\n", - link->consumer, sup_handle); } device_links_write_unlock(); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 60c005223..f6525a7ee 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -790,8 +790,8 @@ static int really_probe_debug(struct device *dev, const struct device_driver *dr * CONFIG_DYNAMIC_DEBUG and we want a simple 'initcall_debug' on the * kernel commandline to print this all the time at the debug level. */ - printk(KERN_DEBUG "probe of %s returned %d after %lld usecs\n", - dev_name(dev), ret, ktime_us_delta(rettime, calltime)); + printk(KERN_DEBUG "probe of %s with driver %s returned %d after %lld usecs\n", + dev_name(dev), drv->name, ret, ktime_us_delta(rettime, calltime)); return ret; } diff --git a/drivers/base/firmware_loader/builtin/Makefile b/drivers/base/firmware_loader/builtin/Makefile index 6c067dedc..c0264b15d 100644 --- a/drivers/base/firmware_loader/builtin/Makefile +++ b/drivers/base/firmware_loader/builtin/Makefile @@ -16,20 +16,24 @@ ASM_ALIGN = $(if $(CONFIG_64BIT),3,2) PROGBITS = $(if $(CONFIG_ARM),%,@)progbits filechk_fwbin = \ - echo "/* Generated by $(src)/Makefile */" ;\ - echo " .section .rodata" ;\ - echo " .p2align 4" ;\ - echo "_fw_$(FWSTR)_bin:" ;\ - echo " .incbin \"$(fwdir)/$(FWNAME)\"" ;\ - echo "_fw_end:" ;\ - echo " .section .rodata.str,\"aMS\",$(PROGBITS),1" ;\ - echo " .p2align $(ASM_ALIGN)" ;\ - echo "_fw_$(FWSTR)_name:" ;\ - echo " .string \"$(FWNAME)\"" ;\ - echo " .section .builtin_fw,\"a\",$(PROGBITS)" ;\ - echo " .p2align $(ASM_ALIGN)" ;\ - echo " $(ASM_WORD) _fw_$(FWSTR)_name" ;\ - echo " $(ASM_WORD) _fw_$(FWSTR)_bin" ;\ + if [ ! -s "$(fwdir)/$(FWNAME)" ]; then \ + echo "error: empty firmware: $(fwdir)/$(FWNAME)" >&2 ;\ + exit 1 ;\ + fi ;\ + echo "/* Generated by $(src)/Makefile */" ;\ + echo " .section .rodata" ;\ + echo " .p2align 4" ;\ + echo "_fw_$(FWSTR)_bin:" ;\ + echo " .incbin \"$(fwdir)/$(FWNAME)\"" ;\ + echo "_fw_end:" ;\ + echo " .section .rodata.str,\"aMS\",$(PROGBITS),1" ;\ + echo " .p2align $(ASM_ALIGN)" ;\ + echo "_fw_$(FWSTR)_name:" ;\ + echo " .string \"$(FWNAME)\"" ;\ + echo " .section .builtin_fw,\"a\",$(PROGBITS)" ;\ + echo " .p2align $(ASM_ALIGN)" ;\ + echo " $(ASM_WORD) _fw_$(FWSTR)_name" ;\ + echo " $(ASM_WORD) _fw_$(FWSTR)_bin" ;\ echo " $(ASM_WORD) _fw_end - _fw_$(FWSTR)_bin" $(obj)/%.gen.S: FORCE diff --git a/drivers/base/firmware_loader/builtin/main.c b/drivers/base/firmware_loader/builtin/main.c index d36befebb..1dcebe8e7 100644 --- a/drivers/base/firmware_loader/builtin/main.c +++ b/drivers/base/firmware_loader/builtin/main.c @@ -53,6 +53,8 @@ bool firmware_request_builtin(struct firmware *fw, const char *name) for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) { if (strcmp(name, b_fw->name) == 0) { + if (b_fw->size == 0) + return false; fw->size = b_fw->size; fw->data = b_fw->data; return true; diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index 3ef0b312a..00d6b6e59 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -95,6 +95,16 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, long timeout) retval = -EINTR; goto out; } + + /* + * device_add() exposes the loading interface before pending_list is + * linked into pending_fw_head, so fw_state_done() may run first. + */ + if (fw_state_is_done(fw_priv)) { + mutex_unlock(&fw_lock); + goto out; + } + list_add(&fw_priv->pending_list, &pending_fw_head); mutex_unlock(&fw_lock); diff --git a/drivers/base/isa.c b/drivers/base/isa.c index 5887e4211..4e9f68080 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -166,14 +166,16 @@ static int __init isa_bus_init(void) int error; error = bus_register(&isa_bus_type); - if (!error) { - isa_bus = root_device_register("isa"); - if (IS_ERR(isa_bus)) { - error = PTR_ERR(isa_bus); - bus_unregister(&isa_bus_type); - } + if (error) + return error; + + isa_bus = root_device_register("isa"); + if (IS_ERR(isa_bus)) { + bus_unregister(&isa_bus_type); + return PTR_ERR(isa_bus); } - return error; + + return 0; } postcore_initcall(isa_bus_init); diff --git a/drivers/base/module.c b/drivers/base/module.c index 218aaa096..6789dca48 100644 --- a/drivers/base/module.c +++ b/drivers/base/module.c @@ -42,7 +42,7 @@ int module_add_driver(struct module *mod, const struct device_driver *drv) if (mod) mk = &mod->mkobj; else if (drv->mod_name) { - /* Lookup or create built-in module entry in /sys/modules */ + /* Lookup or create built-in module entry in /sys/module */ mk = lookup_or_create_module_kobject(drv->mod_name); if (mk) { /* remember our module structure */ diff --git a/drivers/base/platform.c b/drivers/base/platform.c index fb9120b0b..66f9ec73d 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -599,19 +599,19 @@ static void platform_device_release(struct device *dev) struct platform_object *pa = container_of(dev, struct platform_object, pdev.dev); - of_node_put(pa->pdev.dev.of_node); + device_remove_software_node(dev); + /* + * If the primary firmware node is a software node, its reference count + * was already decreased by the call to device_remove_software_node(). + */ + if (!is_software_node(dev_fwnode(dev))) + fwnode_handle_put(pa->pdev.dev.fwnode); kfree(pa->pdev.dev.platform_data); kfree(pa->pdev.mfd_cell); kfree(pa->pdev.resource); kfree(pa); } -static void platform_device_release_full(struct device *dev) -{ - device_remove_software_node(dev); - platform_device_release(dev); -} - /** * platform_device_alloc - create a platform device * @name: base name of the device we're adding @@ -619,6 +619,13 @@ static void platform_device_release_full(struct device *dev) * * Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. + * + * The following fields of the dynamically allocated platform device must not + * be modified manually: resource, num_resources, dev.platform_data, + * dev.of_node and dev.fwnode. Users wishing to do the split platform device + * registration with platform_device_alloc() + platform_device_add() are + * required to use dedicated helpers for adding resources, platform data or + * assigning firmware nodes. */ struct platform_device *platform_device_alloc(const char *name, int id) { @@ -694,6 +701,70 @@ int platform_device_add_data(struct platform_device *pdev, const void *data, EXPORT_SYMBOL_GPL(platform_device_add_data); /** + * platform_device_set_of_node - assign an OF node to device + * @pdev: platform device to add the node for + * @np: new device node + * + * Assign an OF node to this platform device. Internally keep track of the + * reference count. Devices created with platform_device_alloc() must use this + * function instead of assigning the node manually. This function must not be + * called for a platform device that already has a software node as its primary + * firmware node assigned. + */ +void platform_device_set_of_node(struct platform_device *pdev, + struct device_node *np) +{ + platform_device_set_fwnode(pdev, of_fwnode_handle(np)); +} +EXPORT_SYMBOL_GPL(platform_device_set_of_node); + +/** + * platform_device_set_fwnode - assign a firmware node to device + * @pdev: platform device to set the node for + * @fwnode: new firmware node + * + * Assign a firmware node to this platform device. Internally keep track of the + * reference count. Devices created with platform_device_alloc() must use this + * function instead of assigning the node manually. This function must not be + * called for a platform device that already has a software node as its primary + * firmware node assigned. + */ +void platform_device_set_fwnode(struct platform_device *pdev, + struct fwnode_handle *fwnode) +{ + /* + * If we call this function for a platform device whose primary + * firmware node is a software node, we'll never end up calling the + * symmetric software_node_notify_remove(). There are no users for this + * right now in the tree so just disallow it. + */ + WARN_ON(is_software_node(dev_fwnode(&pdev->dev))); + fwnode_handle_put(pdev->dev.fwnode); + device_set_node(&pdev->dev, fwnode_handle_get(fwnode)); +} +EXPORT_SYMBOL_GPL(platform_device_set_fwnode); + +/** + * platform_device_set_of_node_from_dev - reuse OF node of another device + * @pdev: platform device to set the node for + * @dev2: device whose OF node to reuse + * + * Reuses the OF node of another device in this platform device while + * internally keeping track of reference counting. This function must not be + * called for a platform device that already has a software node as its primary + * firmware node assigned. + */ +void platform_device_set_of_node_from_dev(struct platform_device *pdev, + const struct device *dev2) +{ + /* See platform_device_set_fwnode(). */ + WARN_ON(is_software_node(dev_fwnode(&pdev->dev))); + device_set_of_node_from_dev(&pdev->dev, dev2); + pdev->dev.fwnode = of_fwnode_handle(pdev->dev.of_node); +} +EXPORT_SYMBOL_GPL(platform_device_set_of_node_from_dev); + +/** * platform_device_add - add a platform device to device hierarchy * @pdev: platform device we're adding * @@ -868,8 +939,7 @@ struct platform_device *platform_device_register_full(const struct platform_devi return ERR_PTR(-ENOMEM); pdev->dev.parent = pdevinfo->parent; - pdev->dev.fwnode = pdevinfo->fwnode; - pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode)); + device_set_node(&pdev->dev, fwnode_handle_get(pdevinfo->fwnode)); dev_assign_of_node_reused(&pdev->dev, pdevinfo->of_node_reused); if (pdevinfo->dma_mask) { @@ -890,8 +960,6 @@ struct platform_device *platform_device_register_full(const struct platform_devi ret = device_add_software_node(&pdev->dev, pdevinfo->swnode); if (ret) goto err; - - pdev->dev.release = platform_device_release_full; } else if (pdevinfo->properties) { ret = device_create_managed_software_node(&pdev->dev, pdevinfo->properties, NULL); diff --git a/drivers/base/property.c b/drivers/base/property.c index e08eadd66..b136c339d 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -7,10 +7,10 @@ * Mika Westerberg <mika.westerberg@linux.intel.com> */ +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/err.h> #include <linux/export.h> -#include <linux/kconfig.h> #include <linux/of.h> #include <linux/property.h> #include <linux/phy.h> @@ -517,7 +517,6 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_string); int fwnode_property_match_string(const struct fwnode_handle *fwnode, const char *propname, const char *string) { - const char **values; int nval, ret; nval = fwnode_property_string_array_count(fwnode, propname); @@ -527,20 +526,18 @@ int fwnode_property_match_string(const struct fwnode_handle *fwnode, if (nval == 0) return -ENODATA; - values = kcalloc(nval, sizeof(*values), GFP_KERNEL); + const char **values __free(kfree) = kcalloc(nval, sizeof(*values), GFP_KERNEL); if (!values) return -ENOMEM; ret = fwnode_property_read_string_array(fwnode, propname, values, nval); if (ret < 0) - goto out_free; + return ret; ret = match_string(values, nval, string); if (ret < 0) - ret = -ENODATA; + return -ENODATA; -out_free: - kfree(values); return ret; } EXPORT_SYMBOL_GPL(fwnode_property_match_string); @@ -807,18 +804,31 @@ struct fwnode_handle * fwnode_get_next_child_node(const struct fwnode_handle *fwnode, struct fwnode_handle *child) { + const struct fwnode_handle *parent; + struct fwnode_handle *child_parent __free(fwnode_handle) = NULL; struct fwnode_handle *next; - if (IS_ERR_OR_NULL(fwnode)) + /* + * If this function is in a loop and the previous iteration returned + * an child from fwnode->secondary, then we need to use the secondary + * as parent rather than @fwnode. + */ + if (child) { + child_parent = fwnode_get_parent(child); + parent = child_parent; + } else { + parent = fwnode; + } + if (IS_ERR_OR_NULL(parent)) return NULL; /* Try to find a child in primary fwnode */ - next = fwnode_call_ptr_op(fwnode, get_next_child_node, child); + next = fwnode_call_ptr_op(parent, get_next_child_node, child); if (next) return next; /* When no more children in primary, continue with secondary */ - return fwnode_call_ptr_op(fwnode->secondary, get_next_child_node, child); + return fwnode_get_next_child_node(parent->secondary, NULL); } EXPORT_SYMBOL_GPL(fwnode_get_next_child_node); @@ -1115,8 +1125,9 @@ struct fwnode_handle * fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode, struct fwnode_handle *prev) { - struct fwnode_handle *ep, *port_parent = NULL; const struct fwnode_handle *parent; + struct fwnode_handle *port_parent __free(fwnode_handle) = NULL; + struct fwnode_handle *ep; /* * If this function is in a loop and the previous iteration returned @@ -1134,13 +1145,9 @@ fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode, ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev); if (ep) - goto out_put_port_parent; - - ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL); + return ep; -out_put_port_parent: - fwnode_handle_put(port_parent); - return ep; + return fwnode_graph_get_next_endpoint(parent->secondary, NULL); } EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint); diff --git a/drivers/base/soc.c b/drivers/base/soc.c index 65ce72d49..af7d71393 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -191,6 +191,7 @@ EXPORT_SYMBOL_GPL(soc_device_unregister); static int __init soc_bus_register(void) { + struct soc_device *soc_dev; int ret; ret = bus_register(&soc_bus_type); @@ -198,10 +199,20 @@ static int __init soc_bus_register(void) return ret; soc_bus_registered = true; - if (early_soc_dev_attr) - return PTR_ERR(soc_device_register(early_soc_dev_attr)); + if (early_soc_dev_attr) { + soc_dev = soc_device_register(early_soc_dev_attr); + if (IS_ERR(soc_dev)) { + ret = PTR_ERR(soc_dev); + goto err_unregister_bus; + } + } return 0; + +err_unregister_bus: + soc_bus_registered = false; + bus_unregister(&soc_bus_type); + return ret; } core_initcall(soc_bus_register); diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 1f2315858..84a77ffa3 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -537,7 +537,7 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode, if (prop->is_inline) return -EINVAL; - if ((index + 1) * sizeof(*ref) > prop->length) + if (index >= prop->length / sizeof(*ref)) return -ENOENT; ref_array = prop->pointer; diff --git a/drivers/base/test/Kconfig b/drivers/base/test/Kconfig index 1ecf07912..542ce0753 100644 --- a/drivers/base/test/Kconfig +++ b/drivers/base/test/Kconfig @@ -17,6 +17,7 @@ config DM_KUNIT_TEST config DRIVER_PE_KUNIT_TEST tristate "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS depends on KUNIT + select OF default KUNIT_ALL_TESTS config DRIVER_SWNODE_KUNIT_TEST diff --git a/drivers/base/test/platform-device-test.c b/drivers/base/test/platform-device-test.c index 6355a2231..9ce563f76 100644 --- a/drivers/base/test/platform-device-test.c +++ b/drivers/base/test/platform-device-test.c @@ -1,12 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 +#include <kunit/fwnode.h> #include <kunit/platform_device.h> #include <kunit/resource.h> #include <linux/device.h> #include <linux/device/bus.h> +#include <linux/fwnode.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/property.h> #define DEVICE_NAME "test" @@ -253,9 +256,186 @@ static struct kunit_suite platform_device_match_test_suite = { .test_cases = platform_device_match_tests, }; +static int platform_device_swnode_test_probe(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver platform_swnode_test_driver = { + .probe = platform_device_swnode_test_probe, + .driver = { + .name = DEVICE_NAME, + }, +}; + +static const struct software_node platform_device_test_swnode = { }; + +/* + * Check that reusing a software node works correctly. If the call to + * platform_device_register_full() fails after adding the secondary firmware + * node, the software node must be unregistered in the device's release() + * callback or the subsequent call to platform_device_register_full() will fail + * with -EBUSY due to the software node already having been registered. + */ +static void platform_device_swnode_add_twice(struct kunit *test) +{ + struct platform_device_info pdevinfo; + struct platform_device *pdev; + struct fwnode_handle *fwnode; + bool bound = false; + int ret; + + fwnode = kunit_kzalloc(test, sizeof(*fwnode), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); + + ret = kunit_platform_driver_register(test, &platform_swnode_test_driver); + KUNIT_ASSERT_EQ(test, ret, 0); + + fwnode_init(fwnode, NULL); + pdevinfo = (struct platform_device_info){ + .name = DEVICE_NAME, + .id = PLATFORM_DEVID_NONE, + .fwnode = fwnode, + .swnode = &platform_device_test_swnode, + }; + + pdev = platform_device_register_full(&pdevinfo); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + + wait_for_device_probe(); + scoped_guard(device, &pdev->dev) + bound = device_is_bound(&pdev->dev); + + KUNIT_ASSERT_TRUE(test, bound); + + platform_device_unregister(pdev); + + pdev = platform_device_register_full(&pdevinfo); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + + wait_for_device_probe(); + scoped_guard(device, &pdev->dev) + bound = device_is_bound(&pdev->dev); + + KUNIT_ASSERT_TRUE(test, bound); + + platform_device_unregister(pdev); +} + +/* + * Check that passing a software node as the primary firmware node of the + * platform device does not result in it being unregistered by the call to + * device_remove_software_node() in its release path. + */ +static void platform_device_swnode_as_primary(struct kunit *test) +{ + struct platform_device_info pdevinfo; + struct platform_device *pdev; + struct fwnode_handle *fwnode; + bool bound = false; + int ret; + + ret = kunit_platform_driver_register(test, &platform_swnode_test_driver); + KUNIT_ASSERT_EQ(test, ret, 0); + + fwnode = kunit_software_node_register(test, &platform_device_test_swnode); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); + + pdevinfo = (struct platform_device_info){ + .name = DEVICE_NAME, + .id = PLATFORM_DEVID_NONE, + .fwnode = fwnode, + }; + + pdev = platform_device_register_full(&pdevinfo); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + + wait_for_device_probe(); + scoped_guard(device, &pdev->dev) + bound = device_is_bound(&pdev->dev); + + KUNIT_ASSERT_TRUE(test, bound); + + platform_device_unregister(pdev); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, software_node_fwnode(&platform_device_test_swnode)); +} + +/* + * Check that passing two software nodes to platform_device_register_full() + * fails. + */ +static void platform_device_two_swnodes(struct kunit *test) +{ + static const struct property_entry properties[] = { + PROPERTY_ENTRY_U32("foo", 42), + { } + }; + + struct platform_device_info pdevinfo; + struct platform_device *pdev; + struct fwnode_handle *fwnode; + int ret; + + ret = kunit_platform_driver_register(test, &platform_swnode_test_driver); + KUNIT_ASSERT_EQ(test, ret, 0); + + fwnode = kunit_software_node_register(test, &platform_device_test_swnode); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode); + + pdevinfo = (struct platform_device_info){ + .name = DEVICE_NAME, + .id = PLATFORM_DEVID_NONE, + .fwnode = fwnode, + .swnode = &platform_device_test_swnode, + }; + + pdev = platform_device_register_full(&pdevinfo); + KUNIT_ASSERT_TRUE(test, IS_ERR(pdev)); + KUNIT_ASSERT_EQ_MSG(test, PTR_ERR(pdev), -EINVAL, + "Expected errno == -EINVAL, got: %pe", pdev); + + pdevinfo = (struct platform_device_info){ + .name = DEVICE_NAME, + .id = PLATFORM_DEVID_NONE, + .swnode = &platform_device_test_swnode, + .properties = properties, + }; + + pdev = platform_device_register_full(&pdevinfo); + KUNIT_ASSERT_TRUE(test, IS_ERR(pdev)); + KUNIT_ASSERT_EQ_MSG(test, PTR_ERR(pdev), -EINVAL, + "Expected errno == -EINVAL, got: %pe", pdev); + + pdevinfo = (struct platform_device_info){ + .name = DEVICE_NAME, + .id = PLATFORM_DEVID_NONE, + .fwnode = fwnode, + .properties = properties, + }; + + pdev = platform_device_register_full(&pdevinfo); + KUNIT_ASSERT_TRUE(test, IS_ERR(pdev)); + KUNIT_ASSERT_EQ_MSG(test, PTR_ERR(pdev), -EINVAL, + "Expected errno == -EINVAL, got: %pe", pdev); +} + +static struct kunit_case platform_device_swnode_tests[] = { + KUNIT_CASE(platform_device_swnode_add_twice), + KUNIT_CASE(platform_device_swnode_as_primary), + KUNIT_CASE(platform_device_two_swnodes), + {} +}; + +static struct kunit_suite platform_device_swnode_test_suite = { + .name = "platform-device-swnode", + .test_cases = platform_device_swnode_tests, +}; + kunit_test_suites( &platform_device_devm_test_suite, &platform_device_match_test_suite, + &platform_device_swnode_test_suite, ); MODULE_DESCRIPTION("Test module for platform devices"); diff --git a/drivers/base/test/property-entry-test.c b/drivers/base/test/property-entry-test.c index a8657eb06..855e73b9b 100644 --- a/drivers/base/test/property-entry-test.c +++ b/drivers/base/test/property-entry-test.c @@ -4,6 +4,8 @@ // Copyright 2019 Google LLC. #include <kunit/test.h> + +#include <linux/of.h> #include <linux/property.h> #include <linux/types.h> @@ -489,6 +491,139 @@ static void pe_test_reference(struct kunit *test) software_node_unregister_node_group(group); } +static struct fwnode_handle *create_device_node(struct kunit *test, + const char *name, + const char *full_name, + struct device_node *parent) +{ + struct device_node *node; + + node = kunit_kzalloc(test, sizeof(*node), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); + + node->name = kunit_kstrdup(test, name, GFP_KERNEL); + node->full_name = kunit_kstrdup(test, full_name, GFP_KERNEL); + + if (parent) { + node->sibling = parent->child; + /* set the node as the first child of the parent */ + parent->child = node; + node->parent = parent; + } + + of_node_init(node); + return of_fwnode_handle(node); +} + +/* Verifies that fwnode_for_each_child_node() can output correct children */ +static void pe_test_child_iteration(struct kunit *test) +{ + struct fwnode_handle *of_node, *of_node1; + struct fwnode_handle *sw_node, *sw_node1; + struct fwnode_handle *child; + int error, i, num; + + static const struct software_node node = { .name = "sw" }; + static const struct software_node node1 = { .name = "sw-1", .parent = &node}; + static const struct software_node node2 = { .name = "sw-2", .parent = &node}; + static const struct software_node node3 = { .name = "sw-3", .parent = &node}; + static const struct software_node *group[] = { &node, &node1, &node2, &node3, NULL }; + + static const char * const of_child_array[] = { "of-1", "of-2", "of-3" }; + static const char * const sw_child_array[] = { "sw-1", "sw-2", "sw-3" }; + static const char * const of_sw_child_array[] = { "of-1", "of-2", "of-3", + "sw-1", "sw-2", "sw-3" }; + static const char * const sw_of_child_array[] = { "sw-1", "sw-2", "sw-3", + "of-1", "of-2", "of-3" }; + + /* 1. Test OF node child iteration */ + + of_node = create_device_node(test, "of", "of", NULL); + create_device_node(test, "of", "of-3", to_of_node(of_node)); + create_device_node(test, "of", "of-2", to_of_node(of_node)); + of_node1 = create_device_node(test, "of", "of-1", to_of_node(of_node)); + + i = 0; + num = ARRAY_SIZE(of_child_array); + fwnode_for_each_child_node(of_node, child) { + KUNIT_ASSERT_LT(test, i, num); + KUNIT_EXPECT_STREQ(test, of_child_array[i++], fwnode_get_name(child)); + } + KUNIT_EXPECT_PTR_EQ(test, child, NULL); + + /* 2. Test SW node child iteration */ + + error = software_node_register_node_group(group); + KUNIT_ASSERT_EQ(test, error, 0); + + sw_node = software_node_fwnode(&node); + + i = 0; + num = ARRAY_SIZE(sw_child_array); + fwnode_for_each_child_node(sw_node, child) { + KUNIT_ASSERT_LT(test, i, num); + KUNIT_EXPECT_STREQ(test, sw_child_array[i++], fwnode_get_name(child)); + } + KUNIT_EXPECT_PTR_EQ(test, child, NULL); + + /* 3. Test OF (primary) + SW (secondary) node child iteration */ + + of_node->secondary = sw_node; + sw_node->secondary = ERR_PTR(-ENODEV); + + i = 0; + num = ARRAY_SIZE(of_sw_child_array); + fwnode_for_each_child_node(of_node, child) { + KUNIT_ASSERT_LT(test, i, num); + KUNIT_EXPECT_STREQ(test, of_sw_child_array[i++], fwnode_get_name(child)); + } + KUNIT_EXPECT_PTR_EQ(test, child, NULL); + + /* 4. Test SW (primary) + OF (secondary) node child iteration */ + + sw_node->secondary = of_node; + of_node->secondary = ERR_PTR(-ENODEV); + + i = 0; + num = ARRAY_SIZE(sw_of_child_array); + fwnode_for_each_child_node(sw_node, child) { + KUNIT_ASSERT_LT(test, i, num); + KUNIT_EXPECT_STREQ(test, sw_of_child_array[i++], fwnode_get_name(child)); + } + KUNIT_EXPECT_PTR_EQ(test, child, NULL); + + /* 5. Test OF (primary) + SW (secondary, but no children) node child iteration */ + + sw_node1 = software_node_fwnode(&node1); + of_node->secondary = sw_node1; + sw_node->secondary = ERR_PTR(-ENODEV); + + i = 0; + num = ARRAY_SIZE(of_child_array); + fwnode_for_each_child_node(of_node, child) { + KUNIT_ASSERT_LT(test, i, num); + KUNIT_EXPECT_STREQ(test, of_child_array[i++], fwnode_get_name(child)); + } + KUNIT_EXPECT_PTR_EQ(test, child, NULL); + + /* 6. Test SW (primary) + OF (secondary, but no children) node child iteration */ + + sw_node->secondary = of_node1; + of_node->secondary = ERR_PTR(-ENODEV); + + i = 0; + num = ARRAY_SIZE(sw_child_array); + fwnode_for_each_child_node(sw_node, child) { + KUNIT_ASSERT_LT(test, i, num); + KUNIT_EXPECT_STREQ(test, sw_child_array[i++], fwnode_get_name(child)); + } + KUNIT_EXPECT_PTR_EQ(test, child, NULL); + + of_node->secondary = NULL; + sw_node->secondary = NULL; + software_node_unregister_node_group(group); +} + static struct kunit_case property_entry_test_cases[] = { KUNIT_CASE(pe_test_uints), KUNIT_CASE(pe_test_uint_arrays), @@ -497,6 +632,7 @@ static struct kunit_case property_entry_test_cases[] = { KUNIT_CASE(pe_test_move_inline_u8), KUNIT_CASE(pe_test_move_inline_str), KUNIT_CASE(pe_test_reference), + KUNIT_CASE(pe_test_child_iteration), { } }; @@ -509,4 +645,5 @@ kunit_test_suite(property_entry_test_suite); MODULE_DESCRIPTION("Test module for the property entry API"); MODULE_AUTHOR("Dmitry Torokhov <dtor@chromium.org>"); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); MODULE_LICENSE("GPL"); diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c index 416e9f819..351c3d3ce 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c @@ -168,11 +168,14 @@ static int transport_add_class_device(struct attribute_container *cont, if (tcont->encryption) { error = sysfs_create_group(&classdev->kobj, tcont->encryption); if (error) - goto err_del; + goto err_del_statistics; } return 0; +err_del_statistics: + if (tcont->statistics) + sysfs_remove_group(&classdev->kobj, tcont->statistics); err_del: attribute_container_class_device_del(classdev); err_remove: diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs index 5d2785726..d7ead60bf 100644 --- a/drivers/cpufreq/rcpufreq_dt.rs +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -201,7 +201,6 @@ impl cpufreq::Driver for CPUFreqDTDriver { kernel::of_device_table!( OF_TABLE, - MODULE_OF_TABLE, <CPUFreqDTDriver as platform::Driver>::IdInfo, [(of::DeviceId::new(c"operating-points-v2"), ())] ); diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs index 48933d86d..43f15cdfe 100644 --- a/drivers/gpu/drm/nova/driver.rs +++ b/drivers/gpu/drm/nova/driver.rs @@ -43,7 +43,6 @@ const AUXILIARY_NAME: &CStr = c"nova-drm"; kernel::auxiliary_device_table!( AUX_TABLE, - MODULE_AUX_TABLE, <NovaDriver as auxiliary::Driver>::IdInfo, [( auxiliary::DeviceId::new(NOVA_CORE_MODULE_NAME, AUXILIARY_NAME), diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index d063bc664..218e9af89 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -87,7 +87,6 @@ fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result { kernel::of_device_table!( OF_TABLE, - MODULE_OF_TABLE, <TyrPlatformDriver as platform::Driver>::IdInfo, [ (of::DeviceId::new(c"rockchip,rk3588-mali"), ()), diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c index f05f23221..c61d5db07 100644 --- a/drivers/gpu/drm/xe/xe_i2c.c +++ b/drivers/gpu/drm/xe/xe_i2c.c @@ -93,14 +93,9 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c) { struct pci_dev *pci = to_pci_dev(i2c->drm_dev); struct platform_device *pdev; - struct fwnode_handle *fwnode; int ret; u32 id; - fwnode = fwnode_create_software_node(xe_i2c_adapter_properties, NULL); - if (IS_ERR(fwnode)) - return PTR_ERR(fwnode); - id = (pci_domain_nr(pci->bus) << 16) | pci_dev_id(pci); /* @@ -110,10 +105,14 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c) * platform_device_register_full() is done. */ pdev = platform_device_alloc(adapter_name, id); - if (!pdev) { - ret = -ENOMEM; - goto err_fwnode_remove; - } + if (!pdev) + return -ENOMEM; + + ret = device_create_managed_software_node(&pdev->dev, + xe_i2c_adapter_properties, + NULL); + if (ret) + goto err_pdev_put; if (i2c->adapter_irq) { struct resource res; @@ -126,8 +125,6 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c) } pdev->dev.parent = i2c->drm_dev; - pdev->dev.fwnode = fwnode; - i2c->adapter_node = fwnode; i2c->pdev = pdev; ret = platform_device_add(pdev); @@ -138,8 +135,6 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c) err_pdev_put: platform_device_put(pdev); -err_fwnode_remove: - fwnode_remove_software_node(fwnode); return ret; } @@ -147,7 +142,6 @@ err_fwnode_remove: static void xe_i2c_unregister_adapter(struct xe_i2c *i2c) { platform_device_unregister(i2c->pdev); - fwnode_remove_software_node(i2c->adapter_node); } /** diff --git a/drivers/gpu/drm/xe/xe_i2c.h b/drivers/gpu/drm/xe/xe_i2c.h index 425d81608..b28229f05 100644 --- a/drivers/gpu/drm/xe/xe_i2c.h +++ b/drivers/gpu/drm/xe/xe_i2c.h @@ -30,7 +30,6 @@ struct xe_i2c_endpoint { }; struct xe_i2c { - struct fwnode_handle *adapter_node; struct platform_device *pdev; struct i2c_adapter *adapter; struct i2c_client *client[XE_I2C_MAX_CLIENTS]; diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 5738d4ac5..bbd93959e 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -15,7 +15,7 @@ use kernel::{ Atomic, Relaxed, // }, - types::ForLt, + types::CovariantForLt, }; use crate::gpu::Gpu; @@ -29,7 +29,7 @@ pub(crate) struct NovaCore<'bound> { pub(crate) gpu: Gpu<'bound>, bar: pci::Bar<'bound, BAR0_SIZE>, #[allow(clippy::type_complexity)] - _reg: auxiliary::Registration<'bound, ForLt!(())>, + _reg: auxiliary::Registration<'bound, CovariantForLt!(())>, } pub(crate) struct NovaCoreDriver; @@ -40,7 +40,6 @@ pub(crate) type Bar0<'a> = &'a pci::Bar<'a, BAR0_SIZE>; kernel::pci_device_table!( PCI_TABLE, - MODULE_PCI_TABLE, <NovaCoreDriver as pci::Driver>::IdInfo, [ // Modern NVIDIA GPUs will show up as either VGA or 3D controllers. @@ -70,7 +69,7 @@ impl pci::Driver for NovaCoreDriver { fn probe<'bound>( pdev: &'bound pci::Device<Core<'_>>, - _info: &'bound Self::IdInfo, + _info: Option<&'bound Self::IdInfo>, ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { pin_init::pin_init_scope(move || { dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index b3c91731d..b603b0bd2 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -285,10 +285,10 @@ pub(crate) struct Gpu<'gpu> { } impl<'gpu> Gpu<'gpu> { - pub(crate) fn new( - pdev: &'gpu pci::Device<device::Core<'_>>, + pub(crate) fn new<'a>( + pdev: &'gpu pci::Device<device::Core<'a>>, bar: Bar0<'gpu>, - ) -> impl PinInit<Self, Error> + 'gpu { + ) -> impl PinInit<Self, Error> + use<'gpu, 'a> { try_pin_init!(Self { device: pdev.as_ref(), spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| { diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 69175ca33..cfa7553cd 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -9,14 +9,16 @@ use kernel::{ dma::{ Coherent, CoherentBox, + CoherentView, DmaAddress, // }, + io::{ + io_project, + io_write, + Io, // + }, pci, - prelude::*, - transmute::{ - AsBytes, - FromBytes, // - }, // + prelude::*, // }; pub(crate) mod cmdq; @@ -48,21 +50,21 @@ const LOG_BUFFER_SIZE: usize = RM_LOG_BUFFER_NUM_PAGES * GSP_PAGE_SIZE; /// Array of page table entries, as understood by the GSP bootloader. #[repr(C)] +#[derive(FromBytes, IntoBytes)] struct PteArray<const NUM_ENTRIES: usize>([u64; NUM_ENTRIES]); -/// SAFETY: arrays of `u64` implement `FromBytes` and we are but a wrapper around one. -unsafe impl<const NUM_ENTRIES: usize> FromBytes for PteArray<NUM_ENTRIES> {} - -/// SAFETY: arrays of `u64` implement `AsBytes` and we are but a wrapper around one. -unsafe impl<const NUM_ENTRIES: usize> AsBytes for PteArray<NUM_ENTRIES> {} - impl<const NUM_PAGES: usize> PteArray<NUM_PAGES> { - /// Returns the page table entry for `index`, for a mapping starting at `start`. - // TODO: Replace with `IoView` projection once available. - fn entry(start: DmaAddress, index: usize) -> Result<u64> { - start - .checked_add(num::usize_as_u64(index) << GSP_PAGE_SHIFT) - .ok_or(EOVERFLOW) + /// Initialize a new page table array mapping `NUM_PAGES` GSP pages starting at address `start`. + fn init(view: CoherentView<'_, Self>, start: DmaAddress) -> Result<()> { + for i in 0..NUM_PAGES { + io_write!(view, .0[build: i], + start + .checked_add(num::usize_as_u64(i) << GSP_PAGE_SHIFT) + .ok_or(EOVERFLOW)? + ); + } + + Ok(()) } } @@ -89,17 +91,12 @@ impl LogBuffer { let start_addr = obj.0.dma_handle(); - // SAFETY: `obj` has just been created and we are its sole user. - let pte_region = unsafe { - &mut obj.0.as_mut()[size_of::<u64>()..][..RM_LOG_BUFFER_NUM_PAGES * size_of::<u64>()] - }; - - // Write values one by one to avoid an on-stack instance of `PteArray`. - for (i, chunk) in pte_region.chunks_exact_mut(size_of::<u64>()).enumerate() { - let pte_value = PteArray::<0>::entry(start_addr, i)?; - - chunk.copy_from_slice(&pte_value.to_ne_bytes()); - } + let pte_view = io_project!( + obj.0, + [build: size_of::<u64>()..][build: ..RM_LOG_BUFFER_NUM_PAGES * size_of::<u64>()] + ) + .try_cast::<PteArray<RM_LOG_BUFFER_NUM_PAGES>>()?; + PteArray::init(pte_view, start_addr)?; Ok(obj) } diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs index 3c68a6677..9349717b9 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -2,16 +2,23 @@ mod continuation; -use core::mem; +use core::{ + mem, + sync::atomic::{ + fence, + Ordering, // + }, +}; use kernel::{ device, dma::{ Coherent, + CoherentBox, DmaAddress, // }, - dma_write, io::{ + io_project, poll::read_poll_timeout, Io, // }, @@ -171,20 +178,18 @@ static_assert!(align_of::<MsgqData>() == GSP_PAGE_SIZE); #[repr(C)] // There is no struct defined for this in the open-gpu-kernel-source headers. // Instead it is defined by code in `GspMsgQueuesInit()`. -// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module. -pub(super) struct Msgq { +struct Msgq { /// Header for sending messages, including the write pointer. - pub(super) tx: MsgqTxHeader, + tx: MsgqTxHeader, /// Header for receiving messages, including the read pointer. - pub(super) rx: MsgqRxHeader, + rx: MsgqRxHeader, /// The message queue proper. msgq: MsgqData, } /// Structure shared between the driver and the GSP and containing the command and message queues. #[repr(C)] -// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module. -pub(super) struct GspMem { +struct GspMem { /// Self-mapping page table entries. ptes: PteArray<{ Self::PTE_ARRAY_SIZE }>, /// CPU queue: the driver writes commands here, and the GSP reads them. It also contains the @@ -192,13 +197,13 @@ pub(super) struct GspMem { /// index into the GSP queue. /// /// This member is read-only for the GSP. - pub(super) cpuq: Msgq, + cpuq: Msgq, /// GSP queue: the GSP writes messages here, and the driver reads them. It also contains the /// write and read pointers that the GSP updates. This means that the read pointer here is an /// index into the CPU queue. /// /// This member is read-only for the driver. - pub(super) gspq: Msgq, + gspq: Msgq, } impl GspMem { @@ -232,20 +237,12 @@ impl DmaGspMem { const MSGQ_SIZE: u32 = num::usize_into_u32::<{ size_of::<Msgq>() }>(); const RX_HDR_OFF: u32 = num::usize_into_u32::<{ mem::offset_of!(Msgq, rx) }>(); - let gsp_mem = Coherent::<GspMem>::zeroed(dev, GFP_KERNEL)?; - - let start = gsp_mem.dma_handle(); - // Write values one by one to avoid an on-stack instance of `PteArray`. - for i in 0..GspMem::PTE_ARRAY_SIZE { - dma_write!(gsp_mem, .ptes.0[build: i], PteArray::<0>::entry(start, i)?); - } + let mut gsp_mem = CoherentBox::<GspMem>::zeroed(dev, GFP_KERNEL)?; + gsp_mem.cpuq.tx = MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES); + gsp_mem.cpuq.rx = MsgqRxHeader::new(); - dma_write!( - gsp_mem, - .cpuq.tx, - MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES) - ); - dma_write!(gsp_mem, .cpuq.rx, MsgqRxHeader::new()); + let gsp_mem: Coherent<_> = gsp_mem.into(); + PteArray::init(io_project!(gsp_mem, .ptes), gsp_mem.dma_handle())?; Ok(Self(gsp_mem)) } @@ -406,7 +403,7 @@ impl DmaGspMem { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn gsp_write_ptr(&self) -> u32 { - super::fw::gsp_mem::gsp_write_ptr(&self.0) + MsgqTxHeader::write_ptr(io_project!(self.0, .gspq.tx)) % MSGQ_NUM_PAGES } // Returns the index of the memory page the GSP will read the next command from. @@ -415,7 +412,7 @@ impl DmaGspMem { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn gsp_read_ptr(&self) -> u32 { - super::fw::gsp_mem::gsp_read_ptr(&self.0) + MsgqRxHeader::read_ptr(io_project!(self.0, .gspq.rx)) % MSGQ_NUM_PAGES } // Returns the index of the memory page the CPU can read the next message from. @@ -424,12 +421,18 @@ impl DmaGspMem { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn cpu_read_ptr(&self) -> u32 { - super::fw::gsp_mem::cpu_read_ptr(&self.0) + MsgqRxHeader::read_ptr(io_project!(self.0, .cpuq.rx)) % MSGQ_NUM_PAGES } // Informs the GSP that it can send `elem_count` new pages into the message queue. fn advance_cpu_read_ptr(&mut self, elem_count: u32) { - super::fw::gsp_mem::advance_cpu_read_ptr(&self.0, elem_count) + let rx = io_project!(self.0, .cpuq.rx); + let rptr = MsgqRxHeader::read_ptr(rx).wrapping_add(elem_count) % MSGQ_NUM_PAGES; + + // Ensure read pointer is properly ordered. + fence(Ordering::SeqCst); + + MsgqRxHeader::set_read_ptr(rx, rptr) } // Returns the index of the memory page the CPU can write the next command to. @@ -438,12 +441,17 @@ impl DmaGspMem { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn cpu_write_ptr(&self) -> u32 { - super::fw::gsp_mem::cpu_write_ptr(&self.0) + MsgqTxHeader::write_ptr(io_project!(self.0, .cpuq.tx)) % MSGQ_NUM_PAGES } // Informs the GSP that it can process `elem_count` new pages from the command queue. fn advance_cpu_write_ptr(&mut self, elem_count: u32) { - super::fw::gsp_mem::advance_cpu_write_ptr(&self.0, elem_count) + let tx = io_project!(self.0, .cpuq.tx); + let wptr = MsgqTxHeader::write_ptr(tx).wrapping_add(elem_count) % MSGQ_NUM_PAGES; + MsgqTxHeader::set_write_ptr(tx, wptr); + + // Ensure all command data is visible before triggering the GSP read. + fence(Ordering::SeqCst); } } diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index 4db0cfa4d..b0e7de328 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -10,7 +10,14 @@ use r570_144 as bindings; use core::ops::Range; use kernel::{ - dma::Coherent, + dma::{ + Coherent, + CoherentView, // + }, + io::{ + io_read, + io_write, // + }, prelude::*, ptr::{ Alignable, @@ -44,59 +51,6 @@ use crate::{ }, }; -// TODO: Replace with `IoView` projections once available. -pub(super) mod gsp_mem { - use core::sync::atomic::{ - fence, - Ordering, // - }; - - use kernel::{ - dma::Coherent, - dma_read, - dma_write, // - }; - - use crate::gsp::cmdq::{ - GspMem, - MSGQ_NUM_PAGES, // - }; - - pub(in crate::gsp) fn gsp_write_ptr(qs: &Coherent<GspMem>) -> u32 { - dma_read!(qs, .gspq.tx.0.writePtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn gsp_read_ptr(qs: &Coherent<GspMem>) -> u32 { - dma_read!(qs, .gspq.rx.0.readPtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn cpu_read_ptr(qs: &Coherent<GspMem>) -> u32 { - dma_read!(qs, .cpuq.rx.0.readPtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn advance_cpu_read_ptr(qs: &Coherent<GspMem>, count: u32) { - let rptr = cpu_read_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES; - - // Ensure read pointer is properly ordered. - fence(Ordering::SeqCst); - - dma_write!(qs, .cpuq.rx.0.readPtr, rptr); - } - - pub(in crate::gsp) fn cpu_write_ptr(qs: &Coherent<GspMem>) -> u32 { - dma_read!(qs, .cpuq.tx.0.writePtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn advance_cpu_write_ptr(qs: &Coherent<GspMem>, count: u32) { - let wptr = cpu_write_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES; - - dma_write!(qs, .cpuq.tx.0.writePtr, wptr); - - // Ensure all command data is visible before triggering the GSP read. - fence(Ordering::SeqCst); - } -} - /// Maximum size of a single GSP message queue element in bytes. pub(crate) const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: usize = num::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX); @@ -720,6 +674,16 @@ impl MsgqTxHeader { entryOff: num::usize_into_u32::<GSP_PAGE_SIZE>(), }) } + + /// Returns the value of the write pointer for this queue. + pub(crate) fn write_ptr(this: CoherentView<'_, Self>) -> u32 { + io_read!(this, .0.writePtr) + } + + /// Sets the value of the write pointer for this queue. + pub(crate) fn set_write_ptr(this: CoherentView<'_, Self>, val: u32) { + io_write!(this, .0.writePtr, val) + } } // SAFETY: Padding is explicit and does not contain uninitialized data. @@ -735,6 +699,16 @@ impl MsgqRxHeader { pub(crate) fn new() -> Self { Self(Default::default()) } + + /// Returns the value of the read pointer for this queue. + pub(crate) fn read_ptr(this: CoherentView<'_, Self>) -> u32 { + io_read!(this, .0.readPtr) + } + + /// Sets the value of the read pointer for this queue. + pub(crate) fn set_read_ptr(this: CoherentView<'_, Self>, val: u32) { + io_write!(this, .0.readPtr, val) + } } // SAFETY: Padding is explicit and does not contain uninitialized data. diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index dbd542300..92a0647f0 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -76,7 +76,8 @@ static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar) goto out; } pdev->dev.parent = &dev->dev; - pdev->dev.of_node = child; + + platform_device_set_of_node(pdev, child); ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); if (ret) diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c index 25aa477a9..c83bbc3fa 100644 --- a/drivers/iommu/fsl_pamu.c +++ b/drivers/iommu/fsl_pamu.c @@ -8,6 +8,7 @@ #include "fsl_pamu.h" +#include <linux/cleanup.h> #include <linux/fsl/guts.h> #include <linux/interrupt.h> #include <linux/genalloc.h> @@ -933,7 +934,6 @@ static struct platform_driver fsl_of_pamu_driver = { static __init int fsl_pamu_init(void) { struct platform_device *pdev = NULL; - struct device_node *np; int ret; /* @@ -955,7 +955,8 @@ static __init int fsl_pamu_init(void) * PAMU node would require significant changes to a lot of code. */ - np = of_find_compatible_node(NULL, NULL, "fsl,pamu"); + struct device_node *np __free(device_node) = + of_find_compatible_node(NULL, NULL, "fsl,pamu"); if (!np) { pr_err("could not find a PAMU node\n"); return -ENODEV; @@ -964,7 +965,7 @@ static __init int fsl_pamu_init(void) ret = platform_driver_register(&fsl_of_pamu_driver); if (ret) { pr_err("could not register driver (err=%i)\n", ret); - goto error_driver_register; + return ret; } pdev = platform_device_alloc("fsl-of-pamu", 0); @@ -973,7 +974,8 @@ static __init int fsl_pamu_init(void) ret = -ENOMEM; goto error_device_alloc; } - pdev->dev.of_node = of_node_get(np); + + platform_device_set_of_node(pdev, np); ret = pamu_domain_init(); if (ret) @@ -988,17 +990,11 @@ static __init int fsl_pamu_init(void) return 0; error_device_add: - of_node_put(pdev->dev.of_node); - pdev->dev.of_node = NULL; - platform_device_put(pdev); error_device_alloc: platform_driver_unregister(&fsl_of_pamu_driver); -error_driver_register: - of_node_put(np); - return ret; } arch_initcall(fsl_pamu_init); diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index f5f805446..3cfd2f02b 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -397,7 +397,7 @@ static int tps6586x_add_subdevs(struct tps6586x *tps6586x, pdev->dev.parent = tps6586x->dev; pdev->dev.platform_data = subdev->platform_data; - pdev->dev.of_node = of_node_get(subdev->of_node); + platform_device_set_of_node(pdev, subdev->of_node); ret = platform_device_add(pdev); if (ret) { diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index a4e0d5a68..0f0dbabfa 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -490,8 +490,9 @@ static int bcmgenet_mii_register(struct bcmgenet_priv *priv) /* Retain this platform_device pointer for later cleanup */ priv->mii_pdev = ppdev; ppdev->dev.parent = &pdev->dev; + if (dn) - ppdev->dev.of_node = bcmgenet_mii_of_find_mdio(priv); + platform_device_set_of_node(ppdev, bcmgenet_mii_of_find_mdio(priv)); else ppd.phy_mask = ~0; diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 1881583be..9caa1e47c 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -2780,7 +2780,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev, goto put_err; } ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - ppdev->dev.of_node = of_node_get(pnp); + platform_device_set_of_node(ppdev, pnp); ret = platform_device_add_resources(ppdev, &res, 1); if (ret) diff --git a/drivers/of/kobj.c b/drivers/of/kobj.c index 1bb61a2c3..9f17305f1 100644 --- a/drivers/of/kobj.c +++ b/drivers/of/kobj.c @@ -2,6 +2,8 @@ #include <linux/of.h> #include <linux/slab.h> +#include <kunit/visibility.h> + #include "of_private.h" /* true when node is initialized */ @@ -27,6 +29,7 @@ static void of_node_release(struct kobject *kobj) const struct kobj_type of_node_ktype = { .release = of_node_release, }; +EXPORT_SYMBOL_IF_KUNIT(of_node_ktype); static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, const struct bin_attribute *bin_attr, char *buf, diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 53bca8c6f..8b1e76407 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -126,7 +126,7 @@ struct platform_device *of_device_alloc(struct device_node *np, } /* setup generic device info */ - device_set_node(&dev->dev, of_fwnode_handle(of_node_get(np))); + platform_device_set_of_node(dev, np); dev->dev.parent = parent ? : &platform_bus; if (bus_id) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c index b35941390..29b264f2a 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -11,6 +11,7 @@ #include <linux/acpi.h> #include <linux/dmi.h> +#include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -290,9 +291,9 @@ static struct platform_device *surface_gpe_device; static int __init surface_gpe_init(void) { + struct platform_device_info pdevinfo; const struct dmi_system_id *match; struct platform_device *pdev; - struct fwnode_handle *fwnode; int status; match = dmi_first_match(dmi_lid_device_table); @@ -305,44 +306,27 @@ static int __init surface_gpe_init(void) if (status) return status; - fwnode = fwnode_create_software_node(match->driver_data, NULL); - if (IS_ERR(fwnode)) { - status = PTR_ERR(fwnode); - goto err_node; - } + pdevinfo = (struct platform_device_info){ + .name = "surface_gpe", + .id = PLATFORM_DEVID_NONE, + .properties = match->driver_data, + }; - pdev = platform_device_alloc("surface_gpe", PLATFORM_DEVID_NONE); - if (!pdev) { - status = -ENOMEM; - goto err_alloc; + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) { + platform_driver_unregister(&surface_gpe_driver); + return PTR_ERR(pdev); } - pdev->dev.fwnode = fwnode; - - status = platform_device_add(pdev); - if (status) - goto err_add; - surface_gpe_device = pdev; return 0; - -err_add: - platform_device_put(pdev); -err_alloc: - fwnode_remove_software_node(fwnode); -err_node: - platform_driver_unregister(&surface_gpe_driver); - return status; } module_init(surface_gpe_init); static void __exit surface_gpe_exit(void) { - struct fwnode_handle *fwnode = surface_gpe_device->dev.fwnode; - platform_device_unregister(surface_gpe_device); platform_driver_unregister(&surface_gpe_driver); - fwnode_remove_software_node(fwnode); } module_exit(surface_gpe_exit); diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c index 42e50c9b4..abca5f449 100644 --- a/drivers/pmdomain/imx/gpc.c +++ b/drivers/pmdomain/imx/gpc.c @@ -487,8 +487,7 @@ static int imx_gpc_probe(struct platform_device *pdev) domain->ipg_rate_mhz = ipg_rate_mhz; pd_pdev->dev.parent = &pdev->dev; - pd_pdev->dev.of_node = of_node_get(np); - pd_pdev->dev.fwnode = of_fwnode_handle(np); + platform_device_set_of_node(pd_pdev, np); ret = platform_device_add(pd_pdev); if (ret) { diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index 543bd8dea..728993998 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -20,7 +20,6 @@ //! this method is not used in this driver. //! -use core::ops::Deref; use kernel::{ clk::Clk, device::{ @@ -28,9 +27,8 @@ use kernel::{ Core, Device, // }, - devres, io::{ - mem::IoMem, + mem::DevresIoMem, Io, // }, of, @@ -92,7 +90,7 @@ struct Th1520WfHw { #[pin_data(PinnedDrop)] struct Th1520PwmDriverData { #[pin] - iomem: devres::Devres<IoMem<'static, TH1520_PWM_REG_SIZE>>, + iomem: DevresIoMem<TH1520_PWM_REG_SIZE>, clk: Clk, } @@ -219,8 +217,7 @@ impl pwm::PwmOps for Th1520PwmDriverData { ) -> Result<Self::WfHw> { let data = chip.drvdata(); let hwpwm = pwm.hwpwm(); - let iomem_accessor = data.iomem.access(parent_dev)?; - let iomap = iomem_accessor.deref(); + let iomap = data.iomem.access(parent_dev)?; let ctrl = iomap.try_read32(th1520_pwm_ctrl(hwpwm))?; let period_cycles = iomap.try_read32(th1520_pwm_per(hwpwm))?; @@ -254,8 +251,7 @@ impl pwm::PwmOps for Th1520PwmDriverData { ) -> Result { let data = chip.drvdata(); let hwpwm = pwm.hwpwm(); - let iomem_accessor = data.iomem.access(parent_dev)?; - let iomap = iomem_accessor.deref(); + let iomap = data.iomem.access(parent_dev)?; let duty_cycles = iomap.try_read32(th1520_pwm_fp(hwpwm))?; let was_enabled = duty_cycles != 0; @@ -309,7 +305,6 @@ struct Th1520PwmPlatformDriver; kernel::of_device_table!( OF_TABLE, - MODULE_OF_TABLE, <Th1520PwmPlatformDriver as platform::Driver>::IdInfo, [(of::DeviceId::new(c"thead,th1520-pwm"), ())] ); diff --git a/drivers/reset/reset-rzg2l-usbphy-ctrl.c b/drivers/reset/reset-rzg2l-usbphy-ctrl.c index fd75d9601..f003b3606 100644 --- a/drivers/reset/reset-rzg2l-usbphy-ctrl.c +++ b/drivers/reset/reset-rzg2l-usbphy-ctrl.c @@ -249,7 +249,7 @@ static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev) vdev->dev.parent = dev; priv->vdev = vdev; - device_set_of_node_from_dev(&vdev->dev, dev); + platform_device_set_of_node_from_dev(vdev, dev); error = platform_device_add(vdev); if (error) goto err_device_put; diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index 3071e46d0..6e8941571 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -1539,7 +1539,7 @@ static int of_qcom_slim_ngd_register(struct device *parent, kfree(ngd); return ret; } - ngd->pdev->dev.of_node = of_node_get(node); + platform_device_set_of_node(ngd->pdev, node); ctrl->ngd = ngd; ret = platform_device_add(ngd->pdev); diff --git a/drivers/tty/serdev/Kconfig b/drivers/tty/serdev/Kconfig index 46ae732bf..e6dfe949a 100644 --- a/drivers/tty/serdev/Kconfig +++ b/drivers/tty/serdev/Kconfig @@ -9,6 +9,13 @@ menuconfig SERIAL_DEV_BUS Note that you typically also want to enable TTY port controller support. +config RUST_SERIAL_DEV_BUS_ABSTRACTIONS + bool "Rust Serial device bus abstractions" + depends on RUST + select SERIAL_DEV_BUS + help + This enables the Rust abstraction for the serial device bus API. + if SERIAL_DEV_BUS config SERIAL_DEV_CTRL_TTYPORT diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index b53672f3e..3461dd763 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -879,7 +879,7 @@ struct platform_device *ci_hdrc_add_device(struct device *dev, } pdev->dev.parent = dev; - device_set_of_node_from_dev(&pdev->dev, dev); + platform_device_set_of_node_from_dev(pdev, dev); ret = platform_device_add_resources(pdev, res, nres); if (ret) diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index df56c9729..c770ba576 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -273,7 +273,7 @@ static int jz4740_probe(struct platform_device *pdev) musb->dev.parent = dev; musb->dev.dma_mask = &musb->dev.coherent_dma_mask; musb->dev.coherent_dma_mask = DMA_BIT_MASK(32); - device_set_of_node_from_dev(&musb->dev, dev); + platform_device_set_of_node_from_dev(musb, dev); glue->pdev = musb; glue->clk = clk; |
