diff options
109 files changed, 3900 insertions, 876 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index 8aed6d94c4cd..3a05604c21bf 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -764,6 +764,17 @@ Description: participate in load balancing. These CPUs are set by boot parameter "isolcpus=". +What: /sys/devices/system/cpu/housekeeping +Date: Oct 2025 +Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org> +Description: + (RO) the list of logical CPUs that are designated by the kernel as + "housekeeping". Each CPU are responsible for handling essential + system-wide background tasks, including RCU callbacks, delayed + timer callbacks, and unbound workqueues, minimizing scheduling + jitter on low-latency, isolated CPUs. These CPUs are set when boot + parameter "isolcpus=nohz" or "nohz_full=" is specified. + What: /sys/devices/system/cpu/crash_hotplug Date: Aug 2023 Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 5692e19199b3..b242519f57da 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1211,12 +1211,8 @@ Kernel parameters debugfs= [KNL,EARLY] This parameter enables what is exposed to userspace and debugfs internal clients. - Format: { on, no-mount, off } + Format: { on, off } on: All functions are enabled. - no-mount: - Filesystem is not registered but kernel clients can - access APIs and a crashkernel can be used to read - its content. There is nothing to mount. off: Filesystem is not registered and clients get a -EPERM as result when trying to register files or directories within debugfs. diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 2b36ebde9cec..0198ac65e874 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -383,7 +383,6 @@ NET PER-CPU MEM devm_alloc_percpu() - devm_free_percpu() PCI devm_pci_alloc_host_bridge() : managed PCI host bridge allocation diff --git a/MAINTAINERS b/MAINTAINERS index 41dcab23a39d..fdc7368de809 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4432,6 +4432,7 @@ F: arch/*/lib/bitops.c F: include/asm-generic/bitops F: include/asm-generic/bitops.h F: include/linux/bitops.h +F: lib/hweight.c F: lib/test_bitops.c F: tools/*/bitops* @@ -11821,6 +11822,16 @@ F: include/linux/i2c.h F: include/uapi/linux/i2c-*.h F: include/uapi/linux/i2c.h +I2C SUBSYSTEM [RUST] +M: Igor Korotin <igor.korotin.linux@gmail.com> +R: Danilo Krummrich <dakr@kernel.org> +R: Daniel Almeida <daniel.almeida@collabora.com> +L: rust-for-linux@vger.kernel.org +S: Maintained +F: rust/kernel/i2c.rs +F: samples/rust/rust_driver_i2c.rs +F: samples/rust/rust_i2c_client.rs + I2C SUBSYSTEM HOST DRIVERS M: Andi Shyti <andi.shyti@kernel.org> L: linux-i2c@vger.kernel.org @@ -17512,6 +17523,7 @@ M: Luis Chamberlain <mcgrof@kernel.org> M: Petr Pavlu <petr.pavlu@suse.com> M: Daniel Gomez <da.gomez@kernel.org> R: Sami Tolvanen <samitolvanen@google.com> +R: Aaron Tomlin <atomlin@atomlin.com> L: linux-modules@vger.kernel.org L: linux-kernel@vger.kernel.org S: Maintained @@ -17521,6 +17533,8 @@ F: include/linux/module*.h F: kernel/module/ F: lib/test_kmod.c F: lib/tests/module/ +F: rust/kernel/module_param.rs +F: rust/macros/module.rs F: scripts/module* F: tools/testing/selftests/kmod/ F: tools/testing/selftests/module/ diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index 341174bf9106..b9eaf4ad7085 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -36,6 +36,9 @@ void update_freq_counters_refs(void); #define arch_scale_hw_pressure topology_get_hw_pressure #define arch_update_hw_pressure topology_update_hw_pressure +#undef arch_cpu_is_threaded +#define arch_cpu_is_threaded() (read_cpuid_mpidr() & MPIDR_MT_BITMASK) + #include <asm-generic/topology.h> #endif /* _ASM_ARM_TOPOLOGY_H */ diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 5d07ee85bdae..5d24dc53799b 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -25,107 +25,6 @@ #include <asm/cputype.h> #include <asm/topology.h> -#ifdef CONFIG_ACPI -static bool __init acpi_cpu_is_threaded(int cpu) -{ - int is_threaded = acpi_pptt_cpu_is_thread(cpu); - - /* - * if the PPTT doesn't have thread information, assume a homogeneous - * machine and return the current CPU's thread state. - */ - if (is_threaded < 0) - is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK; - - return !!is_threaded; -} - -struct cpu_smt_info { - unsigned int thread_num; - int core_id; -}; - -/* - * Propagate the topology information of the processor_topology_node tree to the - * cpu_topology array. - */ -int __init parse_acpi_topology(void) -{ - unsigned int max_smt_thread_num = 1; - struct cpu_smt_info *entry; - struct xarray hetero_cpu; - unsigned long hetero_id; - int cpu, topology_id; - - if (acpi_disabled) - return 0; - - xa_init(&hetero_cpu); - - for_each_possible_cpu(cpu) { - topology_id = find_acpi_cpu_topology(cpu, 0); - if (topology_id < 0) - return topology_id; - - if (acpi_cpu_is_threaded(cpu)) { - cpu_topology[cpu].thread_id = topology_id; - topology_id = find_acpi_cpu_topology(cpu, 1); - cpu_topology[cpu].core_id = topology_id; - - /* - * In the PPTT, CPUs below a node with the 'identical - * implementation' flag have the same number of threads. - * Count the number of threads for only one CPU (i.e. - * one core_id) among those with the same hetero_id. - * See the comment of find_acpi_cpu_topology_hetero_id() - * for more details. - * - * One entry is created for each node having: - * - the 'identical implementation' flag - * - its parent not having the flag - */ - hetero_id = find_acpi_cpu_topology_hetero_id(cpu); - entry = xa_load(&hetero_cpu, hetero_id); - if (!entry) { - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - WARN_ON_ONCE(!entry); - - if (entry) { - entry->core_id = topology_id; - entry->thread_num = 1; - xa_store(&hetero_cpu, hetero_id, - entry, GFP_KERNEL); - } - } else if (entry->core_id == topology_id) { - entry->thread_num++; - } - } else { - cpu_topology[cpu].thread_id = -1; - cpu_topology[cpu].core_id = topology_id; - } - topology_id = find_acpi_cpu_topology_cluster(cpu); - cpu_topology[cpu].cluster_id = topology_id; - topology_id = find_acpi_cpu_topology_package(cpu); - cpu_topology[cpu].package_id = topology_id; - } - - /* - * This is a short loop since the number of XArray elements is the - * number of heterogeneous CPU clusters. On a homogeneous system - * there's only one entry in the XArray. - */ - xa_for_each(&hetero_cpu, hetero_id, entry) { - max_smt_thread_num = max(max_smt_thread_num, entry->thread_num); - xa_erase(&hetero_cpu, hetero_id); - kfree(entry); - } - - cpu_smt_set_num_threads(max_smt_thread_num, max_smt_thread_num); - xa_destroy(&hetero_cpu); - return 0; -} -#endif - #ifdef CONFIG_ARM64_AMU_EXTN #define read_corecnt() read_sysreg_s(SYS_AMEVCNTR0_CORE_EL0) #define read_constcnt() read_sysreg_s(SYS_AMEVCNTR0_CONST_EL0) diff --git a/arch/x86/include/asm/cpumask.h b/arch/x86/include/asm/cpumask.h index 70f6b60ad67b..9df9e9cde670 100644 --- a/arch/x86/include/asm/cpumask.h +++ b/arch/x86/include/asm/cpumask.h @@ -2,6 +2,8 @@ #ifndef _ASM_X86_CPUMASK_H #define _ASM_X86_CPUMASK_H #ifndef __ASSEMBLER__ + +#include <linux/compiler.h> #include <linux/cpumask.h> extern void setup_cpu_local_masks(void); diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs index e5237e9ec552..ac981614544e 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -19,6 +19,7 @@ use kernel::{ cred::Credential, error::Error, fs::file::{self, File}, + id_pool::IdPool, list::{List, ListArc, ListArcField, ListLinks}, mm, prelude::*, @@ -394,6 +395,8 @@ kernel::list::impl_list_item! { struct ProcessNodeRefs { /// Used to look up nodes using the 32-bit id that this process knows it by. by_handle: RBTree<u32, ListArc<NodeRefInfo, { NodeRefInfo::LIST_PROC }>>, + /// Used to quickly find unused ids in `by_handle`. + handle_is_present: IdPool, /// Used to look up nodes without knowing their local 32-bit id. The usize is the address of /// the underlying `Node` struct as returned by `Node::global_id`. by_node: RBTree<usize, u32>, @@ -408,6 +411,7 @@ impl ProcessNodeRefs { fn new() -> Self { Self { by_handle: RBTree::new(), + handle_is_present: IdPool::new(), by_node: RBTree::new(), freeze_listeners: RBTree::new(), } @@ -802,7 +806,7 @@ impl Process { pub(crate) fn insert_or_update_handle( self: ArcBorrow<'_, Process>, node_ref: NodeRef, - is_mananger: bool, + is_manager: bool, ) -> Result<u32> { { let mut refs = self.node_refs.lock(); @@ -821,7 +825,33 @@ impl Process { let reserve2 = RBTreeNodeReservation::new(GFP_KERNEL)?; let info = UniqueArc::new_uninit(GFP_KERNEL)?; - let mut refs = self.node_refs.lock(); + let mut refs_lock = self.node_refs.lock(); + let mut refs = &mut *refs_lock; + + let (unused_id, by_handle_slot) = loop { + // ID 0 may only be used by the manager. + let start = if is_manager { 0 } else { 1 }; + + if let Some(res) = refs.handle_is_present.find_unused_id(start) { + match refs.by_handle.entry(res.as_u32()) { + rbtree::Entry::Vacant(entry) => break (res, entry), + rbtree::Entry::Occupied(_) => { + pr_err!("Detected mismatch between handle_is_present and by_handle"); + res.acquire(); + kernel::warn_on!(true); + return Err(EINVAL); + } + } + } + + let grow_request = refs.handle_is_present.grow_request().ok_or(ENOMEM)?; + drop(refs_lock); + let resizer = grow_request.realloc(GFP_KERNEL)?; + refs_lock = self.node_refs.lock(); + refs = &mut *refs_lock; + refs.handle_is_present.grow(resizer); + }; + let handle = unused_id.as_u32(); // Do a lookup again as node may have been inserted before the lock was reacquired. if let Some(handle_ref) = refs.by_node.get(&node_ref.node.global_id()) { @@ -831,20 +861,9 @@ impl Process { return Ok(handle); } - // Find id. - let mut target: u32 = if is_mananger { 0 } else { 1 }; - for handle in refs.by_handle.keys() { - if *handle > target { - break; - } - if *handle == target { - target = target.checked_add(1).ok_or(ENOMEM)?; - } - } - let gid = node_ref.node.global_id(); let (info_proc, info_node) = { - let info_init = NodeRefInfo::new(node_ref, target, self.into()); + let info_init = NodeRefInfo::new(node_ref, handle, self.into()); match info.pin_init_with(info_init) { Ok(info) => ListArc::pair_from_pin_unique(info), // error is infallible @@ -865,9 +884,10 @@ impl Process { // `info_node` into the right node's `refs` list. unsafe { info_proc.node_ref2().node.insert_node_info(info_node) }; - refs.by_node.insert(reserve1.into_node(gid, target)); - refs.by_handle.insert(reserve2.into_node(target, info_proc)); - Ok(target) + refs.by_node.insert(reserve1.into_node(gid, handle)); + by_handle_slot.insert(info_proc, reserve2); + unused_id.acquire(); + Ok(handle) } pub(crate) fn get_transaction_node(&self, handle: u32) -> BinderResult<NodeRef> { @@ -932,6 +952,16 @@ impl Process { let id = info.node_ref().node.global_id(); refs.by_handle.remove(&handle); refs.by_node.remove(&id); + refs.handle_is_present.release_id(handle as usize); + + if let Some(shrink) = refs.handle_is_present.shrink_request() { + drop(refs); + // This intentionally ignores allocation failures. + if let Ok(new_bitmap) = shrink.realloc(GFP_KERNEL) { + refs = self.node_refs.lock(); + refs.handle_is_present.shrink(new_bitmap); + } + } } } else { // All refs are cleared in process exit, so this warning is expected in that case. diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index e1eff05bea4a..84ec92bff642 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -823,12 +823,106 @@ void remove_cpu_topology(unsigned int cpu) clear_cpu_topology(cpu); } +#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV) +struct cpu_smt_info { + unsigned int thread_num; + int core_id; +}; + +static bool __init acpi_cpu_is_threaded(int cpu) +{ + int is_threaded = acpi_pptt_cpu_is_thread(cpu); + + /* + * if the PPTT doesn't have thread information, check for architecture + * specific fallback if available + */ + if (is_threaded < 0) + is_threaded = arch_cpu_is_threaded(); + + return !!is_threaded; +} + +/* + * Propagate the topology information of the processor_topology_node tree to the + * cpu_topology array. + */ __weak int __init parse_acpi_topology(void) { + unsigned int max_smt_thread_num = 1; + struct cpu_smt_info *entry; + struct xarray hetero_cpu; + unsigned long hetero_id; + int cpu, topology_id; + + if (acpi_disabled) + return 0; + + xa_init(&hetero_cpu); + + for_each_possible_cpu(cpu) { + topology_id = find_acpi_cpu_topology(cpu, 0); + if (topology_id < 0) + return topology_id; + + if (acpi_cpu_is_threaded(cpu)) { + cpu_topology[cpu].thread_id = topology_id; + topology_id = find_acpi_cpu_topology(cpu, 1); + cpu_topology[cpu].core_id = topology_id; + + /* + * In the PPTT, CPUs below a node with the 'identical + * implementation' flag have the same number of threads. + * Count the number of threads for only one CPU (i.e. + * one core_id) among those with the same hetero_id. + * See the comment of find_acpi_cpu_topology_hetero_id() + * for more details. + * + * One entry is created for each node having: + * - the 'identical implementation' flag + * - its parent not having the flag + */ + hetero_id = find_acpi_cpu_topology_hetero_id(cpu); + entry = xa_load(&hetero_cpu, hetero_id); + if (!entry) { + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + WARN_ON_ONCE(!entry); + + if (entry) { + entry->core_id = topology_id; + entry->thread_num = 1; + xa_store(&hetero_cpu, hetero_id, + entry, GFP_KERNEL); + } + } else if (entry->core_id == topology_id) { + entry->thread_num++; + } + } else { + cpu_topology[cpu].thread_id = -1; + cpu_topology[cpu].core_id = topology_id; + } + topology_id = find_acpi_cpu_topology_cluster(cpu); + cpu_topology[cpu].cluster_id = topology_id; + topology_id = find_acpi_cpu_topology_package(cpu); + cpu_topology[cpu].package_id = topology_id; + } + + /* + * This is a short loop since the number of XArray elements is the + * number of heterogeneous CPU clusters. On a homogeneous system + * there's only one entry in the XArray. + */ + xa_for_each(&hetero_cpu, hetero_id, entry) { + max_smt_thread_num = max(max_smt_thread_num, entry->thread_num); + xa_erase(&hetero_cpu, hetero_id); + kfree(entry); + } + + cpu_smt_set_num_threads(max_smt_thread_num, max_smt_thread_num); + xa_destroy(&hetero_cpu); return 0; } -#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV) void __init init_cpu_topology(void) { int cpu, ret; diff --git a/drivers/base/base.h b/drivers/base/base.h index 86fa7fbb3548..430cbefbc97f 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -85,6 +85,18 @@ struct driver_private { }; #define to_driver(obj) container_of(obj, struct driver_private, kobj) +#ifdef CONFIG_RUST +/** + * struct driver_type - Representation of a Rust driver type. + */ +struct driver_type { + /** + * @id: Representation of core::any::TypeId. + */ + u8 id[16]; +} __packed; +#endif + /** * struct device_private - structure to hold the private to the driver core portions of the device structure. * @@ -100,6 +112,7 @@ struct driver_private { * @async_driver - pointer to device driver awaiting probe via async_probe * @device - pointer back to the struct device that this structure is * associated with. + * @driver_type - The type of the bound Rust driver. * @dead - This device is currently either in the process of or has been * removed from the system. Any asynchronous events scheduled for this * device should exit without taking any action. @@ -116,6 +129,9 @@ struct device_private { const struct device_driver *async_driver; char *deferred_probe_reason; struct device *device; +#ifdef CONFIG_RUST + struct driver_type driver_type; +#endif u8 dead:1; }; #define to_device_private_parent(obj) \ diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 5e75e1bce551..320e155c6be7 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -533,8 +533,7 @@ void bus_probe_device(struct device *dev) if (!sp) return; - if (sp->drivers_autoprobe) - device_initial_probe(dev); + device_initial_probe(dev); mutex_lock(&sp->mutex); list_for_each_entry(sif, &sp->interfaces, node) diff --git a/drivers/base/core.c b/drivers/base/core.c index f69dc9c85954..40de2f51a1b1 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -4138,7 +4138,7 @@ int __init devices_init(void) sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj); if (!sysfs_dev_char_kobj) goto char_kobj_err; - device_link_wq = alloc_workqueue("device_link_wq", 0, 0); + device_link_wq = alloc_workqueue("device_link_wq", WQ_PERCPU, 0); if (!device_link_wq) goto wq_err; diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index fa0a2eef93ac..c6c57b6f61c6 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -300,13 +300,30 @@ static ssize_t print_cpus_isolated(struct device *dev, } static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL); +static ssize_t housekeeping_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct cpumask *hk_mask; + + hk_mask = housekeeping_cpumask(HK_TYPE_KERNEL_NOISE); + + if (housekeeping_enabled(HK_TYPE_KERNEL_NOISE)) + return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(hk_mask)); + return sysfs_emit(buf, "\n"); +} +static DEVICE_ATTR_RO(housekeeping); + #ifdef CONFIG_NO_HZ_FULL -static ssize_t print_cpus_nohz_full(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t nohz_full_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask)); + if (cpumask_available(tick_nohz_full_mask)) + return sysfs_emit(buf, "%*pbl\n", + cpumask_pr_args(tick_nohz_full_mask)); + return sysfs_emit(buf, "\n"); } -static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL); +static DEVICE_ATTR_RO(nohz_full); #endif #ifdef CONFIG_CRASH_HOTPLUG @@ -505,6 +522,7 @@ static struct attribute *cpu_root_attrs[] = { &dev_attr_offline.attr, &dev_attr_enabled.attr, &dev_attr_isolated.attr, + &dev_attr_housekeeping.attr, #ifdef CONFIG_NO_HZ_FULL &dev_attr_nohz_full.attr, #endif diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 13ab98e033ea..349f31bedfa1 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -193,7 +193,7 @@ void driver_deferred_probe_trigger(void) * Kick the re-probe thread. It may already be scheduled, but it is * safe to kick it again. */ - queue_work(system_unbound_wq, &deferred_probe_work); + queue_work(system_dfl_wq, &deferred_probe_work); } /** @@ -1077,7 +1077,15 @@ EXPORT_SYMBOL_GPL(device_attach); void device_initial_probe(struct device *dev) { - __device_attach(dev, true); + struct subsys_private *sp = bus_to_subsys(dev->bus); + + if (!sp) + return; + + if (sp->drivers_autoprobe) + __device_attach(dev, true); + + subsys_put(sp); } /* diff --git a/drivers/base/devres.c b/drivers/base/devres.c index c948c88d3956..f54db6d138ab 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -1222,13 +1222,6 @@ static void devm_percpu_release(struct device *dev, void *pdata) free_percpu(p); } -static int devm_percpu_match(struct device *dev, void *data, void *p) -{ - struct devres *devr = container_of(data, struct devres, data); - - return *(void **)devr->data == p; -} - /** * __devm_alloc_percpu - Resource-managed alloc_percpu * @dev: Device to allocate per-cpu memory for @@ -1264,21 +1257,3 @@ void __percpu *__devm_alloc_percpu(struct device *dev, size_t size, return pcpu; } EXPORT_SYMBOL_GPL(__devm_alloc_percpu); - -/** - * devm_free_percpu - Resource-managed free_percpu - * @dev: Device this memory belongs to - * @pdata: Per-cpu memory to free - * - * Free memory allocated with devm_alloc_percpu(). - */ -void devm_free_percpu(struct device *dev, void __percpu *pdata) -{ - /* - * Use devres_release() to prevent memory leakage as - * devm_free_pages() does. - */ - WARN_ON(devres_release(dev, devm_percpu_release, devm_percpu_match, - (void *)(__force unsigned long)pdata)); -} -EXPORT_SYMBOL_GPL(devm_free_percpu); diff --git a/drivers/base/firmware_loader/sysfs.c b/drivers/base/firmware_loader/sysfs.c index add0b9b75edd..92e91050f96a 100644 --- a/drivers/base/firmware_loader/sysfs.c +++ b/drivers/base/firmware_loader/sysfs.c @@ -47,7 +47,10 @@ static ssize_t timeout_show(const struct class *class, const struct class_attrib static ssize_t timeout_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count) { - int tmp_loading_timeout = simple_strtol(buf, NULL, 10); + int tmp_loading_timeout; + + if (kstrtoint(buf, 10, &tmp_loading_timeout)) + return -EINVAL; if (tmp_loading_timeout < 0) tmp_loading_timeout = 0; @@ -157,7 +160,10 @@ static ssize_t firmware_loading_store(struct device *dev, struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); struct fw_priv *fw_priv; ssize_t written = count; - int loading = simple_strtol(buf, NULL, 10); + int loading; + + if (kstrtoint(buf, 10, &loading)) + return -EINVAL; mutex_lock(&fw_lock); fw_priv = fw_sysfs->fw_priv; diff --git a/drivers/base/firmware_loader/sysfs_upload.c b/drivers/base/firmware_loader/sysfs_upload.c index 829270067d16..c3797b93c5f5 100644 --- a/drivers/base/firmware_loader/sysfs_upload.c +++ b/drivers/base/firmware_loader/sysfs_upload.c @@ -100,8 +100,10 @@ static ssize_t cancel_store(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&fwlp->lock); - if (fwlp->progress == FW_UPLOAD_PROG_IDLE) - ret = -ENODEV; + if (fwlp->progress == FW_UPLOAD_PROG_IDLE) { + mutex_unlock(&fwlp->lock); + return -ENODEV; + } fwlp->ops->cancel(fwlp->fw_upload); mutex_unlock(&fwlp->lock); diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c index e700f40fd87f..e7208c47268b 100644 --- a/drivers/clk/at91/clk-peripheral.c +++ b/drivers/clk/at91/clk-peripheral.c @@ -3,6 +3,7 @@ * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> */ +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 5daa32c4cf25..543d7aee8d24 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -117,9 +117,6 @@ struct at91_clk_pms { unsigned int parent; }; -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - #define ndck(a, s) (a[s - 1].id + 1) #define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1) diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c index 3abd6e5400ad..f7b827b5e9b2 100644 --- a/drivers/clk/renesas/clk-div6.c +++ b/drivers/clk/renesas/clk-div6.c @@ -7,6 +7,7 @@ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> */ +#include <linux/bitfield.h> #include <linux/clk-provider.h> #include <linux/init.h> #include <linux/io.h> @@ -171,8 +172,7 @@ static u8 cpg_div6_clock_get_parent(struct clk_hw *hw) if (clock->src_mask == 0) return 0; - hw_index = (readl(clock->reg) & clock->src_mask) >> - __ffs(clock->src_mask); + hw_index = field_get(clock->src_mask, readl(clock->reg)); for (i = 0; i < clk_hw_get_num_parents(hw); i++) { if (clock->parents[i] == hw_index) return i; @@ -191,7 +191,7 @@ static int cpg_div6_clock_set_parent(struct clk_hw *hw, u8 index) if (index >= clk_hw_get_num_parents(hw)) return -EINVAL; - src = clock->parents[index] << __ffs(clock->src_mask); + src = field_prep(clock->src_mask, clock->parents[index]); writel((readl(clock->reg) & ~clock->src_mask) | src, clock->reg); return 0; } diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 10ae20489df9..b954278ddd9d 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -54,10 +54,8 @@ static unsigned long cpg_pll_clk_recalc_rate(struct clk_hw *hw, { struct cpg_pll_clk *pll_clk = to_pll_clk(hw); unsigned int mult; - u32 val; - val = readl(pll_clk->pllcr_reg) & CPG_PLLnCR_STC_MASK; - mult = (val >> __ffs(CPG_PLLnCR_STC_MASK)) + 1; + mult = FIELD_GET(CPG_PLLnCR_STC_MASK, readl(pll_clk->pllcr_reg)) + 1; return parent_rate * mult * pll_clk->fixed_mult; } @@ -94,7 +92,7 @@ static int cpg_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, val = readl(pll_clk->pllcr_reg); val &= ~CPG_PLLnCR_STC_MASK; - val |= (mult - 1) << __ffs(CPG_PLLnCR_STC_MASK); + val |= FIELD_PREP(CPG_PLLnCR_STC_MASK, mult - 1); writel(val, pll_clk->pllcr_reg); for (i = 1000; i; i--) { @@ -176,11 +174,7 @@ static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct cpg_z_clk *zclk = to_z_clk(hw); - unsigned int mult; - u32 val; - - val = readl(zclk->reg) & zclk->mask; - mult = 32 - (val >> __ffs(zclk->mask)); + unsigned int mult = 32 - field_get(zclk->mask, readl(zclk->reg)); return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, 32 * zclk->fixed_div); @@ -231,7 +225,8 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) return -EBUSY; - cpg_reg_modify(zclk->reg, zclk->mask, (32 - mult) << __ffs(zclk->mask)); + cpg_reg_modify(zclk->reg, zclk->mask, + field_prep(zclk->mask, 32 - mult)); /* * Set KICK bit in FRQCRB to update hardware setting and wait for diff --git a/drivers/clk/renesas/rcar-gen4-cpg.c b/drivers/clk/renesas/rcar-gen4-cpg.c index fb9a876aaba5..db3a0b8ef2b9 100644 --- a/drivers/clk/renesas/rcar-gen4-cpg.c +++ b/drivers/clk/renesas/rcar-gen4-cpg.c @@ -279,11 +279,7 @@ static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct cpg_z_clk *zclk = to_z_clk(hw); - unsigned int mult; - u32 val; - - val = readl(zclk->reg) & zclk->mask; - mult = 32 - (val >> __ffs(zclk->mask)); + unsigned int mult = 32 - field_get(zclk->mask, readl(zclk->reg)); return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, 32 * zclk->fixed_div); @@ -334,7 +330,8 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) return -EBUSY; - cpg_reg_modify(zclk->reg, zclk->mask, (32 - mult) << __ffs(zclk->mask)); + cpg_reg_modify(zclk->reg, zclk->mask, + field_prep(zclk->mask, 32 - mult)); /* * Set KICK bit in FRQCRB to update hardware setting and wait for diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs index 53923b8ef7a1..31e07f0279db 100644 --- a/drivers/cpufreq/rcpufreq_dt.rs +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -207,9 +207,9 @@ impl platform::Driver for CPUFreqDTDriver { fn probe( pdev: &platform::Device<Core>, _id_info: Option<&Self::IdInfo>, - ) -> Result<Pin<KBox<Self>>> { + ) -> impl PinInit<Self, Error> { cpufreq::Registration::<CPUFreqDTDriver>::new_foreign_owned(pdev.as_ref())?; - Ok(KBox::new(Self {}, GFP_KERNEL)?.into()) + Ok(Self {}) } } diff --git a/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c b/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c index 69295a9ddf0a..4ccc94ed9493 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c +++ b/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c @@ -1,18 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2025 Intel Corporation */ +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/sprintf.h> #include <linux/string_helpers.h> #include "adf_pm_dbgfs_utils.h" -/* - * This is needed because a variable is used to index the mask at - * pm_scnprint_table(), making it not compile time constant, so the compile - * asserts from FIELD_GET() or u32_get_bits() won't be fulfilled. - */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) - #define PM_INFO_MAX_KEY_LEN 21 static int pm_scnprint_table(char *buff, const struct pm_status_row *table, diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c index 8d4ddaa85ae8..eaab6af143e1 100644 --- a/drivers/edac/ie31200_edac.c +++ b/drivers/edac/ie31200_edac.c @@ -44,6 +44,7 @@ * but lo_hi_readq() ensures that we are safe across all e3-1200 processors. */ +#include <linux/bitfield.h> #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> @@ -139,9 +140,6 @@ #define IE31200_CAPID0_DDPCD BIT(6) #define IE31200_CAPID0_ECC BIT(1) -/* Non-constant mask variant of FIELD_GET() */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) - static int nr_channels; static struct pci_dev *mci_pdev; static int ie31200_registered = 1; diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 2e0ae953dd99..cbdf781994dc 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -5,6 +5,7 @@ * Joel Stanley <joel@jms.id.au> */ +#include <linux/bitfield.h> #include <linux/cleanup.h> #include <linux/clk.h> #include <linux/gpio/aspeed.h> @@ -30,10 +31,6 @@ */ #include <linux/gpio/consumer.h> -/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - #define GPIO_G7_IRQ_STS_BASE 0x100 #define GPIO_G7_IRQ_STS_OFFSET(x) (GPIO_G7_IRQ_STS_BASE + (x) * 0x4) #define GPIO_G7_CTRL_REG_BASE 0x180 diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs index 91b7380f83ab..2246d8e104e0 100644 --- a/drivers/gpu/drm/nova/driver.rs +++ b/drivers/gpu/drm/nova/driver.rs @@ -45,13 +45,13 @@ impl auxiliary::Driver for NovaDriver { type IdInfo = (); const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE; - fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { + fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { let data = try_pin_init!(NovaData { adev: adev.into() }); let drm = drm::Device::<Self>::new(adev.as_ref(), data)?; drm::Registration::new_foreign_owned(&drm, adev.as_ref(), 0)?; - Ok(KBox::new(Self { drm }, GFP_KERNEL)?.into()) + Ok(Self { drm }) } } diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs index 90b9d2d0ec4a..a3b7bd36792c 100644 --- a/drivers/gpu/drm/nova/file.rs +++ b/drivers/gpu/drm/nova/file.rs @@ -28,7 +28,7 @@ impl File { _file: &drm::File<File>, ) -> Result<u32> { let adev = &dev.adev; - let parent = adev.parent().ok_or(ENOENT)?; + let parent = adev.parent(); let pdev: &pci::Device = parent.try_into()?; let value = match getparam.param as u32 { diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index d5625dd1e41c..0389c558c036 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -103,7 +103,7 @@ impl platform::Driver for TyrDriver { fn probe( pdev: &platform::Device<Core>, _info: Option<&Self::IdInfo>, - ) -> Result<Pin<KBox<Self>>> { + ) -> impl PinInit<Self, Error> { let core_clk = Clk::get(pdev.as_ref(), Some(c_str!("core")))?; let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("stacks")))?; let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("coregroup")))?; @@ -143,7 +143,7 @@ impl platform::Driver for TyrDriver { let tdev: ARef<TyrDevice> = drm::Device::new(pdev.as_ref(), data)?; drm::driver::Registration::new_foreign_owned(&tdev, pdev.as_ref(), 0)?; - let driver = KBox::pin_init(try_pin_init!(TyrDriver { device: tdev }), GFP_KERNEL)?; + let driver = TyrDriver { device: tdev }; // We need this to be dev_info!() because dev_dbg!() does not work at // all in Rust for now, and we need to see whether probe succeeded. diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index d91bbc50cde7..b8b0cc0f2d93 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -4,6 +4,7 @@ use kernel::{ auxiliary, c_str, device::Core, + devres::Devres, dma::Device, dma::DmaMask, pci, @@ -23,7 +24,8 @@ use crate::gpu::Gpu; pub(crate) struct NovaCore { #[pin] pub(crate) gpu: Gpu, - _reg: auxiliary::Registration, + #[pin] + _reg: Devres<auxiliary::Registration>, } const BAR0_SIZE: usize = SZ_16M; @@ -67,41 +69,33 @@ impl pci::Driver for NovaCore { type IdInfo = (); const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; - fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { - dev_dbg!(pdev.as_ref(), "Probe Nova Core GPU driver.\n"); - - pdev.enable_device_mem()?; - pdev.set_master(); + fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { + pin_init::pin_init_scope(move || { + dev_dbg!(pdev.as_ref(), "Probe Nova Core GPU driver.\n"); - // SAFETY: No concurrent DMA allocations or mappings can be made because - // the device is still being probed and therefore isn't being used by - // other threads of execution. - unsafe { pdev.dma_set_mask_and_coherent(DmaMask::new::<GPU_DMA_BITS>())? }; + pdev.enable_device_mem()?; + pdev.set_master(); - let devres_bar = Arc::pin_init( - pdev.iomap_region_sized::<BAR0_SIZE>(0, c_str!("nova-core/bar0")), - GFP_KERNEL, - )?; + // SAFETY: No concurrent DMA allocations or mappings can be made because + // the device is still being probed and therefore isn't being used by + // other threads of execution. + unsafe { pdev.dma_set_mask_and_coherent(DmaMask::new::<GPU_DMA_BITS>())? }; - // Used to provided a `&Bar0` to `Gpu::new` without tying it to the lifetime of - // `devres_bar`. - let bar_clone = Arc::clone(&devres_bar); - let bar = bar_clone.access(pdev.as_ref())?; + let bar = Arc::pin_init( + pdev.iomap_region_sized::<BAR0_SIZE>(0, c_str!("nova-core/bar0")), + GFP_KERNEL, + )?; - let this = KBox::pin_init( - try_pin_init!(Self { - gpu <- Gpu::new(pdev, devres_bar, bar), - _reg: auxiliary::Registration::new( + Ok(try_pin_init!(Self { + gpu <- Gpu::new(pdev, bar.clone(), bar.access(pdev.as_ref())?), + _reg <- auxiliary::Registration::new( pdev.as_ref(), c_str!("nova-drm"), 0, // TODO[XARR]: Once it lands, use XArray; for now we don't use the ID. crate::MODULE_NAME - )?, - }), - GFP_KERNEL, - )?; - - Ok(this) + ), + })) + }) } fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) { diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c index 6134613777b8..b97b46090d80 100644 --- a/drivers/iio/dac/ad3530r.c +++ b/drivers/iio/dac/ad3530r.c @@ -53,9 +53,6 @@ #define AD3530R_MAX_CHANNELS 8 #define AD3531R_MAX_CHANNELS 4 -/* Non-constant mask variant of FIELD_PREP() */ -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - enum ad3530r_mode { AD3530R_NORMAL_OP, AD3530R_POWERDOWN_1K, diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 8a44a00bfd5e..1ad21b73e1b4 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -22,6 +22,7 @@ * the "wakeup" GPIO is not given, power management will be disabled. */ +#include <linux/bitfield.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/gpio/consumer.h> @@ -68,10 +69,6 @@ #define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */ #define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */ -/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - struct mlx_chip_info { /* EEPROM offsets with 16-bit data, MSB first */ /* emissivity correction coefficient */ diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index cdd2ac198f2c..3932a449a1b1 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -10,7 +10,7 @@ /* driver definitions */ -#define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>"; +#define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>" #define DRIVER_CARD "Silicon Labs Si470x FM Radio" #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" #define DRIVER_VERSION "1.0.2" diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 0c510035805b..05c18b6de5c6 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -70,12 +70,12 @@ #include "ts2020.h" -#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw"; -#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw"; -#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw"; -#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw"; -#define LME2510_LG "dvb-usb-lme2510-lg.fw"; -#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw"; +#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw" +#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw" +#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw" +#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw" +#define LME2510_LG "dvb-usb-lme2510-lg.fw" +#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw" /* debug */ static int dvb_usb_lme2510_debug; diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35.c b/drivers/pinctrl/nuvoton/pinctrl-ma35.c index cdad01d68a37..8d71dc53cc1d 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-ma35.c +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35.c @@ -81,10 +81,6 @@ #define MVOLT_1800 0 #define MVOLT_3300 1 -/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - static const char * const gpio_group_name[] = { "gpioa", "gpiob", "gpioc", "gpiod", "gpioe", "gpiof", "gpiog", "gpioh", "gpioi", "gpioj", "gpiok", "gpiol", "gpiom", "gpion", diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index 955c359b07fb..e3b7e77356fc 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -337,7 +337,7 @@ impl platform::Driver for Th1520PwmPlatformDriver { fn probe( pdev: &platform::Device<Core>, _id_info: Option<&Self::IdInfo>, - ) -> Result<Pin<KBox<Self>>> { + ) -> impl PinInit<Self, Error> { let dev = pdev.as_ref(); let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; @@ -374,7 +374,7 @@ impl platform::Driver for Th1520PwmPlatformDriver { pwm::Registration::register(dev, chip)?; - Ok(KBox::new(Th1520PwmPlatformDriver, GFP_KERNEL)?.into()) + Ok(Th1520PwmPlatformDriver) } } diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index 1eb52356b996..ee4f17bb4db4 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -5,6 +5,7 @@ * Copyright (C) 2014-2016 Glider bvba */ +#include <linux/bitfield.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> @@ -524,8 +525,7 @@ static int __init renesas_soc_init(void) eshi, eslo); } - if (soc->id && - ((product & id->mask) >> __ffs(id->mask)) != soc->id) { + if (soc->id && field_get(id->mask, product) != soc->id) { pr_warn("SoC mismatch (product = 0x%x)\n", product); ret = -ENODEV; goto free_soc_dev_attr; diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c index 19c1e666279b..ae727d9c8cc5 100644 --- a/drivers/soc/renesas/rz-sysc.c +++ b/drivers/soc/renesas/rz-sysc.c @@ -5,6 +5,7 @@ * Copyright (C) 2024 Renesas Electronics Corp. */ +#include <linux/bitfield.h> #include <linux/cleanup.h> #include <linux/io.h> #include <linux/mfd/syscon.h> @@ -16,8 +17,6 @@ #include "rz-sysc.h" -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) - /** * struct rz_sysc - RZ SYSC private data structure * @base: SYSC base address diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 5f15f855b4b9..4b263c328ed2 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -35,7 +35,7 @@ static struct vfsmount *debugfs_mount; static int debugfs_mount_count; static bool debugfs_registered; -static unsigned int debugfs_allow __ro_after_init = DEFAULT_DEBUGFS_ALLOW_BITS; +static bool debugfs_enabled __ro_after_init = IS_ENABLED(CONFIG_DEBUG_FS_ALLOW_ALL); /* * Don't allow access attributes to be changed whilst the kernel is locked down @@ -287,9 +287,6 @@ static int debugfs_get_tree(struct fs_context *fc) { int err; - if (!(debugfs_allow & DEBUGFS_ALLOW_API)) - return -EPERM; - err = get_tree_single(fc, debugfs_fill_super); if (err) return err; @@ -368,7 +365,7 @@ static struct dentry *debugfs_start_creating(const char *name, struct dentry *dentry; int error; - if (!(debugfs_allow & DEBUGFS_ALLOW_API)) + if (!debugfs_enabled) return ERR_PTR(-EPERM); if (!debugfs_initialized()) @@ -883,21 +880,25 @@ static int __init debugfs_kernel(char *str) { if (str) { if (!strcmp(str, "on")) - debugfs_allow = DEBUGFS_ALLOW_API | DEBUGFS_ALLOW_MOUNT; - else if (!strcmp(str, "no-mount")) - debugfs_allow = DEBUGFS_ALLOW_API; + debugfs_enabled = true; else if (!strcmp(str, "off")) - debugfs_allow = 0; + debugfs_enabled = false; + else if (!strcmp(str, "no-mount")) { + pr_notice("debugfs=no-mount is a deprecated alias " + "for debugfs=off\n"); + debugfs_enabled = false; + } } return 0; } early_param("debugfs", debugfs_kernel); + static int __init debugfs_init(void) { int retval; - if (!(debugfs_allow & DEBUGFS_ALLOW_MOUNT)) + if (!debugfs_enabled) return -EPERM; retval = sysfs_create_mount_point(kernel_kobj, "debug"); diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index 427987f81571..c95699b27a56 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -55,17 +55,4 @@ enum { HAS_IOCTL = 16 }; -#define DEBUGFS_ALLOW_API BIT(0) -#define DEBUGFS_ALLOW_MOUNT BIT(1) - -#ifdef CONFIG_DEBUG_FS_ALLOW_ALL -#define DEFAULT_DEBUGFS_ALLOW_BITS (DEBUGFS_ALLOW_MOUNT | DEBUGFS_ALLOW_API) -#endif -#ifdef CONFIG_DEBUG_FS_DISALLOW_MOUNT -#define DEFAULT_DEBUGFS_ALLOW_BITS (DEBUGFS_ALLOW_API) -#endif -#ifdef CONFIG_DEBUG_FS_ALLOW_NONE -#define DEFAULT_DEBUGFS_ALLOW_BITS (0) -#endif - #endif /* _DEBUGFS_INTERNAL_H_ */ diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index a670ba3e565e..5c0efd6b239f 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -675,11 +675,14 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, if (parent) { ret = security_kernfs_init_security(parent, kn); if (ret) - goto err_out3; + goto err_out4; } return kn; + err_out4: + simple_xattrs_free(&kn->iattr->xattrs, NULL); + kmem_cache_free(kernfs_iattrs_cache, kn->iattr); err_out3: spin_lock(&root->kernfs_idr_lock); idr_remove(&root->ino_idr, (u32)kernfs_ino(kn)); diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 76eaf64b9d9e..3ac52e141766 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -298,6 +298,7 @@ static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *k if (info->root->flags & KERNFS_ROOT_SUPPORT_EXPORTOP) sb->s_export_op = &kernfs_export_ops; sb->s_time_gran = 1; + sb->s_maxbytes = MAX_LFS_FILESIZE; /* sysfs dentries and inodes don't require IO to create */ sb->s_shrink->seeks = 0; diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index e142bac4f9f8..e1e639f515a0 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -36,6 +36,9 @@ static umode_t __first_visible(const struct attribute_group *grp, struct kobject if (grp->attrs && grp->attrs[0] && grp->is_visible) return grp->is_visible(kobj, grp->attrs[0], 0); + if (grp->attrs && grp->attrs[0] && grp->is_visible_const) + return grp->is_visible_const(kobj, grp->attrs[0], 0); + if (grp->bin_attrs && grp->bin_attrs[0] && grp->is_bin_visible) return grp->is_bin_visible(kobj, grp->bin_attrs[0], 0); @@ -61,8 +64,11 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj, */ if (update) kernfs_remove_by_name(parent, (*attr)->name); - if (grp->is_visible) { - mode = grp->is_visible(kobj, *attr, i); + if (grp->is_visible || grp->is_visible_const) { + if (grp->is_visible) + mode = grp->is_visible(kobj, *attr, i); + else + mode = grp->is_visible_const(kobj, *attr, i); mode &= ~SYSFS_GROUP_INVISIBLE; if (!mode) continue; diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h index 0c2a8b846c20..ebd7f8935f96 100644 --- a/include/linux/arch_topology.h +++ b/include/linux/arch_topology.h @@ -80,6 +80,11 @@ extern struct cpu_topology cpu_topology[NR_CPUS]; #define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling) #define topology_cluster_cpumask(cpu) (&cpu_topology[cpu].cluster_sibling) #define topology_llc_cpumask(cpu) (&cpu_topology[cpu].llc_sibling) + +#ifndef arch_cpu_is_threaded +#define arch_cpu_is_threaded() (0) +#endif + void init_cpu_topology(void); void store_cpu_topology(unsigned int cpuid); const struct cpumask *cpu_coregroup_mask(int cpu); diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index 5355f8f806a9..126dc5b380af 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -17,6 +17,7 @@ * FIELD_{GET,PREP} macros take as first parameter shifted mask * from which they extract the base mask and shift amount. * Mask must be a compilation time constant. + * field_{get,prep} are variants that take a non-const mask. * * Example: * @@ -60,7 +61,7 @@ #define __bf_cast_unsigned(type, x) ((__unsigned_scalar_typeof(type))(x)) -#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \ +#define __BF_FIELD_CHECK_MASK(_mask, _val, _pfx) \ ({ \ BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \ _pfx "mask is not constant"); \ @@ -69,13 +70,33 @@ ~((_mask) >> __bf_shf(_mask)) & \ (0 + (_val)) : 0, \ _pfx "value too large for the field"); \ - BUILD_BUG_ON_MSG(__bf_cast_unsigned(_mask, _mask) > \ - __bf_cast_unsigned(_reg, ~0ull), \ - _pfx "type of reg too small for mask"); \ __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ (1ULL << __bf_shf(_mask))); \ }) +#define __BF_FIELD_CHECK_REG(mask, reg, pfx) \ + BUILD_BUG_ON_MSG(__bf_cast_unsigned(mask, mask) > \ + __bf_cast_unsigned(reg, ~0ull), \ + pfx "type of reg too small for mask") + +#define __BF_FIELD_CHECK(mask, reg, val, pfx) \ + ({ \ + __BF_FIELD_CHECK_MASK(mask, val, pfx); \ + __BF_FIELD_CHECK_REG(mask, reg, pfx); \ + }) + +#define __FIELD_PREP(mask, val, pfx) \ + ({ \ + __BF_FIELD_CHECK_MASK(mask, val, pfx); \ + ((typeof(mask))(val) << __bf_shf(mask)) & (mask); \ + }) + +#define __FIELD_GET(mask, reg, pfx) \ + ({ \ + __BF_FIELD_CHECK_MASK(mask, 0U, pfx); \ + (typeof(mask))(((reg) & (mask)) >> __bf_shf(mask)); \ + }) + /** * FIELD_MAX() - produce the maximum value representable by a field * @_mask: shifted mask defining the field's length and position @@ -112,8 +133,8 @@ */ #define FIELD_PREP(_mask, _val) \ ({ \ - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \ - ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ + __BF_FIELD_CHECK_REG(_mask, 0ULL, "FIELD_PREP: "); \ + __FIELD_PREP(_mask, _val, "FIELD_PREP: "); \ }) #define __BF_CHECK_POW2(n) BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) != 0) @@ -152,8 +173,8 @@ */ #define FIELD_GET(_mask, _reg) \ ({ \ - __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ - (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ + __BF_FIELD_CHECK_REG(_mask, _reg, "FIELD_GET: "); \ + __FIELD_GET(_mask, _reg, "FIELD_GET: "); \ }) /** @@ -220,4 +241,62 @@ __MAKE_OP(64) #undef __MAKE_OP #undef ____MAKE_OP +#define __field_prep(mask, val) \ + ({ \ + __auto_type __mask = (mask); \ + typeof(__mask) __val = (val); \ + unsigned int __shift = BITS_PER_TYPE(__mask) <= 32 ? \ + __ffs(__mask) : __ffs64(__mask); \ + (__val << __shift) & __mask; \ + }) + +#define __field_get(mask, reg) \ + ({ \ + __auto_type __mask = (mask); \ + typeof(__mask) __reg = (reg); \ + unsigned int __shift = BITS_PER_TYPE(__mask) <= 32 ? \ + __ffs(__mask) : __ffs64(__mask); \ + (__reg & __mask) >> __shift; \ + }) + +/** + * field_prep() - prepare a bitfield element + * @mask: shifted mask defining the field's length and position, must be + * non-zero + * @val: value to put in the field + * + * Return: field value masked and shifted to its final destination + * + * field_prep() masks and shifts up the value. The result should be + * combined with other fields of the bitfield using logical OR. + * Unlike FIELD_PREP(), @mask is not limited to a compile-time constant. + * Typical usage patterns are a value stored in a table, or calculated by + * shifting a constant by a variable number of bits. + * If you want to ensure that @mask is a compile-time constant, please use + * FIELD_PREP() directly instead. + */ +#define field_prep(mask, val) \ + (__builtin_constant_p(mask) ? __FIELD_PREP(mask, val, "field_prep: ") \ + : __field_prep(mask, val)) + +/** + * field_get() - extract a bitfield element + * @mask: shifted mask defining the field's length and position, must be + * non-zero + * @reg: value of entire bitfield + * + * Return: extracted field value + * + * field_get() extracts the field specified by @mask from the + * bitfield passed in as @reg by masking and shifting it down. + * Unlike FIELD_GET(), @mask is not limited to a compile-time constant. + * Typical usage patterns are a value stored in a table, or calculated by + * shifting a constant by a variable number of bits. + * If you want to ensure that @mask is a compile-time constant, please use + * FIELD_GET() directly instead. + */ +#define field_get(mask, reg) \ + (__builtin_constant_p(mask) ? __FIELD_GET(mask, reg, "field_get: ") \ + : __field_get(mask, reg)) + #endif diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index afedfd5bea07..80211900f373 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -7,14 +7,16 @@ * set of CPUs in a system, one bit position per CPU number. In general, * only nr_cpu_ids (<= NR_CPUS) bits are valid. */ -#include <linux/cleanup.h> -#include <linux/kernel.h> +#include <linux/atomic.h> #include <linux/bitmap.h> +#include <linux/cleanup.h> #include <linux/cpumask_types.h> -#include <linux/atomic.h> -#include <linux/bug.h> #include <linux/gfp_types.h> #include <linux/numa.h> +#include <linux/threads.h> +#include <linux/types.h> + +#include <asm/bug.h> /** * cpumask_pr_args - printf args to output a cpumask diff --git a/include/linux/device.h b/include/linux/device.h index b031ff71a5bd..0be95294b6e6 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -281,25 +281,6 @@ int __must_check device_create_bin_file(struct device *dev, void device_remove_bin_file(struct device *dev, const struct bin_attribute *attr); -/** - * devm_alloc_percpu - Resource-managed alloc_percpu - * @dev: Device to allocate per-cpu memory for - * @type: Type to allocate per-cpu memory for - * - * Managed alloc_percpu. Per-cpu memory allocated with this function is - * automatically freed on driver detach. - * - * RETURNS: - * Pointer to allocated memory on success, NULL on failure. - */ -#define devm_alloc_percpu(dev, type) \ - ((typeof(type) __percpu *)__devm_alloc_percpu((dev), sizeof(type), \ - __alignof__(type))) - -void __percpu *__devm_alloc_percpu(struct device *dev, size_t size, - size_t align); -void devm_free_percpu(struct device *dev, void __percpu *pdata); - struct device_dma_parameters { /* * a low level driver may set these to teach IOMMU code about diff --git a/include/linux/device/devres.h b/include/linux/device/devres.h index 8c5f57e0d613..9c1e3d643d69 100644 --- a/include/linux/device/devres.h +++ b/include/linux/device/devres.h @@ -9,6 +9,7 @@ #include <linux/stdarg.h> #include <linux/types.h> #include <asm/bug.h> +#include <asm/percpu.h> struct device; struct device_node; @@ -96,6 +97,22 @@ devm_kvasprintf(struct device *dev, gfp_t gfp, const char *fmt, va_list ap); char * __printf(3, 4) __malloc devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...); +/** + * devm_alloc_percpu - Resource-managed alloc_percpu + * @dev: Device to allocate per-cpu memory for + * @type: Type to allocate per-cpu memory for + * + * Managed alloc_percpu. Per-cpu memory allocated with this function is + * automatically freed on driver detach. + * + * RETURNS: + * Pointer to allocated memory on success, NULL on failure. + */ +#define devm_alloc_percpu(dev, type) \ + ((typeof(type) __percpu *)__devm_alloc_percpu((dev), sizeof(type), __alignof__(type))) + +void __percpu *__devm_alloc_percpu(struct device *dev, size_t size, size_t align); + unsigned long devm_get_free_pages(struct device *dev, gfp_t gfp_mask, unsigned int order); void devm_free_pages(struct device *dev, unsigned long addr); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 6077972e8b45..24eb5a88a5c5 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -867,7 +867,7 @@ struct mhi_device_id { kernel_ulong_t driver_data; }; -#define AUXILIARY_NAME_SIZE 32 +#define AUXILIARY_NAME_SIZE 40 #define AUXILIARY_MODULE_PREFIX "auxiliary:" struct auxiliary_device_id { diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 6907aedc4f74..915f32f7d888 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -26,6 +26,9 @@ /* Generic info of form tag = "info" */ #define MODULE_INFO(tag, info) \ + static_assert( \ + sizeof(info) - 1 == __builtin_strlen(info), \ + "MODULE_INFO(" #tag ", ...) contains embedded NUL byte"); \ static const char __UNIQUE_ID(modinfo)[] \ __used __section(".modinfo") __aligned(1) \ = __MODULE_INFO_PREFIX __stringify(tag) "=" info diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 7ad1f5c7407e..bd38648c998d 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -245,18 +245,18 @@ static __always_inline int __nodes_weight(const nodemask_t *srcp, unsigned int n } /* FIXME: better would be to fix all architectures to never return - > MAX_NUMNODES, then the silly min_ts could be dropped. */ + > MAX_NUMNODES, then the silly min()s could be dropped. */ #define first_node(src) __first_node(&(src)) static __always_inline unsigned int __first_node(const nodemask_t *srcp) { - return min_t(unsigned int, MAX_NUMNODES, find_first_bit(srcp->bits, MAX_NUMNODES)); + return min(MAX_NUMNODES, find_first_bit(srcp->bits, MAX_NUMNODES)); } #define next_node(n, src) __next_node((n), &(src)) static __always_inline unsigned int __next_node(int n, const nodemask_t *srcp) { - return min_t(unsigned int, MAX_NUMNODES, find_next_bit(srcp->bits, MAX_NUMNODES, n+1)); + return min(MAX_NUMNODES, find_next_bit(srcp->bits, MAX_NUMNODES, n+1)); } /* @@ -293,8 +293,7 @@ static __always_inline void init_nodemask_of_node(nodemask_t *mask, int node) #define first_unset_node(mask) __first_unset_node(&(mask)) static __always_inline unsigned int __first_unset_node(const nodemask_t *maskp) { - return min_t(unsigned int, MAX_NUMNODES, - find_first_zero_bit(maskp->bits, MAX_NUMNODES)); + return min(MAX_NUMNODES, find_first_zero_bit(maskp->bits, MAX_NUMNODES)); } #define NODE_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(MAX_NUMNODES) diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 93c945331f39..813da101b5bf 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -80,7 +80,7 @@ static inline void __iomem * devm_platform_get_and_ioremap_resource(struct platform_device *pdev, unsigned int index, struct resource **res) { - return ERR_PTR(-EINVAL); + return IOMEM_ERR_PTR(-EINVAL); } @@ -88,14 +88,14 @@ static inline void __iomem * devm_platform_ioremap_resource(struct platform_device *pdev, unsigned int index) { - return ERR_PTR(-EINVAL); + return IOMEM_ERR_PTR(-EINVAL); } static inline void __iomem * devm_platform_ioremap_resource_byname(struct platform_device *pdev, const char *name) { - return ERR_PTR(-EINVAL); + return IOMEM_ERR_PTR(-EINVAL); } #endif diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 9a25a2911652..c33a96b7391a 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -58,6 +58,12 @@ do { \ #define sysfs_attr_init(attr) do {} while (0) #endif +#ifdef CONFIG_CFI +#define __SYSFS_FUNCTION_ALTERNATIVE(MEMBERS...) struct { MEMBERS } +#else +#define __SYSFS_FUNCTION_ALTERNATIVE(MEMBERS...) union { MEMBERS } +#endif + /** * struct attribute_group - data structure used to declare an attribute group. * @name: Optional: Attribute group name @@ -98,14 +104,21 @@ do { \ */ struct attribute_group { const char *name; - umode_t (*is_visible)(struct kobject *, - struct attribute *, int); + __SYSFS_FUNCTION_ALTERNATIVE( + umode_t (*is_visible)(struct kobject *, + struct attribute *, int); + umode_t (*is_visible_const)(struct kobject *, + const struct attribute *, int); + ); umode_t (*is_bin_visible)(struct kobject *, const struct bin_attribute *, int); size_t (*bin_size)(struct kobject *, const struct bin_attribute *, int); - struct attribute **attrs; + union { + struct attribute **attrs; + const struct attribute *const *attrs_const; + }; const struct bin_attribute *const *bin_attrs; }; @@ -238,28 +251,20 @@ struct attribute_group { .store = _store, \ } -#define __ATTR_RO(_name) { \ - .attr = { .name = __stringify(_name), .mode = 0444 }, \ - .show = _name##_show, \ -} - #define __ATTR_RO_MODE(_name, _mode) { \ .attr = { .name = __stringify(_name), \ .mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \ .show = _name##_show, \ } -#define __ATTR_RW_MODE(_name, _mode) { \ - .attr = { .name = __stringify(_name), \ - .mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \ - .show = _name##_show, \ - .store = _name##_store, \ -} +#define __ATTR_RO(_name) \ + __ATTR_RO_MODE(_name, 0444) -#define __ATTR_WO(_name) { \ - .attr = { .name = __stringify(_name), .mode = 0200 }, \ - .store = _name##_store, \ -} +#define __ATTR_RW_MODE(_name, _mode) \ + __ATTR(_name, _mode, _name##_show, _name##_store) + +#define __ATTR_WO(_name) \ + __ATTR(_name, 0200, NULL, _name##_store) #define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store) @@ -284,7 +289,12 @@ static const struct attribute_group *_name##_groups[] = { \ #define ATTRIBUTE_GROUPS(_name) \ static const struct attribute_group _name##_group = { \ - .attrs = _name##_attrs, \ + .attrs = _Generic(_name##_attrs, \ + struct attribute **: \ + _name##_attrs, \ + const struct attribute *const *: \ + (void *)_name##_attrs \ + ), \ }; \ __ATTRIBUTE_GROUPS(_name) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 742b23ef0d8b..c2654075377e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -688,7 +688,7 @@ choice help This selects the default access restrictions for debugfs. It can be overridden with kernel command line option - debugfs=[on,no-mount,off]. The restrictions apply for API access + debugfs=[on,off]. The restrictions apply for API access and filesystem registration. config DEBUG_FS_ALLOW_ALL @@ -697,13 +697,6 @@ config DEBUG_FS_ALLOW_ALL No restrictions apply. Both API and filesystem registration is on. This is the normal default operation. -config DEBUG_FS_DISALLOW_MOUNT - bool "Do not register debugfs as filesystem" - help - The API is open but filesystem is not loaded. Clients can still do - their work and read with debug tools that do not need - debugfs filesystem. - config DEBUG_FS_ALLOW_NONE bool "No access" help diff --git a/lib/hweight.c b/lib/hweight.c index c94586b62551..0dfcafc3fd39 100644 --- a/lib/hweight.c +++ b/lib/hweight.c @@ -4,8 +4,8 @@ #include <asm/types.h> /** - * hweightN - returns the hamming weight of a N-bit word - * @x: the word to weigh + * DOC: __sw_hweightN - returns the hamming weight of a N-bit word + * @w: the word to weigh * * The Hamming Weight of a number is the total number of bits set in it. */ diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 139786c0337d..5ea7b49f7dd9 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -58,6 +58,7 @@ #include <linux/firmware.h> #include <linux/interrupt.h> #include <linux/fs.h> +#include <linux/i2c.h> #include <linux/ioport.h> #include <linux/jiffies.h> #include <linux/jump_label.h> @@ -86,6 +87,12 @@ #include <linux/xarray.h> #include <trace/events/rust_sample.h> +/* + * The driver-core Rust code needs to know about some C driver-core private + * structures. + */ +#include <../../drivers/base/base.h> + #if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE) // Used by `#[export]` in `drivers/gpu/drm/drm_panic_qr.rs`. #include <drm/drm_panic.h> diff --git a/rust/helpers/pci.c b/rust/helpers/pci.c index fb814572b236..bf8173979c5e 100644 --- a/rust/helpers/pci.c +++ b/rust/helpers/pci.c @@ -23,9 +23,21 @@ bool rust_helper_dev_is_pci(const struct device *dev) } #ifndef CONFIG_PCI_MSI +int rust_helper_pci_alloc_irq_vectors(struct pci_dev *dev, + unsigned int min_vecs, + unsigned int max_vecs, + unsigned int flags) +{ + return pci_alloc_irq_vectors(dev, min_vecs, max_vecs, flags); +} + +void rust_helper_pci_free_irq_vectors(struct pci_dev *dev) +{ + pci_free_irq_vectors(dev); +} + int rust_helper_pci_irq_vector(struct pci_dev *pdev, unsigned int nvec) { return pci_irq_vector(pdev, nvec); } - #endif diff --git a/rust/helpers/time.c b/rust/helpers/time.c index a318e9fa4408..67a36ccc3ec4 100644 --- a/rust/helpers/time.c +++ b/rust/helpers/time.c @@ -33,3 +33,8 @@ s64 rust_helper_ktime_to_ms(const ktime_t kt) { return ktime_to_ms(kt); } + +void rust_helper_udelay(unsigned long usec) +{ + udelay(usec); +} diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 7a3b0b9c418e..56f3c180e8f6 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -7,6 +7,7 @@ use crate::{ bindings, container_of, device, device_id::{RawDeviceId, RawDeviceIdIndex}, + devres::Devres, driver, error::{from_result, to_result, Result}, prelude::*, @@ -15,6 +16,7 @@ use crate::{ }; use core::{ marker::PhantomData, + mem::offset_of, ptr::{addr_of_mut, NonNull}, }; @@ -68,9 +70,9 @@ impl<T: Driver + 'static> Adapter<T> { let info = T::ID_TABLE.info(id.index()); from_result(|| { - let data = T::probe(adev, info)?; + let data = T::probe(adev, info); - adev.as_ref().set_drvdata(data); + adev.as_ref().set_drvdata(data)?; Ok(0) }) } @@ -85,7 +87,7 @@ impl<T: Driver + 'static> Adapter<T> { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin<KBox<T>>`. - drop(unsafe { adev.as_ref().drvdata_obtain::<Pin<KBox<T>>>() }); + drop(unsafe { adev.as_ref().drvdata_obtain::<T>() }); } } @@ -184,7 +186,7 @@ pub trait Driver { /// Auxiliary driver probe. /// /// Called when an auxiliary device is matches a corresponding driver. - fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> Result<Pin<KBox<Self>>>; + fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>; } /// The auxiliary device representation. @@ -214,14 +216,25 @@ impl<Ctx: device::DeviceContext> Device<Ctx> { // `struct auxiliary_device`. unsafe { (*self.as_raw()).id } } +} + +impl Device<device::Bound> { + /// Returns a bound reference to the parent [`device::Device`]. + pub fn parent(&self) -> &device::Device<device::Bound> { + let parent = (**self).parent(); - /// Returns a reference to the parent [`device::Device`], if any. - pub fn parent(&self) -> Option<&device::Device> { - self.as_ref().parent() + // SAFETY: A bound auxiliary device always has a bound parent device. + unsafe { parent.as_bound() } } } impl Device { + /// Returns a reference to the parent [`device::Device`]. + pub fn parent(&self) -> &device::Device { + // SAFETY: A `struct auxiliary_device` always has a parent. + unsafe { self.as_ref().parent().unwrap_unchecked() } + } + extern "C" fn release(dev: *mut bindings::device) { // SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device` // embedded in `struct auxiliary_device`. @@ -233,6 +246,12 @@ impl Device { } } +// SAFETY: `auxiliary::Device` is a transparent wrapper of `struct auxiliary_device`. +// The offset is guaranteed to point to a valid device field inside `auxiliary::Device`. +unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> { + const OFFSET: usize = offset_of!(bindings::auxiliary_device, dev); +} + // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic // argument. kernel::impl_device_context_deref!(unsafe { Device }); @@ -278,8 +297,8 @@ unsafe impl Sync for Device {} /// The registration of an auxiliary device. /// -/// This type represents the registration of a [`struct auxiliary_device`]. When an instance of this -/// type is dropped, its respective auxiliary device will be unregistered from the system. +/// This type represents the registration of a [`struct auxiliary_device`]. When its parent device +/// is unbound, the corresponding auxiliary device will be unregistered from the system. /// /// # Invariants /// @@ -289,44 +308,55 @@ pub struct Registration(NonNull<bindings::auxiliary_device>); impl Registration { /// Create and register a new auxiliary device. - pub fn new(parent: &device::Device, name: &CStr, id: u32, modname: &CStr) -> Result<Self> { - let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?; - let adev = boxed.get(); - - // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. - unsafe { - (*adev).dev.parent = parent.as_raw(); - (*adev).dev.release = Some(Device::release); - (*adev).name = name.as_char_ptr(); - (*adev).id = id; - } - - // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, - // which has not been initialized yet. - unsafe { bindings::auxiliary_device_init(adev) }; + pub fn new<'a>( + parent: &'a device::Device<device::Bound>, + name: &'a CStr, + id: u32, + modname: &'a CStr, + ) -> impl PinInit<Devres<Self>, Error> + 'a { + pin_init::pin_init_scope(move || { + let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?; + let adev = boxed.get(); + + // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. + unsafe { + (*adev).dev.parent = parent.as_raw(); + (*adev).dev.release = Some(Device::release); + (*adev).name = name.as_char_ptr(); + (*adev).id = id; + } - // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be freed - // by `Device::release` when the last reference to the `struct auxiliary_device` is dropped. - let _ = KBox::into_raw(boxed); - - // SAFETY: - // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which has - // been initialialized, - // - `modname.as_char_ptr()` is a NULL terminated string. - let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; - if ret != 0 { // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, - // which has been initialialized. - unsafe { bindings::auxiliary_device_uninit(adev) }; - - return Err(Error::from_errno(ret)); - } - - // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated successfully. - // - // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is called, - // which happens in `Self::drop()`. - Ok(Self(unsafe { NonNull::new_unchecked(adev) })) + // which has not been initialized yet. + unsafe { bindings::auxiliary_device_init(adev) }; + + // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be + // freed by `Device::release` when the last reference to the `struct auxiliary_device` + // is dropped. + let _ = KBox::into_raw(boxed); + + // SAFETY: + // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which + // has been initialized, + // - `modname.as_char_ptr()` is a NULL terminated string. + let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; + if ret != 0 { + // SAFETY: `adev` is guaranteed to be a valid pointer to a + // `struct auxiliary_device`, which has been initialized. + unsafe { bindings::auxiliary_device_uninit(adev) }; + + return Err(Error::from_errno(ret)); + } + + // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is + // called, which happens in `Self::drop()`. + Ok(Devres::new( + parent, + // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated + // successfully. + Self(unsafe { NonNull::new_unchecked(adev) }), + )) + }) } } diff --git a/rust/kernel/bitmap.rs b/rust/kernel/bitmap.rs index aa8fc7bf06fc..83d7dea99137 100644 --- a/rust/kernel/bitmap.rs +++ b/rust/kernel/bitmap.rs @@ -12,8 +12,6 @@ use crate::bindings; use crate::pr_err; use core::ptr::NonNull; -const BITS_PER_LONG: usize = bindings::BITS_PER_LONG as usize; - /// Represents a C bitmap. Wraps underlying C bitmap API. /// /// # Invariants @@ -149,14 +147,14 @@ macro_rules! bitmap_assert_return { /// /// # Invariants /// -/// * `nbits` is `<= i32::MAX` and never changes. -/// * if `nbits <= bindings::BITS_PER_LONG`, then `repr` is a `usize`. +/// * `nbits` is `<= MAX_LEN`. +/// * if `nbits <= MAX_INLINE_LEN`, then `repr` is a `usize`. /// * otherwise, `repr` holds a non-null pointer to an initialized /// array of `unsigned long` that is large enough to hold `nbits` bits. pub struct BitmapVec { /// Representation of bitmap. repr: BitmapRepr, - /// Length of this bitmap. Must be `<= i32::MAX`. + /// Length of this bitmap. Must be `<= MAX_LEN`. nbits: usize, } @@ -164,7 +162,7 @@ impl core::ops::Deref for BitmapVec { type Target = Bitmap; fn deref(&self) -> &Bitmap { - let ptr = if self.nbits <= BITS_PER_LONG { + let ptr = if self.nbits <= BitmapVec::MAX_INLINE_LEN { // SAFETY: Bitmap is represented inline. #[allow(unused_unsafe, reason = "Safe since Rust 1.92.0")] unsafe { @@ -183,7 +181,7 @@ impl core::ops::Deref for BitmapVec { impl core::ops::DerefMut for BitmapVec { fn deref_mut(&mut self) -> &mut Bitmap { - let ptr = if self.nbits <= BITS_PER_LONG { + let ptr = if self.nbits <= BitmapVec::MAX_INLINE_LEN { // SAFETY: Bitmap is represented inline. #[allow(unused_unsafe, reason = "Safe since Rust 1.92.0")] unsafe { @@ -213,7 +211,7 @@ unsafe impl Sync for BitmapVec {} impl Drop for BitmapVec { fn drop(&mut self) { - if self.nbits <= BITS_PER_LONG { + if self.nbits <= BitmapVec::MAX_INLINE_LEN { return; } // SAFETY: `self.ptr` was returned by the C `bitmap_zalloc`. @@ -226,23 +224,39 @@ impl Drop for BitmapVec { } impl BitmapVec { + /// The maximum possible length of a `BitmapVec`. + pub const MAX_LEN: usize = i32::MAX as usize; + + /// The maximum length that uses the inline representation. + pub const MAX_INLINE_LEN: usize = usize::BITS as usize; + + /// Construct a longest possible inline [`BitmapVec`]. + #[inline] + pub fn new_inline() -> Self { + // INVARIANT: `nbits <= MAX_INLINE_LEN`, so an inline bitmap is the right repr. + BitmapVec { + repr: BitmapRepr { bitmap: 0 }, + nbits: BitmapVec::MAX_INLINE_LEN, + } + } + /// Constructs a new [`BitmapVec`]. /// /// Fails with [`AllocError`] when the [`BitmapVec`] could not be allocated. This - /// includes the case when `nbits` is greater than `i32::MAX`. + /// includes the case when `nbits` is greater than `MAX_LEN`. #[inline] pub fn new(nbits: usize, flags: Flags) -> Result<Self, AllocError> { - if nbits <= BITS_PER_LONG { + if nbits <= BitmapVec::MAX_INLINE_LEN { return Ok(BitmapVec { repr: BitmapRepr { bitmap: 0 }, nbits, }); } - if nbits > i32::MAX.try_into().unwrap() { + if nbits > Self::MAX_LEN { return Err(AllocError); } let nbits_u32 = u32::try_from(nbits).unwrap(); - // SAFETY: `BITS_PER_LONG < nbits` and `nbits <= i32::MAX`. + // SAFETY: `MAX_INLINE_LEN < nbits` and `nbits <= MAX_LEN`. let ptr = unsafe { bindings::bitmap_zalloc(nbits_u32, flags.as_raw()) }; let ptr = NonNull::new(ptr).ok_or(AllocError)?; // INVARIANT: `ptr` returned by C `bitmap_zalloc` and `nbits` checked. @@ -495,9 +509,10 @@ mod tests { #[test] fn bitmap_borrow() { let fake_bitmap: [usize; 2] = [0, 0]; + let fake_bitmap_len = 2 * usize::BITS as usize; // SAFETY: `fake_c_bitmap` is an array of expected length. - let b = unsafe { Bitmap::from_raw(fake_bitmap.as_ptr(), 2 * BITS_PER_LONG) }; - assert_eq!(2 * BITS_PER_LONG, b.len()); + let b = unsafe { Bitmap::from_raw(fake_bitmap.as_ptr(), fake_bitmap_len) }; + assert_eq!(fake_bitmap_len, b.len()); assert_eq!(None, b.next_bit(0)); } diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index 1a555fcb120a..f968fbd22890 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -893,9 +893,9 @@ pub trait Driver { /// fn probe( /// pdev: &platform::Device<Core>, /// _id_info: Option<&Self::IdInfo>, -/// ) -> Result<Pin<KBox<Self>>> { +/// ) -> impl PinInit<Self, Error> { /// cpufreq::Registration::<SampleDriver>::new_foreign_owned(pdev.as_ref())?; -/// Ok(KBox::new(Self {}, GFP_KERNEL)?.into()) +/// Ok(Self {}) /// } /// } /// ``` diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index 8c35d032acfe..facad81e8290 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -21,12 +21,15 @@ use core::mem::ManuallyDrop; use core::ops::Deref; mod traits; -pub use traits::{Reader, Writer}; +pub use traits::{BinaryReader, BinaryReaderMut, BinaryWriter, Reader, Writer}; mod callback_adapters; use callback_adapters::{FormatAdapter, NoWriter, WritableAdapter}; mod file_ops; -use file_ops::{FileOps, ReadFile, ReadWriteFile, WriteFile}; +use file_ops::{ + BinaryReadFile, BinaryReadWriteFile, BinaryWriteFile, FileOps, ReadFile, ReadWriteFile, + WriteFile, +}; #[cfg(CONFIG_DEBUG_FS)] mod entry; #[cfg(CONFIG_DEBUG_FS)] @@ -150,6 +153,32 @@ impl Dir { self.create_file(name, data, file_ops) } + /// Creates a read-only binary file in this directory. + /// + /// The file's contents are produced by invoking [`BinaryWriter::write_to_slice`] on the value + /// initialized by `data`. + /// + /// # Examples + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::Dir; + /// # use kernel::prelude::*; + /// # let dir = Dir::new(c_str!("my_debugfs_dir")); + /// let file = KBox::pin_init(dir.read_binary_file(c_str!("foo"), [0x1, 0x2]), GFP_KERNEL)?; + /// # Ok::<(), Error>(()) + /// ``` + pub fn read_binary_file<'a, T, E: 'a>( + &'a self, + name: &'a CStr, + data: impl PinInit<T, E> + 'a, + ) -> impl PinInit<File<T>, E> + 'a + where + T: BinaryWriter + Send + Sync + 'static, + { + self.create_file(name, data, &T::FILE_OPS) + } + /// Creates a read-only file in this directory, with contents from a callback. /// /// `f` must be a function item or a non-capturing closure. @@ -206,6 +235,22 @@ impl Dir { self.create_file(name, data, file_ops) } + /// Creates a read-write binary file in this directory. + /// + /// Reading the file uses the [`BinaryWriter`] implementation. + /// Writing to the file uses the [`BinaryReader`] implementation. + pub fn read_write_binary_file<'a, T, E: 'a>( + &'a self, + name: &'a CStr, + data: impl PinInit<T, E> + 'a, + ) -> impl PinInit<File<T>, E> + 'a + where + T: BinaryWriter + BinaryReader + Send + Sync + 'static, + { + let file_ops = &<T as BinaryReadWriteFile<_>>::FILE_OPS; + self.create_file(name, data, file_ops) + } + /// Creates a read-write file in this directory, with logic from callbacks. /// /// Reading from the file is handled by `f`. Writing to the file is handled by `w`. @@ -248,6 +293,23 @@ impl Dir { self.create_file(name, data, &T::FILE_OPS) } + /// Creates a write-only binary file in this directory. + /// + /// The file owns its backing data. Writing to the file uses the [`BinaryReader`] + /// implementation. + /// + /// The file is removed when the returned [`File`] is dropped. + pub fn write_binary_file<'a, T, E: 'a>( + &'a self, + name: &'a CStr, + data: impl PinInit<T, E> + 'a, + ) -> impl PinInit<File<T>, E> + 'a + where + T: BinaryReader + Send + Sync + 'static, + { + self.create_file(name, data, &T::FILE_OPS) + } + /// Creates a write-only file in this directory, with write logic from a callback. /// /// `w` must be a function item or a non-capturing closure. @@ -468,6 +530,20 @@ impl<'data, 'dir> ScopedDir<'data, 'dir> { self.create_file(name, data, &T::FILE_OPS) } + /// Creates a read-only binary file in this directory. + /// + /// The file's contents are produced by invoking [`BinaryWriter::write_to_slice`]. + /// + /// This function does not produce an owning handle to the file. The created file is removed + /// when the [`Scope`] that this directory belongs to is dropped. + pub fn read_binary_file<T: BinaryWriter + Send + Sync + 'static>( + &self, + name: &CStr, + data: &'data T, + ) { + self.create_file(name, data, &T::FILE_OPS) + } + /// Creates a read-only file in this directory, with contents from a callback. /// /// The file contents are generated by calling `f` with `data`. @@ -505,6 +581,22 @@ impl<'data, 'dir> ScopedDir<'data, 'dir> { self.create_file(name, data, vtable) } + /// Creates a read-write binary file in this directory. + /// + /// Reading the file uses the [`BinaryWriter`] implementation on `data`. Writing to the file + /// uses the [`BinaryReader`] implementation on `data`. + /// + /// This function does not produce an owning handle to the file. The created file is removed + /// when the [`Scope`] that this directory belongs to is dropped. + pub fn read_write_binary_file<T: BinaryWriter + BinaryReader + Send + Sync + 'static>( + &self, + name: &CStr, + data: &'data T, + ) { + let vtable = &<T as BinaryReadWriteFile<_>>::FILE_OPS; + self.create_file(name, data, vtable) + } + /// Creates a read-write file in this directory, with logic from callbacks. /// /// Reading from the file is handled by `f`. Writing to the file is handled by `w`. @@ -544,6 +636,20 @@ impl<'data, 'dir> ScopedDir<'data, 'dir> { self.create_file(name, data, vtable) } + /// Creates a write-only binary file in this directory. + /// + /// Writing to the file uses the [`BinaryReader`] implementation on `data`. + /// + /// This function does not produce an owning handle to the file. The created file is removed + /// when the [`Scope`] that this directory belongs to is dropped. + pub fn write_binary_file<T: BinaryReader + Send + Sync + 'static>( + &self, + name: &CStr, + data: &'data T, + ) { + self.create_file(name, data, &T::FILE_OPS) + } + /// Creates a write-only file in this directory, with write logic from a callback. /// /// Writing to the file is handled by `w`. diff --git a/rust/kernel/debugfs/file_ops.rs b/rust/kernel/debugfs/file_ops.rs index 9ad5e3fa6f69..8a0442d6dd7a 100644 --- a/rust/kernel/debugfs/file_ops.rs +++ b/rust/kernel/debugfs/file_ops.rs @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2025 Google LLC. -use super::{Reader, Writer}; +use super::{BinaryReader, BinaryWriter, Reader, Writer}; use crate::debugfs::callback_adapters::Adapter; use crate::fmt; +use crate::fs::file; use crate::prelude::*; use crate::seq_file::SeqFile; use crate::seq_print; @@ -245,3 +246,140 @@ impl<T: Reader + Sync> WriteFile<T> for T { unsafe { FileOps::new(operations, 0o200) } }; } + +extern "C" fn blob_read<T: BinaryWriter>( + file: *mut bindings::file, + buf: *mut c_char, + count: usize, + ppos: *mut bindings::loff_t, +) -> isize { + // SAFETY: + // - `file` is a valid pointer to a `struct file`. + // - The type invariant of `FileOps` guarantees that `private_data` points to a valid `T`. + let this = unsafe { &*((*file).private_data.cast::<T>()) }; + + // SAFETY: + // - `ppos` is a valid `file::Offset` pointer. + // - We have exclusive access to `ppos`. + let pos: &mut file::Offset = unsafe { &mut *ppos }; + + let mut writer = UserSlice::new(UserPtr::from_ptr(buf.cast()), count).writer(); + + let ret = || -> Result<isize> { + let written = this.write_to_slice(&mut writer, pos)?; + + Ok(written.try_into()?) + }(); + + match ret { + Ok(n) => n, + Err(e) => e.to_errno() as isize, + } +} + +/// Representation of [`FileOps`] for read only binary files. +pub(crate) trait BinaryReadFile<T> { + const FILE_OPS: FileOps<T>; +} + +impl<T: BinaryWriter + Sync> BinaryReadFile<T> for T { + const FILE_OPS: FileOps<T> = { + let operations = bindings::file_operations { + read: Some(blob_read::<T>), + llseek: Some(bindings::default_llseek), + open: Some(bindings::simple_open), + // SAFETY: `file_operations` supports zeroes in all fields. + ..unsafe { core::mem::zeroed() } + }; + + // SAFETY: + // - The private data of `struct inode` does always contain a pointer to a valid `T`. + // - `simple_open()` stores the `struct inode`'s private data in the private data of the + // corresponding `struct file`. + // - `blob_read()` re-creates a reference to `T` from the `struct file`'s private data. + // - `default_llseek()` does not access the `struct file`'s private data. + unsafe { FileOps::new(operations, 0o400) } + }; +} + +extern "C" fn blob_write<T: BinaryReader>( + file: *mut bindings::file, + buf: *const c_char, + count: usize, + ppos: *mut bindings::loff_t, +) -> isize { + // SAFETY: + // - `file` is a valid pointer to a `struct file`. + // - The type invariant of `FileOps` guarantees that `private_data` points to a valid `T`. + let this = unsafe { &*((*file).private_data.cast::<T>()) }; + + // SAFETY: + // - `ppos` is a valid `file::Offset` pointer. + // - We have exclusive access to `ppos`. + let pos: &mut file::Offset = unsafe { &mut *ppos }; + + let mut reader = UserSlice::new(UserPtr::from_ptr(buf.cast_mut().cast()), count).reader(); + + let ret = || -> Result<isize> { + let read = this.read_from_slice(&mut reader, pos)?; + + Ok(read.try_into()?) + }(); + + match ret { + Ok(n) => n, + Err(e) => e.to_errno() as isize, + } +} + +/// Representation of [`FileOps`] for write only binary files. +pub(crate) trait BinaryWriteFile<T> { + const FILE_OPS: FileOps<T>; +} + +impl<T: BinaryReader + Sync> BinaryWriteFile<T> for T { + const FILE_OPS: FileOps<T> = { + let operations = bindings::file_operations { + write: Some(blob_write::<T>), + llseek: Some(bindings::default_llseek), + open: Some(bindings::simple_open), + // SAFETY: `file_operations` supports zeroes in all fields. + ..unsafe { core::mem::zeroed() } + }; + + // SAFETY: + // - The private data of `struct inode` does always contain a pointer to a valid `T`. + // - `simple_open()` stores the `struct inode`'s private data in the private data of the + // corresponding `struct file`. + // - `blob_write()` re-creates a reference to `T` from the `struct file`'s private data. + // - `default_llseek()` does not access the `struct file`'s private data. + unsafe { FileOps::new(operations, 0o200) } + }; +} + +/// Representation of [`FileOps`] for read/write binary files. +pub(crate) trait BinaryReadWriteFile<T> { + const FILE_OPS: FileOps<T>; +} + +impl<T: BinaryWriter + BinaryReader + Sync> BinaryReadWriteFile<T> for T { + const FILE_OPS: FileOps<T> = { + let operations = bindings::file_operations { + read: Some(blob_read::<T>), + write: Some(blob_write::<T>), + llseek: Some(bindings::default_llseek), + open: Some(bindings::simple_open), + // SAFETY: `file_operations` supports zeroes in all fields. + ..unsafe { core::mem::zeroed() } + }; + + // SAFETY: + // - The private data of `struct inode` does always contain a pointer to a valid `T`. + // - `simple_open()` stores the `struct inode`'s private data in the private data of the + // corresponding `struct file`. + // - `blob_read()` re-creates a reference to `T` from the `struct file`'s private data. + // - `blob_write()` re-creates a reference to `T` from the `struct file`'s private data. + // - `default_llseek()` does not access the `struct file`'s private data. + unsafe { FileOps::new(operations, 0o600) } + }; +} diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs index e8a8a98f18dc..3eee60463fd5 100644 --- a/rust/kernel/debugfs/traits.rs +++ b/rust/kernel/debugfs/traits.rs @@ -3,11 +3,16 @@ //! Traits for rendering or updating values exported to DebugFS. +use crate::alloc::Allocator; use crate::fmt; +use crate::fs::file; use crate::prelude::*; use crate::sync::atomic::{Atomic, AtomicBasicOps, AtomicType, Relaxed}; +use crate::sync::Arc; use crate::sync::Mutex; -use crate::uaccess::UserSliceReader; +use crate::transmute::{AsBytes, FromBytes}; +use crate::uaccess::{UserSliceReader, UserSliceWriter}; +use core::ops::{Deref, DerefMut}; use core::str::FromStr; /// A trait for types that can be written into a string. @@ -36,6 +41,110 @@ impl<T: fmt::Debug> Writer for T { } } +/// Trait for types that can be written out as binary. +pub trait BinaryWriter { + /// Writes the binary form of `self` into `writer`. + /// + /// `offset` is the requested offset into the binary representation of `self`. + /// + /// On success, returns the number of bytes written in to `writer`. + fn write_to_slice( + &self, + writer: &mut UserSliceWriter, + offset: &mut file::Offset, + ) -> Result<usize>; +} + +// Base implementation for any `T: AsBytes`. +impl<T: AsBytes> BinaryWriter for T { + fn write_to_slice( + &self, + writer: &mut UserSliceWriter, + offset: &mut file::Offset, + ) -> Result<usize> { + writer.write_slice_file(self.as_bytes(), offset) + } +} + +// Delegate for `Mutex<T>`: Support a `T` with an outer mutex. +impl<T: BinaryWriter> BinaryWriter for Mutex<T> { + fn write_to_slice( + &self, + writer: &mut UserSliceWriter, + offset: &mut file::Offset, + ) -> Result<usize> { + let guard = self.lock(); + + guard.write_to_slice(writer, offset) + } +} + +// Delegate for `Box<T, A>`: Support a `Box<T, A>` with no lock or an inner lock. +impl<T, A> BinaryWriter for Box<T, A> +where + T: BinaryWriter, + A: Allocator, +{ + fn write_to_slice( + &self, + writer: &mut UserSliceWriter, + offset: &mut file::Offset, + ) -> Result<usize> { + self.deref().write_to_slice(writer, offset) + } +} + +// Delegate for `Pin<Box<T, A>>`: Support a `Pin<Box<T, A>>` with no lock or an inner lock. +impl<T, A> BinaryWriter for Pin<Box<T, A>> +where + T: BinaryWriter, + A: Allocator, +{ + fn write_to_slice( + &self, + writer: &mut UserSliceWriter, + offset: &mut file::Offset, + ) -> Result<usize> { + self.deref().write_to_slice(writer, offset) + } +} + +// Delegate for `Arc<T>`: Support a `Arc<T>` with no lock or an inner lock. +impl<T> BinaryWriter for Arc<T> +where + T: BinaryWriter, +{ + fn write_to_slice( + &self, + writer: &mut UserSliceWriter, + offset: &mut file::Offset, + ) -> Result<usize> { + self.deref().write_to_slice(writer, offset) + } +} + +// Delegate for `Vec<T, A>`. +impl<T, A> BinaryWriter for Vec<T, A> +where + T: AsBytes, + A: Allocator, +{ + fn write_to_slice( + &self, + writer: &mut UserSliceWriter, + offset: &mut file::Offset, + ) -> Result<usize> { + let slice = self.as_slice(); + + // SAFETY: `T: AsBytes` allows us to treat `&[T]` as `&[u8]`. + let buffer = unsafe { + core::slice::from_raw_parts(slice.as_ptr().cast(), core::mem::size_of_val(slice)) + }; + + writer.write_slice_file(buffer, offset) + } +} + /// A trait for types that can be updated from a user slice. /// /// This works similarly to `FromStr`, but operates on a `UserSliceReader` rather than a &str. @@ -81,3 +190,130 @@ where Ok(()) } } + +/// Trait for types that can be constructed from a binary representation. +/// +/// See also [`BinaryReader`] for interior mutability. +pub trait BinaryReaderMut { + /// Reads the binary form of `self` from `reader`. + /// + /// Same as [`BinaryReader::read_from_slice`], but takes a mutable reference. + /// + /// `offset` is the requested offset into the binary representation of `self`. + /// + /// On success, returns the number of bytes read from `reader`. + fn read_from_slice_mut( + &mut self, + reader: &mut UserSliceReader, + offset: &mut file::Offset, + ) -> Result<usize>; +} + +// Base implementation for any `T: AsBytes + FromBytes`. +impl<T: AsBytes + FromBytes> BinaryReaderMut for T { + fn read_from_slice_mut( + &mut self, + reader: &mut UserSliceReader, + offset: &mut file::Offset, + ) -> Result<usize> { + reader.read_slice_file(self.as_bytes_mut(), offset) + } +} + +// Delegate for `Box<T, A>`: Support a `Box<T, A>` with an outer lock. +impl<T: ?Sized + BinaryReaderMut, A: Allocator> BinaryReaderMut for Box<T, A> { + fn read_from_slice_mut( + &mut self, + reader: &mut UserSliceReader, + offset: &mut file::Offset, + ) -> Result<usize> { + self.deref_mut().read_from_slice_mut(reader, offset) + } +} + +// Delegate for `Vec<T, A>`: Support a `Vec<T, A>` with an outer lock. +impl<T, A> BinaryReaderMut for Vec<T, A> +where + T: AsBytes + FromBytes, + A: Allocator, +{ + fn read_from_slice_mut( + &mut self, + reader: &mut UserSliceReader, + offset: &mut file::Offset, + ) -> Result<usize> { + let slice = self.as_mut_slice(); + + // SAFETY: `T: AsBytes + FromBytes` allows us to treat `&mut [T]` as `&mut [u8]`. + let buffer = unsafe { + core::slice::from_raw_parts_mut( + slice.as_mut_ptr().cast(), + core::mem::size_of_val(slice), + ) + }; + + reader.read_slice_file(buffer, offset) + } +} + +/// Trait for types that can be constructed from a binary representation. +/// +/// See also [`BinaryReaderMut`] for the mutable version. +pub trait BinaryReader { + /// Reads the binary form of `self` from `reader`. + /// + /// `offset` is the requested offset into the binary representation of `self`. + /// + /// On success, returns the number of bytes read from `reader`. + fn read_from_slice( + &self, + reader: &mut UserSliceReader, + offset: &mut file::Offset, + ) -> Result<usize>; +} + +// Delegate for `Mutex<T>`: Support a `T` with an outer `Mutex`. +impl<T: BinaryReaderMut + Unpin> BinaryReader for Mutex<T> { + fn read_from_slice( + &self, + reader: &mut UserSliceReader, + offset: &mut file::Offset, + ) -> Result<usize> { + let mut this = self.lock(); + + this.read_from_slice_mut(reader, offset) + } +} + +// Delegate for `Box<T, A>`: Support a `Box<T, A>` with an inner lock. +impl<T: ?Sized + BinaryReader, A: Allocator> BinaryReader for Box<T, A> { + fn read_from_slice( + &self, + reader: &mut UserSliceReader, + offset: &mut file::Offset, + ) -> Result<usize> { + self.deref().read_from_slice(reader, offset) + } +} + +// Delegate for `Pin<Box<T, A>>`: Support a `Pin<Box<T, A>>` with an inner lock. +impl<T: ?Sized + BinaryReader, A: Allocator> BinaryReader for Pin<Box<T, A>> { + fn read_from_slice( + &self, + reader: &mut UserSliceReader, + offset: &mut file::Offset, + ) -> Result<usize> { + self.deref().read_from_slice(reader, offset) + } +} + +// Delegate for `Arc<T>`: Support an `Arc<T>` with an inner lock. +impl<T: ?Sized + BinaryReader> BinaryReader for Arc<T> { + fn read_from_slice( + &self, + reader: &mut UserSliceReader, + offset: &mut file::Offset, + ) -> Result<usize> { + self.deref().read_from_slice(reader, offset) + } +} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 7116dd7539a6..c79be2e2bfe3 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -6,10 +6,11 @@ use crate::{ bindings, fmt, + prelude::*, sync::aref::ARef, types::{ForeignOwnable, Opaque}, }; -use core::{marker::PhantomData, ptr}; +use core::{any::TypeId, marker::PhantomData, ptr}; #[cfg(CONFIG_PRINTK)] use crate::c_str; @@ -17,6 +18,9 @@ use crate::str::CStrExt as _; pub mod property; +// Assert that we can `read()` / `write()` a `TypeId` instance from / into `struct driver_type`. +static_assert!(core::mem::size_of::<bindings::driver_type>() >= core::mem::size_of::<TypeId>()); + /// The core representation of a device in the kernel's driver model. /// /// This structure represents the Rust abstraction for a C `struct device`. A [`Device`] can either @@ -198,10 +202,31 @@ impl Device { } impl Device<CoreInternal> { + fn set_type_id<T: 'static>(&self) { + // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. + let private = unsafe { (*self.as_raw()).p }; + + // SAFETY: For a bound device (implied by the `CoreInternal` device context), `private` is + // guaranteed to be a valid pointer to a `struct device_private`. + let driver_type = unsafe { &raw mut (*private).driver_type }; + + // SAFETY: `driver_type` is valid for (unaligned) writes of a `TypeId`. + unsafe { + driver_type + .cast::<TypeId>() + .write_unaligned(TypeId::of::<T>()) + }; + } + /// Store a pointer to the bound driver's private data. - pub fn set_drvdata(&self, data: impl ForeignOwnable) { + pub fn set_drvdata<T: 'static>(&self, data: impl PinInit<T, Error>) -> Result { + let data = KBox::pin_init(data, GFP_KERNEL)?; + // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. - unsafe { bindings::dev_set_drvdata(self.as_raw(), data.into_foreign().cast()) } + unsafe { bindings::dev_set_drvdata(self.as_raw(), data.into_foreign().cast()) }; + self.set_type_id::<T>(); + + Ok(()) } /// Take ownership of the private data stored in this [`Device`]. @@ -211,16 +236,19 @@ impl Device<CoreInternal> { /// - Must only be called once after a preceding call to [`Device::set_drvdata`]. /// - The type `T` must match the type of the `ForeignOwnable` previously stored by /// [`Device::set_drvdata`]. - pub unsafe fn drvdata_obtain<T: ForeignOwnable>(&self) -> T { + pub unsafe fn drvdata_obtain<T: 'static>(&self) -> Pin<KBox<T>> { // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) }; + // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. + unsafe { bindings::dev_set_drvdata(self.as_raw(), core::ptr::null_mut()) }; + // SAFETY: // - By the safety requirements of this function, `ptr` comes from a previous call to // `into_foreign()`. // - `dev_get_drvdata()` guarantees to return the same pointer given to `dev_set_drvdata()` // in `into_foreign()`. - unsafe { T::from_foreign(ptr.cast()) } + unsafe { Pin::<KBox<T>>::from_foreign(ptr.cast()) } } /// Borrow the driver's private data bound to this [`Device`]. @@ -231,7 +259,23 @@ impl Device<CoreInternal> { /// [`Device::drvdata_obtain`]. /// - The type `T` must match the type of the `ForeignOwnable` previously stored by /// [`Device::set_drvdata`]. - pub unsafe fn drvdata_borrow<T: ForeignOwnable>(&self) -> T::Borrowed<'_> { + pub unsafe fn drvdata_borrow<T: 'static>(&self) -> Pin<&T> { + // SAFETY: `drvdata_unchecked()` has the exact same safety requirements as the ones + // required by this method. + unsafe { self.drvdata_unchecked() } + } +} + +impl Device<Bound> { + /// Borrow the driver's private data bound to this [`Device`]. + /// + /// # Safety + /// + /// - Must only be called after a preceding call to [`Device::set_drvdata`] and before + /// [`Device::drvdata_obtain`]. + /// - The type `T` must match the type of the `ForeignOwnable` previously stored by + /// [`Device::set_drvdata`]. + unsafe fn drvdata_unchecked<T: 'static>(&self) -> Pin<&T> { // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) }; @@ -240,7 +284,46 @@ impl Device<CoreInternal> { // `into_foreign()`. // - `dev_get_drvdata()` guarantees to return the same pointer given to `dev_set_drvdata()` // in `into_foreign()`. - unsafe { T::borrow(ptr.cast()) } + unsafe { Pin::<KBox<T>>::borrow(ptr.cast()) } + } + + fn match_type_id<T: 'static>(&self) -> Result { + // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. + let private = unsafe { (*self.as_raw()).p }; + + // SAFETY: For a bound device, `private` is guaranteed to be a valid pointer to a + // `struct device_private`. + let driver_type = unsafe { &raw mut (*private).driver_type }; + + // SAFETY: + // - `driver_type` is valid for (unaligned) reads of a `TypeId`. + // - A bound device guarantees that `driver_type` contains a valid `TypeId` value. + let type_id = unsafe { driver_type.cast::<TypeId>().read_unaligned() }; + + if type_id != TypeId::of::<T>() { + return Err(EINVAL); + } + + Ok(()) + } + + /// Access a driver's private data. + /// + /// Returns a pinned reference to the driver's private data or [`EINVAL`] if it doesn't match + /// the asserted type `T`. + pub fn drvdata<T: 'static>(&self) -> Result<Pin<&T>> { + // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. + if unsafe { bindings::dev_get_drvdata(self.as_raw()) }.is_null() { + return Err(ENOENT); + } + + self.match_type_id::<T>()?; + + // SAFETY: + // - The above check of `dev_get_drvdata()` guarantees that we are called after + // `set_drvdata()` and before `drvdata_obtain()`. + // - We've just checked that the type of the driver's private data is in fact `T`. + Ok(unsafe { self.drvdata_unchecked() }) } } @@ -512,6 +595,39 @@ impl DeviceContext for Core {} impl DeviceContext for CoreInternal {} impl DeviceContext for Normal {} +/// Convert device references to bus device references. +/// +/// Bus devices can implement this trait to allow abstractions to provide the bus device in +/// class device callbacks. +/// +/// This must not be used by drivers and is intended for bus and class device abstractions only. +/// +/// # Safety +/// +/// `AsBusDevice::OFFSET` must be the offset of the embedded base `struct device` field within a +/// bus device structure. +pub unsafe trait AsBusDevice<Ctx: DeviceContext>: AsRef<Device<Ctx>> { + /// The relative offset to the device field. + /// + /// Use `offset_of!(bindings, field)` macro to avoid breakage. + const OFFSET: usize; + + /// Convert a reference to [`Device`] into `Self`. + /// + /// # Safety + /// + /// `dev` must be contained in `Self`. + unsafe fn from_device(dev: &Device<Ctx>) -> &Self + where + Self: Sized, + { + let raw = dev.as_raw(); + // SAFETY: `raw - Self::OFFSET` is guaranteed by the safety requirements + // to be a valid pointer to `Self`. + unsafe { &*raw.byte_sub(Self::OFFSET).cast::<Self>() } + } +} + /// # Safety /// /// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 2392c281459e..835d9c11948e 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -52,8 +52,20 @@ struct Inner<T: Send> { /// # Examples /// /// ```no_run -/// # use kernel::{bindings, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}}; -/// # use core::ops::Deref; +/// use kernel::{ +/// bindings, +/// device::{ +/// Bound, +/// Device, +/// }, +/// devres::Devres, +/// io::{ +/// Io, +/// IoRaw, +/// PhysAddr, +/// }, +/// }; +/// use core::ops::Deref; /// /// // See also [`pci::Bar`] for a real example. /// struct IoMem<const SIZE: usize>(IoRaw<SIZE>); @@ -66,7 +78,7 @@ struct Inner<T: Send> { /// unsafe fn new(paddr: usize) -> Result<Self>{ /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is /// // valid for `ioremap`. -/// let addr = unsafe { bindings::ioremap(paddr as bindings::phys_addr_t, SIZE) }; +/// let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) }; /// if addr.is_null() { /// return Err(ENOMEM); /// } diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 4e0af3e1a3b9..84d3c67269e8 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -12,6 +12,7 @@ use crate::{ sync::aref::ARef, transmute::{AsBytes, FromBytes}, }; +use core::ptr::NonNull; /// DMA address type. /// @@ -358,7 +359,7 @@ pub struct CoherentAllocation<T: AsBytes + FromBytes> { dev: ARef<device::Device>, dma_handle: DmaAddress, count: usize, - cpu_addr: *mut T, + cpu_addr: NonNull<T>, dma_attrs: Attrs, } @@ -392,7 +393,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> { .ok_or(EOVERFLOW)?; let mut dma_handle = 0; // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`. - let ret = unsafe { + let addr = unsafe { bindings::dma_alloc_attrs( dev.as_raw(), size, @@ -401,9 +402,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> { dma_attrs.as_raw(), ) }; - if ret.is_null() { - return Err(ENOMEM); - } + let addr = NonNull::new(addr).ok_or(ENOMEM)?; // INVARIANT: // - We just successfully allocated a coherent region which is accessible for // `count` elements, hence the cpu address is valid. We also hold a refcounted reference @@ -414,7 +413,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> { dev: dev.into(), dma_handle, count, - cpu_addr: ret.cast::<T>(), + cpu_addr: addr.cast(), dma_attrs, }) } @@ -446,13 +445,13 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> { /// Returns the base address to the allocated region in the CPU's virtual address space. pub fn start_ptr(&self) -> *const T { - self.cpu_addr + self.cpu_addr.as_ptr() } /// Returns the base address to the allocated region in the CPU's virtual address space as /// a mutable pointer. pub fn start_ptr_mut(&mut self) -> *mut T { - self.cpu_addr + self.cpu_addr.as_ptr() } /// Returns a DMA handle which may be given to the device as the DMA address base of @@ -505,7 +504,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> { // data is also guaranteed by the safety requirements of the function. // - `offset + count` can't overflow since it is smaller than `self.count` and we've checked // that `self.count` won't overflow early in the constructor. - Ok(unsafe { core::slice::from_raw_parts(self.cpu_addr.add(offset), count) }) + Ok(unsafe { core::slice::from_raw_parts(self.start_ptr().add(offset), count) }) } /// Performs the same functionality as [`CoherentAllocation::as_slice`], except that a mutable @@ -525,7 +524,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> { // data is also guaranteed by the safety requirements of the function. // - `offset + count` can't overflow since it is smaller than `self.count` and we've checked // that `self.count` won't overflow early in the constructor. - Ok(unsafe { core::slice::from_raw_parts_mut(self.cpu_addr.add(offset), count) }) + Ok(unsafe { core::slice::from_raw_parts_mut(self.start_ptr_mut().add(offset), count) }) } /// Writes data to the region starting from `offset`. `offset` is in units of `T`, not the @@ -557,7 +556,11 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> { // - `offset + count` can't overflow since it is smaller than `self.count` and we've checked // that `self.count` won't overflow early in the constructor. unsafe { - core::ptr::copy_nonoverlapping(src.as_ptr(), self.cpu_addr.add(offset), src.len()) + core::ptr::copy_nonoverlapping( + src.as_ptr(), + self.start_ptr_mut().add(offset), + src.len(), + ) }; Ok(()) } @@ -576,7 +579,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> { // and we've just checked that the range and index is within bounds. // - `offset` can't overflow since it is smaller than `self.count` and we've checked // that `self.count` won't overflow early in the constructor. - Ok(unsafe { self.cpu_addr.add(offset) }) + Ok(unsafe { self.cpu_addr.as_ptr().add(offset) }) } /// Reads the value of `field` and ensures that its type is [`FromBytes`]. @@ -637,7 +640,7 @@ impl<T: AsBytes + FromBytes> Drop for CoherentAllocation<T> { bindings::dma_free_attrs( self.dev.as_raw(), size, - self.cpu_addr.cast(), + self.start_ptr_mut().cast(), self.dma_handle, self.dma_attrs.as_raw(), ) diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index 279e3af20682..9beae2e3d57e 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -24,7 +24,7 @@ //! const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None; //! //! /// Driver probe. -//! fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> Result<Pin<KBox<Self>>>; +//! fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>; //! //! /// Driver unbind (optional). //! fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { @@ -35,7 +35,7 @@ //! //! For specific examples see [`auxiliary::Driver`], [`pci::Driver`] and [`platform::Driver`]. //! -//! The `probe()` callback should return a `Result<Pin<KBox<Self>>>`, i.e. the driver's private +//! The `probe()` callback should return a `impl PinInit<Self, Error>`, i.e. the driver's private //! data. The bus abstraction should store the pointer in the corresponding bus device. The generic //! [`Device`] infrastructure provides common helpers for this purpose on its //! [`Device<CoreInternal>`] implementation. diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs index cd6987850332..23ee689bd240 100644 --- a/rust/kernel/fs/file.rs +++ b/rust/kernel/fs/file.rs @@ -17,6 +17,11 @@ use crate::{ }; use core::ptr; +/// Primitive type representing the offset within a [`File`]. +/// +/// Type alias for `bindings::loff_t`. +pub type Offset = bindings::loff_t; + /// Flags associated with a [`File`]. pub mod flags { /// File is opened in append mode. diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs new file mode 100644 index 000000000000..491e6cc25cf4 --- /dev/null +++ b/rust/kernel/i2c.rs @@ -0,0 +1,586 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! I2C Driver subsystem + +// I2C Driver abstractions. +use crate::{ + acpi, + container_of, + device, + device_id::{ + RawDeviceId, + RawDeviceIdIndex, // + }, + devres::Devres, + driver, + error::*, + of, + prelude::*, + types::{ + AlwaysRefCounted, + Opaque, // + }, // +}; + +use core::{ + marker::PhantomData, + mem::offset_of, + ptr::{ + from_ref, + NonNull, // + }, // +}; + +use kernel::types::ARef; + +/// An I2C device id table. +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct DeviceId(bindings::i2c_device_id); + +impl DeviceId { + const I2C_NAME_SIZE: usize = 20; + + /// Create a new device id from an I2C 'id' string. + #[inline(always)] + pub const fn new(id: &'static CStr) -> Self { + let src = id.to_bytes_with_nul(); + build_assert!(src.len() <= Self::I2C_NAME_SIZE, "ID exceeds 20 bytes"); + let mut i2c: bindings::i2c_device_id = pin_init::zeroed(); + let mut i = 0; + while i < src.len() { + i2c.name[i] = src[i]; + i += 1; + } + + Self(i2c) + } +} + +// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `i2c_device_id` and does not add +// additional invariants, so it's safe to transmute to `RawType`. +unsafe impl RawDeviceId for DeviceId { + type RawType = bindings::i2c_device_id; +} + +// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. +unsafe impl RawDeviceIdIndex for DeviceId { + const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::i2c_device_id, driver_data); + + fn index(&self) -> usize { + self.0.driver_data + } +} + +/// IdTable type for I2C +pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>; + +/// Create a I2C `IdTable` with its alias for modpost. +#[macro_export] +macro_rules! i2c_device_table { + ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { + const $table_name: $crate::device_id::IdArray< + $crate::i2c::DeviceId, + $id_info_type, + { $table_data.len() }, + > = $crate::device_id::IdArray::new($table_data); + + $crate::module_device_table!("i2c", $module_table_name, $table_name); + }; +} + +/// An adapter for the registration of I2C drivers. +pub struct Adapter<T: Driver>(T); + +// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if +// a preceding call to `register` has been successful. +unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { + type RegType = bindings::i2c_driver; + + unsafe fn register( + idrv: &Opaque<Self::RegType>, + name: &'static CStr, + module: &'static ThisModule, + ) -> Result { + build_assert!( + T::ACPI_ID_TABLE.is_some() || T::OF_ID_TABLE.is_some() || T::I2C_ID_TABLE.is_some(), + "At least one of ACPI/OF/Legacy tables must be present when registering an i2c driver" + ); + + let i2c_table = match T::I2C_ID_TABLE { + Some(table) => table.as_ptr(), + None => core::ptr::null(), + }; + + let of_table = match T::OF_ID_TABLE { + Some(table) => table.as_ptr(), + None => core::ptr::null(), + }; + + let acpi_table = match T::ACPI_ID_TABLE { + Some(table) => table.as_ptr(), + None => core::ptr::null(), + }; + + // SAFETY: It's safe to set the fields of `struct i2c_client` on initialization. + unsafe { + (*idrv.get()).driver.name = name.as_char_ptr(); + (*idrv.get()).probe = Some(Self::probe_callback); + (*idrv.get()).remove = Some(Self::remove_callback); + (*idrv.get()).shutdown = Some(Self::shutdown_callback); + (*idrv.get()).id_table = i2c_table; + (*idrv.get()).driver.of_match_table = of_table; + (*idrv.get()).driver.acpi_match_table = acpi_table; + } + + // SAFETY: `idrv` is guaranteed to be a valid `RegType`. + to_result(unsafe { bindings::i2c_register_driver(module.0, idrv.get()) }) + } + + unsafe fn unregister(idrv: &Opaque<Self::RegType>) { + // SAFETY: `idrv` is guaranteed to be a valid `RegType`. + unsafe { bindings::i2c_del_driver(idrv.get()) } + } +} + +impl<T: Driver + 'static> Adapter<T> { + extern "C" fn probe_callback(idev: *mut bindings::i2c_client) -> kernel::ffi::c_int { + // SAFETY: The I2C bus only ever calls the probe callback with a valid pointer to a + // `struct i2c_client`. + // + // INVARIANT: `idev` is valid for the duration of `probe_callback()`. + let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() }; + + let info = + Self::i2c_id_info(idev).or_else(|| <Self as driver::Adapter>::id_info(idev.as_ref())); + + from_result(|| { + let data = T::probe(idev, info); + + idev.as_ref().set_drvdata(data)?; + Ok(0) + }) + } + + extern "C" fn remove_callback(idev: *mut bindings::i2c_client) { + // SAFETY: `idev` is a valid pointer to a `struct i2c_client`. + let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() }; + + // SAFETY: `remove_callback` is only ever called after a successful call to + // `probe_callback`, hence it's guaranteed that `I2cClient::set_drvdata()` has been called + // and stored a `Pin<KBox<T>>`. + let data = unsafe { idev.as_ref().drvdata_obtain::<T>() }; + + T::unbind(idev, data.as_ref()); + } + + extern "C" fn shutdown_callback(idev: *mut bindings::i2c_client) { + // SAFETY: `shutdown_callback` is only ever called for a valid `idev` + let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() }; + + // SAFETY: `shutdown_callback` is only ever called after a successful call to + // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called + // and stored a `Pin<KBox<T>>`. + let data = unsafe { idev.as_ref().drvdata_obtain::<T>() }; + + T::shutdown(idev, data.as_ref()); + } + + /// The [`i2c::IdTable`] of the corresponding driver. + fn i2c_id_table() -> Option<IdTable<<Self as driver::Adapter>::IdInfo>> { + T::I2C_ID_TABLE + } + + /// Returns the driver's private data from the matching entry in the [`i2c::IdTable`], if any. + /// + /// If this returns `None`, it means there is no match with an entry in the [`i2c::IdTable`]. + fn i2c_id_info(dev: &I2cClient) -> Option<&'static <Self as driver::Adapter>::IdInfo> { + let table = Self::i2c_id_table()?; + + // SAFETY: + // - `table` has static lifetime, hence it's valid for reads + // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`. + let raw_id = unsafe { bindings::i2c_match_id(table.as_ptr(), dev.as_raw()) }; + + if raw_id.is_null() { + return None; + } + + // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct i2c_device_id` and + // does not add additional invariants, so it's safe to transmute. + let id = unsafe { &*raw_id.cast::<DeviceId>() }; + + Some(table.info(<DeviceId as RawDeviceIdIndex>::index(id))) + } +} + +impl<T: Driver + 'static> driver::Adapter for Adapter<T> { + type IdInfo = T::IdInfo; + + fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> { + T::OF_ID_TABLE + } + + fn acpi_id_table() -> Option<acpi::IdTable<Self::IdInfo>> { + T::ACPI_ID_TABLE + } +} + +/// Declares a kernel module that exposes a single i2c driver. +/// +/// # Examples +/// +/// ```ignore +/// kernel::module_i2c_driver! { +/// type: MyDriver, +/// name: "Module name", +/// authors: ["Author name"], +/// description: "Description", +/// license: "GPL v2", +/// } +/// ``` +#[macro_export] +macro_rules! module_i2c_driver { + ($($f:tt)*) => { + $crate::module_driver!(<T>, $crate::i2c::Adapter<T>, { $($f)* }); + }; +} + +/// The i2c driver trait. +/// +/// Drivers must implement this trait in order to get a i2c driver registered. +/// +/// # Example +/// +///``` +/// # use kernel::{acpi, bindings, c_str, device::Core, i2c, of}; +/// +/// struct MyDriver; +/// +/// kernel::acpi_device_table!( +/// ACPI_TABLE, +/// MODULE_ACPI_TABLE, +/// <MyDriver as i2c::Driver>::IdInfo, +/// [ +/// (acpi::DeviceId::new(c_str!("LNUXBEEF")), ()) +/// ] +/// ); +/// +/// kernel::i2c_device_table!( +/// I2C_TABLE, +/// MODULE_I2C_TABLE, +/// <MyDriver as i2c::Driver>::IdInfo, +/// [ +/// (i2c::DeviceId::new(c_str!("rust_driver_i2c")), ()) +/// ] +/// ); +/// +/// kernel::of_device_table!( +/// OF_TABLE, +/// MODULE_OF_TABLE, +/// <MyDriver as i2c::Driver>::IdInfo, +/// [ +/// (of::DeviceId::new(c_str!("test,device")), ()) +/// ] +/// ); +/// +/// impl i2c::Driver for MyDriver { +/// type IdInfo = (); +/// const I2C_ID_TABLE: Option<i2c::IdTable<Self::IdInfo>> = Some(&I2C_TABLE); +/// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); +/// const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); +/// +/// fn probe( +/// _idev: &i2c::I2cClient<Core>, +/// _id_info: Option<&Self::IdInfo>, +/// ) -> impl PinInit<Self, Error> { +/// Err(ENODEV) +/// } +/// +/// fn shutdown(_idev: &i2c::I2cClient<Core>, this: Pin<&Self>) { +/// } +/// } +///``` +pub trait Driver: Send { + /// The type holding information about each device id supported by the driver. + // TODO: Use `associated_type_defaults` once stabilized: + // + // ``` + // type IdInfo: 'static = (); + // ``` + type IdInfo: 'static; + + /// The table of device ids supported by the driver. + const I2C_ID_TABLE: Option<IdTable<Self::IdInfo>> = None; + + /// The table of OF device ids supported by the driver. + const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; + + /// The table of ACPI device ids supported by the driver. + const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None; + + /// I2C driver probe. + /// + /// Called when a new i2c client is added or discovered. + /// Implementers should attempt to initialize the client here. + fn probe( + dev: &I2cClient<device::Core>, + id_info: Option<&Self::IdInfo>, + ) -> impl PinInit<Self, Error>; + + /// I2C driver shutdown. + /// + /// Called by the kernel during system reboot or power-off to allow the [`Driver`] to bring the + /// [`I2cClient`] into a safe state. Implementing this callback is optional. + /// + /// Typical actions include stopping transfers, disabling interrupts, or resetting the hardware + /// to prevent undesired behavior during shutdown. + /// + /// This callback is distinct from final resource cleanup, as the driver instance remains valid + /// after it returns. Any deallocation or teardown of driver-owned resources should instead be + /// handled in `Self::drop`. + fn shutdown(dev: &I2cClient<device::Core>, this: Pin<&Self>) { + let _ = (dev, this); + } + + /// I2C driver unbind. + /// + /// Called when the [`I2cClient`] is unbound from its bound [`Driver`]. Implementing this + /// callback is optional. + /// + /// This callback serves as a place for drivers to perform teardown operations that require a + /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O + /// operations to gracefully tear down the device. + /// + /// Otherwise, release operations for driver resources should be performed in `Self::drop`. + fn unbind(dev: &I2cClient<device::Core>, this: Pin<&Self>) { + let _ = (dev, this); + } +} + +/// The i2c adapter representation. +/// +/// This structure represents the Rust abstraction for a C `struct i2c_adapter`. The +/// implementation abstracts the usage of an existing C `struct i2c_adapter` that +/// gets passed from the C side +/// +/// # Invariants +/// +/// A [`I2cAdapter`] instance represents a valid `struct i2c_adapter` created by the C portion of +/// the kernel. +#[repr(transparent)] +pub struct I2cAdapter<Ctx: device::DeviceContext = device::Normal>( + Opaque<bindings::i2c_adapter>, + PhantomData<Ctx>, +); + +impl<Ctx: device::DeviceContext> I2cAdapter<Ctx> { + fn as_raw(&self) -> *mut bindings::i2c_adapter { + self.0.get() + } +} + +impl I2cAdapter { + /// Returns the I2C Adapter index. + #[inline] + pub fn index(&self) -> i32 { + // SAFETY: `self.as_raw` is a valid pointer to a `struct i2c_adapter`. + unsafe { (*self.as_raw()).nr } + } + + /// Gets pointer to an `i2c_adapter` by index. + pub fn get(index: i32) -> Result<ARef<Self>> { + // SAFETY: `index` must refer to a valid I2C adapter; the kernel + // guarantees that `i2c_get_adapter(index)` returns either a valid + // pointer or NULL. `NonNull::new` guarantees the correct check. + let adapter = NonNull::new(unsafe { bindings::i2c_get_adapter(index) }).ok_or(ENODEV)?; + + // SAFETY: `adapter` is non-null and points to a live `i2c_adapter`. + // `I2cAdapter` is #[repr(transparent)], so this cast is valid. + Ok(unsafe { (&*adapter.as_ptr().cast::<I2cAdapter<device::Normal>>()).into() }) + } +} + +// SAFETY: `I2cAdapter` is a transparent wrapper of a type that doesn't depend on +// `I2cAdapter`'s generic argument. +kernel::impl_device_context_deref!(unsafe { I2cAdapter }); +kernel::impl_device_context_into_aref!(I2cAdapter); + +// SAFETY: Instances of `I2cAdapter` are always reference-counted. +unsafe impl crate::types::AlwaysRefCounted for I2cAdapter { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. + unsafe { bindings::i2c_get_adapter(self.index()) }; + } + + unsafe fn dec_ref(obj: NonNull<Self>) { + // SAFETY: The safety requirements guarantee that the refcount is non-zero. + unsafe { bindings::i2c_put_adapter(obj.as_ref().as_raw()) } + } +} + +/// The i2c board info representation +/// +/// This structure represents the Rust abstraction for a C `struct i2c_board_info` structure, +/// which is used for manual I2C client creation. +#[repr(transparent)] +pub struct I2cBoardInfo(bindings::i2c_board_info); + +impl I2cBoardInfo { + const I2C_TYPE_SIZE: usize = 20; + /// Create a new [`I2cBoardInfo`] for a kernel driver. + #[inline(always)] + pub const fn new(type_: &'static CStr, addr: u16) -> Self { + let src = type_.to_bytes_with_nul(); + build_assert!(src.len() <= Self::I2C_TYPE_SIZE, "Type exceeds 20 bytes"); + let mut i2c_board_info: bindings::i2c_board_info = pin_init::zeroed(); + let mut i: usize = 0; + while i < src.len() { + i2c_board_info.type_[i] = src[i]; + i += 1; + } + + i2c_board_info.addr = addr; + Self(i2c_board_info) + } + + fn as_raw(&self) -> *const bindings::i2c_board_info { + from_ref(&self.0) + } +} + +/// The i2c client representation. +/// +/// This structure represents the Rust abstraction for a C `struct i2c_client`. The +/// implementation abstracts the usage of an existing C `struct i2c_client` that +/// gets passed from the C side +/// +/// # Invariants +/// +/// A [`I2cClient`] instance represents a valid `struct i2c_client` created by the C portion of +/// the kernel. +#[repr(transparent)] +pub struct I2cClient<Ctx: device::DeviceContext = device::Normal>( + Opaque<bindings::i2c_client>, + PhantomData<Ctx>, +); + +impl<Ctx: device::DeviceContext> I2cClient<Ctx> { + fn as_raw(&self) -> *mut bindings::i2c_client { + self.0.get() + } +} + +// SAFETY: `I2cClient` is a transparent wrapper of `struct i2c_client`. +// The offset is guaranteed to point to a valid device field inside `I2cClient`. +unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for I2cClient<Ctx> { + const OFFSET: usize = offset_of!(bindings::i2c_client, dev); +} + +// SAFETY: `I2cClient` is a transparent wrapper of a type that doesn't depend on +// `I2cClient`'s generic argument. +kernel::impl_device_context_deref!(unsafe { I2cClient }); +kernel::impl_device_context_into_aref!(I2cClient); + +// SAFETY: Instances of `I2cClient` are always reference-counted. +unsafe impl AlwaysRefCounted for I2cClient { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. + unsafe { bindings::get_device(self.as_ref().as_raw()) }; + } + + unsafe fn dec_ref(obj: NonNull<Self>) { + // SAFETY: The safety requirements guarantee that the refcount is non-zero. + unsafe { bindings::put_device(&raw mut (*obj.as_ref().as_raw()).dev) } + } +} + +impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for I2cClient<Ctx> { + fn as_ref(&self) -> &device::Device<Ctx> { + let raw = self.as_raw(); + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid + // `struct i2c_client`. + let dev = unsafe { &raw mut (*raw).dev }; + + // SAFETY: `dev` points to a valid `struct device`. + unsafe { device::Device::from_raw(dev) } + } +} + +impl<Ctx: device::DeviceContext> TryFrom<&device::Device<Ctx>> for &I2cClient<Ctx> { + type Error = kernel::error::Error; + + fn try_from(dev: &device::Device<Ctx>) -> Result<Self, Self::Error> { + // SAFETY: By the type invariant of `Device`, `dev.as_raw()` is a valid pointer to a + // `struct device`. + if unsafe { bindings::i2c_verify_client(dev.as_raw()).is_null() } { + return Err(EINVAL); + } + + // SAFETY: We've just verified that the type of `dev` equals to + // `bindings::i2c_client_type`, hence `dev` must be embedded in a valid + // `struct i2c_client` as guaranteed by the corresponding C code. + let idev = unsafe { container_of!(dev.as_raw(), bindings::i2c_client, dev) }; + + // SAFETY: `idev` is a valid pointer to a `struct i2c_client`. + Ok(unsafe { &*idev.cast() }) + } +} + +// SAFETY: A `I2cClient` is always reference-counted and can be released from any thread. +unsafe impl Send for I2cClient {} + +// SAFETY: `I2cClient` can be shared among threads because all methods of `I2cClient` +// (i.e. `I2cClient<Normal>) are thread safe. +unsafe impl Sync for I2cClient {} + +/// The registration of an i2c client device. +/// +/// This type represents the registration of a [`struct i2c_client`]. When an instance of this +/// type is dropped, its respective i2c client device will be unregistered from the system. +/// +/// # Invariants +/// +/// `self.0` always holds a valid pointer to an initialized and registered +/// [`struct i2c_client`]. +#[repr(transparent)] +pub struct Registration(NonNull<bindings::i2c_client>); + +impl Registration { + /// The C `i2c_new_client_device` function wrapper for manual I2C client creation. + pub fn new<'a>( + i2c_adapter: &I2cAdapter, + i2c_board_info: &I2cBoardInfo, + parent_dev: &'a device::Device<device::Bound>, + ) -> impl PinInit<Devres<Self>, Error> + 'a { + Devres::new(parent_dev, Self::try_new(i2c_adapter, i2c_board_info)) + } + + fn try_new(i2c_adapter: &I2cAdapter, i2c_board_info: &I2cBoardInfo) -> Result<Self> { + // SAFETY: the kernel guarantees that `i2c_new_client_device()` returns either a valid + // pointer or NULL. `from_err_ptr` separates errors. Following `NonNull::new` + // checks for NULL. + let raw_dev = from_err_ptr(unsafe { + bindings::i2c_new_client_device(i2c_adapter.as_raw(), i2c_board_info.as_raw()) + })?; + + let dev_ptr = NonNull::new(raw_dev).ok_or(ENODEV)?; + + Ok(Self(dev_ptr)) + } +} + +impl Drop for Registration { + fn drop(&mut self) { + // SAFETY: `Drop` is only called for a valid `Registration`, which by invariant + // always contains a non-null pointer to an `i2c_client`. + unsafe { bindings::i2c_unregister_device(self.0.as_ptr()) } + } +} + +// SAFETY: A `Registration` of a `struct i2c_client` can be released from any thread. +unsafe impl Send for Registration {} + +// SAFETY: `Registration` offers no interior mutability (no mutation through &self +// and no mutable access is exposed) +unsafe impl Sync for Registration {} diff --git a/rust/kernel/id_pool.rs b/rust/kernel/id_pool.rs index a41a3404213c..384753fe0e44 100644 --- a/rust/kernel/id_pool.rs +++ b/rust/kernel/id_pool.rs @@ -7,8 +7,6 @@ use crate::alloc::{AllocError, Flags}; use crate::bitmap::BitmapVec; -const BITS_PER_LONG: usize = bindings::BITS_PER_LONG as usize; - /// Represents a dynamic ID pool backed by a [`BitmapVec`]. /// /// Clients acquire and release IDs from unset bits in a bitmap. @@ -25,22 +23,22 @@ const BITS_PER_LONG: usize = bindings::BITS_PER_LONG as usize; /// Basic usage /// /// ``` -/// use kernel::alloc::{AllocError, flags::GFP_KERNEL}; -/// use kernel::id_pool::IdPool; +/// use kernel::alloc::AllocError; +/// use kernel::id_pool::{IdPool, UnusedId}; /// -/// let mut pool = IdPool::new(64, GFP_KERNEL)?; +/// let mut pool = IdPool::with_capacity(64, GFP_KERNEL)?; /// for i in 0..64 { -/// assert_eq!(i, pool.acquire_next_id(i).ok_or(ENOSPC)?); +/// assert_eq!(i, pool.find_unused_id(i).ok_or(ENOSPC)?.acquire()); /// } /// /// pool.release_id(23); -/// assert_eq!(23, pool.acquire_next_id(0).ok_or(ENOSPC)?); +/// assert_eq!(23, pool.find_unused_id(0).ok_or(ENOSPC)?.acquire()); /// -/// assert_eq!(None, pool.acquire_next_id(0)); // time to realloc. +/// assert!(pool.find_unused_id(0).is_none()); // time to realloc. /// let resizer = pool.grow_request().ok_or(ENOSPC)?.realloc(GFP_KERNEL)?; /// pool.grow(resizer); /// -/// assert_eq!(pool.acquire_next_id(0), Some(64)); +/// assert_eq!(pool.find_unused_id(0).ok_or(ENOSPC)?.acquire(), 64); /// # Ok::<(), Error>(()) /// ``` /// @@ -54,8 +52,8 @@ const BITS_PER_LONG: usize = bindings::BITS_PER_LONG as usize; /// fn get_id_maybe_realloc(guarded_pool: &SpinLock<IdPool>) -> Result<usize, AllocError> { /// let mut pool = guarded_pool.lock(); /// loop { -/// match pool.acquire_next_id(0) { -/// Some(index) => return Ok(index), +/// match pool.find_unused_id(0) { +/// Some(index) => return Ok(index.acquire()), /// None => { /// let alloc_request = pool.grow_request(); /// drop(pool); @@ -97,13 +95,24 @@ impl ReallocRequest { impl IdPool { /// Constructs a new [`IdPool`]. /// - /// A capacity below [`BITS_PER_LONG`] is adjusted to - /// [`BITS_PER_LONG`]. + /// The pool will have a capacity of [`MAX_INLINE_LEN`]. + /// + /// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN + #[inline] + pub fn new() -> Self { + Self { + map: BitmapVec::new_inline(), + } + } + + /// Constructs a new [`IdPool`] with space for a specific number of bits. + /// + /// A capacity below [`MAX_INLINE_LEN`] is adjusted to [`MAX_INLINE_LEN`]. /// - /// [`BITS_PER_LONG`]: srctree/include/asm-generic/bitsperlong.h + /// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN #[inline] - pub fn new(num_ids: usize, flags: Flags) -> Result<Self, AllocError> { - let num_ids = core::cmp::max(num_ids, BITS_PER_LONG); + pub fn with_capacity(num_ids: usize, flags: Flags) -> Result<Self, AllocError> { + let num_ids = usize::max(num_ids, BitmapVec::MAX_INLINE_LEN); let map = BitmapVec::new(num_ids, flags)?; Ok(Self { map }) } @@ -116,28 +125,34 @@ impl IdPool { /// Returns a [`ReallocRequest`] if the [`IdPool`] can be shrunk, [`None`] otherwise. /// - /// The capacity of an [`IdPool`] cannot be shrunk below [`BITS_PER_LONG`]. + /// The capacity of an [`IdPool`] cannot be shrunk below [`MAX_INLINE_LEN`]. /// - /// [`BITS_PER_LONG`]: srctree/include/asm-generic/bitsperlong.h + /// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN /// /// # Examples /// /// ``` - /// use kernel::alloc::{AllocError, flags::GFP_KERNEL}; - /// use kernel::id_pool::{ReallocRequest, IdPool}; + /// use kernel::{ + /// alloc::AllocError, + /// bitmap::BitmapVec, + /// id_pool::{ + /// IdPool, + /// ReallocRequest, + /// }, + /// }; /// - /// let mut pool = IdPool::new(1024, GFP_KERNEL)?; + /// let mut pool = IdPool::with_capacity(1024, GFP_KERNEL)?; /// let alloc_request = pool.shrink_request().ok_or(AllocError)?; /// let resizer = alloc_request.realloc(GFP_KERNEL)?; /// pool.shrink(resizer); - /// assert_eq!(pool.capacity(), kernel::bindings::BITS_PER_LONG as usize); + /// assert_eq!(pool.capacity(), BitmapVec::MAX_INLINE_LEN); /// # Ok::<(), AllocError>(()) /// ``` #[inline] pub fn shrink_request(&self) -> Option<ReallocRequest> { let cap = self.capacity(); - // Shrinking below [`BITS_PER_LONG`] is never possible. - if cap <= BITS_PER_LONG { + // Shrinking below `MAX_INLINE_LEN` is never possible. + if cap <= BitmapVec::MAX_INLINE_LEN { return None; } // Determine if the bitmap can shrink based on the position of @@ -146,13 +161,13 @@ impl IdPool { // bitmap should shrink to half its current size. let Some(bit) = self.map.last_bit() else { return Some(ReallocRequest { - num_ids: BITS_PER_LONG, + num_ids: BitmapVec::MAX_INLINE_LEN, }); }; if bit >= (cap / 4) { return None; } - let num_ids = usize::max(BITS_PER_LONG, cap / 2); + let num_ids = usize::max(BitmapVec::MAX_INLINE_LEN, cap / 2); Some(ReallocRequest { num_ids }) } @@ -177,11 +192,13 @@ impl IdPool { /// Returns a [`ReallocRequest`] for growing this [`IdPool`], if possible. /// - /// The capacity of an [`IdPool`] cannot be grown above [`i32::MAX`]. + /// The capacity of an [`IdPool`] cannot be grown above [`MAX_LEN`]. + /// + /// [`MAX_LEN`]: BitmapVec::MAX_LEN #[inline] pub fn grow_request(&self) -> Option<ReallocRequest> { let num_ids = self.capacity() * 2; - if num_ids > i32::MAX.try_into().unwrap() { + if num_ids > BitmapVec::MAX_LEN { return None; } Some(ReallocRequest { num_ids }) @@ -204,18 +221,18 @@ impl IdPool { self.map = resizer.new; } - /// Acquires a new ID by finding and setting the next zero bit in the - /// bitmap. + /// Finds an unused ID in the bitmap. /// /// Upon success, returns its index. Otherwise, returns [`None`] /// to indicate that a [`Self::grow_request`] is needed. #[inline] - pub fn acquire_next_id(&mut self, offset: usize) -> Option<usize> { - let next_zero_bit = self.map.next_zero_bit(offset); - if let Some(nr) = next_zero_bit { - self.map.set_bit(nr); - } - next_zero_bit + #[must_use] + pub fn find_unused_id(&mut self, offset: usize) -> Option<UnusedId<'_>> { + // INVARIANT: `next_zero_bit()` returns None or an integer less than `map.len()` + Some(UnusedId { + id: self.map.next_zero_bit(offset)?, + pool: self, + }) } /// Releases an ID. @@ -224,3 +241,55 @@ impl IdPool { self.map.clear_bit(id); } } + +/// Represents an unused id in an [`IdPool`]. +/// +/// # Invariants +/// +/// The value of `id` is less than `pool.map.len()`. +pub struct UnusedId<'pool> { + id: usize, + pool: &'pool mut IdPool, +} + +impl<'pool> UnusedId<'pool> { + /// Get the unused id as an usize. + /// + /// Be aware that the id has not yet been acquired in the pool. The + /// [`acquire`] method must be called to prevent others from taking the id. + /// + /// [`acquire`]: UnusedId::acquire() + #[inline] + #[must_use] + pub fn as_usize(&self) -> usize { + self.id + } + + /// Get the unused id as an u32. + /// + /// Be aware that the id has not yet been acquired in the pool. The + /// [`acquire`] method must be called to prevent others from taking the id. + /// + /// [`acquire`]: UnusedId::acquire() + #[inline] + #[must_use] + pub fn as_u32(&self) -> u32 { + // CAST: By the type invariants: + // `self.id < pool.map.len() <= BitmapVec::MAX_LEN = i32::MAX`. + self.id as u32 + } + + /// Acquire the unused id. + #[inline] + pub fn acquire(self) -> usize { + self.pool.map.set_bit(self.id); + self.id + } +} + +impl Default for IdPool { + #[inline] + fn default() -> Self { + Self::new() + } +} diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index ee182b0b5452..98e8b84e68d1 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -4,8 +4,10 @@ //! //! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.h) -use crate::error::{code::EINVAL, Result}; -use crate::{bindings, build_assert, ffi::c_void}; +use crate::{ + bindings, + prelude::*, // +}; pub mod mem; pub mod poll; @@ -13,6 +15,18 @@ pub mod resource; pub use resource::Resource; +/// Physical address type. +/// +/// This is a type alias to either `u32` or `u64` depending on the config option +/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. +pub type PhysAddr = bindings::phys_addr_t; + +/// Resource Size type. +/// +/// This is a type alias to either `u32` or `u64` depending on the config option +/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. +pub type ResourceSize = bindings::resource_size_t; + /// Raw representation of an MMIO region. /// /// By itself, the existence of an instance of this structure does not provide any guarantees that @@ -62,8 +76,16 @@ impl<const SIZE: usize> IoRaw<SIZE> { /// # Examples /// /// ```no_run -/// # use kernel::{bindings, ffi::c_void, io::{Io, IoRaw}}; -/// # use core::ops::Deref; +/// use kernel::{ +/// bindings, +/// ffi::c_void, +/// io::{ +/// Io, +/// IoRaw, +/// PhysAddr, +/// }, +/// }; +/// use core::ops::Deref; /// /// // See also [`pci::Bar`] for a real example. /// struct IoMem<const SIZE: usize>(IoRaw<SIZE>); @@ -76,7 +98,7 @@ impl<const SIZE: usize> IoRaw<SIZE> { /// unsafe fn new(paddr: usize) -> Result<Self>{ /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is /// // valid for `ioremap`. -/// let addr = unsafe { bindings::ioremap(paddr as bindings::phys_addr_t, SIZE) }; +/// let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) }; /// if addr.is_null() { /// return Err(ENOMEM); /// } diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index 6f99510bfc3a..b03b82cd531b 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -4,16 +4,24 @@ use core::ops::Deref; -use crate::c_str; -use crate::device::Bound; -use crate::device::Device; -use crate::devres::Devres; -use crate::io; -use crate::io::resource::Region; -use crate::io::resource::Resource; -use crate::io::Io; -use crate::io::IoRaw; -use crate::prelude::*; +use crate::{ + c_str, + device::{ + Bound, + Device, // + }, + devres::Devres, + io::{ + self, + resource::{ + Region, + Resource, // + }, + Io, + IoRaw, // + }, + prelude::*, +}; /// An IO request for a specific device and resource. pub struct IoRequest<'a> { @@ -53,7 +61,7 @@ impl<'a> IoRequest<'a> { /// fn probe( /// pdev: &platform::Device<Core>, /// info: Option<&Self::IdInfo>, - /// ) -> Result<Pin<KBox<Self>>> { + /// ) -> impl PinInit<Self, Error> { /// let offset = 0; // Some offset. /// /// // If the size is known at compile time, use [`Self::iomap_sized`]. @@ -70,7 +78,7 @@ impl<'a> IoRequest<'a> { /// /// io.write32_relaxed(data, offset); /// - /// # Ok(KBox::new(SampleDriver, GFP_KERNEL)?.into()) + /// # Ok(SampleDriver) /// } /// } /// ``` @@ -111,7 +119,7 @@ impl<'a> IoRequest<'a> { /// fn probe( /// pdev: &platform::Device<Core>, /// info: Option<&Self::IdInfo>, - /// ) -> Result<Pin<KBox<Self>>> { + /// ) -> impl PinInit<Self, Error> { /// let offset = 0; // Some offset. /// /// // Unlike [`Self::iomap_sized`], here the size of the memory region @@ -128,7 +136,7 @@ impl<'a> IoRequest<'a> { /// /// io.try_write32_relaxed(data, offset)?; /// - /// # Ok(KBox::new(SampleDriver, GFP_KERNEL)?.into()) + /// # Ok(SampleDriver) /// } /// } /// ``` diff --git a/rust/kernel/io/poll.rs b/rust/kernel/io/poll.rs index 613eb25047ef..b1a2570364f4 100644 --- a/rust/kernel/io/poll.rs +++ b/rust/kernel/io/poll.rs @@ -5,10 +5,18 @@ //! C header: [`include/linux/iopoll.h`](srctree/include/linux/iopoll.h). use crate::{ - error::{code::*, Result}, + prelude::*, processor::cpu_relax, task::might_sleep, - time::{delay::fsleep, Delta, Instant, Monotonic}, + time::{ + delay::{ + fsleep, + udelay, // + }, + Delta, + Instant, + Monotonic, // + }, }; /// Polls periodically until a condition is met, an error occurs, @@ -42,8 +50,8 @@ use crate::{ /// /// const HW_READY: u16 = 0x01; /// -/// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result<()> { -/// match read_poll_timeout( +/// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result { +/// read_poll_timeout( /// // The `op` closure reads the value of a specific status register. /// || io.try_read16(0x1000), /// // The `cond` closure takes a reference to the value returned by `op` @@ -51,14 +59,8 @@ use crate::{ /// |val: &u16| *val == HW_READY, /// Delta::from_millis(50), /// Delta::from_secs(3), -/// ) { -/// Ok(_) => { -/// // The hardware is ready. The returned value of the `op` closure -/// // isn't used. -/// Ok(()) -/// } -/// Err(e) => Err(e), -/// } +/// )?; +/// Ok(()) /// } /// ``` #[track_caller] @@ -102,3 +104,70 @@ where cpu_relax(); } } + +/// Polls periodically until a condition is met, an error occurs, +/// or the attempt limit is reached. +/// +/// The function repeatedly executes the given operation `op` closure and +/// checks its result using the condition closure `cond`. +/// +/// If `cond` returns `true`, the function returns successfully with the result of `op`. +/// Otherwise, it performs a busy wait for a duration specified by `delay_delta` +/// before executing `op` again. +/// +/// This process continues until either `op` returns an error, `cond` +/// returns `true`, or the attempt limit specified by `retry` is reached. +/// +/// # Errors +/// +/// If `op` returns an error, then that error is returned directly. +/// +/// If the attempt limit specified by `retry` is reached, then +/// `Err(ETIMEDOUT)` is returned. +/// +/// # Examples +/// +/// ```no_run +/// use kernel::io::{poll::read_poll_timeout_atomic, Io}; +/// use kernel::time::Delta; +/// +/// const HW_READY: u16 = 0x01; +/// +/// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result { +/// read_poll_timeout_atomic( +/// // The `op` closure reads the value of a specific status register. +/// || io.try_read16(0x1000), +/// // The `cond` closure takes a reference to the value returned by `op` +/// // and checks whether the hardware is ready. +/// |val: &u16| *val == HW_READY, +/// Delta::from_micros(50), +/// 1000, +/// )?; +/// Ok(()) +/// } +/// ``` +pub fn read_poll_timeout_atomic<Op, Cond, T>( + mut op: Op, + mut cond: Cond, + delay_delta: Delta, + retry: usize, +) -> Result<T> +where + Op: FnMut() -> Result<T>, + Cond: FnMut(&T) -> bool, +{ + for _ in 0..retry { + let val = op()?; + if cond(&val) { + return Ok(val); + } + + if !delay_delta.is_zero() { + udelay(delay_delta); + } + + cpu_relax(); + } + + Err(ETIMEDOUT) +} diff --git a/rust/kernel/io/resource.rs b/rust/kernel/io/resource.rs index bea3ee0ed87b..56cfde97ce87 100644 --- a/rust/kernel/io/resource.rs +++ b/rust/kernel/io/resource.rs @@ -5,18 +5,21 @@ //! //! C header: [`include/linux/ioport.h`](srctree/include/linux/ioport.h) -use core::ops::Deref; -use core::ptr::NonNull; - -use crate::prelude::*; -use crate::str::{CStr, CString}; -use crate::types::Opaque; - -/// Resource Size type. -/// -/// This is a type alias to either `u32` or `u64` depending on the config option -/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. -pub type ResourceSize = bindings::phys_addr_t; +use core::{ + ops::Deref, + ptr::NonNull, // +}; + +use crate::{ + prelude::*, + str::CString, + types::Opaque, // +}; + +pub use super::{ + PhysAddr, + ResourceSize, // +}; /// A region allocated from a parent [`Resource`]. /// @@ -97,7 +100,7 @@ impl Resource { /// the region, or a part of it, is already in use. pub fn request_region( &self, - start: ResourceSize, + start: PhysAddr, size: ResourceSize, name: CString, flags: Flags, @@ -131,7 +134,7 @@ impl Resource { } /// Returns the start address of the resource. - pub fn start(&self) -> ResourceSize { + pub fn start(&self) -> PhysAddr { let inner = self.0.get(); // SAFETY: Safe as per the invariants of `Resource`. unsafe { (*inner).start } diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index a4eee75cf07a..6083dec1f190 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -97,6 +97,8 @@ pub mod faux; pub mod firmware; pub mod fmt; pub mod fs; +#[cfg(CONFIG_I2C = "y")] +pub mod i2c; pub mod id_pool; pub mod init; pub mod io; @@ -110,6 +112,7 @@ pub mod list; pub mod maple_tree; pub mod miscdevice; pub mod mm; +pub mod module_param; #[cfg(CONFIG_NET)] pub mod net; pub mod num; diff --git a/rust/kernel/module_param.rs b/rust/kernel/module_param.rs new file mode 100644 index 000000000000..6a8a7a875643 --- /dev/null +++ b/rust/kernel/module_param.rs @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Support for module parameters. +//! +//! C header: [`include/linux/moduleparam.h`](srctree/include/linux/moduleparam.h) + +use crate::prelude::*; +use crate::str::BStr; +use bindings; +use kernel::sync::SetOnce; + +/// Newtype to make `bindings::kernel_param` [`Sync`]. +#[repr(transparent)] +#[doc(hidden)] +pub struct KernelParam(bindings::kernel_param); + +impl KernelParam { + #[doc(hidden)] + pub const fn new(val: bindings::kernel_param) -> Self { + Self(val) + } +} + +// SAFETY: C kernel handles serializing access to this type. We never access it +// from Rust module. +unsafe impl Sync for KernelParam {} + +/// Types that can be used for module parameters. +// NOTE: This trait is `Copy` because drop could produce unsoundness during teardown. +pub trait ModuleParam: Sized + Copy { + /// Parse a parameter argument into the parameter value. + fn try_from_param_arg(arg: &BStr) -> Result<Self>; +} + +/// Set the module parameter from a string. +/// +/// Used to set the parameter value at kernel initialization, when loading +/// the module or when set through `sysfs`. +/// +/// See `struct kernel_param_ops.set`. +/// +/// # Safety +/// +/// - If `val` is non-null then it must point to a valid null-terminated string that must be valid +/// for reads for the duration of the call. +/// - `param` must be a pointer to a `bindings::kernel_param` initialized by the rust module macro. +/// The pointee must be valid for reads for the duration of the call. +/// +/// # Note +/// +/// - The safety requirements are satisfied by C API contract when this function is invoked by the +/// module subsystem C code. +/// - Currently, we only support read-only parameters that are not readable from `sysfs`. Thus, this +/// function is only called at kernel initialization time, or at module load time, and we have +/// exclusive access to the parameter for the duration of the function. +/// +/// [`module!`]: macros::module +unsafe extern "C" fn set_param<T>(val: *const c_char, param: *const bindings::kernel_param) -> c_int +where + T: ModuleParam, +{ + // NOTE: If we start supporting arguments without values, val _is_ allowed + // to be null here. + if val.is_null() { + // TODO: Use pr_warn_once available. + crate::pr_warn!("Null pointer passed to `module_param::set_param`"); + return EINVAL.to_errno(); + } + + // SAFETY: By function safety requirement, val is non-null, null-terminated + // and valid for reads for the duration of this function. + let arg = unsafe { CStr::from_char_ptr(val) }; + let arg: &BStr = arg.as_ref(); + + crate::error::from_result(|| { + let new_value = T::try_from_param_arg(arg)?; + + // SAFETY: By function safety requirements, this access is safe. + let container = unsafe { &*((*param).__bindgen_anon_1.arg.cast::<SetOnce<T>>()) }; + + container + .populate(new_value) + .then_some(0) + .ok_or(kernel::error::code::EEXIST) + }) +} + +macro_rules! impl_int_module_param { + ($ty:ident) => { + impl ModuleParam for $ty { + fn try_from_param_arg(arg: &BStr) -> Result<Self> { + <$ty as crate::str::parse_int::ParseInt>::from_str(arg) + } + } + }; +} + +impl_int_module_param!(i8); +impl_int_module_param!(u8); +impl_int_module_param!(i16); +impl_int_module_param!(u16); +impl_int_module_param!(i32); +impl_int_module_param!(u32); +impl_int_module_param!(i64); +impl_int_module_param!(u64); +impl_int_module_param!(isize); +impl_int_module_param!(usize); + +/// A wrapper for kernel parameters. +/// +/// This type is instantiated by the [`module!`] macro when module parameters are +/// defined. You should never need to instantiate this type directly. +/// +/// Note: This type is `pub` because it is used by module crates to access +/// parameter values. +pub struct ModuleParamAccess<T> { + value: SetOnce<T>, + default: T, +} + +// SAFETY: We only create shared references to the contents of this container, +// so if `T` is `Sync`, so is `ModuleParamAccess`. +unsafe impl<T: Sync> Sync for ModuleParamAccess<T> {} + +impl<T> ModuleParamAccess<T> { + #[doc(hidden)] + pub const fn new(default: T) -> Self { + Self { + value: SetOnce::new(), + default, + } + } + + /// Get a shared reference to the parameter value. + // Note: When sysfs access to parameters are enabled, we have to pass in a + // held lock guard here. + pub fn value(&self) -> &T { + self.value.as_ref().unwrap_or(&self.default) + } + + /// Get a mutable pointer to `self`. + /// + /// NOTE: In most cases it is not safe deref the returned pointer. + pub const fn as_void_ptr(&self) -> *mut c_void { + core::ptr::from_ref(self).cast_mut().cast() + } +} + +#[doc(hidden)] +/// Generate a static [`kernel_param_ops`](srctree/include/linux/moduleparam.h) struct. +/// +/// # Examples +/// +/// ```ignore +/// make_param_ops!( +/// /// Documentation for new param ops. +/// PARAM_OPS_MYTYPE, // Name for the static. +/// MyType // A type which implements [`ModuleParam`]. +/// ); +/// ``` +macro_rules! make_param_ops { + ($ops:ident, $ty:ty) => { + #[doc(hidden)] + pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops { + flags: 0, + set: Some(set_param::<$ty>), + get: None, + free: None, + }; + }; +} + +make_param_ops!(PARAM_OPS_I8, i8); +make_param_ops!(PARAM_OPS_U8, u8); +make_param_ops!(PARAM_OPS_I16, i16); +make_param_ops!(PARAM_OPS_U16, u16); +make_param_ops!(PARAM_OPS_I32, i32); +make_param_ops!(PARAM_OPS_U32, u32); +make_param_ops!(PARAM_OPS_I64, i64); +make_param_ops!(PARAM_OPS_U64, u64); +make_param_ops!(PARAM_OPS_ISIZE, isize); +make_param_ops!(PARAM_OPS_USIZE, usize); diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 7fcc5f6022c1..82e128431f08 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -5,28 +5,47 @@ //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use crate::{ - bindings, container_of, device, - device_id::{RawDeviceId, RawDeviceIdIndex}, - devres::Devres, + bindings, + container_of, + device, + device_id::{ + RawDeviceId, + RawDeviceIdIndex, // + }, driver, - error::{from_result, to_result, Result}, - io::{Io, IoRaw}, - irq::{self, IrqRequest}, + error::{ + from_result, + to_result, // + }, + prelude::*, str::CStr, - sync::aref::ARef, types::Opaque, - ThisModule, + ThisModule, // }; use core::{ marker::PhantomData, - ops::Deref, - ptr::{addr_of_mut, NonNull}, + mem::offset_of, + ptr::{ + addr_of_mut, + NonNull, // + }, }; -use kernel::prelude::*; mod id; +mod io; +mod irq; -pub use self::id::{Class, ClassMask, Vendor}; +pub use self::id::{ + Class, + ClassMask, + Vendor, // +}; +pub use self::io::Bar; +pub use self::irq::{ + IrqType, + IrqTypes, + IrqVector, // +}; /// An adapter for the registration of PCI drivers. pub struct Adapter<T: Driver>(T); @@ -78,9 +97,9 @@ impl<T: Driver + 'static> Adapter<T> { let info = T::ID_TABLE.info(id.index()); from_result(|| { - let data = T::probe(pdev, info)?; + let data = T::probe(pdev, info); - pdev.as_ref().set_drvdata(data); + pdev.as_ref().set_drvdata(data)?; Ok(0) }) } @@ -95,7 +114,7 @@ impl<T: Driver + 'static> Adapter<T> { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin<KBox<T>>`. - let data = unsafe { pdev.as_ref().drvdata_obtain::<Pin<KBox<T>>>() }; + let data = unsafe { pdev.as_ref().drvdata_obtain::<T>() }; T::unbind(pdev, data.as_ref()); } @@ -249,7 +268,7 @@ macro_rules! pci_device_table { /// fn probe( /// _pdev: &pci::Device<Core>, /// _id_info: &Self::IdInfo, -/// ) -> Result<Pin<KBox<Self>>> { +/// ) -> impl PinInit<Self, Error> { /// Err(ENODEV) /// } /// } @@ -272,7 +291,7 @@ pub trait Driver: Send { /// /// Called when a new pci device is added or discovered. Implementers should /// attempt to initialize the device here. - fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> Result<Pin<KBox<Self>>>; + fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>; /// PCI driver unbind. /// @@ -305,112 +324,6 @@ pub struct Device<Ctx: device::DeviceContext = device::Normal>( PhantomData<Ctx>, ); -/// A PCI BAR to perform I/O-Operations on. -/// -/// # Invariants -/// -/// `Bar` always holds an `IoRaw` inststance that holds a valid pointer to the start of the I/O -/// memory mapped PCI bar and its size. -pub struct Bar<const SIZE: usize = 0> { - pdev: ARef<Device>, - io: IoRaw<SIZE>, - num: i32, -} - -impl<const SIZE: usize> Bar<SIZE> { - fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> { - let len = pdev.resource_len(num)?; - if len == 0 { - return Err(ENOMEM); - } - - // Convert to `i32`, since that's what all the C bindings use. - let num = i32::try_from(num)?; - - // SAFETY: - // `pdev` is valid by the invariants of `Device`. - // `num` is checked for validity by a previous call to `Device::resource_len`. - // `name` is always valid. - let ret = unsafe { bindings::pci_request_region(pdev.as_raw(), num, name.as_char_ptr()) }; - if ret != 0 { - return Err(EBUSY); - } - - // SAFETY: - // `pdev` is valid by the invariants of `Device`. - // `num` is checked for validity by a previous call to `Device::resource_len`. - // `name` is always valid. - let ioptr: usize = unsafe { bindings::pci_iomap(pdev.as_raw(), num, 0) } as usize; - if ioptr == 0 { - // SAFETY: - // `pdev` valid by the invariants of `Device`. - // `num` is checked for validity by a previous call to `Device::resource_len`. - unsafe { bindings::pci_release_region(pdev.as_raw(), num) }; - return Err(ENOMEM); - } - - let io = match IoRaw::new(ioptr, len as usize) { - Ok(io) => io, - Err(err) => { - // SAFETY: - // `pdev` is valid by the invariants of `Device`. - // `ioptr` is guaranteed to be the start of a valid I/O mapped memory region. - // `num` is checked for validity by a previous call to `Device::resource_len`. - unsafe { Self::do_release(pdev, ioptr, num) }; - return Err(err); - } - }; - - Ok(Bar { - pdev: pdev.into(), - io, - num, - }) - } - - /// # Safety - /// - /// `ioptr` must be a valid pointer to the memory mapped PCI bar number `num`. - unsafe fn do_release(pdev: &Device, ioptr: usize, num: i32) { - // SAFETY: - // `pdev` is valid by the invariants of `Device`. - // `ioptr` is valid by the safety requirements. - // `num` is valid by the safety requirements. - unsafe { - bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut c_void); - bindings::pci_release_region(pdev.as_raw(), num); - } - } - - fn release(&self) { - // SAFETY: The safety requirements are guaranteed by the type invariant of `self.pdev`. - unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) }; - } -} - -impl Bar { - #[inline] - fn index_is_valid(index: u32) -> bool { - // A `struct pci_dev` owns an array of resources with at most `PCI_NUM_RESOURCES` entries. - index < bindings::PCI_NUM_RESOURCES - } -} - -impl<const SIZE: usize> Drop for Bar<SIZE> { - fn drop(&mut self) { - self.release(); - } -} - -impl<const SIZE: usize> Deref for Bar<SIZE> { - type Target = Io<SIZE>; - - fn deref(&self) -> &Self::Target { - // SAFETY: By the type invariant of `Self`, the MMIO range in `self.io` is properly mapped. - unsafe { Io::from_raw(&self.io) } - } -} - impl<Ctx: device::DeviceContext> Device<Ctx> { #[inline] fn as_raw(&self) -> *mut bindings::pci_dev { @@ -484,7 +397,7 @@ impl Device { unsafe { (*self.as_raw()).subsystem_device } } - /// Returns the start of the given PCI bar resource. + /// Returns the start of the given PCI BAR resource. pub fn resource_start(&self, bar: u32) -> Result<bindings::resource_size_t> { if !Bar::index_is_valid(bar) { return Err(EINVAL); @@ -496,7 +409,7 @@ impl Device { Ok(unsafe { bindings::pci_resource_start(self.as_raw(), bar.try_into()?) }) } - /// Returns the size of the given PCI bar resource. + /// Returns the size of the given PCI BAR resource. pub fn resource_len(&self, bar: u32) -> Result<bindings::resource_size_t> { if !Bar::index_is_valid(bar) { return Err(EINVAL); @@ -516,68 +429,6 @@ impl Device { } } -impl Device<device::Bound> { - /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks - /// can be performed on compile time for offsets (plus the requested type size) < SIZE. - pub fn iomap_region_sized<'a, const SIZE: usize>( - &'a self, - bar: u32, - name: &'a CStr, - ) -> impl PinInit<Devres<Bar<SIZE>>, Error> + 'a { - Devres::new(self.as_ref(), Bar::<SIZE>::new(self, bar, name)) - } - - /// Mapps an entire PCI-BAR after performing a region-request on it. - pub fn iomap_region<'a>( - &'a self, - bar: u32, - name: &'a CStr, - ) -> impl PinInit<Devres<Bar>, Error> + 'a { - self.iomap_region_sized::<0>(bar, name) - } - - /// Returns an [`IrqRequest`] for the IRQ vector at the given index, if any. - pub fn irq_vector(&self, index: u32) -> Result<IrqRequest<'_>> { - // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_dev`. - let irq = unsafe { crate::bindings::pci_irq_vector(self.as_raw(), index) }; - if irq < 0 { - return Err(crate::error::Error::from_errno(irq)); - } - // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. - Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) }) - } - - /// Returns a [`kernel::irq::Registration`] for the IRQ vector at the given - /// index. - pub fn request_irq<'a, T: crate::irq::Handler + 'static>( - &'a self, - index: u32, - flags: irq::Flags, - name: &'static CStr, - handler: impl PinInit<T, Error> + 'a, - ) -> Result<impl PinInit<irq::Registration<T>, Error> + 'a> { - let request = self.irq_vector(index)?; - - Ok(irq::Registration::<T>::new(request, flags, name, handler)) - } - - /// Returns a [`kernel::irq::ThreadedRegistration`] for the IRQ vector at - /// the given index. - pub fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'static>( - &'a self, - index: u32, - flags: irq::Flags, - name: &'static CStr, - handler: impl PinInit<T, Error> + 'a, - ) -> Result<impl PinInit<irq::ThreadedRegistration<T>, Error> + 'a> { - let request = self.irq_vector(index)?; - - Ok(irq::ThreadedRegistration::<T>::new( - request, flags, name, handler, - )) - } -} - impl Device<device::Core> { /// Enable memory resources for this device. pub fn enable_device_mem(&self) -> Result { @@ -593,6 +444,12 @@ impl Device<device::Core> { } } +// SAFETY: `pci::Device` is a transparent wrapper of `struct pci_dev`. +// The offset is guaranteed to point to a valid device field inside `pci::Device`. +unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> { + const OFFSET: usize = offset_of!(bindings::pci_dev, dev); +} + // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic // argument. kernel::impl_device_context_deref!(unsafe { Device }); diff --git a/rust/kernel/pci/id.rs b/rust/kernel/pci/id.rs index 5f5d59ff49fc..c09125946d9e 100644 --- a/rust/kernel/pci/id.rs +++ b/rust/kernel/pci/id.rs @@ -4,7 +4,11 @@ //! //! This module contains PCI class codes, Vendor IDs, and supporting types. -use crate::{bindings, error::code::EINVAL, error::Error, fmt, prelude::*}; +use crate::{ + bindings, + fmt, + prelude::*, // +}; /// PCI device class codes. /// diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs new file mode 100644 index 000000000000..0d55c3139b6f --- /dev/null +++ b/rust/kernel/pci/io.rs @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! PCI memory-mapped I/O infrastructure. + +use super::Device; +use crate::{ + bindings, + device, + devres::Devres, + io::{ + Io, + IoRaw, // + }, + prelude::*, + sync::aref::ARef, // +}; +use core::ops::Deref; + +/// A PCI BAR to perform I/O-Operations on. +/// +/// # Invariants +/// +/// `Bar` always holds an `IoRaw` inststance that holds a valid pointer to the start of the I/O +/// memory mapped PCI BAR and its size. +pub struct Bar<const SIZE: usize = 0> { + pdev: ARef<Device>, + io: IoRaw<SIZE>, + num: i32, +} + +impl<const SIZE: usize> Bar<SIZE> { + pub(super) fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> { + let len = pdev.resource_len(num)?; + if len == 0 { + return Err(ENOMEM); + } + + // Convert to `i32`, since that's what all the C bindings use. + let num = i32::try_from(num)?; + + // SAFETY: + // `pdev` is valid by the invariants of `Device`. + // `num` is checked for validity by a previous call to `Device::resource_len`. + // `name` is always valid. + let ret = unsafe { bindings::pci_request_region(pdev.as_raw(), num, name.as_char_ptr()) }; + if ret != 0 { + return Err(EBUSY); + } + + // SAFETY: + // `pdev` is valid by the invariants of `Device`. + // `num` is checked for validity by a previous call to `Device::resource_len`. + // `name` is always valid. + let ioptr: usize = unsafe { bindings::pci_iomap(pdev.as_raw(), num, 0) } as usize; + if ioptr == 0 { + // SAFETY: + // `pdev` valid by the invariants of `Device`. + // `num` is checked for validity by a previous call to `Device::resource_len`. + unsafe { bindings::pci_release_region(pdev.as_raw(), num) }; + return Err(ENOMEM); + } + + let io = match IoRaw::new(ioptr, len as usize) { + Ok(io) => io, + Err(err) => { + // SAFETY: + // `pdev` is valid by the invariants of `Device`. + // `ioptr` is guaranteed to be the start of a valid I/O mapped memory region. + // `num` is checked for validity by a previous call to `Device::resource_len`. + unsafe { Self::do_release(pdev, ioptr, num) }; + return Err(err); + } + }; + + Ok(Bar { + pdev: pdev.into(), + io, + num, + }) + } + + /// # Safety + /// + /// `ioptr` must be a valid pointer to the memory mapped PCI BAR number `num`. + unsafe fn do_release(pdev: &Device, ioptr: usize, num: i32) { + // SAFETY: + // `pdev` is valid by the invariants of `Device`. + // `ioptr` is valid by the safety requirements. + // `num` is valid by the safety requirements. + unsafe { + bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut c_void); + bindings::pci_release_region(pdev.as_raw(), num); + } + } + + fn release(&self) { + // SAFETY: The safety requirements are guaranteed by the type invariant of `self.pdev`. + unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) }; + } +} + +impl Bar { + #[inline] + pub(super) fn index_is_valid(index: u32) -> bool { + // A `struct pci_dev` owns an array of resources with at most `PCI_NUM_RESOURCES` entries. + index < bindings::PCI_NUM_RESOURCES + } +} + +impl<const SIZE: usize> Drop for Bar<SIZE> { + fn drop(&mut self) { + self.release(); + } +} + +impl<const SIZE: usize> Deref for Bar<SIZE> { + type Target = Io<SIZE>; + + fn deref(&self) -> &Self::Target { + // SAFETY: By the type invariant of `Self`, the MMIO range in `self.io` is properly mapped. + unsafe { Io::from_raw(&self.io) } + } +} + +impl Device<device::Bound> { + /// Maps an entire PCI BAR after performing a region-request on it. I/O operation bound checks + /// can be performed on compile time for offsets (plus the requested type size) < SIZE. + pub fn iomap_region_sized<'a, const SIZE: usize>( + &'a self, + bar: u32, + name: &'a CStr, + ) -> impl PinInit<Devres<Bar<SIZE>>, Error> + 'a { + Devres::new(self.as_ref(), Bar::<SIZE>::new(self, bar, name)) + } + + /// Maps an entire PCI BAR after performing a region-request on it. + pub fn iomap_region<'a>( + &'a self, + bar: u32, + name: &'a CStr, + ) -> impl PinInit<Devres<Bar>, Error> + 'a { + self.iomap_region_sized::<0>(bar, name) + } +} diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs new file mode 100644 index 000000000000..d9230e105541 --- /dev/null +++ b/rust/kernel/pci/irq.rs @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! PCI interrupt infrastructure. + +use super::Device; +use crate::{ + bindings, + device, + device::Bound, + devres, + error::to_result, + irq::{ + self, + IrqRequest, // + }, + prelude::*, + str::CStr, + sync::aref::ARef, // +}; +use core::ops::RangeInclusive; + +/// IRQ type flags for PCI interrupt allocation. +#[derive(Debug, Clone, Copy)] +pub enum IrqType { + /// INTx interrupts. + Intx, + /// Message Signaled Interrupts (MSI). + Msi, + /// Extended Message Signaled Interrupts (MSI-X). + MsiX, +} + +impl IrqType { + /// Convert to the corresponding kernel flags. + const fn as_raw(self) -> u32 { + match self { + IrqType::Intx => bindings::PCI_IRQ_INTX, + IrqType::Msi => bindings::PCI_IRQ_MSI, + IrqType::MsiX => bindings::PCI_IRQ_MSIX, + } + } +} + +/// Set of IRQ types that can be used for PCI interrupt allocation. +#[derive(Debug, Clone, Copy, Default)] +pub struct IrqTypes(u32); + +impl IrqTypes { + /// Create a set containing all IRQ types (MSI-X, MSI, and INTx). + pub const fn all() -> Self { + Self(bindings::PCI_IRQ_ALL_TYPES) + } + + /// Build a set of IRQ types. + /// + /// # Examples + /// + /// ```ignore + /// // Create a set with only MSI and MSI-X (no INTx interrupts). + /// let msi_only = IrqTypes::default() + /// .with(IrqType::Msi) + /// .with(IrqType::MsiX); + /// ``` + pub const fn with(self, irq_type: IrqType) -> Self { + Self(self.0 | irq_type.as_raw()) + } + + /// Get the raw flags value. + const fn as_raw(self) -> u32 { + self.0 + } +} + +/// Represents an allocated IRQ vector for a specific PCI device. +/// +/// This type ties an IRQ vector to the device it was allocated for, +/// ensuring the vector is only used with the correct device. +#[derive(Clone, Copy)] +pub struct IrqVector<'a> { + dev: &'a Device<Bound>, + index: u32, +} + +impl<'a> IrqVector<'a> { + /// Creates a new [`IrqVector`] for the given device and index. + /// + /// # Safety + /// + /// - `index` must be a valid IRQ vector index for `dev`. + /// - `dev` must point to a [`Device`] that has successfully allocated IRQ vectors. + unsafe fn new(dev: &'a Device<Bound>, index: u32) -> Self { + Self { dev, index } + } + + /// Returns the raw vector index. + fn index(&self) -> u32 { + self.index + } +} + +impl<'a> TryInto<IrqRequest<'a>> for IrqVector<'a> { + type Error = Error; + + fn try_into(self) -> Result<IrqRequest<'a>> { + // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_dev`. + let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), self.index()) }; + if irq < 0 { + return Err(crate::error::Error::from_errno(irq)); + } + // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. + Ok(unsafe { IrqRequest::new(self.dev.as_ref(), irq as u32) }) + } +} + +/// Represents an IRQ vector allocation for a PCI device. +/// +/// This type ensures that IRQ vectors are properly allocated and freed by +/// tying the allocation to the lifetime of this registration object. +/// +/// # Invariants +/// +/// The [`Device`] has successfully allocated IRQ vectors. +struct IrqVectorRegistration { + dev: ARef<Device>, +} + +impl IrqVectorRegistration { + /// Allocate and register IRQ vectors for the given PCI device. + /// + /// Allocates IRQ vectors and registers them with devres for automatic cleanup. + /// Returns a range of valid IRQ vectors. + fn register<'a>( + dev: &'a Device<Bound>, + min_vecs: u32, + max_vecs: u32, + irq_types: IrqTypes, + ) -> Result<RangeInclusive<IrqVector<'a>>> { + // SAFETY: + // - `dev.as_raw()` is guaranteed to be a valid pointer to a `struct pci_dev` + // by the type invariant of `Device`. + // - `pci_alloc_irq_vectors` internally validates all other parameters + // and returns error codes. + let ret = unsafe { + bindings::pci_alloc_irq_vectors(dev.as_raw(), min_vecs, max_vecs, irq_types.as_raw()) + }; + + to_result(ret)?; + let count = ret as u32; + + // SAFETY: + // - `pci_alloc_irq_vectors` returns the number of allocated vectors on success. + // - Vectors are 0-based, so valid indices are [0, count-1]. + // - `pci_alloc_irq_vectors` guarantees `count >= min_vecs > 0`, so both `0` and + // `count - 1` are valid IRQ vector indices for `dev`. + let range = unsafe { IrqVector::new(dev, 0)..=IrqVector::new(dev, count - 1) }; + + // INVARIANT: The IRQ vector allocation for `dev` above was successful. + let irq_vecs = Self { dev: dev.into() }; + devres::register(dev.as_ref(), irq_vecs, GFP_KERNEL)?; + + Ok(range) + } +} + +impl Drop for IrqVectorRegistration { + fn drop(&mut self) { + // SAFETY: + // - By the type invariant, `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`. + // - `self.dev` has successfully allocated IRQ vectors. + unsafe { bindings::pci_free_irq_vectors(self.dev.as_raw()) }; + } +} + +impl Device<device::Bound> { + /// Returns a [`kernel::irq::Registration`] for the given IRQ vector. + pub fn request_irq<'a, T: crate::irq::Handler + 'static>( + &'a self, + vector: IrqVector<'a>, + flags: irq::Flags, + name: &'static CStr, + handler: impl PinInit<T, Error> + 'a, + ) -> impl PinInit<irq::Registration<T>, Error> + 'a { + pin_init::pin_init_scope(move || { + let request = vector.try_into()?; + + Ok(irq::Registration::<T>::new(request, flags, name, handler)) + }) + } + + /// Returns a [`kernel::irq::ThreadedRegistration`] for the given IRQ vector. + pub fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'static>( + &'a self, + vector: IrqVector<'a>, + flags: irq::Flags, + name: &'static CStr, + handler: impl PinInit<T, Error> + 'a, + ) -> impl PinInit<irq::ThreadedRegistration<T>, Error> + 'a { + pin_init::pin_init_scope(move || { + let request = vector.try_into()?; + + Ok(irq::ThreadedRegistration::<T>::new( + request, flags, name, handler, + )) + }) + } + + /// Allocate IRQ vectors for this PCI device with automatic cleanup. + /// + /// Allocates between `min_vecs` and `max_vecs` interrupt vectors for the device. + /// The allocation will use MSI-X, MSI, or INTx interrupts based on the `irq_types` + /// parameter and hardware capabilities. When multiple types are specified, the kernel + /// will try them in order of preference: MSI-X first, then MSI, then INTx interrupts. + /// + /// The allocated vectors are automatically freed when the device is unbound, using the + /// devres (device resource management) system. + /// + /// # Arguments + /// + /// * `min_vecs` - Minimum number of vectors required. + /// * `max_vecs` - Maximum number of vectors to allocate. + /// * `irq_types` - Types of interrupts that can be used. + /// + /// # Returns + /// + /// Returns a range of IRQ vectors that were successfully allocated, or an error if the + /// allocation fails or cannot meet the minimum requirement. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{ device::Bound, pci}; + /// # fn no_run(dev: &pci::Device<Bound>) -> Result { + /// // Allocate using any available interrupt type in the order mentioned above. + /// let vectors = dev.alloc_irq_vectors(1, 32, pci::IrqTypes::all())?; + /// + /// // Allocate MSI or MSI-X only (no INTx interrupts). + /// let msi_only = pci::IrqTypes::default() + /// .with(pci::IrqType::Msi) + /// .with(pci::IrqType::MsiX); + /// let vectors = dev.alloc_irq_vectors(4, 16, msi_only)?; + /// # Ok(()) + /// # } + /// ``` + pub fn alloc_irq_vectors( + &self, + min_vecs: u32, + max_vecs: u32, + irq_types: IrqTypes, + ) -> Result<RangeInclusive<IrqVector<'_>>> { + IrqVectorRegistration::register(self, min_vecs, max_vecs, irq_types) + } +} diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 7205fe3416d3..ed889f079cab 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -19,6 +19,7 @@ use crate::{ use core::{ marker::PhantomData, + mem::offset_of, ptr::{addr_of_mut, NonNull}, }; @@ -74,9 +75,9 @@ impl<T: Driver + 'static> Adapter<T> { let info = <Self as driver::Adapter>::id_info(pdev.as_ref()); from_result(|| { - let data = T::probe(pdev, info)?; + let data = T::probe(pdev, info); - pdev.as_ref().set_drvdata(data); + pdev.as_ref().set_drvdata(data)?; Ok(0) }) } @@ -91,7 +92,7 @@ impl<T: Driver + 'static> Adapter<T> { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin<KBox<T>>`. - let data = unsafe { pdev.as_ref().drvdata_obtain::<Pin<KBox<T>>>() }; + let data = unsafe { pdev.as_ref().drvdata_obtain::<T>() }; T::unbind(pdev, data.as_ref()); } @@ -166,7 +167,7 @@ macro_rules! module_platform_driver { /// fn probe( /// _pdev: &platform::Device<Core>, /// _id_info: Option<&Self::IdInfo>, -/// ) -> Result<Pin<KBox<Self>>> { +/// ) -> impl PinInit<Self, Error> { /// Err(ENODEV) /// } /// } @@ -190,8 +191,10 @@ pub trait Driver: Send { /// /// Called when a new platform device is added or discovered. /// Implementers should attempt to initialize the device here. - fn probe(dev: &Device<device::Core>, id_info: Option<&Self::IdInfo>) - -> Result<Pin<KBox<Self>>>; + fn probe( + dev: &Device<device::Core>, + id_info: Option<&Self::IdInfo>, + ) -> impl PinInit<Self, Error>; /// Platform driver unbind. /// @@ -285,6 +288,12 @@ impl Device<Bound> { } } +// SAFETY: `platform::Device` is a transparent wrapper of `struct platform_device`. +// The offset is guaranteed to point to a valid device field inside `platform::Device`. +unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> { + const OFFSET: usize = offset_of!(bindings::platform_device, dev); +} + macro_rules! define_irq_accessor_by_index { ( $(#[$meta:meta])* $fn_name:ident, @@ -299,15 +308,17 @@ macro_rules! define_irq_accessor_by_index { index: u32, name: &'static CStr, handler: impl PinInit<T, Error> + 'a, - ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + 'a> { - let request = self.$request_fn(index)?; - - Ok(irq::$reg_type::<T>::new( - request, - flags, - name, - handler, - )) + ) -> impl PinInit<irq::$reg_type<T>, Error> + 'a { + pin_init::pin_init_scope(move || { + let request = self.$request_fn(index)?; + + Ok(irq::$reg_type::<T>::new( + request, + flags, + name, + handler, + )) + }) } }; } @@ -323,18 +334,20 @@ macro_rules! define_irq_accessor_by_name { pub fn $fn_name<'a, T: irq::$handler_trait + 'static>( &'a self, flags: irq::Flags, - irq_name: &CStr, + irq_name: &'a CStr, name: &'static CStr, handler: impl PinInit<T, Error> + 'a, - ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + 'a> { - let request = self.$request_fn(irq_name)?; - - Ok(irq::$reg_type::<T>::new( - request, - flags, - name, - handler, - )) + ) -> impl PinInit<irq::$reg_type<T>, Error> + 'a { + pin_init::pin_init_scope(move || { + let request = self.$request_fn(irq_name)?; + + Ok(irq::$reg_type::<T>::new( + request, + flags, + name, + handler, + )) + }) } }; } diff --git a/rust/kernel/scatterlist.rs b/rust/kernel/scatterlist.rs index 9709dff60b5a..196fdb9a75e7 100644 --- a/rust/kernel/scatterlist.rs +++ b/rust/kernel/scatterlist.rs @@ -35,7 +35,7 @@ use crate::{ device::{Bound, Device}, devres::Devres, dma, error, - io::resource::ResourceSize, + io::ResourceSize, page, prelude::*, types::{ARef, Opaque}, diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 6fcc9d47f12e..fa87779d2253 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -15,6 +15,8 @@ use core::{ pub use crate::prelude::CStr; +pub mod parse_int; + /// Byte string without UTF-8 validity guarantee. #[repr(transparent)] pub struct BStr([u8]); diff --git a/rust/kernel/str/parse_int.rs b/rust/kernel/str/parse_int.rs new file mode 100644 index 000000000000..48eb4c202984 --- /dev/null +++ b/rust/kernel/str/parse_int.rs @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Integer parsing functions. +//! +//! Integer parsing functions for parsing signed and unsigned integers +//! potentially prefixed with `0x`, `0o`, or `0b`. + +use crate::prelude::*; +use crate::str::BStr; +use core::ops::Deref; + +// Make `FromStrRadix` a public type with a private name. This seals +// `ParseInt`, that is, prevents downstream users from implementing the +// trait. +mod private { + use crate::prelude::*; + use crate::str::BStr; + + /// Trait that allows parsing a [`&BStr`] to an integer with a radix. + pub trait FromStrRadix: Sized { + /// Parse `src` to [`Self`] using radix `radix`. + fn from_str_radix(src: &BStr, radix: u32) -> Result<Self>; + + /// Tries to convert `value` into [`Self`] and negates the resulting value. + fn from_u64_negated(value: u64) -> Result<Self>; + } +} + +/// Extract the radix from an integer literal optionally prefixed with +/// one of `0x`, `0X`, `0o`, `0O`, `0b`, `0B`, `0`. +fn strip_radix(src: &BStr) -> (u32, &BStr) { + match src.deref() { + [b'0', b'x' | b'X', rest @ ..] => (16, rest.as_ref()), + [b'0', b'o' | b'O', rest @ ..] => (8, rest.as_ref()), + [b'0', b'b' | b'B', rest @ ..] => (2, rest.as_ref()), + // NOTE: We are including the leading zero to be able to parse + // literal `0` here. If we removed it as a radix prefix, we would + // not be able to parse `0`. + [b'0', ..] => (8, src), + _ => (10, src), + } +} + +/// Trait for parsing string representations of integers. +/// +/// Strings beginning with `0x`, `0o`, or `0b` are parsed as hex, octal, or +/// binary respectively. Strings beginning with `0` otherwise are parsed as +/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also +/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be +/// successfully parsed. +/// +/// [`kstrtol()`]: https://docs.kernel.org/core-api/kernel-api.html#c.kstrtol +/// [`kstrtoul()`]: https://docs.kernel.org/core-api/kernel-api.html#c.kstrtoul +/// +/// # Examples +/// +/// ``` +/// # use kernel::str::parse_int::ParseInt; +/// # use kernel::b_str; +/// +/// assert_eq!(Ok(0u8), u8::from_str(b_str!("0"))); +/// +/// assert_eq!(Ok(0xa2u8), u8::from_str(b_str!("0xa2"))); +/// assert_eq!(Ok(-0xa2i32), i32::from_str(b_str!("-0xa2"))); +/// +/// assert_eq!(Ok(-0o57i8), i8::from_str(b_str!("-0o57"))); +/// assert_eq!(Ok(0o57i8), i8::from_str(b_str!("057"))); +/// +/// assert_eq!(Ok(0b1001i16), i16::from_str(b_str!("0b1001"))); +/// assert_eq!(Ok(-0b1001i16), i16::from_str(b_str!("-0b1001"))); +/// +/// assert_eq!(Ok(127i8), i8::from_str(b_str!("127"))); +/// assert!(i8::from_str(b_str!("128")).is_err()); +/// assert_eq!(Ok(-128i8), i8::from_str(b_str!("-128"))); +/// assert!(i8::from_str(b_str!("-129")).is_err()); +/// assert_eq!(Ok(255u8), u8::from_str(b_str!("255"))); +/// assert!(u8::from_str(b_str!("256")).is_err()); +/// ``` +pub trait ParseInt: private::FromStrRadix + TryFrom<u64> { + /// Parse a string according to the description in [`Self`]. + fn from_str(src: &BStr) -> Result<Self> { + match src.deref() { + [b'-', rest @ ..] => { + let (radix, digits) = strip_radix(rest.as_ref()); + // 2's complement values range from -2^(b-1) to 2^(b-1)-1. + // So if we want to parse negative numbers as positive and + // later multiply by -1, we have to parse into a larger + // integer. We choose `u64` as sufficiently large. + // + // NOTE: 128 bit integers are not available on all + // platforms, hence the choice of 64 bits. + let val = + u64::from_str_radix(core::str::from_utf8(digits).map_err(|_| EINVAL)?, radix) + .map_err(|_| EINVAL)?; + Self::from_u64_negated(val) + } + _ => { + let (radix, digits) = strip_radix(src); + Self::from_str_radix(digits, radix).map_err(|_| EINVAL) + } + } + } +} + +macro_rules! impl_parse_int { + ($($ty:ty),*) => { + $( + impl private::FromStrRadix for $ty { + fn from_str_radix(src: &BStr, radix: u32) -> Result<Self> { + <$ty>::from_str_radix(core::str::from_utf8(src).map_err(|_| EINVAL)?, radix) + .map_err(|_| EINVAL) + } + + fn from_u64_negated(value: u64) -> Result<Self> { + const ABS_MIN: u64 = { + #[allow(unused_comparisons)] + if <$ty>::MIN < 0 { + 1u64 << (<$ty>::BITS - 1) + } else { + 0 + } + }; + + if value > ABS_MIN { + return Err(EINVAL); + } + + if value == ABS_MIN { + return Ok(<$ty>::MIN); + } + + // SAFETY: The above checks guarantee that `value` fits into `Self`: + // - if `Self` is unsigned, then `ABS_MIN == 0` and thus we have returned above + // (either `EINVAL` or `MIN`). + // - if `Self` is signed, then we have that `0 <= value < ABS_MIN`. And since + // `ABS_MIN - 1` fits into `Self` by construction, `value` also does. + let value: Self = unsafe { value.try_into().unwrap_unchecked() }; + + Ok((!value).wrapping_add(1)) + } + } + + impl ParseInt for $ty {} + )* + }; +} + +impl_parse_int![i8, u8, i16, u16, i32, u32, i64, u64, isize, usize]; diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index c94753d6413e..5df87e2bd212 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -20,6 +20,7 @@ mod locked_by; pub mod poll; pub mod rcu; mod refcount; +mod set_once; pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use completion::Completion; @@ -29,6 +30,7 @@ pub use lock::mutex::{new_mutex, Mutex, MutexGuard}; pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard}; pub use locked_by::LockedBy; pub use refcount::Refcount; +pub use set_once::SetOnce; /// Represents a lockdep class. It's a wrapper around C's `lock_class_key`. #[repr(transparent)] diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs index 3afc376be42d..4aebeacb961a 100644 --- a/rust/kernel/sync/atomic.rs +++ b/rust/kernel/sync/atomic.rs @@ -22,6 +22,7 @@ mod predefine; pub use internal::AtomicImpl; pub use ordering::{Acquire, Full, Relaxed, Release}; + pub(crate) use internal::{AtomicArithmeticOps, AtomicBasicOps, AtomicExchangeOps}; use crate::build_error; diff --git a/rust/kernel/sync/set_once.rs b/rust/kernel/sync/set_once.rs new file mode 100644 index 000000000000..bdba601807d8 --- /dev/null +++ b/rust/kernel/sync/set_once.rs @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! A container that can be initialized at most once. + +use super::atomic::{ + ordering::{Acquire, Relaxed, Release}, + Atomic, +}; +use core::{cell::UnsafeCell, mem::MaybeUninit}; + +/// A container that can be populated at most once. Thread safe. +/// +/// Once the a [`SetOnce`] is populated, it remains populated by the same object for the +/// lifetime `Self`. +/// +/// # Invariants +/// +/// - `init` may only increase in value. +/// - `init` may only assume values in the range `0..=2`. +/// - `init == 0` if and only if `value` is uninitialized. +/// - `init == 1` if and only if there is exactly one thread with exclusive +/// access to `self.value`. +/// - `init == 2` if and only if `value` is initialized and valid for shared +/// access. +/// +/// # Example +/// +/// ``` +/// # use kernel::sync::SetOnce; +/// let value = SetOnce::new(); +/// assert_eq!(None, value.as_ref()); +/// +/// let status = value.populate(42u8); +/// assert_eq!(true, status); +/// assert_eq!(Some(&42u8), value.as_ref()); +/// assert_eq!(Some(42u8), value.copy()); +/// +/// let status = value.populate(101u8); +/// assert_eq!(false, status); +/// assert_eq!(Some(&42u8), value.as_ref()); +/// assert_eq!(Some(42u8), value.copy()); +/// ``` +pub struct SetOnce<T> { + init: Atomic<u32>, + value: UnsafeCell<MaybeUninit<T>>, +} + +impl<T> Default for SetOnce<T> { + fn default() -> Self { + Self::new() + } +} + +impl<T> SetOnce<T> { + /// Create a new [`SetOnce`]. + /// + /// The returned instance will be empty. + pub const fn new() -> Self { + // INVARIANT: The container is empty and we initialize `init` to `0`. + Self { + value: UnsafeCell::new(MaybeUninit::uninit()), + init: Atomic::new(0), + } + } + + /// Get a reference to the contained object. + /// + /// Returns [`None`] if this [`SetOnce`] is empty. + pub fn as_ref(&self) -> Option<&T> { + if self.init.load(Acquire) == 2 { + // SAFETY: By the type invariants of `Self`, `self.init == 2` means that `self.value` + // is initialized and valid for shared access. + Some(unsafe { &*self.value.get().cast() }) + } else { + None + } + } + + /// Populate the [`SetOnce`]. + /// + /// Returns `true` if the [`SetOnce`] was successfully populated. + pub fn populate(&self, value: T) -> bool { + // INVARIANT: If the swap succeeds: + // - We increase `init`. + // - We write the valid value `1` to `init`. + // - Only one thread can succeed in this write, so we have exclusive access after the + // write. + if let Ok(0) = self.init.cmpxchg(0, 1, Relaxed) { + // SAFETY: By the type invariants of `Self`, the fact that we succeeded in writing `1` + // to `self.init` means we obtained exclusive access to `self.value`. + unsafe { core::ptr::write(self.value.get().cast(), value) }; + // INVARIANT: + // - We increase `init`. + // - We write the valid value `2` to `init`. + // - We release our exclusive access to `self.value` and it is now valid for shared + // access. + self.init.store(2, Release); + true + } else { + false + } + } + + /// Get a copy of the contained object. + /// + /// Returns [`None`] if the [`SetOnce`] is empty. + pub fn copy(&self) -> Option<T> + where + T: Copy, + { + self.as_ref().copied() + } +} + +impl<T> Drop for SetOnce<T> { + fn drop(&mut self) { + if *self.init.get_mut() == 2 { + let value = self.value.get_mut(); + // SAFETY: By the type invariants of `Self`, `self.init == 2` means that `self.value` + // contains a valid value. We have exclusive access, as we hold a `mut` reference to + // `self`. + unsafe { value.assume_init_drop() }; + } + } +} diff --git a/rust/kernel/time/delay.rs b/rust/kernel/time/delay.rs index eb8838da62bc..b5b1b42797a0 100644 --- a/rust/kernel/time/delay.rs +++ b/rust/kernel/time/delay.rs @@ -47,3 +47,40 @@ pub fn fsleep(delta: Delta) { bindings::fsleep(delta.as_micros_ceil() as c_ulong) } } + +/// Inserts a delay based on microseconds with busy waiting. +/// +/// Equivalent to the C side [`udelay()`], which delays in microseconds. +/// +/// `delta` must be within `[0, MAX_UDELAY_MS]` in milliseconds; +/// otherwise, it is erroneous behavior. That is, it is considered a bug to +/// call this function with an out-of-range value. +/// +/// The behavior above differs from the C side [`udelay()`] for which out-of-range +/// values could lead to an overflow and unexpected behavior. +/// +/// [`udelay()`]: https://docs.kernel.org/timers/delay_sleep_functions.html#c.udelay +pub fn udelay(delta: Delta) { + const MAX_UDELAY_DELTA: Delta = Delta::from_millis(bindings::MAX_UDELAY_MS as i64); + + debug_assert!(delta.as_nanos() >= 0); + debug_assert!(delta <= MAX_UDELAY_DELTA); + + let delta = if (Delta::ZERO..=MAX_UDELAY_DELTA).contains(&delta) { + delta + } else { + MAX_UDELAY_DELTA + }; + + // SAFETY: It is always safe to call `udelay()` with any duration. + // Note that the kernel is compiled with `-fno-strict-overflow` + // so any out-of-range value could lead to unexpected behavior + // but won't lead to undefined behavior. + unsafe { + // Convert the duration to microseconds and round up to preserve + // the guarantee; `udelay()` inserts a delay for at least + // the provided duration, but that it may delay for longer + // under some circumstances. + bindings::udelay(delta.as_micros_ceil() as c_ulong) + } +} diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs index a8fb4764185a..f989539a31b4 100644 --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -9,6 +9,7 @@ use crate::{ bindings, error::Result, ffi::{c_char, c_void}, + fs::file, prelude::*, transmute::{AsBytes, FromBytes}, }; @@ -287,6 +288,48 @@ impl UserSliceReader { self.read_raw(out) } + /// Reads raw data from the user slice into a kernel buffer partially. + /// + /// This is the same as [`Self::read_slice`] but considers the given `offset` into `out` and + /// truncates the read to the boundaries of `self` and `out`. + /// + /// On success, returns the number of bytes read. + pub fn read_slice_partial(&mut self, out: &mut [u8], offset: usize) -> Result<usize> { + let end = offset.saturating_add(self.len()).min(out.len()); + + let Some(dst) = out.get_mut(offset..end) else { + return Ok(0); + }; + + self.read_slice(dst)?; + Ok(dst.len()) + } + + /// Reads raw data from the user slice into a kernel buffer partially. + /// + /// This is the same as [`Self::read_slice_partial`] but updates the given [`file::Offset`] by + /// the number of bytes read. + /// + /// This is equivalent to C's `simple_write_to_buffer()`. + /// + /// On success, returns the number of bytes read. + pub fn read_slice_file(&mut self, out: &mut [u8], offset: &mut file::Offset) -> Result<usize> { + if offset.is_negative() { + return Err(EINVAL); + } + + let Ok(offset_index) = (*offset).try_into() else { + return Ok(0); + }; + + let read = self.read_slice_partial(out, offset_index)?; + + // OVERFLOW: `offset + read <= data.len() <= isize::MAX <= Offset::MAX` + *offset += read as i64; + + Ok(read) + } + /// Reads a value of the specified type. /// /// Fails with [`EFAULT`] if the read happens on a bad address, or if the read goes out of @@ -438,6 +481,48 @@ impl UserSliceWriter { Ok(()) } + /// Writes raw data to this user pointer from a kernel buffer partially. + /// + /// This is the same as [`Self::write_slice`] but considers the given `offset` into `data` and + /// truncates the write to the boundaries of `self` and `data`. + /// + /// On success, returns the number of bytes written. + pub fn write_slice_partial(&mut self, data: &[u8], offset: usize) -> Result<usize> { + let end = offset.saturating_add(self.len()).min(data.len()); + + let Some(src) = data.get(offset..end) else { + return Ok(0); + }; + + self.write_slice(src)?; + Ok(src.len()) + } + + /// Writes raw data to this user pointer from a kernel buffer partially. + /// + /// This is the same as [`Self::write_slice_partial`] but updates the given [`file::Offset`] by + /// the number of bytes written. + /// + /// This is equivalent to C's `simple_read_from_buffer()`. + /// + /// On success, returns the number of bytes written. + pub fn write_slice_file(&mut self, data: &[u8], offset: &mut file::Offset) -> Result<usize> { + if offset.is_negative() { + return Err(EINVAL); + } + + let Ok(offset_index) = (*offset).try_into() else { + return Ok(0); + }; + + let written = self.write_slice_partial(data, offset_index)?; + + // OVERFLOW: `offset + written <= data.len() <= isize::MAX <= Offset::MAX` + *offset += written as i64; + + Ok(written) + } + /// Writes the provided Rust value to this userspace pointer. /// /// Fails with [`EFAULT`] if the write happens on a bad address, or if the write goes out of diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 14ddb711bab3..d10b65e9fb6a 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -15,7 +15,14 @@ use crate::{ types::{AlwaysRefCounted, Opaque}, ThisModule, }; -use core::{marker::PhantomData, mem::MaybeUninit, ptr::NonNull}; +use core::{ + marker::PhantomData, + mem::{ + offset_of, + MaybeUninit, // + }, + ptr::NonNull, +}; /// An adapter for the registration of USB drivers. pub struct Adapter<T: Driver>(T); @@ -67,10 +74,10 @@ impl<T: Driver + 'static> Adapter<T> { let id = unsafe { &*id.cast::<DeviceId>() }; let info = T::ID_TABLE.info(id.index()); - let data = T::probe(intf, id, info)?; + let data = T::probe(intf, id, info); let dev: &device::Device<device::CoreInternal> = intf.as_ref(); - dev.set_drvdata(data); + dev.set_drvdata(data)?; Ok(0) }) } @@ -87,7 +94,7 @@ impl<T: Driver + 'static> Adapter<T> { // SAFETY: `disconnect_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin<KBox<T>>`. - let data = unsafe { dev.drvdata_obtain::<Pin<KBox<T>>>() }; + let data = unsafe { dev.drvdata_obtain::<T>() }; T::disconnect(intf, data.as_ref()); } @@ -270,7 +277,7 @@ macro_rules! usb_device_table { /// _interface: &usb::Interface<Core>, /// _id: &usb::DeviceId, /// _info: &Self::IdInfo, -/// ) -> Result<Pin<KBox<Self>>> { +/// ) -> impl PinInit<Self, Error> { /// Err(ENODEV) /// } /// @@ -292,7 +299,7 @@ pub trait Driver { interface: &Interface<device::Core>, id: &DeviceId, id_info: &Self::IdInfo, - ) -> Result<Pin<KBox<Self>>>; + ) -> impl PinInit<Self, Error>; /// USB driver disconnect. /// @@ -324,6 +331,12 @@ impl<Ctx: device::DeviceContext> Interface<Ctx> { } } +// SAFETY: `usb::Interface` is a transparent wrapper of `struct usb_interface`. +// The offset is guaranteed to point to a valid device field inside `usb::Interface`. +unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Interface<Ctx> { + const OFFSET: usize = offset_of!(bindings::usb_interface, dev); +} + // SAFETY: `Interface` is a transparent wrapper of a type that doesn't depend on // `Interface`'s generic argument. kernel::impl_device_context_deref!(unsafe { Interface }); diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs index e2602be402c1..365d7eb499c0 100644 --- a/rust/macros/helpers.rs +++ b/rust/macros/helpers.rs @@ -10,6 +10,17 @@ pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> { } } +pub(crate) fn try_sign(it: &mut token_stream::IntoIter) -> Option<char> { + let peek = it.clone().next(); + match peek { + Some(TokenTree::Punct(punct)) if punct.as_char() == '-' => { + let _ = it.next(); + Some(punct.as_char()) + } + _ => None, + } +} + pub(crate) fn try_literal(it: &mut token_stream::IntoIter) -> Option<String> { if let Some(TokenTree::Literal(literal)) = it.next() { Some(literal.to_string()) @@ -103,3 +114,17 @@ pub(crate) fn file() -> String { proc_macro::Span::call_site().file() } } + +/// Parse a token stream of the form `expected_name: "value",` and return the +/// string in the position of "value". +/// +/// # Panics +/// +/// - On parse error. +pub(crate) fn expect_string_field(it: &mut token_stream::IntoIter, expected_name: &str) -> String { + assert_eq!(expect_ident(it), expected_name); + assert_eq!(expect_punct(it), ':'); + let string = expect_string(it); + assert_eq!(expect_punct(it), ','); + string +} diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 793f712dbf7c..b38002151871 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -29,6 +29,30 @@ use proc_macro::TokenStream; /// The `type` argument should be a type which implements the [`Module`] /// trait. Also accepts various forms of kernel metadata. /// +/// The `params` field describe module parameters. Each entry has the form +/// +/// ```ignore +/// parameter_name: type { +/// default: default_value, +/// description: "Description", +/// } +/// ``` +/// +/// `type` may be one of +/// +/// - [`i8`] +/// - [`u8`] +/// - [`i8`] +/// - [`u8`] +/// - [`i16`] +/// - [`u16`] +/// - [`i32`] +/// - [`u32`] +/// - [`i64`] +/// - [`u64`] +/// - [`isize`] +/// - [`usize`] +/// /// C header: [`include/linux/moduleparam.h`](srctree/include/linux/moduleparam.h) /// /// [`Module`]: ../kernel/trait.Module.html @@ -45,6 +69,12 @@ use proc_macro::TokenStream; /// description: "My very own kernel module!", /// license: "GPL", /// alias: ["alternate_module_name"], +/// params: { +/// my_parameter: i64 { +/// default: 1, +/// description: "This parameter has a default of 1", +/// }, +/// }, /// } /// /// struct MyModule(i32); @@ -53,6 +83,7 @@ use proc_macro::TokenStream; /// fn init(_module: &'static ThisModule) -> Result<Self> { /// let foo: i32 = 42; /// pr_info!("I contain: {}\n", foo); +/// pr_info!("i32 param is: {}\n", module_parameters::my_parameter.read()); /// Ok(Self(foo)) /// } /// } diff --git a/rust/macros/module.rs b/rust/macros/module.rs index 49131ff3e097..80cb9b16f5aa 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -26,6 +26,7 @@ struct ModInfoBuilder<'a> { module: &'a str, counter: usize, buffer: String, + param_buffer: String, } impl<'a> ModInfoBuilder<'a> { @@ -34,10 +35,11 @@ impl<'a> ModInfoBuilder<'a> { module, counter: 0, buffer: String::new(), + param_buffer: String::new(), } } - fn emit_base(&mut self, field: &str, content: &str, builtin: bool) { + fn emit_base(&mut self, field: &str, content: &str, builtin: bool, param: bool) { let string = if builtin { // Built-in modules prefix their modinfo strings by `module.`. format!( @@ -51,8 +53,14 @@ impl<'a> ModInfoBuilder<'a> { format!("{field}={content}\0") }; + let buffer = if param { + &mut self.param_buffer + } else { + &mut self.buffer + }; + write!( - &mut self.buffer, + buffer, " {cfg} #[doc(hidden)] @@ -75,20 +83,119 @@ impl<'a> ModInfoBuilder<'a> { self.counter += 1; } - fn emit_only_builtin(&mut self, field: &str, content: &str) { - self.emit_base(field, content, true) + fn emit_only_builtin(&mut self, field: &str, content: &str, param: bool) { + self.emit_base(field, content, true, param) } - fn emit_only_loadable(&mut self, field: &str, content: &str) { - self.emit_base(field, content, false) + fn emit_only_loadable(&mut self, field: &str, content: &str, param: bool) { + self.emit_base(field, content, false, param) } fn emit(&mut self, field: &str, content: &str) { - self.emit_only_builtin(field, content); - self.emit_only_loadable(field, content); + self.emit_internal(field, content, false); + } + + fn emit_internal(&mut self, field: &str, content: &str, param: bool) { + self.emit_only_builtin(field, content, param); + self.emit_only_loadable(field, content, param); + } + + fn emit_param(&mut self, field: &str, param: &str, content: &str) { + let content = format!("{param}:{content}", param = param, content = content); + self.emit_internal(field, &content, true); + } + + fn emit_params(&mut self, info: &ModuleInfo) { + let Some(params) = &info.params else { + return; + }; + + for param in params { + let ops = param_ops_path(¶m.ptype); + + // Note: The spelling of these fields is dictated by the user space + // tool `modinfo`. + self.emit_param("parmtype", ¶m.name, ¶m.ptype); + self.emit_param("parm", ¶m.name, ¶m.description); + + write!( + self.param_buffer, + " + pub(crate) static {param_name}: + ::kernel::module_param::ModuleParamAccess<{param_type}> = + ::kernel::module_param::ModuleParamAccess::new({param_default}); + + const _: () = {{ + #[link_section = \"__param\"] + #[used] + static __{module_name}_{param_name}_struct: + ::kernel::module_param::KernelParam = + ::kernel::module_param::KernelParam::new( + ::kernel::bindings::kernel_param {{ + name: if ::core::cfg!(MODULE) {{ + ::kernel::c_str!(\"{param_name}\").to_bytes_with_nul() + }} else {{ + ::kernel::c_str!(\"{module_name}.{param_name}\") + .to_bytes_with_nul() + }}.as_ptr(), + // SAFETY: `__this_module` is constructed by the kernel at load + // time and will not be freed until the module is unloaded. + #[cfg(MODULE)] + mod_: unsafe {{ + core::ptr::from_ref(&::kernel::bindings::__this_module) + .cast_mut() + }}, + #[cfg(not(MODULE))] + mod_: ::core::ptr::null_mut(), + ops: core::ptr::from_ref(&{ops}), + perm: 0, // Will not appear in sysfs + level: -1, + flags: 0, + __bindgen_anon_1: ::kernel::bindings::kernel_param__bindgen_ty_1 {{ + arg: {param_name}.as_void_ptr() + }}, + }} + ); + }}; + ", + module_name = info.name, + param_type = param.ptype, + param_default = param.default, + param_name = param.name, + ops = ops, + ) + .unwrap(); + } + } +} + +fn param_ops_path(param_type: &str) -> &'static str { + match param_type { + "i8" => "::kernel::module_param::PARAM_OPS_I8", + "u8" => "::kernel::module_param::PARAM_OPS_U8", + "i16" => "::kernel::module_param::PARAM_OPS_I16", + "u16" => "::kernel::module_param::PARAM_OPS_U16", + "i32" => "::kernel::module_param::PARAM_OPS_I32", + "u32" => "::kernel::module_param::PARAM_OPS_U32", + "i64" => "::kernel::module_param::PARAM_OPS_I64", + "u64" => "::kernel::module_param::PARAM_OPS_U64", + "isize" => "::kernel::module_param::PARAM_OPS_ISIZE", + "usize" => "::kernel::module_param::PARAM_OPS_USIZE", + t => panic!("Unsupported parameter type {}", t), } } +fn expect_param_default(param_it: &mut token_stream::IntoIter) -> String { + assert_eq!(expect_ident(param_it), "default"); + assert_eq!(expect_punct(param_it), ':'); + let sign = try_sign(param_it); + let default = try_literal(param_it).expect("Expected default param value"); + assert_eq!(expect_punct(param_it), ','); + let mut value = sign.map(String::from).unwrap_or_default(); + value.push_str(&default); + value +} + #[derive(Debug, Default)] struct ModuleInfo { type_: String, @@ -99,6 +206,50 @@ struct ModuleInfo { alias: Option<Vec<String>>, firmware: Option<Vec<String>>, imports_ns: Option<Vec<String>>, + params: Option<Vec<Parameter>>, +} + +#[derive(Debug)] +struct Parameter { + name: String, + ptype: String, + default: String, + description: String, +} + +fn expect_params(it: &mut token_stream::IntoIter) -> Vec<Parameter> { + let params = expect_group(it); + assert_eq!(params.delimiter(), Delimiter::Brace); + let mut it = params.stream().into_iter(); + let mut parsed = Vec::new(); + + loop { + let param_name = match it.next() { + Some(TokenTree::Ident(ident)) => ident.to_string(), + Some(_) => panic!("Expected Ident or end"), + None => break, + }; + + assert_eq!(expect_punct(&mut it), ':'); + let param_type = expect_ident(&mut it); + let group = expect_group(&mut it); + assert_eq!(group.delimiter(), Delimiter::Brace); + assert_eq!(expect_punct(&mut it), ','); + + let mut param_it = group.stream().into_iter(); + let param_default = expect_param_default(&mut param_it); + let param_description = expect_string_field(&mut param_it, "description"); + expect_end(&mut param_it); + + parsed.push(Parameter { + name: param_name, + ptype: param_type, + default: param_default, + description: param_description, + }) + } + + parsed } impl ModuleInfo { @@ -114,6 +265,7 @@ impl ModuleInfo { "alias", "firmware", "imports_ns", + "params", ]; const REQUIRED_KEYS: &[&str] = &["type", "name", "license"]; let mut seen_keys = Vec::new(); @@ -140,6 +292,7 @@ impl ModuleInfo { "alias" => info.alias = Some(expect_string_array(it)), "firmware" => info.firmware = Some(expect_string_array(it)), "imports_ns" => info.imports_ns = Some(expect_string_array(it)), + "params" => info.params = Some(expect_params(it)), _ => panic!("Unknown key \"{key}\". Valid keys are: {EXPECTED_KEYS:?}."), } @@ -179,35 +332,37 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { // Rust does not allow hyphens in identifiers, use underscore instead. let ident = info.name.replace('-', "_"); let mut modinfo = ModInfoBuilder::new(ident.as_ref()); - if let Some(authors) = info.authors { + if let Some(authors) = &info.authors { for author in authors { - modinfo.emit("author", &author); + modinfo.emit("author", author); } } - if let Some(description) = info.description { - modinfo.emit("description", &description); + if let Some(description) = &info.description { + modinfo.emit("description", description); } modinfo.emit("license", &info.license); - if let Some(aliases) = info.alias { + if let Some(aliases) = &info.alias { for alias in aliases { - modinfo.emit("alias", &alias); + modinfo.emit("alias", alias); } } - if let Some(firmware) = info.firmware { + if let Some(firmware) = &info.firmware { for fw in firmware { - modinfo.emit("firmware", &fw); + modinfo.emit("firmware", fw); } } - if let Some(imports) = info.imports_ns { + if let Some(imports) = &info.imports_ns { for ns in imports { - modinfo.emit("import_ns", &ns); + modinfo.emit("import_ns", ns); } } // Built-in modules also export the `file` modinfo string. let file = std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable"); - modinfo.emit_only_builtin("file", &file); + modinfo.emit_only_builtin("file", &file, false); + + modinfo.emit_params(&info); format!( " @@ -371,15 +526,18 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { __MOD.assume_init_drop(); }} }} - {modinfo} }} }} + mod module_parameters {{ + {params} + }} ", type_ = info.type_, name = info.name, ident = ident, modinfo = modinfo.buffer, + params = modinfo.param_buffer, initcall_section = ".initcall6.init" ) .parse() diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index dd553212836e..8dc9dd5ac6fd 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -1392,6 +1392,93 @@ where unsafe { pin_init_from_closure(init) } } +/// Construct an initializer in a closure and run it. +/// +/// Returns an initializer that first runs the closure and then the initializer returned by it. +/// +/// See also [`init_scope`]. +/// +/// # Examples +/// +/// ``` +/// # use pin_init::*; +/// # #[pin_data] +/// # struct Foo { a: u64, b: isize } +/// # struct Bar { a: u32, b: isize } +/// # fn lookup_bar() -> Result<Bar, Error> { todo!() } +/// # struct Error; +/// fn init_foo() -> impl PinInit<Foo, Error> { +/// pin_init_scope(|| { +/// let bar = lookup_bar()?; +/// Ok(try_pin_init!(Foo { a: bar.a.into(), b: bar.b }? Error)) +/// }) +/// } +/// ``` +/// +/// This initializer will first execute `lookup_bar()`, match on it, if it returned an error, the +/// initializer itself will fail with that error. If it returned `Ok`, then it will run the +/// initializer returned by the [`try_pin_init!`] invocation. +pub fn pin_init_scope<T, E, F, I>(make_init: F) -> impl PinInit<T, E> +where + F: FnOnce() -> Result<I, E>, + I: PinInit<T, E>, +{ + // SAFETY: + // - If `make_init` returns `Err`, `Err` is returned and `slot` is completely uninitialized, + // - If `make_init` returns `Ok`, safety requirement are fulfilled by `init.__pinned_init`. + // - The safety requirements of `init.__pinned_init` are fulfilled, since it's being called + // from an initializer. + unsafe { + pin_init_from_closure(move |slot: *mut T| -> Result<(), E> { + let init = make_init()?; + init.__pinned_init(slot) + }) + } +} + +/// Construct an initializer in a closure and run it. +/// +/// Returns an initializer that first runs the closure and then the initializer returned by it. +/// +/// See also [`pin_init_scope`]. +/// +/// # Examples +/// +/// ``` +/// # use pin_init::*; +/// # struct Foo { a: u64, b: isize } +/// # struct Bar { a: u32, b: isize } +/// # fn lookup_bar() -> Result<Bar, Error> { todo!() } +/// # struct Error; +/// fn init_foo() -> impl Init<Foo, Error> { +/// init_scope(|| { +/// let bar = lookup_bar()?; +/// Ok(try_init!(Foo { a: bar.a.into(), b: bar.b }? Error)) +/// }) +/// } +/// ``` +/// +/// This initializer will first execute `lookup_bar()`, match on it, if it returned an error, the +/// initializer itself will fail with that error. If it returned `Ok`, then it will run the +/// initializer returned by the [`try_init!`] invocation. +pub fn init_scope<T, E, F, I>(make_init: F) -> impl Init<T, E> +where + F: FnOnce() -> Result<I, E>, + I: Init<T, E>, +{ + // SAFETY: + // - If `make_init` returns `Err`, `Err` is returned and `slot` is completely uninitialized, + // - If `make_init` returns `Ok`, safety requirement are fulfilled by `init.__init`. + // - The safety requirements of `init.__init` are fulfilled, since it's being called from an + // initializer. + unsafe { + init_from_closure(move |slot: *mut T| -> Result<(), E> { + let init = make_init()?; + init.__init(slot) + }) + } +} + // SAFETY: the `__init` function always returns `Ok(())` and initializes every field of `slot`. unsafe impl<T> Init<T> for T { unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> { diff --git a/samples/kobject/kset-example.c b/samples/kobject/kset-example.c index 579ce150217c..d0103904e5dd 100644 --- a/samples/kobject/kset-example.c +++ b/samples/kobject/kset-example.c @@ -37,10 +37,11 @@ struct foo_obj { /* a custom attribute that works just for a struct foo_obj. */ struct foo_attribute { struct attribute attr; - ssize_t (*show)(struct foo_obj *foo, struct foo_attribute *attr, char *buf); - ssize_t (*store)(struct foo_obj *foo, struct foo_attribute *attr, const char *buf, size_t count); + ssize_t (*show)(struct foo_obj *foo, const struct foo_attribute *attr, char *buf); + ssize_t (*store)(struct foo_obj *foo, const struct foo_attribute *attr, + const char *buf, size_t count); }; -#define to_foo_attr(x) container_of(x, struct foo_attribute, attr) +#define to_foo_attr(x) container_of_const(x, struct foo_attribute, attr) /* * The default show function that must be passed to sysfs. This will be @@ -53,7 +54,7 @@ static ssize_t foo_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { - struct foo_attribute *attribute; + const struct foo_attribute *attribute; struct foo_obj *foo; attribute = to_foo_attr(attr); @@ -73,7 +74,7 @@ static ssize_t foo_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len) { - struct foo_attribute *attribute; + const struct foo_attribute *attribute; struct foo_obj *foo; attribute = to_foo_attr(attr); @@ -109,13 +110,13 @@ static void foo_release(struct kobject *kobj) /* * The "foo" file where the .foo variable is read from and written to. */ -static ssize_t foo_show(struct foo_obj *foo_obj, struct foo_attribute *attr, +static ssize_t foo_show(struct foo_obj *foo_obj, const struct foo_attribute *attr, char *buf) { return sysfs_emit(buf, "%d\n", foo_obj->foo); } -static ssize_t foo_store(struct foo_obj *foo_obj, struct foo_attribute *attr, +static ssize_t foo_store(struct foo_obj *foo_obj, const struct foo_attribute *attr, const char *buf, size_t count) { int ret; @@ -128,14 +129,14 @@ static ssize_t foo_store(struct foo_obj *foo_obj, struct foo_attribute *attr, } /* Sysfs attributes cannot be world-writable. */ -static struct foo_attribute foo_attribute = +static const struct foo_attribute foo_attribute = __ATTR(foo, 0664, foo_show, foo_store); /* * More complex function where we determine which variable is being accessed by * looking at the attribute for the "baz" and "bar" files. */ -static ssize_t b_show(struct foo_obj *foo_obj, struct foo_attribute *attr, +static ssize_t b_show(struct foo_obj *foo_obj, const struct foo_attribute *attr, char *buf) { int var; @@ -147,7 +148,7 @@ static ssize_t b_show(struct foo_obj *foo_obj, struct foo_attribute *attr, return sysfs_emit(buf, "%d\n", var); } -static ssize_t b_store(struct foo_obj *foo_obj, struct foo_attribute *attr, +static ssize_t b_store(struct foo_obj *foo_obj, const struct foo_attribute *attr, const char *buf, size_t count) { int var, ret; @@ -163,22 +164,37 @@ static ssize_t b_store(struct foo_obj *foo_obj, struct foo_attribute *attr, return count; } -static struct foo_attribute baz_attribute = +static const struct foo_attribute baz_attribute = __ATTR(baz, 0664, b_show, b_store); -static struct foo_attribute bar_attribute = +static const struct foo_attribute bar_attribute = __ATTR(bar, 0664, b_show, b_store); /* * Create a group of attributes so that we can create and destroy them all * at once. */ -static struct attribute *foo_default_attrs[] = { +static const struct attribute *const foo_default_attrs[] = { &foo_attribute.attr, &baz_attribute.attr, &bar_attribute.attr, NULL, /* need to NULL terminate the list of attributes */ }; -ATTRIBUTE_GROUPS(foo_default); + +static umode_t foo_default_attrs_is_visible(struct kobject *kobj, + const struct attribute *attr, + int n) +{ + /* Hide attributes with the same name as the kobject. */ + if (strcmp(kobject_name(kobj), attr->name) == 0) + return 0; + return attr->mode; +} + +static const struct attribute_group foo_default_group = { + .attrs_const = foo_default_attrs, + .is_visible_const = foo_default_attrs_is_visible, +}; +__ATTRIBUTE_GROUPS(foo_default); /* * Our own ktype for our kobjects. Here we specify our sysfs ops, the diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index c376eb899b7a..cde1dc9451d3 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -84,6 +84,29 @@ config SAMPLE_RUST_DEBUGFS_SCOPED If unsure, say N. +config SAMPLE_RUST_DRIVER_I2C + tristate "I2C Driver" + depends on I2C=y + help + This option builds the Rust I2C driver sample. + + To compile this as a module, choose M here: + the module will be called rust_driver_i2c. + + If unsure, say N. + +config SAMPLE_RUST_I2C_CLIENT + tristate "I2C Client Registration" + depends on I2C=y + help + This option builds the Rust I2C client manual creation + sample. + + To compile this as a module, choose M here: + the module will be called rust_i2c_client. + + If unsure, say N. + config SAMPLE_RUST_DRIVER_PCI tristate "PCI Driver" depends on PCI @@ -91,7 +114,7 @@ config SAMPLE_RUST_DRIVER_PCI This option builds the Rust PCI driver sample. To compile this as a module, choose M here: - the module will be called driver_pci. + the module will be called rust_driver_pci. If unsure, say N. diff --git a/samples/rust/Makefile b/samples/rust/Makefile index cf8422f8f219..f65885d1d62b 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o obj-$(CONFIG_SAMPLE_RUST_DEBUGFS) += rust_debugfs.o obj-$(CONFIG_SAMPLE_RUST_DEBUGFS_SCOPED) += rust_debugfs_scoped.o obj-$(CONFIG_SAMPLE_RUST_DMA) += rust_dma.o +obj-$(CONFIG_SAMPLE_RUST_DRIVER_I2C) += rust_driver_i2c.o +obj-$(CONFIG_SAMPLE_RUST_I2C_CLIENT) += rust_i2c_client.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_USB) += rust_driver_usb.o diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs index 711faa07bece..025e8f9d12de 100644 --- a/samples/rust/rust_debugfs.rs +++ b/samples/rust/rust_debugfs.rs @@ -36,6 +36,7 @@ use kernel::c_str; use kernel::debugfs::{Dir, File}; use kernel::new_mutex; use kernel::prelude::*; +use kernel::sizes::*; use kernel::sync::atomic::{Atomic, Relaxed}; use kernel::sync::Mutex; use kernel::{acpi, device::Core, of, platform, str::CString, types::ARef}; @@ -60,6 +61,10 @@ struct RustDebugFs { counter: File<Atomic<usize>>, #[pin] inner: File<Mutex<Inner>>, + #[pin] + array_blob: File<Mutex<[u8; 4]>>, + #[pin] + vector_blob: File<Mutex<KVec<u8>>>, } #[derive(Debug)] @@ -104,16 +109,17 @@ impl platform::Driver for RustDebugFs { fn probe( pdev: &platform::Device<Core>, _info: Option<&Self::IdInfo>, - ) -> Result<Pin<KBox<Self>>> { - let result = KBox::try_pin_init(RustDebugFs::new(pdev), GFP_KERNEL)?; - // We can still mutate fields through the files which are atomic or mutexed: - result.counter.store(91, Relaxed); - { - let mut guard = result.inner.lock(); - guard.x = guard.y; - guard.y = 42; - } - Ok(result) + ) -> impl PinInit<Self, Error> { + RustDebugFs::new(pdev).pin_chain(|this| { + this.counter.store(91, Relaxed); + { + let mut guard = this.inner.lock(); + guard.x = guard.y; + guard.y = 42; + } + + Ok(()) + }) } } @@ -141,6 +147,14 @@ impl RustDebugFs { ), counter <- Self::build_counter(&debugfs), inner <- Self::build_inner(&debugfs), + array_blob <- debugfs.read_write_binary_file( + c_str!("array_blob"), + new_mutex!([0x62, 0x6c, 0x6f, 0x62]), + ), + vector_blob <- debugfs.read_write_binary_file( + c_str!("vector_blob"), + new_mutex!(kernel::kvec!(0x42; SZ_4K)?), + ), _debugfs: debugfs, pdev: pdev.into(), } diff --git a/samples/rust/rust_debugfs_scoped.rs b/samples/rust/rust_debugfs_scoped.rs index 406e6588b17a..702a6546d3fb 100644 --- a/samples/rust/rust_debugfs_scoped.rs +++ b/samples/rust/rust_debugfs_scoped.rs @@ -8,6 +8,7 @@ use kernel::debugfs::{Dir, Scope}; use kernel::prelude::*; +use kernel::sizes::*; use kernel::sync::atomic::Atomic; use kernel::sync::Mutex; use kernel::{c_str, new_mutex, str::CString}; @@ -66,18 +67,22 @@ fn create_file_write( GFP_KERNEL, )?; } + let blob = KBox::pin_init(new_mutex!([0x42; SZ_4K]), GFP_KERNEL)?; let scope = KBox::pin_init( - mod_data - .device_dir - .scope(DeviceData { name, nums }, &file_name, |dev_data, dir| { + mod_data.device_dir.scope( + DeviceData { name, nums, blob }, + &file_name, + |dev_data, dir| { for (idx, val) in dev_data.nums.iter().enumerate() { let Ok(name) = CString::try_from_fmt(fmt!("{idx}")) else { return; }; dir.read_write_file(&name, val); } - }), + dir.read_write_binary_file(c_str!("blob"), &dev_data.blob); + }, + ), GFP_KERNEL, )?; (*mod_data.devices.lock()).push(scope, GFP_KERNEL)?; @@ -110,6 +115,7 @@ impl ModuleData { struct DeviceData { name: CString, nums: KVec<Atomic<usize>>, + blob: Pin<KBox<Mutex<[u8; SZ_4K]>>>, } fn init_control(base_dir: &Dir, dyn_dirs: Dir) -> impl PinInit<Scope<ModuleData>> + '_ { diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index 4d324f06cc2a..f53bce2a73e3 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -55,36 +55,33 @@ impl pci::Driver for DmaSampleDriver { type IdInfo = (); const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; - fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { - dev_info!(pdev.as_ref(), "Probe DMA test driver.\n"); + fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { + pin_init::pin_init_scope(move || { + dev_info!(pdev.as_ref(), "Probe DMA test driver.\n"); - let mask = DmaMask::new::<64>(); + let mask = DmaMask::new::<64>(); - // SAFETY: There are no concurrent calls to DMA allocation and mapping primitives. - unsafe { pdev.dma_set_mask_and_coherent(mask)? }; + // SAFETY: There are no concurrent calls to DMA allocation and mapping primitives. + unsafe { pdev.dma_set_mask_and_coherent(mask)? }; - let ca: CoherentAllocation<MyStruct> = - CoherentAllocation::alloc_coherent(pdev.as_ref(), TEST_VALUES.len(), GFP_KERNEL)?; + let ca: CoherentAllocation<MyStruct> = + CoherentAllocation::alloc_coherent(pdev.as_ref(), TEST_VALUES.len(), GFP_KERNEL)?; - for (i, value) in TEST_VALUES.into_iter().enumerate() { - kernel::dma_write!(ca[i] = MyStruct::new(value.0, value.1))?; - } + for (i, value) in TEST_VALUES.into_iter().enumerate() { + kernel::dma_write!(ca[i] = MyStruct::new(value.0, value.1))?; + } - let size = 4 * page::PAGE_SIZE; - let pages = VVec::with_capacity(size, GFP_KERNEL)?; + let size = 4 * page::PAGE_SIZE; + let pages = VVec::with_capacity(size, GFP_KERNEL)?; - let sgt = SGTable::new(pdev.as_ref(), pages, DataDirection::ToDevice, GFP_KERNEL); + let sgt = SGTable::new(pdev.as_ref(), pages, DataDirection::ToDevice, GFP_KERNEL); - let drvdata = KBox::pin_init( - try_pin_init!(Self { + Ok(try_pin_init!(Self { pdev: pdev.into(), ca, sgt <- sgt, - }), - GFP_KERNEL, - )?; - - Ok(drvdata) + })) + }) } } diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index 55ece336ee45..5761ea314f44 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -5,9 +5,17 @@ //! To make this driver probe, QEMU must be run with `-device pci-testdev`. use kernel::{ - auxiliary, c_str, device::Core, driver, error::Error, pci, prelude::*, InPlaceModule, + auxiliary, c_str, + device::{Bound, Core}, + devres::Devres, + driver, + error::Error, + pci, + prelude::*, + InPlaceModule, }; +use core::any::TypeId; use pin_init::PinInit; const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME; @@ -27,7 +35,7 @@ impl auxiliary::Driver for AuxiliaryDriver { const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE; - fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { + fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { dev_info!( adev.as_ref(), "Probing auxiliary driver for auxiliary device with id={}\n", @@ -36,14 +44,17 @@ impl auxiliary::Driver for AuxiliaryDriver { ParentDriver::connect(adev)?; - let this = KBox::new(Self, GFP_KERNEL)?; - - Ok(this.into()) + Ok(Self) } } +#[pin_data] struct ParentDriver { - _reg: [auxiliary::Registration; 2], + private: TypeId, + #[pin] + _reg0: Devres<auxiliary::Registration>, + #[pin] + _reg1: Devres<auxiliary::Registration>, } kernel::pci_device_table!( @@ -58,35 +69,35 @@ impl pci::Driver for ParentDriver { const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; - fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { - let this = KBox::new( - Self { - _reg: [ - auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME)?, - auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME)?, - ], - }, - GFP_KERNEL, - )?; - - Ok(this.into()) + fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { + try_pin_init!(Self { + private: TypeId::of::<Self>(), + _reg0 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME), + _reg1 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME), + }) } } impl ParentDriver { - fn connect(adev: &auxiliary::Device) -> Result<()> { - let parent = adev.parent().ok_or(EINVAL)?; - let pdev: &pci::Device = parent.try_into()?; + fn connect(adev: &auxiliary::Device<Bound>) -> Result { + let dev = adev.parent(); + let pdev: &pci::Device<Bound> = dev.try_into()?; + let drvdata = dev.drvdata::<Self>()?; - let vendor = pdev.vendor_id(); dev_info!( - adev.as_ref(), + dev, "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n", adev.id(), - vendor, + pdev.vendor_id(), pdev.device_id() ); + dev_info!( + dev, + "We have access to the private data of {:?}.\n", + drvdata.private + ); + Ok(()) } } diff --git a/samples/rust/rust_driver_i2c.rs b/samples/rust/rust_driver_i2c.rs new file mode 100644 index 000000000000..ecefeca3e22f --- /dev/null +++ b/samples/rust/rust_driver_i2c.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust I2C driver sample. + +use kernel::{ + acpi, + c_str, + device::Core, + i2c, + of, + prelude::*, // +}; + +struct SampleDriver; + +kernel::acpi_device_table! { + ACPI_TABLE, + MODULE_ACPI_TABLE, + <SampleDriver as i2c::Driver>::IdInfo, + [(acpi::DeviceId::new(c_str!("LNUXBEEF")), 0)] +} + +kernel::i2c_device_table! { + I2C_TABLE, + MODULE_I2C_TABLE, + <SampleDriver as i2c::Driver>::IdInfo, + [(i2c::DeviceId::new(c_str!("rust_driver_i2c")), 0)] +} + +kernel::of_device_table! { + OF_TABLE, + MODULE_OF_TABLE, + <SampleDriver as i2c::Driver>::IdInfo, + [(of::DeviceId::new(c_str!("test,rust_driver_i2c")), 0)] +} + +impl i2c::Driver for SampleDriver { + type IdInfo = u32; + + const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); + const I2C_ID_TABLE: Option<i2c::IdTable<Self::IdInfo>> = Some(&I2C_TABLE); + const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); + + fn probe( + idev: &i2c::I2cClient<Core>, + info: Option<&Self::IdInfo>, + ) -> impl PinInit<Self, Error> { + let dev = idev.as_ref(); + + dev_info!(dev, "Probe Rust I2C driver sample.\n"); + + if let Some(info) = info { + dev_info!(dev, "Probed with info: '{}'.\n", info); + } + + Ok(Self) + } + + fn shutdown(idev: &i2c::I2cClient<Core>, _this: Pin<&Self>) { + dev_info!(idev.as_ref(), "Shutdown Rust I2C driver sample.\n"); + } + + fn unbind(idev: &i2c::I2cClient<Core>, _this: Pin<&Self>) { + dev_info!(idev.as_ref(), "Unbind Rust I2C driver sample.\n"); + } +} + +kernel::module_i2c_driver! { + type: SampleDriver, + name: "rust_driver_i2c", + authors: ["Igor Korotin"], + description: "Rust I2C driver", + license: "GPL v2", +} diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 55a683c39ed9..5823787bea8e 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -65,35 +65,34 @@ impl pci::Driver for SampleDriver { const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; - fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { - let vendor = pdev.vendor_id(); - dev_dbg!( - pdev.as_ref(), - "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", - vendor, - pdev.device_id() - ); - - pdev.enable_device_mem()?; - pdev.set_master(); - - let drvdata = KBox::pin_init( - try_pin_init!(Self { + fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> impl PinInit<Self, Error> { + pin_init::pin_init_scope(move || { + let vendor = pdev.vendor_id(); + dev_dbg!( + pdev.as_ref(), + "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", + vendor, + pdev.device_id() + ); + + pdev.enable_device_mem()?; + pdev.set_master(); + + Ok(try_pin_init!(Self { bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci")), - pdev: pdev.into(), index: *info, - }), - GFP_KERNEL, - )?; - - let bar = drvdata.bar.access(pdev.as_ref())?; - dev_info!( - pdev.as_ref(), - "pci-testdev data-match count: {}\n", - Self::testdev(info, bar)? - ); - - Ok(drvdata) + _: { + let bar = bar.access(pdev.as_ref())?; + + dev_info!( + pdev.as_ref(), + "pci-testdev data-match count: {}\n", + Self::testdev(info, bar)? + ); + }, + pdev: pdev.into(), + })) + }) } fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) { diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index 8a82e251820f..6bf4f0c9633d 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -103,7 +103,7 @@ impl platform::Driver for SampleDriver { fn probe( pdev: &platform::Device<Core>, info: Option<&Self::IdInfo>, - ) -> Result<Pin<KBox<Self>>> { + ) -> impl PinInit<Self, Error> { let dev = pdev.as_ref(); dev_dbg!(dev, "Probe Rust Platform driver sample.\n"); @@ -116,9 +116,7 @@ impl platform::Driver for SampleDriver { Self::properties_parse(dev)?; } - let drvdata = KBox::new(Self { pdev: pdev.into() }, GFP_KERNEL)?; - - Ok(drvdata.into()) + Ok(Self { pdev: pdev.into() }) } } diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb.rs index 5c396f421de7..4eaad14867b2 100644 --- a/samples/rust/rust_driver_usb.rs +++ b/samples/rust/rust_driver_usb.rs @@ -24,12 +24,11 @@ impl usb::Driver for SampleDriver { intf: &usb::Interface<Core>, _id: &usb::DeviceId, _info: &Self::IdInfo, - ) -> Result<Pin<KBox<Self>>> { + ) -> impl PinInit<Self, Error> { let dev: &device::Device<Core> = intf.as_ref(); dev_info!(dev, "Rust USB driver sample probed\n"); - let drvdata = KBox::new(Self { _intf: intf.into() }, GFP_KERNEL)?; - Ok(drvdata.into()) + Ok(Self { _intf: intf.into() }) } fn disconnect(intf: &usb::Interface<Core>, _data: Pin<&Self>) { diff --git a/samples/rust/rust_i2c_client.rs b/samples/rust/rust_i2c_client.rs new file mode 100644 index 000000000000..f67938396dce --- /dev/null +++ b/samples/rust/rust_i2c_client.rs @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust I2C client registration sample. +//! +//! An I2C client in Rust cannot exist on its own. To register a new I2C client, +//! it must be bound to a parent device. In this sample driver, a platform device +//! is used as the parent. +//! + +//! ACPI match table test +//! +//! This demonstrates how to test an ACPI-based Rust I2C client registration driver +//! using QEMU with a custom SSDT. +//! +//! Steps: +//! +//! 1. **Create an SSDT source file** (`ssdt.dsl`) with the following content: +//! +//! ```asl +//! DefinitionBlock ("", "SSDT", 2, "TEST", "VIRTACPI", 0x00000001) +//! { +//! Scope (\_SB) +//! { +//! Device (T432) +//! { +//! Name (_HID, "LNUXBEEF") // ACPI hardware ID to match +//! Name (_UID, 1) +//! Name (_STA, 0x0F) // Device present, enabled +//! Name (_CRS, ResourceTemplate () +//! { +//! Memory32Fixed (ReadWrite, 0xFED00000, 0x1000) +//! }) +//! } +//! } +//! } +//! ``` +//! +//! 2. **Compile the table**: +//! +//! ```sh +//! iasl -tc ssdt.dsl +//! ``` +//! +//! This generates `ssdt.aml` +//! +//! 3. **Run QEMU** with the compiled AML file: +//! +//! ```sh +//! qemu-system-x86_64 -m 512M \ +//! -enable-kvm \ +//! -kernel path/to/bzImage \ +//! -append "root=/dev/sda console=ttyS0" \ +//! -hda rootfs.img \ +//! -serial stdio \ +//! -acpitable file=ssdt.aml +//! ``` +//! +//! Requirements: +//! - The `rust_driver_platform` must be present either: +//! - built directly into the kernel (`bzImage`), or +//! - available as a `.ko` file and loadable from `rootfs.img` +//! +//! 4. **Verify it worked** by checking `dmesg`: +//! +//! ``` +//! rust_driver_platform LNUXBEEF:00: Probed with info: '0'. +//! ``` +//! + +use kernel::{ + acpi, + c_str, + device, + devres::Devres, + i2c, + of, + platform, + prelude::*, + sync::aref::ARef, // +}; + +#[pin_data] +struct SampleDriver { + parent_dev: ARef<platform::Device>, + #[pin] + _reg: Devres<i2c::Registration>, +} + +kernel::of_device_table!( + OF_TABLE, + MODULE_OF_TABLE, + <SampleDriver as platform::Driver>::IdInfo, + [(of::DeviceId::new(c_str!("test,rust-device")), ())] +); + +kernel::acpi_device_table!( + ACPI_TABLE, + MODULE_ACPI_TABLE, + <SampleDriver as platform::Driver>::IdInfo, + [(acpi::DeviceId::new(c_str!("LNUXBEEF")), ())] +); + +const SAMPLE_I2C_CLIENT_ADDR: u16 = 0x30; +const SAMPLE_I2C_ADAPTER_INDEX: i32 = 0; +const BOARD_INFO: i2c::I2cBoardInfo = + i2c::I2cBoardInfo::new(c_str!("rust_driver_i2c"), SAMPLE_I2C_CLIENT_ADDR); + +impl platform::Driver for SampleDriver { + type IdInfo = (); + const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); + const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); + + fn probe( + pdev: &platform::Device<device::Core>, + _info: Option<&Self::IdInfo>, + ) -> impl PinInit<Self, Error> { + dev_info!( + pdev.as_ref(), + "Probe Rust I2C Client registration sample.\n" + ); + + kernel::try_pin_init!( Self { + parent_dev: pdev.into(), + + _reg <- { + let adapter = i2c::I2cAdapter::get(SAMPLE_I2C_ADAPTER_INDEX)?; + + i2c::Registration::new(&adapter, &BOARD_INFO, pdev.as_ref()) + } + }) + } + + fn unbind(pdev: &platform::Device<device::Core>, _this: Pin<&Self>) { + dev_info!( + pdev.as_ref(), + "Unbind Rust I2C Client registration sample.\n" + ); + } +} + +kernel::module_platform_driver! { + type: SampleDriver, + name: "rust_device_i2c", + authors: ["Danilo Krummrich", "Igor Korotin"], + description: "Rust I2C client registration", + license: "GPL v2", +} diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs index 1fc7a1be6b6d..8eb9583571d7 100644 --- a/samples/rust/rust_minimal.rs +++ b/samples/rust/rust_minimal.rs @@ -10,6 +10,12 @@ module! { authors: ["Rust for Linux Contributors"], description: "Rust minimal sample", license: "GPL", + params: { + test_parameter: i64 { + default: 1, + description: "This parameter has a default of 1", + }, + }, } struct RustMinimal { @@ -20,6 +26,10 @@ impl kernel::Module for RustMinimal { fn init(_module: &'static ThisModule) -> Result<Self> { pr_info!("Rust minimal sample (init)\n"); pr_info!("Am I built-in? {}\n", !cfg!(MODULE)); + pr_info!( + "test_parameter: {}\n", + *module_parameters::test_parameter.value() + ); let mut numbers = KVec::new(); numbers.push(72, GFP_KERNEL)?; diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index fe6c2cebc7f0..f7189990dd6a 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3416,10 +3416,6 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) #define RME_DIGIFACE_REGISTER(reg, mask) (((reg) << 16) | (mask)) #define RME_DIGIFACE_INVERT BIT(31) -/* Nonconst helpers */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - static int snd_rme_digiface_write_reg(struct snd_kcontrol *kcontrol, int item, u16 mask, u16 val) { struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); |
