Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'driver-core-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core

Pull driver core updates from Danilo Krummrich:
"Bus:

- Ensure bus->match() is consistently called with the device lock
held

- Improve type safety of bus_find_device_by_acpi_dev()

Devtmpfs:

- Parse 'devtmpfs.mount=' boot parameter with kstrtoint() instead of
simple_strtoul()

- Avoid sparse warning by making devtmpfs_context_ops static

IOMMU:

- Do not register the qcom_smmu_tbu_driver in arm_smmu_device_probe()

MAINTAINERS:

- Add the new driver-core mailing list (driver-core@lists.linux.dev)
to all relevant entries

- Add missing tree location for "FIRMWARE LOADER (request_firmware)"

- Add driver-model documentation to the "DRIVER CORE" entry

- Add missing driver-core maintainers to the "AUXILIARY BUS" entry

Misc:

- Change return type of attribute_container_register() to void; it
has always been infallible

- Do not export sysfs_change_owner(), sysfs_file_change_owner() and
device_change_owner()

- Move devres_for_each_res() from the public devres header to
drivers/base/base.h

- Do not use a static struct device for the faux bus; allocate it
dynamically

Revocable:

- Patches for the revocable synchronization primitive have been
scheduled for v7.0-rc1, but have been reverted as they need some
more refinement

Rust:

- Device:
- Support dev_printk on all device types, not just the core Device
struct; remove now-redundant .as_ref() calls in dev_* print
calls

- Devres:
- Introduce an internal reference count in Devres<T> to avoid a
deadlock condition in case of (indirect) nesting

- DMA:
- Allow drivers to tune the maximum DMA segment size via
dma_set_max_seg_size()

- I/O:
- Introduce the concept of generic I/O backends to handle
different kinds of device shared memory through a common
interface.

This enables higher-level concepts such as register
abstractions, I/O slices, and field projections to be built
generically on top.

In a first step, introduce the Io, IoCapable<T>, and IoKnownSize
trait hierarchy for sharing a common interface supporting offset
validation and bound-checking logic between I/O backends.

- Refactor MMIO to use the common I/O backend infrastructure

- Misc:
- Add __rust_helper annotations to C helpers for inlining into
Rust code

- Use "kernel vertical" style for imports

- Replace kernel::c_str! with C string literals

- Update ARef imports to use sync::aref

- Use pin_init::zeroed() for struct auxiliary_device_id and
debugfs file_operations initialization

- Use LKMM atomic types in debugfs doc-tests

- Various minor comment and documentation fixes

- PCI:
- Implement PCI configuration space accessors using the common I/O
backend infrastructure

- Document pci::Bar device endianness assumptions

- SoC:
- Abstractions for struct soc_device and struct soc_device_attribute

- Sample driver for soc::Device"

* tag 'driver-core-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: (79 commits)
rust: devres: fix race condition due to nesting
rust: dma: add missing __rust_helper annotations
samples: rust: pci: Remove some additional `.as_ref()` for `dev_*` print
Revert "revocable: Revocable resource management"
Revert "revocable: Add Kunit test cases"
Revert "selftests: revocable: Add kselftest cases"
driver core: remove device_change_owner() export
sysfs: remove exports of sysfs_*change_owner()
driver core: disable revocable code from build
revocable: Add KUnit test for concurrent access
revocable: fix SRCU index corruption by requiring caller-provided storage
revocable: Add KUnit test for provider lifetime races
revocable: Fix races in revocable_alloc() using RCU
driver core: fix inverted "locked" suffix of driver_match_device()
rust: io: move MIN_SIZE and io_addr_assert to IoKnownSize
rust: pci: re-export ConfigSpace
rust: dma: allow drivers to tune max segment size
gpu: tyr: remove redundant `.as_ref()` for `dev_*` print
rust: auxiliary: use `pin_init::zeroed()` for device ID
rust: debugfs: use pin_init::zeroed() for file_operations
...

+1609 -578
+12 -3
MAINTAINERS
··· 4191 4191 4192 4192 AUXILIARY BUS DRIVER 4193 4193 M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 4194 + M: "Rafael J. Wysocki" <rafael@kernel.org> 4195 + M: Danilo Krummrich <dakr@kernel.org> 4194 4196 R: Dave Ertman <david.m.ertman@intel.com> 4195 4197 R: Ira Weiny <ira.weiny@intel.com> 4196 4198 R: Leon Romanovsky <leon@kernel.org> 4199 + L: driver-core@lists.linux.dev 4197 4200 S: Supported 4198 4201 T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git 4199 4202 F: Documentation/driver-api/auxiliary_bus.rst ··· 7289 7286 M: Danilo Krummrich <dakr@kernel.org> 7290 7287 M: Alice Ryhl <aliceryhl@google.com> 7291 7288 M: Daniel Almeida <daniel.almeida@collabora.com> 7292 - L: rust-for-linux@vger.kernel.org 7289 + L: driver-core@lists.linux.dev 7293 7290 S: Supported 7294 7291 W: https://rust-for-linux.com 7295 7292 B: https://github.com/Rust-for-Linux/linux/issues ··· 7540 7537 R: Daniel Almeida <daniel.almeida@collabora.com> 7541 7538 R: Robin Murphy <robin.murphy@arm.com> 7542 7539 R: Andreas Hindborg <a.hindborg@kernel.org> 7543 - L: rust-for-linux@vger.kernel.org 7540 + L: driver-core@lists.linux.dev 7544 7541 S: Supported 7545 7542 W: https://rust-for-linux.com 7546 7543 T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git ··· 7754 7751 M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 7755 7752 M: "Rafael J. Wysocki" <rafael@kernel.org> 7756 7753 M: Danilo Krummrich <dakr@kernel.org> 7754 + L: driver-core@lists.linux.dev 7757 7755 S: Supported 7758 7756 T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git 7759 7757 F: Documentation/core-api/kobject.rst 7758 + F: Documentation/driver-api/driver-model/ 7760 7759 F: drivers/base/ 7761 7760 F: fs/debugfs/ 7762 7761 F: fs/sysfs/ ··· 7779 7774 F: rust/kernel/driver.rs 7780 7775 F: rust/kernel/faux.rs 7781 7776 F: rust/kernel/platform.rs 7777 + F: rust/kernel/soc.rs 7782 7778 F: samples/rust/rust_debugfs.rs 7783 7779 F: samples/rust/rust_debugfs_scoped.rs 7784 7780 F: samples/rust/rust_driver_platform.rs 7785 7781 F: samples/rust/rust_driver_faux.rs 7782 + F: samples/rust/rust_soc.rs 7786 7783 7787 7784 DRIVERS FOR OMAP ADAPTIVE VOLTAGE SCALING (AVS) 7788 7785 M: Nishanth Menon <nm@ti.com> ··· 9909 9902 M: Luis Chamberlain <mcgrof@kernel.org> 9910 9903 M: Russ Weight <russ.weight@linux.dev> 9911 9904 M: Danilo Krummrich <dakr@kernel.org> 9912 - L: linux-kernel@vger.kernel.org 9905 + L: driver-core@lists.linux.dev 9913 9906 S: Maintained 9907 + T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git 9914 9908 F: Documentation/firmware_class/ 9915 9909 F: drivers/base/firmware_loader/ 9916 9910 F: rust/kernel/firmware.rs ··· 14058 14050 KERNFS 14059 14051 M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 14060 14052 M: Tejun Heo <tj@kernel.org> 14053 + L: driver-core@lists.linux.dev 14061 14054 S: Supported 14062 14055 T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git 14063 14056 F: fs/kernfs/
+1 -3
drivers/base/attribute_container.c
··· 69 69 * @cont: The container to register. This must be allocated by the 70 70 * callee and should also be zeroed by it. 71 71 */ 72 - int 72 + void 73 73 attribute_container_register(struct attribute_container *cont) 74 74 { 75 75 INIT_LIST_HEAD(&cont->node); ··· 79 79 mutex_lock(&attribute_container_mutex); 80 80 list_add_tail(&cont->node, &attribute_container_list); 81 81 mutex_unlock(&attribute_container_mutex); 82 - 83 - return 0; 84 82 } 85 83 EXPORT_SYMBOL_GPL(attribute_container_register); 86 84
+14 -1
drivers/base/base.h
··· 179 179 void driver_detach(const struct device_driver *drv); 180 180 void driver_deferred_probe_del(struct device *dev); 181 181 void device_set_deferred_probe_reason(const struct device *dev, struct va_format *vaf); 182 + static inline int driver_match_device_locked(const struct device_driver *drv, 183 + struct device *dev) 184 + { 185 + device_lock_assert(dev); 186 + 187 + return drv->bus->match ? drv->bus->match(dev, drv) : 1; 188 + } 189 + 182 190 static inline int driver_match_device(const struct device_driver *drv, 183 191 struct device *dev) 184 192 { 185 - return drv->bus->match ? drv->bus->match(dev, drv) : 1; 193 + guard(device)(dev); 194 + return driver_match_device_locked(drv, dev); 186 195 } 187 196 188 197 static inline void dev_sync_state(struct device *dev) ··· 222 213 WRITE_ONCE(dev->driver, (struct device_driver *)drv); 223 214 } 224 215 216 + void devres_for_each_res(struct device *dev, dr_release_t release, 217 + dr_match_t match, void *match_data, 218 + void (*fn)(struct device *, void *, void *), 219 + void *data); 225 220 int devres_release_all(struct device *dev); 226 221 void device_block_probing(void); 227 222 void device_unblock_probing(void);
-1
drivers/base/core.c
··· 4781 4781 put_device(dev); 4782 4782 return error; 4783 4783 } 4784 - EXPORT_SYMBOL_GPL(device_change_owner); 4785 4784 4786 4785 /** 4787 4786 * device_shutdown - call ->shutdown() on each device to shutdown.
+1 -1
drivers/base/dd.c
··· 928 928 bool async_allowed; 929 929 int ret; 930 930 931 - ret = driver_match_device(drv, dev); 931 + ret = driver_match_device_locked(drv, dev); 932 932 if (ret == 0) { 933 933 /* no match */ 934 934 return 0;
+2 -3
drivers/base/devtmpfs.c
··· 56 56 57 57 static int __init mount_param(char *str) 58 58 { 59 - mount_dev = simple_strtoul(str, NULL, 0); 60 - return 1; 59 + return kstrtoint(str, 0, &mount_dev) == 0; 61 60 } 62 61 __setup("devtmpfs.mount=", mount_param); 63 62 ··· 84 85 } 85 86 86 87 /* Ops are filled in during init depending on underlying shmem or ramfs type */ 87 - struct fs_context_operations devtmpfs_context_ops = {}; 88 + static struct fs_context_operations devtmpfs_context_ops = {}; 88 89 89 90 /* Call the underlying initialization and set to our ops */ 90 91 static int devtmpfs_init_fs_context(struct fs_context *fc)
+11 -7
drivers/base/faux.c
··· 29 29 }; 30 30 #define to_faux_object(dev) container_of_const(dev, struct faux_object, faux_dev.dev) 31 31 32 - static struct device faux_bus_root = { 33 - .init_name = "faux", 34 - }; 32 + static struct device *faux_bus_root; 35 33 36 34 static int faux_match(struct device *dev, const struct device_driver *drv) 37 35 { ··· 150 152 if (parent) 151 153 dev->parent = parent; 152 154 else 153 - dev->parent = &faux_bus_root; 155 + dev->parent = faux_bus_root; 154 156 dev->bus = &faux_bus_type; 155 157 dev_set_name(dev, "%s", name); 156 158 device_set_pm_not_required(dev); ··· 234 236 { 235 237 int ret; 236 238 237 - ret = device_register(&faux_bus_root); 239 + faux_bus_root = kzalloc(sizeof(*faux_bus_root), GFP_KERNEL); 240 + if (!faux_bus_root) 241 + return -ENOMEM; 242 + 243 + dev_set_name(faux_bus_root, "faux"); 244 + 245 + ret = device_register(faux_bus_root); 238 246 if (ret) { 239 - put_device(&faux_bus_root); 247 + put_device(faux_bus_root); 240 248 return ret; 241 249 } 242 250 ··· 260 256 bus_unregister(&faux_bus_type); 261 257 262 258 error_bus: 263 - device_unregister(&faux_bus_root); 259 + device_unregister(faux_bus_root); 264 260 return ret; 265 261 }
+2 -6
drivers/base/transport_class.c
··· 88 88 * events. Use prezero and then use DECLARE_ANON_TRANSPORT_CLASS() to 89 89 * initialise the anon transport class storage. 90 90 */ 91 - int anon_transport_class_register(struct anon_transport_class *atc) 91 + void anon_transport_class_register(struct anon_transport_class *atc) 92 92 { 93 - int error; 94 93 atc->container.class = &atc->tclass.class; 95 94 attribute_container_set_no_classdevs(&atc->container); 96 - error = attribute_container_register(&atc->container); 97 - if (error) 98 - return error; 95 + attribute_container_register(&atc->container); 99 96 atc->tclass.setup = anon_transport_dummy_function; 100 97 atc->tclass.remove = anon_transport_dummy_function; 101 - return 0; 102 98 } 103 99 EXPORT_SYMBOL_GPL(anon_transport_class_register); 104 100
+1 -1
drivers/gpu/drm/tyr/driver.rs
··· 140 140 141 141 // We need this to be dev_info!() because dev_dbg!() does not work at 142 142 // all in Rust for now, and we need to see whether probe succeeded. 143 - dev_info!(pdev.as_ref(), "Tyr initialized correctly.\n"); 143 + dev_info!(pdev, "Tyr initialized correctly.\n"); 144 144 Ok(driver) 145 145 } 146 146 }
+3 -3
drivers/gpu/drm/tyr/gpu.rs
··· 98 98 }; 99 99 100 100 dev_info!( 101 - pdev.as_ref(), 101 + pdev, 102 102 "mali-{} id 0x{:x} major 0x{:x} minor 0x{:x} status 0x{:x}", 103 103 model_name, 104 104 self.gpu_id >> 16, ··· 108 108 ); 109 109 110 110 dev_info!( 111 - pdev.as_ref(), 111 + pdev, 112 112 "Features: L2:{:#x} Tiler:{:#x} Mem:{:#x} MMU:{:#x} AS:{:#x}", 113 113 self.l2_features, 114 114 self.tiler_features, ··· 118 118 ); 119 119 120 120 dev_info!( 121 - pdev.as_ref(), 121 + pdev, 122 122 "shader_present=0x{:016x} l2_present=0x{:016x} tiler_present=0x{:016x}", 123 123 self.shader_present, 124 124 self.l2_present,
+1
drivers/gpu/drm/tyr/regs.rs
··· 11 11 use kernel::device::Bound; 12 12 use kernel::device::Device; 13 13 use kernel::devres::Devres; 14 + use kernel::io::Io; 14 15 use kernel::prelude::*; 15 16 16 17 use crate::driver::IoMem;
+4 -1
drivers/gpu/nova-core/gsp/sequencer.rs
··· 6 6 7 7 use kernel::{ 8 8 device, 9 - io::poll::read_poll_timeout, 9 + io::{ 10 + poll::read_poll_timeout, 11 + Io, // 12 + }, 10 13 prelude::*, 11 14 sync::aref::ARef, 12 15 time::{
+54 -36
drivers/gpu/nova-core/regs/macros.rs
··· 369 369 370 370 /// Read the register from its address in `io`. 371 371 #[inline(always)] 372 - pub(crate) fn read<const SIZE: usize, T>(io: &T) -> Self where 373 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 372 + pub(crate) fn read<T, I>(io: &T) -> Self where 373 + T: ::core::ops::Deref<Target = I>, 374 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 374 375 { 375 376 Self(io.read32($offset)) 376 377 } 377 378 378 379 /// Write the value contained in `self` to the register address in `io`. 379 380 #[inline(always)] 380 - pub(crate) fn write<const SIZE: usize, T>(self, io: &T) where 381 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 381 + pub(crate) fn write<T, I>(self, io: &T) where 382 + T: ::core::ops::Deref<Target = I>, 383 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 382 384 { 383 385 io.write32(self.0, $offset) 384 386 } ··· 388 386 /// Read the register from its address in `io` and run `f` on its value to obtain a new 389 387 /// value to write back. 390 388 #[inline(always)] 391 - pub(crate) fn update<const SIZE: usize, T, F>( 389 + pub(crate) fn update<T, I, F>( 392 390 io: &T, 393 391 f: F, 394 392 ) where 395 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 393 + T: ::core::ops::Deref<Target = I>, 394 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 396 395 F: ::core::ops::FnOnce(Self) -> Self, 397 396 { 398 397 let reg = f(Self::read(io)); ··· 411 408 /// Read the register from `io`, using the base address provided by `base` and adding 412 409 /// the register's offset to it. 413 410 #[inline(always)] 414 - pub(crate) fn read<const SIZE: usize, T, B>( 411 + pub(crate) fn read<T, I, B>( 415 412 io: &T, 416 413 #[allow(unused_variables)] 417 414 base: &B, 418 415 ) -> Self where 419 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 416 + T: ::core::ops::Deref<Target = I>, 417 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 420 418 B: crate::regs::macros::RegisterBase<$base>, 421 419 { 422 420 const OFFSET: usize = $name::OFFSET; ··· 432 428 /// Write the value contained in `self` to `io`, using the base address provided by 433 429 /// `base` and adding the register's offset to it. 434 430 #[inline(always)] 435 - pub(crate) fn write<const SIZE: usize, T, B>( 431 + pub(crate) fn write<T, I, B>( 436 432 self, 437 433 io: &T, 438 434 #[allow(unused_variables)] 439 435 base: &B, 440 436 ) where 441 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 437 + T: ::core::ops::Deref<Target = I>, 438 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 442 439 B: crate::regs::macros::RegisterBase<$base>, 443 440 { 444 441 const OFFSET: usize = $name::OFFSET; ··· 454 449 /// the register's offset to it, then run `f` on its value to obtain a new value to 455 450 /// write back. 456 451 #[inline(always)] 457 - pub(crate) fn update<const SIZE: usize, T, B, F>( 452 + pub(crate) fn update<T, I, B, F>( 458 453 io: &T, 459 454 base: &B, 460 455 f: F, 461 456 ) where 462 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 457 + T: ::core::ops::Deref<Target = I>, 458 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 463 459 B: crate::regs::macros::RegisterBase<$base>, 464 460 F: ::core::ops::FnOnce(Self) -> Self, 465 461 { ··· 480 474 481 475 /// Read the array register at index `idx` from its address in `io`. 482 476 #[inline(always)] 483 - pub(crate) fn read<const SIZE: usize, T>( 477 + pub(crate) fn read<T, I>( 484 478 io: &T, 485 479 idx: usize, 486 480 ) -> Self where 487 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 481 + T: ::core::ops::Deref<Target = I>, 482 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 488 483 { 489 484 build_assert!(idx < Self::SIZE); 490 485 ··· 497 490 498 491 /// Write the value contained in `self` to the array register with index `idx` in `io`. 499 492 #[inline(always)] 500 - pub(crate) fn write<const SIZE: usize, T>( 493 + pub(crate) fn write<T, I>( 501 494 self, 502 495 io: &T, 503 496 idx: usize 504 497 ) where 505 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 498 + T: ::core::ops::Deref<Target = I>, 499 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 506 500 { 507 501 build_assert!(idx < Self::SIZE); 508 502 ··· 515 507 /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a 516 508 /// new value to write back. 517 509 #[inline(always)] 518 - pub(crate) fn update<const SIZE: usize, T, F>( 510 + pub(crate) fn update<T, I, F>( 519 511 io: &T, 520 512 idx: usize, 521 513 f: F, 522 514 ) where 523 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 515 + T: ::core::ops::Deref<Target = I>, 516 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 524 517 F: ::core::ops::FnOnce(Self) -> Self, 525 518 { 526 519 let reg = f(Self::read(io, idx)); ··· 533 524 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 534 525 /// access was out-of-bounds. 535 526 #[inline(always)] 536 - pub(crate) fn try_read<const SIZE: usize, T>( 527 + pub(crate) fn try_read<T, I>( 537 528 io: &T, 538 529 idx: usize, 539 530 ) -> ::kernel::error::Result<Self> where 540 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 531 + T: ::core::ops::Deref<Target = I>, 532 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 541 533 { 542 534 if idx < Self::SIZE { 543 535 Ok(Self::read(io, idx)) ··· 552 542 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 553 543 /// access was out-of-bounds. 554 544 #[inline(always)] 555 - pub(crate) fn try_write<const SIZE: usize, T>( 545 + pub(crate) fn try_write<T, I>( 556 546 self, 557 547 io: &T, 558 548 idx: usize, 559 549 ) -> ::kernel::error::Result where 560 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 550 + T: ::core::ops::Deref<Target = I>, 551 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 561 552 { 562 553 if idx < Self::SIZE { 563 554 Ok(self.write(io, idx)) ··· 573 562 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 574 563 /// access was out-of-bounds. 575 564 #[inline(always)] 576 - pub(crate) fn try_update<const SIZE: usize, T, F>( 565 + pub(crate) fn try_update<T, I, F>( 577 566 io: &T, 578 567 idx: usize, 579 568 f: F, 580 569 ) -> ::kernel::error::Result where 581 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 570 + T: ::core::ops::Deref<Target = I>, 571 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 582 572 F: ::core::ops::FnOnce(Self) -> Self, 583 573 { 584 574 if idx < Self::SIZE { ··· 605 593 /// Read the array register at index `idx` from `io`, using the base address provided 606 594 /// by `base` and adding the register's offset to it. 607 595 #[inline(always)] 608 - pub(crate) fn read<const SIZE: usize, T, B>( 596 + pub(crate) fn read<T, I, B>( 609 597 io: &T, 610 598 #[allow(unused_variables)] 611 599 base: &B, 612 600 idx: usize, 613 601 ) -> Self where 614 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 602 + T: ::core::ops::Deref<Target = I>, 603 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 615 604 B: crate::regs::macros::RegisterBase<$base>, 616 605 { 617 606 build_assert!(idx < Self::SIZE); ··· 627 614 /// Write the value contained in `self` to `io`, using the base address provided by 628 615 /// `base` and adding the offset of array register `idx` to it. 629 616 #[inline(always)] 630 - pub(crate) fn write<const SIZE: usize, T, B>( 617 + pub(crate) fn write<T, I, B>( 631 618 self, 632 619 io: &T, 633 620 #[allow(unused_variables)] 634 621 base: &B, 635 622 idx: usize 636 623 ) where 637 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 624 + T: ::core::ops::Deref<Target = I>, 625 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 638 626 B: crate::regs::macros::RegisterBase<$base>, 639 627 { 640 628 build_assert!(idx < Self::SIZE); ··· 650 636 /// by `base` and adding the register's offset to it, then run `f` on its value to 651 637 /// obtain a new value to write back. 652 638 #[inline(always)] 653 - pub(crate) fn update<const SIZE: usize, T, B, F>( 639 + pub(crate) fn update<T, I, B, F>( 654 640 io: &T, 655 641 base: &B, 656 642 idx: usize, 657 643 f: F, 658 644 ) where 659 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 645 + T: ::core::ops::Deref<Target = I>, 646 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 660 647 B: crate::regs::macros::RegisterBase<$base>, 661 648 F: ::core::ops::FnOnce(Self) -> Self, 662 649 { ··· 671 656 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 672 657 /// access was out-of-bounds. 673 658 #[inline(always)] 674 - pub(crate) fn try_read<const SIZE: usize, T, B>( 659 + pub(crate) fn try_read<T, I, B>( 675 660 io: &T, 676 661 base: &B, 677 662 idx: usize, 678 663 ) -> ::kernel::error::Result<Self> where 679 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 664 + T: ::core::ops::Deref<Target = I>, 665 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 680 666 B: crate::regs::macros::RegisterBase<$base>, 681 667 { 682 668 if idx < Self::SIZE { ··· 693 677 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 694 678 /// access was out-of-bounds. 695 679 #[inline(always)] 696 - pub(crate) fn try_write<const SIZE: usize, T, B>( 680 + pub(crate) fn try_write<T, I, B>( 697 681 self, 698 682 io: &T, 699 683 base: &B, 700 684 idx: usize, 701 685 ) -> ::kernel::error::Result where 702 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 686 + T: ::core::ops::Deref<Target = I>, 687 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 703 688 B: crate::regs::macros::RegisterBase<$base>, 704 689 { 705 690 if idx < Self::SIZE { ··· 717 700 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 718 701 /// access was out-of-bounds. 719 702 #[inline(always)] 720 - pub(crate) fn try_update<const SIZE: usize, T, B, F>( 703 + pub(crate) fn try_update<T, I, B, F>( 721 704 io: &T, 722 705 base: &B, 723 706 idx: usize, 724 707 f: F, 725 708 ) -> ::kernel::error::Result where 726 - T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 709 + T: ::core::ops::Deref<Target = I>, 710 + I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 727 711 B: crate::regs::macros::RegisterBase<$base>, 728 712 F: ::core::ops::FnOnce(Self) -> Self, 729 713 {
+1
drivers/gpu/nova-core/vbios.rs
··· 6 6 7 7 use kernel::{ 8 8 device, 9 + io::Io, 9 10 prelude::*, 10 11 ptr::{ 11 12 Alignable,
+14
drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
··· 228 228 229 229 return smmu; 230 230 } 231 + 232 + int __init arm_smmu_impl_module_init(void) 233 + { 234 + if (IS_ENABLED(CONFIG_ARM_SMMU_QCOM)) 235 + return qcom_smmu_module_init(); 236 + 237 + return 0; 238 + } 239 + 240 + void __exit arm_smmu_impl_module_exit(void) 241 + { 242 + if (IS_ENABLED(CONFIG_ARM_SMMU_QCOM)) 243 + qcom_smmu_module_exit(); 244 + }
+10 -4
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
··· 802 802 { 803 803 const struct device_node *np = smmu->dev->of_node; 804 804 const struct of_device_id *match; 805 - static u8 tbu_registered; 806 - 807 - if (!tbu_registered++) 808 - platform_driver_register(&qcom_smmu_tbu_driver); 809 805 810 806 #ifdef CONFIG_ACPI 811 807 if (np == NULL) { ··· 825 829 dev_name(smmu->dev)); 826 830 827 831 return smmu; 832 + } 833 + 834 + int __init qcom_smmu_module_init(void) 835 + { 836 + return platform_driver_register(&qcom_smmu_tbu_driver); 837 + } 838 + 839 + void __exit qcom_smmu_module_exit(void) 840 + { 841 + platform_driver_unregister(&qcom_smmu_tbu_driver); 828 842 }
+23 -1
drivers/iommu/arm/arm-smmu/arm-smmu.c
··· 2365 2365 .remove = arm_smmu_device_remove, 2366 2366 .shutdown = arm_smmu_device_shutdown, 2367 2367 }; 2368 - module_platform_driver(arm_smmu_driver); 2368 + 2369 + static int __init arm_smmu_init(void) 2370 + { 2371 + int ret; 2372 + 2373 + ret = platform_driver_register(&arm_smmu_driver); 2374 + if (ret) 2375 + return ret; 2376 + 2377 + ret = arm_smmu_impl_module_init(); 2378 + if (ret) 2379 + platform_driver_unregister(&arm_smmu_driver); 2380 + 2381 + return ret; 2382 + } 2383 + module_init(arm_smmu_init); 2384 + 2385 + static void __exit arm_smmu_exit(void) 2386 + { 2387 + arm_smmu_impl_module_exit(); 2388 + platform_driver_unregister(&arm_smmu_driver); 2389 + } 2390 + module_exit(arm_smmu_exit); 2369 2391 2370 2392 MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations"); 2371 2393 MODULE_AUTHOR("Will Deacon <will@kernel.org>");
+5
drivers/iommu/arm/arm-smmu/arm-smmu.h
··· 540 540 struct arm_smmu_device *nvidia_smmu_impl_init(struct arm_smmu_device *smmu); 541 541 struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu); 542 542 543 + int __init arm_smmu_impl_module_init(void); 544 + void __exit arm_smmu_impl_module_exit(void); 545 + int __init qcom_smmu_module_init(void); 546 + void __exit qcom_smmu_module_exit(void); 547 + 543 548 void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx); 544 549 int arm_mmu500_reset(struct arm_smmu_device *smmu); 545 550
+4 -1
drivers/pwm/pwm_th1520.rs
··· 25 25 clk::Clk, 26 26 device::{Bound, Core, Device}, 27 27 devres, 28 - io::mem::IoMem, 28 + io::{ 29 + mem::IoMem, 30 + Io, // 31 + }, 29 32 of, platform, 30 33 prelude::*, 31 34 pwm, time,
+1 -1
drivers/scsi/scsi_transport_spi.c
··· 1622 1622 error = transport_class_register(&spi_transport_class); 1623 1623 if (error) 1624 1624 return error; 1625 - error = anon_transport_class_register(&spi_device_class); 1625 + anon_transport_class_register(&spi_device_class); 1626 1626 return transport_class_register(&spi_host_class); 1627 1627 } 1628 1628
-2
fs/sysfs/file.c
··· 689 689 690 690 return error; 691 691 } 692 - EXPORT_SYMBOL_GPL(sysfs_file_change_owner); 693 692 694 693 /** 695 694 * sysfs_change_owner - change owner of the given object. ··· 735 736 736 737 return 0; 737 738 } 738 - EXPORT_SYMBOL_GPL(sysfs_change_owner); 739 739 740 740 /** 741 741 * sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.
+1 -1
include/linux/attribute_container.h
··· 36 36 atc->flags |= ATTRIBUTE_CONTAINER_NO_CLASSDEVS; 37 37 } 38 38 39 - int attribute_container_register(struct attribute_container *cont); 39 + void attribute_container_register(struct attribute_container *cont); 40 40 int __must_check attribute_container_unregister(struct attribute_container *cont); 41 41 void attribute_container_create_device(struct device *dev, 42 42 int (*fn)(struct attribute_container *,
+2 -2
include/linux/device/bus.h
··· 215 215 return bus_find_device(bus, cur, NULL, device_match_any); 216 216 } 217 217 218 - #ifdef CONFIG_ACPI 219 218 struct acpi_device; 220 219 220 + #ifdef CONFIG_ACPI 221 221 /** 222 222 * bus_find_device_by_acpi_dev : device iterator for locating a particular device 223 223 * matching the ACPI COMPANION device. ··· 231 231 } 232 232 #else 233 233 static inline struct device * 234 - bus_find_device_by_acpi_dev(const struct bus_type *bus, const void *adev) 234 + bus_find_device_by_acpi_dev(const struct bus_type *bus, const struct acpi_device *adev) 235 235 { 236 236 return NULL; 237 237 }
-4
include/linux/device/devres.h
··· 26 26 #define devres_alloc_node(release, size, gfp, nid) \ 27 27 __devres_alloc_node(release, size, gfp, nid, #release) 28 28 29 - void devres_for_each_res(struct device *dev, dr_release_t release, 30 - dr_match_t match, void *match_data, 31 - void (*fn)(struct device *, void *, void *), 32 - void *data); 33 29 void devres_free(void *res); 34 30 void devres_add(struct device *dev, void *res); 35 31 void *devres_find(struct device *dev, dr_release_t release, dr_match_t match, void *match_data);
+3 -3
include/linux/transport_class.h
··· 87 87 transport_destroy_device(dev); 88 88 } 89 89 90 - static inline int transport_container_register(struct transport_container *tc) 90 + static inline void transport_container_register(struct transport_container *tc) 91 91 { 92 - return attribute_container_register(&tc->ac); 92 + attribute_container_register(&tc->ac); 93 93 } 94 94 95 95 static inline void transport_container_unregister(struct transport_container *tc) ··· 99 99 } 100 100 101 101 int transport_class_register(struct transport_class *); 102 - int anon_transport_class_register(struct anon_transport_class *); 102 + void anon_transport_class_register(struct anon_transport_class *); 103 103 void transport_class_unregister(struct transport_class *); 104 104 void anon_transport_class_unregister(struct anon_transport_class *); 105 105
+1
rust/bindings/bindings_helper.h
··· 81 81 #include <linux/sched.h> 82 82 #include <linux/security.h> 83 83 #include <linux/slab.h> 84 + #include <linux/sys_soc.h> 84 85 #include <linux/task_work.h> 85 86 #include <linux/tracepoint.h> 86 87 #include <linux/usb.h>
+4 -2
rust/helpers/auxiliary.c
··· 2 2 3 3 #include <linux/auxiliary_bus.h> 4 4 5 - void rust_helper_auxiliary_device_uninit(struct auxiliary_device *adev) 5 + __rust_helper void 6 + rust_helper_auxiliary_device_uninit(struct auxiliary_device *adev) 6 7 { 7 8 return auxiliary_device_uninit(adev); 8 9 } 9 10 10 - void rust_helper_auxiliary_device_delete(struct auxiliary_device *adev) 11 + __rust_helper void 12 + rust_helper_auxiliary_device_delete(struct auxiliary_device *adev) 11 13 { 12 14 return auxiliary_device_delete(adev); 13 15 }
+8 -8
rust/helpers/device.c
··· 2 2 3 3 #include <linux/device.h> 4 4 5 - int rust_helper_devm_add_action(struct device *dev, 6 - void (*action)(void *), 7 - void *data) 5 + __rust_helper int rust_helper_devm_add_action(struct device *dev, 6 + void (*action)(void *), 7 + void *data) 8 8 { 9 9 return devm_add_action(dev, action, data); 10 10 } 11 11 12 - int rust_helper_devm_add_action_or_reset(struct device *dev, 13 - void (*action)(void *), 14 - void *data) 12 + __rust_helper int rust_helper_devm_add_action_or_reset(struct device *dev, 13 + void (*action)(void *), 14 + void *data) 15 15 { 16 16 return devm_add_action_or_reset(dev, action, data); 17 17 } 18 18 19 - void *rust_helper_dev_get_drvdata(const struct device *dev) 19 + __rust_helper void *rust_helper_dev_get_drvdata(const struct device *dev) 20 20 { 21 21 return dev_get_drvdata(dev); 22 22 } 23 23 24 - void rust_helper_dev_set_drvdata(struct device *dev, void *data) 24 + __rust_helper void rust_helper_dev_set_drvdata(struct device *dev, void *data) 25 25 { 26 26 dev_set_drvdata(dev, data); 27 27 }
+20 -11
rust/helpers/dma.c
··· 2 2 3 3 #include <linux/dma-mapping.h> 4 4 5 - void *rust_helper_dma_alloc_attrs(struct device *dev, size_t size, 6 - dma_addr_t *dma_handle, gfp_t flag, 7 - unsigned long attrs) 5 + __rust_helper void *rust_helper_dma_alloc_attrs(struct device *dev, size_t size, 6 + dma_addr_t *dma_handle, 7 + gfp_t flag, unsigned long attrs) 8 8 { 9 9 return dma_alloc_attrs(dev, size, dma_handle, flag, attrs); 10 10 } 11 11 12 - void rust_helper_dma_free_attrs(struct device *dev, size_t size, void *cpu_addr, 13 - dma_addr_t dma_handle, unsigned long attrs) 12 + __rust_helper void rust_helper_dma_free_attrs(struct device *dev, size_t size, 13 + void *cpu_addr, 14 + dma_addr_t dma_handle, 15 + unsigned long attrs) 14 16 { 15 17 dma_free_attrs(dev, size, cpu_addr, dma_handle, attrs); 16 18 } 17 19 18 - int rust_helper_dma_set_mask_and_coherent(struct device *dev, u64 mask) 20 + __rust_helper int rust_helper_dma_set_mask_and_coherent(struct device *dev, 21 + u64 mask) 19 22 { 20 23 return dma_set_mask_and_coherent(dev, mask); 21 24 } 22 25 23 - int rust_helper_dma_set_mask(struct device *dev, u64 mask) 26 + __rust_helper int rust_helper_dma_set_mask(struct device *dev, u64 mask) 24 27 { 25 28 return dma_set_mask(dev, mask); 26 29 } 27 30 28 - int rust_helper_dma_set_coherent_mask(struct device *dev, u64 mask) 31 + __rust_helper int rust_helper_dma_set_coherent_mask(struct device *dev, u64 mask) 29 32 { 30 33 return dma_set_coherent_mask(dev, mask); 31 34 } 32 35 33 - int rust_helper_dma_map_sgtable(struct device *dev, struct sg_table *sgt, 34 - enum dma_data_direction dir, unsigned long attrs) 36 + __rust_helper int rust_helper_dma_map_sgtable(struct device *dev, struct sg_table *sgt, 37 + enum dma_data_direction dir, unsigned long attrs) 35 38 { 36 39 return dma_map_sgtable(dev, sgt, dir, attrs); 37 40 } 38 41 39 - size_t rust_helper_dma_max_mapping_size(struct device *dev) 42 + __rust_helper size_t rust_helper_dma_max_mapping_size(struct device *dev) 40 43 { 41 44 return dma_max_mapping_size(dev); 45 + } 46 + 47 + __rust_helper void rust_helper_dma_set_max_seg_size(struct device *dev, 48 + unsigned int size) 49 + { 50 + dma_set_max_seg_size(dev, size); 42 51 }
+34 -30
rust/helpers/io.c
··· 3 3 #include <linux/io.h> 4 4 #include <linux/ioport.h> 5 5 6 - void __iomem *rust_helper_ioremap(phys_addr_t offset, size_t size) 6 + __rust_helper void __iomem *rust_helper_ioremap(phys_addr_t offset, size_t size) 7 7 { 8 8 return ioremap(offset, size); 9 9 } 10 10 11 - void __iomem *rust_helper_ioremap_np(phys_addr_t offset, size_t size) 11 + __rust_helper void __iomem *rust_helper_ioremap_np(phys_addr_t offset, 12 + size_t size) 12 13 { 13 14 return ioremap_np(offset, size); 14 15 } 15 16 16 - void rust_helper_iounmap(void __iomem *addr) 17 + __rust_helper void rust_helper_iounmap(void __iomem *addr) 17 18 { 18 19 iounmap(addr); 19 20 } 20 21 21 - u8 rust_helper_readb(const void __iomem *addr) 22 + __rust_helper u8 rust_helper_readb(const void __iomem *addr) 22 23 { 23 24 return readb(addr); 24 25 } 25 26 26 - u16 rust_helper_readw(const void __iomem *addr) 27 + __rust_helper u16 rust_helper_readw(const void __iomem *addr) 27 28 { 28 29 return readw(addr); 29 30 } 30 31 31 - u32 rust_helper_readl(const void __iomem *addr) 32 + __rust_helper u32 rust_helper_readl(const void __iomem *addr) 32 33 { 33 34 return readl(addr); 34 35 } 35 36 36 37 #ifdef CONFIG_64BIT 37 - u64 rust_helper_readq(const void __iomem *addr) 38 + __rust_helper u64 rust_helper_readq(const void __iomem *addr) 38 39 { 39 40 return readq(addr); 40 41 } 41 42 #endif 42 43 43 - void rust_helper_writeb(u8 value, void __iomem *addr) 44 + __rust_helper void rust_helper_writeb(u8 value, void __iomem *addr) 44 45 { 45 46 writeb(value, addr); 46 47 } 47 48 48 - void rust_helper_writew(u16 value, void __iomem *addr) 49 + __rust_helper void rust_helper_writew(u16 value, void __iomem *addr) 49 50 { 50 51 writew(value, addr); 51 52 } 52 53 53 - void rust_helper_writel(u32 value, void __iomem *addr) 54 + __rust_helper void rust_helper_writel(u32 value, void __iomem *addr) 54 55 { 55 56 writel(value, addr); 56 57 } 57 58 58 59 #ifdef CONFIG_64BIT 59 - void rust_helper_writeq(u64 value, void __iomem *addr) 60 + __rust_helper void rust_helper_writeq(u64 value, void __iomem *addr) 60 61 { 61 62 writeq(value, addr); 62 63 } 63 64 #endif 64 65 65 - u8 rust_helper_readb_relaxed(const void __iomem *addr) 66 + __rust_helper u8 rust_helper_readb_relaxed(const void __iomem *addr) 66 67 { 67 68 return readb_relaxed(addr); 68 69 } 69 70 70 - u16 rust_helper_readw_relaxed(const void __iomem *addr) 71 + __rust_helper u16 rust_helper_readw_relaxed(const void __iomem *addr) 71 72 { 72 73 return readw_relaxed(addr); 73 74 } 74 75 75 - u32 rust_helper_readl_relaxed(const void __iomem *addr) 76 + __rust_helper u32 rust_helper_readl_relaxed(const void __iomem *addr) 76 77 { 77 78 return readl_relaxed(addr); 78 79 } 79 80 80 81 #ifdef CONFIG_64BIT 81 - u64 rust_helper_readq_relaxed(const void __iomem *addr) 82 + __rust_helper u64 rust_helper_readq_relaxed(const void __iomem *addr) 82 83 { 83 84 return readq_relaxed(addr); 84 85 } 85 86 #endif 86 87 87 - void rust_helper_writeb_relaxed(u8 value, void __iomem *addr) 88 + __rust_helper void rust_helper_writeb_relaxed(u8 value, void __iomem *addr) 88 89 { 89 90 writeb_relaxed(value, addr); 90 91 } 91 92 92 - void rust_helper_writew_relaxed(u16 value, void __iomem *addr) 93 + __rust_helper void rust_helper_writew_relaxed(u16 value, void __iomem *addr) 93 94 { 94 95 writew_relaxed(value, addr); 95 96 } 96 97 97 - void rust_helper_writel_relaxed(u32 value, void __iomem *addr) 98 + __rust_helper void rust_helper_writel_relaxed(u32 value, void __iomem *addr) 98 99 { 99 100 writel_relaxed(value, addr); 100 101 } 101 102 102 103 #ifdef CONFIG_64BIT 103 - void rust_helper_writeq_relaxed(u64 value, void __iomem *addr) 104 + __rust_helper void rust_helper_writeq_relaxed(u64 value, void __iomem *addr) 104 105 { 105 106 writeq_relaxed(value, addr); 106 107 } 107 108 #endif 108 109 109 - resource_size_t rust_helper_resource_size(struct resource *res) 110 + __rust_helper resource_size_t rust_helper_resource_size(struct resource *res) 110 111 { 111 112 return resource_size(res); 112 113 } 113 114 114 - struct resource *rust_helper_request_mem_region(resource_size_t start, 115 - resource_size_t n, 116 - const char *name) 115 + __rust_helper struct resource * 116 + rust_helper_request_mem_region(resource_size_t start, resource_size_t n, 117 + const char *name) 117 118 { 118 119 return request_mem_region(start, n, name); 119 120 } 120 121 121 - void rust_helper_release_mem_region(resource_size_t start, resource_size_t n) 122 + __rust_helper void rust_helper_release_mem_region(resource_size_t start, 123 + resource_size_t n) 122 124 { 123 125 release_mem_region(start, n); 124 126 } 125 127 126 - struct resource *rust_helper_request_region(resource_size_t start, 127 - resource_size_t n, const char *name) 128 + __rust_helper struct resource *rust_helper_request_region(resource_size_t start, 129 + resource_size_t n, 130 + const char *name) 128 131 { 129 132 return request_region(start, n, name); 130 133 } 131 134 132 - struct resource *rust_helper_request_muxed_region(resource_size_t start, 133 - resource_size_t n, 134 - const char *name) 135 + __rust_helper struct resource * 136 + rust_helper_request_muxed_region(resource_size_t start, resource_size_t n, 137 + const char *name) 135 138 { 136 139 return request_muxed_region(start, n, name); 137 140 } 138 141 139 - void rust_helper_release_region(resource_size_t start, resource_size_t n) 142 + __rust_helper void rust_helper_release_region(resource_size_t start, 143 + resource_size_t n) 140 144 { 141 145 release_region(start, n); 142 146 }
+4 -2
rust/helpers/irq.c
··· 2 2 3 3 #include <linux/interrupt.h> 4 4 5 - int rust_helper_request_irq(unsigned int irq, irq_handler_t handler, 6 - unsigned long flags, const char *name, void *dev) 5 + __rust_helper int rust_helper_request_irq(unsigned int irq, 6 + irq_handler_t handler, 7 + unsigned long flags, const char *name, 8 + void *dev) 7 9 { 8 10 return request_irq(irq, handler, flags, name, dev); 9 11 }
+13 -10
rust/helpers/pci.c
··· 2 2 3 3 #include <linux/pci.h> 4 4 5 - u16 rust_helper_pci_dev_id(struct pci_dev *dev) 5 + __rust_helper u16 rust_helper_pci_dev_id(struct pci_dev *dev) 6 6 { 7 7 return PCI_DEVID(dev->bus->number, dev->devfn); 8 8 } 9 9 10 - resource_size_t rust_helper_pci_resource_start(struct pci_dev *pdev, int bar) 10 + __rust_helper resource_size_t 11 + rust_helper_pci_resource_start(struct pci_dev *pdev, int bar) 11 12 { 12 13 return pci_resource_start(pdev, bar); 13 14 } 14 15 15 - resource_size_t rust_helper_pci_resource_len(struct pci_dev *pdev, int bar) 16 + __rust_helper resource_size_t rust_helper_pci_resource_len(struct pci_dev *pdev, 17 + int bar) 16 18 { 17 19 return pci_resource_len(pdev, bar); 18 20 } 19 21 20 - bool rust_helper_dev_is_pci(const struct device *dev) 22 + __rust_helper bool rust_helper_dev_is_pci(const struct device *dev) 21 23 { 22 24 return dev_is_pci(dev); 23 25 } 24 26 25 27 #ifndef CONFIG_PCI_MSI 26 - int rust_helper_pci_alloc_irq_vectors(struct pci_dev *dev, 27 - unsigned int min_vecs, 28 - unsigned int max_vecs, 29 - unsigned int flags) 28 + __rust_helper int rust_helper_pci_alloc_irq_vectors(struct pci_dev *dev, 29 + unsigned int min_vecs, 30 + unsigned int max_vecs, 31 + unsigned int flags) 30 32 { 31 33 return pci_alloc_irq_vectors(dev, min_vecs, max_vecs, flags); 32 34 } 33 35 34 - void rust_helper_pci_free_irq_vectors(struct pci_dev *dev) 36 + __rust_helper void rust_helper_pci_free_irq_vectors(struct pci_dev *dev) 35 37 { 36 38 pci_free_irq_vectors(dev); 37 39 } 38 40 39 - int rust_helper_pci_irq_vector(struct pci_dev *pdev, unsigned int nvec) 41 + __rust_helper int rust_helper_pci_irq_vector(struct pci_dev *pdev, 42 + unsigned int nvec) 40 43 { 41 44 return pci_irq_vector(pdev, nvec); 42 45 }
+1 -1
rust/helpers/platform.c
··· 2 2 3 3 #include <linux/platform_device.h> 4 4 5 - bool rust_helper_dev_is_platform(const struct device *dev) 5 + __rust_helper bool rust_helper_dev_is_platform(const struct device *dev) 6 6 { 7 7 return dev_is_platform(dev); 8 8 }
+1 -1
rust/helpers/property.c
··· 2 2 3 3 #include <linux/property.h> 4 4 5 - void rust_helper_fwnode_handle_put(struct fwnode_handle *fwnode) 5 + __rust_helper void rust_helper_fwnode_handle_put(struct fwnode_handle *fwnode) 6 6 { 7 7 fwnode_handle_put(fwnode); 8 8 }
+7 -5
rust/helpers/scatterlist.c
··· 2 2 3 3 #include <linux/dma-direction.h> 4 4 5 - dma_addr_t rust_helper_sg_dma_address(struct scatterlist *sg) 5 + __rust_helper dma_addr_t rust_helper_sg_dma_address(struct scatterlist *sg) 6 6 { 7 7 return sg_dma_address(sg); 8 8 } 9 9 10 - unsigned int rust_helper_sg_dma_len(struct scatterlist *sg) 10 + __rust_helper unsigned int rust_helper_sg_dma_len(struct scatterlist *sg) 11 11 { 12 12 return sg_dma_len(sg); 13 13 } 14 14 15 - struct scatterlist *rust_helper_sg_next(struct scatterlist *sg) 15 + __rust_helper struct scatterlist *rust_helper_sg_next(struct scatterlist *sg) 16 16 { 17 17 return sg_next(sg); 18 18 } 19 19 20 - void rust_helper_dma_unmap_sgtable(struct device *dev, struct sg_table *sgt, 21 - enum dma_data_direction dir, unsigned long attrs) 20 + __rust_helper void rust_helper_dma_unmap_sgtable(struct device *dev, 21 + struct sg_table *sgt, 22 + enum dma_data_direction dir, 23 + unsigned long attrs) 22 24 { 23 25 return dma_unmap_sgtable(dev, sgt, dir, attrs); 24 26 }
+18 -12
rust/kernel/auxiliary.rs
··· 5 5 //! C header: [`include/linux/auxiliary_bus.h`](srctree/include/linux/auxiliary_bus.h) 6 6 7 7 use crate::{ 8 - bindings, container_of, device, 9 - device_id::{RawDeviceId, RawDeviceIdIndex}, 8 + bindings, 9 + container_of, 10 + device, 11 + device_id::{ 12 + RawDeviceId, 13 + RawDeviceIdIndex, // 14 + }, 10 15 devres::Devres, 11 16 driver, 12 - error::{from_result, to_result, Result}, 17 + error::{ 18 + from_result, 19 + to_result, // 20 + }, 13 21 prelude::*, 14 22 types::Opaque, 15 - ThisModule, 23 + ThisModule, // 16 24 }; 17 25 use core::{ 18 26 marker::PhantomData, 19 27 mem::offset_of, 20 - ptr::{addr_of_mut, NonNull}, 28 + ptr::{ 29 + addr_of_mut, 30 + NonNull, // 31 + }, 21 32 }; 22 33 23 34 /// An adapter for the registration of auxiliary drivers. ··· 101 90 // SAFETY: The auxiliary bus only ever calls the probe callback with a valid pointer to a 102 91 // `struct auxiliary_device`. 103 92 // 104 - // INVARIANT: `adev` is valid for the duration of `probe_callback()`. 93 + // INVARIANT: `adev` is valid for the duration of `remove_callback()`. 105 94 let adev = unsafe { &*adev.cast::<Device<device::CoreInternal>>() }; 106 95 107 96 // SAFETY: `remove_callback` is only ever called after a successful call to ··· 132 121 let name = name.to_bytes_with_nul(); 133 122 let modname = modname.to_bytes_with_nul(); 134 123 135 - // TODO: Replace with `bindings::auxiliary_device_id::default()` once stabilized for 136 - // `const`. 137 - // 138 - // SAFETY: FFI type is valid to be zero-initialized. 139 - let mut id: bindings::auxiliary_device_id = unsafe { core::mem::zeroed() }; 140 - 124 + let mut id: bindings::auxiliary_device_id = pin_init::zeroed(); 141 125 let mut i = 0; 142 126 while i < modname.len() { 143 127 id.name[i] = modname[i];
+55 -31
rust/kernel/debugfs.rs
··· 8 8 // When DebugFS is disabled, many parameters are dead. Linting for this isn't helpful. 9 9 #![cfg_attr(not(CONFIG_DEBUG_FS), allow(unused_variables))] 10 10 11 - use crate::fmt; 12 - use crate::prelude::*; 13 - use crate::str::CStr; 14 11 #[cfg(CONFIG_DEBUG_FS)] 15 12 use crate::sync::Arc; 16 - use crate::uaccess::UserSliceReader; 17 - use core::marker::PhantomData; 18 - use core::marker::PhantomPinned; 13 + use crate::{ 14 + fmt, 15 + prelude::*, 16 + str::CStr, 17 + uaccess::UserSliceReader, // 18 + }; 19 + 19 20 #[cfg(CONFIG_DEBUG_FS)] 20 21 use core::mem::ManuallyDrop; 21 - use core::ops::Deref; 22 + use core::{ 23 + marker::{ 24 + PhantomData, 25 + PhantomPinned, // 26 + }, 27 + ops::Deref, 28 + }; 22 29 23 30 mod traits; 24 - pub use traits::{BinaryReader, BinaryReaderMut, BinaryWriter, Reader, Writer}; 31 + pub use traits::{ 32 + BinaryReader, 33 + BinaryReaderMut, 34 + BinaryWriter, 35 + Reader, 36 + Writer, // 37 + }; 25 38 26 39 mod callback_adapters; 27 - use callback_adapters::{FormatAdapter, NoWriter, WritableAdapter}; 40 + use callback_adapters::{ 41 + FormatAdapter, 42 + NoWriter, 43 + WritableAdapter, // 44 + }; 45 + 28 46 mod file_ops; 29 47 use file_ops::{ 30 - BinaryReadFile, BinaryReadWriteFile, BinaryWriteFile, FileOps, ReadFile, ReadWriteFile, 31 - WriteFile, 48 + BinaryReadFile, 49 + BinaryReadWriteFile, 50 + BinaryWriteFile, 51 + FileOps, 52 + ReadFile, 53 + ReadWriteFile, 54 + WriteFile, // 32 55 }; 56 + 33 57 #[cfg(CONFIG_DEBUG_FS)] 34 58 mod entry; 35 59 #[cfg(CONFIG_DEBUG_FS)] ··· 126 102 /// # Examples 127 103 /// 128 104 /// ``` 129 - /// # use kernel::c_str; 130 105 /// # use kernel::debugfs::Dir; 131 - /// let debugfs = Dir::new(c_str!("parent")); 106 + /// let debugfs = Dir::new(c"parent"); 132 107 /// ``` 133 108 pub fn new(name: &CStr) -> Self { 134 109 Dir::create(name, None) ··· 138 115 /// # Examples 139 116 /// 140 117 /// ``` 141 - /// # use kernel::c_str; 142 118 /// # use kernel::debugfs::Dir; 143 - /// let parent = Dir::new(c_str!("parent")); 144 - /// let child = parent.subdir(c_str!("child")); 119 + /// let parent = Dir::new(c"parent"); 120 + /// let child = parent.subdir(c"child"); 145 121 /// ``` 146 122 pub fn subdir(&self, name: &CStr) -> Self { 147 123 Dir::create(name, Some(self)) ··· 154 132 /// # Examples 155 133 /// 156 134 /// ``` 157 - /// # use kernel::c_str; 158 135 /// # use kernel::debugfs::Dir; 159 136 /// # use kernel::prelude::*; 160 - /// # let dir = Dir::new(c_str!("my_debugfs_dir")); 161 - /// let file = KBox::pin_init(dir.read_only_file(c_str!("foo"), 200), GFP_KERNEL)?; 137 + /// # let dir = Dir::new(c"my_debugfs_dir"); 138 + /// let file = KBox::pin_init(dir.read_only_file(c"foo", 200), GFP_KERNEL)?; 162 139 /// // "my_debugfs_dir/foo" now contains the number 200. 163 140 /// // The file is removed when `file` is dropped. 164 141 /// # Ok::<(), Error>(()) ··· 182 161 /// # Examples 183 162 /// 184 163 /// ``` 185 - /// # use kernel::c_str; 186 164 /// # use kernel::debugfs::Dir; 187 165 /// # use kernel::prelude::*; 188 - /// # let dir = Dir::new(c_str!("my_debugfs_dir")); 189 - /// let file = KBox::pin_init(dir.read_binary_file(c_str!("foo"), [0x1, 0x2]), GFP_KERNEL)?; 166 + /// # let dir = Dir::new(c"my_debugfs_dir"); 167 + /// let file = KBox::pin_init(dir.read_binary_file(c"foo", [0x1, 0x2]), GFP_KERNEL)?; 190 168 /// # Ok::<(), Error>(()) 191 169 /// ``` 192 170 pub fn read_binary_file<'a, T, E: 'a>( ··· 207 187 /// # Examples 208 188 /// 209 189 /// ``` 210 - /// # use core::sync::atomic::{AtomicU32, Ordering}; 211 - /// # use kernel::c_str; 212 - /// # use kernel::debugfs::Dir; 213 - /// # use kernel::prelude::*; 214 - /// # let dir = Dir::new(c_str!("foo")); 190 + /// # use kernel::{ 191 + /// # debugfs::Dir, 192 + /// # prelude::*, 193 + /// # sync::atomic::{ 194 + /// # Atomic, 195 + /// # Relaxed, 196 + /// # }, 197 + /// # }; 198 + /// # let dir = Dir::new(c"foo"); 215 199 /// let file = KBox::pin_init( 216 - /// dir.read_callback_file(c_str!("bar"), 217 - /// AtomicU32::new(3), 200 + /// dir.read_callback_file(c"bar", 201 + /// Atomic::<u32>::new(3), 218 202 /// &|val, f| { 219 - /// let out = val.load(Ordering::Relaxed); 203 + /// let out = val.load(Relaxed); 220 204 /// writeln!(f, "{out:#010x}") 221 205 /// }), 222 206 /// GFP_KERNEL)?; 223 207 /// // Reading "foo/bar" will show "0x00000003". 224 - /// file.store(10, Ordering::Relaxed); 208 + /// file.store(10, Relaxed); 225 209 /// // Reading "foo/bar" will now show "0x0000000a". 226 210 /// # Ok::<(), Error>(()) 227 211 /// ```
+15 -6
rust/kernel/debugfs/callback_adapters.rs
··· 4 4 //! Adapters which allow the user to supply a write or read implementation as a value rather 5 5 //! than a trait implementation. If provided, it will override the trait implementation. 6 6 7 - use super::{Reader, Writer}; 8 - use crate::fmt; 9 - use crate::prelude::*; 10 - use crate::uaccess::UserSliceReader; 11 - use core::marker::PhantomData; 12 - use core::ops::Deref; 7 + use super::{ 8 + Reader, 9 + Writer, // 10 + }; 11 + 12 + use crate::{ 13 + fmt, 14 + prelude::*, 15 + uaccess::UserSliceReader, // 16 + }; 17 + 18 + use core::{ 19 + marker::PhantomData, 20 + ops::Deref, // 21 + }; 13 22 14 23 /// # Safety 15 24 ///
+10 -4
rust/kernel/debugfs/entry.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 // Copyright (C) 2025 Google LLC. 3 3 4 - use crate::debugfs::file_ops::FileOps; 5 - use crate::ffi::c_void; 6 - use crate::str::{CStr, CStrExt as _}; 7 - use crate::sync::Arc; 4 + use crate::{ 5 + debugfs::file_ops::FileOps, 6 + prelude::*, 7 + str::{ 8 + CStr, 9 + CStrExt as _, // 10 + }, 11 + sync::Arc, 12 + }; 13 + 8 14 use core::marker::PhantomData; 9 15 10 16 /// Owning handle to a DebugFS entry.
+23 -20
rust/kernel/debugfs/file_ops.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 // Copyright (C) 2025 Google LLC. 3 3 4 - use super::{BinaryReader, BinaryWriter, Reader, Writer}; 5 - use crate::debugfs::callback_adapters::Adapter; 6 - use crate::fmt; 7 - use crate::fs::file; 8 - use crate::prelude::*; 9 - use crate::seq_file::SeqFile; 10 - use crate::seq_print; 11 - use crate::uaccess::UserSlice; 4 + use super::{ 5 + BinaryReader, 6 + BinaryWriter, 7 + Reader, 8 + Writer, // 9 + }; 10 + 11 + use crate::{ 12 + debugfs::callback_adapters::Adapter, 13 + fmt, 14 + fs::file, 15 + prelude::*, 16 + seq_file::SeqFile, 17 + seq_print, 18 + uaccess::UserSlice, // 19 + }; 20 + 12 21 use core::marker::PhantomData; 13 22 14 23 #[cfg(CONFIG_DEBUG_FS)] ··· 135 126 llseek: Some(bindings::seq_lseek), 136 127 release: Some(bindings::single_release), 137 128 open: Some(writer_open::<Self>), 138 - // SAFETY: `file_operations` supports zeroes in all fields. 139 - ..unsafe { core::mem::zeroed() } 129 + ..pin_init::zeroed() 140 130 }; 141 131 // SAFETY: `operations` is all stock `seq_file` implementations except for `writer_open`. 142 132 // `open`'s only requirement beyond what is provided to all open functions is that the ··· 187 179 write: Some(write::<T>), 188 180 llseek: Some(bindings::seq_lseek), 189 181 release: Some(bindings::single_release), 190 - // SAFETY: `file_operations` supports zeroes in all fields. 191 - ..unsafe { core::mem::zeroed() } 182 + ..pin_init::zeroed() 192 183 }; 193 184 // SAFETY: `operations` is all stock `seq_file` implementations except for `writer_open` 194 185 // and `write`. ··· 242 235 open: Some(write_only_open), 243 236 write: Some(write_only_write::<T>), 244 237 llseek: Some(bindings::noop_llseek), 245 - // SAFETY: `file_operations` supports zeroes in all fields. 246 - ..unsafe { core::mem::zeroed() } 238 + ..pin_init::zeroed() 247 239 }; 248 240 // SAFETY: 249 241 // * `write_only_open` populates the file private data with the inode private data ··· 294 288 read: Some(blob_read::<T>), 295 289 llseek: Some(bindings::default_llseek), 296 290 open: Some(bindings::simple_open), 297 - // SAFETY: `file_operations` supports zeroes in all fields. 298 - ..unsafe { core::mem::zeroed() } 291 + ..pin_init::zeroed() 299 292 }; 300 293 301 294 // SAFETY: ··· 348 343 write: Some(blob_write::<T>), 349 344 llseek: Some(bindings::default_llseek), 350 345 open: Some(bindings::simple_open), 351 - // SAFETY: `file_operations` supports zeroes in all fields. 352 - ..unsafe { core::mem::zeroed() } 346 + ..pin_init::zeroed() 353 347 }; 354 348 355 349 // SAFETY: ··· 373 369 write: Some(blob_write::<T>), 374 370 llseek: Some(bindings::default_llseek), 375 371 open: Some(bindings::simple_open), 376 - // SAFETY: `file_operations` supports zeroes in all fields. 377 - ..unsafe { core::mem::zeroed() } 372 + ..pin_init::zeroed() 378 373 }; 379 374 380 375 // SAFETY:
+32 -11
rust/kernel/debugfs/traits.rs
··· 3 3 4 4 //! Traits for rendering or updating values exported to DebugFS. 5 5 6 - use crate::alloc::Allocator; 7 - use crate::fmt; 8 - use crate::fs::file; 9 - use crate::prelude::*; 10 - use crate::sync::atomic::{Atomic, AtomicBasicOps, AtomicType, Relaxed}; 11 - use crate::sync::Arc; 12 - use crate::sync::Mutex; 13 - use crate::transmute::{AsBytes, FromBytes}; 14 - use crate::uaccess::{UserSliceReader, UserSliceWriter}; 15 - use core::ops::{Deref, DerefMut}; 16 - use core::str::FromStr; 6 + use crate::{ 7 + alloc::Allocator, 8 + fmt, 9 + fs::file, 10 + prelude::*, 11 + sync::{ 12 + atomic::{ 13 + Atomic, 14 + AtomicBasicOps, 15 + AtomicType, 16 + Relaxed, // 17 + }, 18 + Arc, 19 + Mutex, // 20 + }, 21 + transmute::{ 22 + AsBytes, 23 + FromBytes, // 24 + }, 25 + uaccess::{ 26 + UserSliceReader, 27 + UserSliceWriter, // 28 + }, 29 + }; 30 + 31 + use core::{ 32 + ops::{ 33 + Deref, 34 + DerefMut, // 35 + }, 36 + str::FromStr, 37 + }; 17 38 18 39 /// A trait for types that can be written into a string. 19 40 ///
+22 -10
rust/kernel/device.rs
··· 5 5 //! C header: [`include/linux/device.h`](srctree/include/linux/device.h) 6 6 7 7 use crate::{ 8 - bindings, fmt, 8 + bindings, 9 + fmt, 9 10 prelude::*, 10 11 sync::aref::ARef, 11 - types::{ForeignOwnable, Opaque}, 12 + types::{ 13 + ForeignOwnable, 14 + Opaque, // 15 + }, // 12 16 }; 13 - use core::{any::TypeId, marker::PhantomData, ptr}; 14 - 15 - #[cfg(CONFIG_PRINTK)] 16 - use crate::c_str; 17 + use core::{ 18 + any::TypeId, 19 + marker::PhantomData, 20 + ptr, // 21 + }; 17 22 18 23 pub mod property; 19 24 ··· 163 158 /// `bindings::device::release` is valid to be called from any thread, hence `ARef<Device>` can be 164 159 /// dropped from any thread. 165 160 /// 166 - /// [`AlwaysRefCounted`]: kernel::types::AlwaysRefCounted 161 + /// [`AlwaysRefCounted`]: kernel::sync::aref::AlwaysRefCounted 167 162 /// [`impl_device_context_deref`]: kernel::impl_device_context_deref 168 163 /// [`platform::Device`]: kernel::platform::Device 169 164 #[repr(transparent)] ··· 469 464 bindings::_dev_printk( 470 465 klevel.as_ptr().cast::<crate::ffi::c_char>(), 471 466 self.as_raw(), 472 - c_str!("%pA").as_char_ptr(), 467 + c"%pA".as_char_ptr(), 473 468 core::ptr::from_ref(&msg).cast::<crate::ffi::c_void>(), 474 469 ) 475 470 }; ··· 546 541 /// [`Device<Normal>`]. It is the only [`DeviceContext`] for which it is valid to implement 547 542 /// [`AlwaysRefCounted`] for. 548 543 /// 549 - /// [`AlwaysRefCounted`]: kernel::types::AlwaysRefCounted 544 + /// [`AlwaysRefCounted`]: kernel::sync::aref::AlwaysRefCounted 550 545 pub struct Normal; 551 546 552 547 /// The [`Core`] context is the context of a bus specific device when it appears as argument of ··· 600 595 impl DeviceContext for Core {} 601 596 impl DeviceContext for CoreInternal {} 602 597 impl DeviceContext for Normal {} 598 + 599 + impl<Ctx: DeviceContext> AsRef<Device<Ctx>> for Device<Ctx> { 600 + #[inline] 601 + fn as_ref(&self) -> &Device<Ctx> { 602 + self 603 + } 604 + } 603 605 604 606 /// Convert device references to bus device references. 605 607 /// ··· 727 715 macro_rules! dev_printk { 728 716 ($method:ident, $dev:expr, $($f:tt)*) => { 729 717 { 730 - ($dev).$method($crate::prelude::fmt!($($f)*)); 718 + $crate::device::Device::$method($dev.as_ref(), $crate::prelude::fmt!($($f)*)) 731 719 } 732 720 } 733 721 }
+6 -5
rust/kernel/device/property.rs
··· 14 14 fmt, 15 15 prelude::*, 16 16 str::{CStr, CString}, 17 - types::{ARef, Opaque}, 17 + sync::aref::ARef, 18 + types::Opaque, 18 19 }; 19 20 20 21 /// A reference-counted fwnode_handle. ··· 179 178 /// # Examples 180 179 /// 181 180 /// ``` 182 - /// # use kernel::{c_str, device::{Device, property::FwNode}, str::CString}; 181 + /// # use kernel::{device::{Device, property::FwNode}, str::CString}; 183 182 /// fn examples(dev: &Device) -> Result { 184 183 /// let fwnode = dev.fwnode().ok_or(ENOENT)?; 185 - /// let b: u32 = fwnode.property_read(c_str!("some-number")).required_by(dev)?; 186 - /// if let Some(s) = fwnode.property_read::<CString>(c_str!("some-str")).optional() { 184 + /// let b: u32 = fwnode.property_read(c"some-number").required_by(dev)?; 185 + /// if let Some(s) = fwnode.property_read::<CString>(c"some-str").optional() { 187 186 /// // ... 188 187 /// } 189 188 /// Ok(()) ··· 360 359 } 361 360 362 361 // SAFETY: Instances of `FwNode` are always reference-counted. 363 - unsafe impl crate::types::AlwaysRefCounted for FwNode { 362 + unsafe impl crate::sync::aref::AlwaysRefCounted for FwNode { 364 363 fn inc_ref(&self) { 365 364 // SAFETY: The existence of a shared reference guarantees that the 366 365 // refcount is non-zero.
+80 -119
rust/kernel/devres.rs
··· 8 8 use crate::{ 9 9 alloc::Flags, 10 10 bindings, 11 - device::{Bound, Device}, 12 - error::{to_result, Error, Result}, 13 - ffi::c_void, 11 + device::{ 12 + Bound, 13 + Device, // 14 + }, 15 + error::to_result, 14 16 prelude::*, 15 - revocable::{Revocable, RevocableGuard}, 16 - sync::{aref::ARef, rcu, Completion}, 17 - types::{ForeignOwnable, Opaque, ScopeGuard}, 17 + revocable::{ 18 + Revocable, 19 + RevocableGuard, // 20 + }, 21 + sync::{ 22 + aref::ARef, 23 + rcu, 24 + Arc, // 25 + }, 26 + types::ForeignOwnable, 18 27 }; 19 - 20 - use pin_init::Wrapper; 21 - 22 - /// [`Devres`] inner data accessed from [`Devres::callback`]. 23 - #[pin_data] 24 - struct Inner<T: Send> { 25 - #[pin] 26 - data: Revocable<T>, 27 - /// Tracks whether [`Devres::callback`] has been completed. 28 - #[pin] 29 - devm: Completion, 30 - /// Tracks whether revoking [`Self::data`] has been completed. 31 - #[pin] 32 - revoke: Completion, 33 - } 34 28 35 29 /// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to 36 30 /// manage their lifetime. ··· 55 61 /// devres::Devres, 56 62 /// io::{ 57 63 /// Io, 58 - /// IoRaw, 59 - /// PhysAddr, 64 + /// IoKnownSize, 65 + /// Mmio, 66 + /// MmioRaw, 67 + /// PhysAddr, // 60 68 /// }, 69 + /// prelude::*, 61 70 /// }; 62 71 /// use core::ops::Deref; 63 72 /// 64 73 /// // See also [`pci::Bar`] for a real example. 65 - /// struct IoMem<const SIZE: usize>(IoRaw<SIZE>); 74 + /// struct IoMem<const SIZE: usize>(MmioRaw<SIZE>); 66 75 /// 67 76 /// impl<const SIZE: usize> IoMem<SIZE> { 68 77 /// /// # Safety ··· 80 83 /// return Err(ENOMEM); 81 84 /// } 82 85 /// 83 - /// Ok(IoMem(IoRaw::new(addr as usize, SIZE)?)) 86 + /// Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?)) 84 87 /// } 85 88 /// } 86 89 /// ··· 92 95 /// } 93 96 /// 94 97 /// impl<const SIZE: usize> Deref for IoMem<SIZE> { 95 - /// type Target = Io<SIZE>; 98 + /// type Target = Mmio<SIZE>; 96 99 /// 97 100 /// fn deref(&self) -> &Self::Target { 98 101 /// // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`. 99 - /// unsafe { Io::from_raw(&self.0) } 102 + /// unsafe { Mmio::from_raw(&self.0) } 100 103 /// } 101 104 /// } 102 105 /// # fn no_run(dev: &Device<Bound>) -> Result<(), Error> { 103 106 /// // SAFETY: Invalid usage for example purposes. 104 107 /// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? }; 105 - /// let devres = KBox::pin_init(Devres::new(dev, iomem), GFP_KERNEL)?; 108 + /// let devres = Devres::new(dev, iomem)?; 106 109 /// 107 110 /// let res = devres.try_access().ok_or(ENXIO)?; 108 111 /// res.write8(0x42, 0x0); 109 112 /// # Ok(()) 110 113 /// # } 111 114 /// ``` 112 - /// 113 - /// # Invariants 114 - /// 115 - /// `Self::inner` is guaranteed to be initialized and is always accessed read-only. 116 - #[pin_data(PinnedDrop)] 117 115 pub struct Devres<T: Send> { 118 116 dev: ARef<Device>, 119 117 /// Pointer to [`Self::devres_callback`]. ··· 116 124 /// Has to be stored, since Rust does not guarantee to always return the same address for a 117 125 /// function. However, the C API uses the address as a key. 118 126 callback: unsafe extern "C" fn(*mut c_void), 119 - /// Contains all the fields shared with [`Self::callback`]. 120 - // TODO: Replace with `UnsafePinned`, once available. 121 - // 122 - // Subsequently, the `drop_in_place()` in `Devres::drop` and `Devres::new` as well as the 123 - // explicit `Send` and `Sync' impls can be removed. 124 - #[pin] 125 - inner: Opaque<Inner<T>>, 126 - _add_action: (), 127 + data: Arc<Revocable<T>>, 127 128 } 128 129 129 130 impl<T: Send> Devres<T> { ··· 124 139 /// 125 140 /// The `data` encapsulated within the returned `Devres` instance' `data` will be 126 141 /// (revoked)[`Revocable`] once the device is detached. 127 - pub fn new<'a, E>( 128 - dev: &'a Device<Bound>, 129 - data: impl PinInit<T, E> + 'a, 130 - ) -> impl PinInit<Self, Error> + 'a 142 + pub fn new<E>(dev: &Device<Bound>, data: impl PinInit<T, E>) -> Result<Self> 131 143 where 132 - T: 'a, 133 144 Error: From<E>, 134 145 { 135 - try_pin_init!(&this in Self { 146 + let callback = Self::devres_callback; 147 + let data = Arc::pin_init(Revocable::new(data), GFP_KERNEL)?; 148 + let devres_data = data.clone(); 149 + 150 + // SAFETY: 151 + // - `dev.as_raw()` is a pointer to a valid bound device. 152 + // - `data` is guaranteed to be a valid for the duration of the lifetime of `Self`. 153 + // - `devm_add_action()` is guaranteed not to call `callback` for the entire lifetime of 154 + // `dev`. 155 + to_result(unsafe { 156 + bindings::devm_add_action( 157 + dev.as_raw(), 158 + Some(callback), 159 + Arc::as_ptr(&data).cast_mut().cast(), 160 + ) 161 + })?; 162 + 163 + // `devm_add_action()` was successful and has consumed the reference count. 164 + core::mem::forget(devres_data); 165 + 166 + Ok(Self { 136 167 dev: dev.into(), 137 - callback: Self::devres_callback, 138 - // INVARIANT: `inner` is properly initialized. 139 - inner <- Opaque::pin_init(try_pin_init!(Inner { 140 - devm <- Completion::new(), 141 - revoke <- Completion::new(), 142 - data <- Revocable::new(data), 143 - })), 144 - // TODO: Replace with "initializer code blocks" [1] once available. 145 - // 146 - // [1] https://github.com/Rust-for-Linux/pin-init/pull/69 147 - _add_action: { 148 - // SAFETY: `this` is a valid pointer to uninitialized memory. 149 - let inner = unsafe { &raw mut (*this.as_ptr()).inner }; 150 - 151 - // SAFETY: 152 - // - `dev.as_raw()` is a pointer to a valid bound device. 153 - // - `inner` is guaranteed to be a valid for the duration of the lifetime of `Self`. 154 - // - `devm_add_action()` is guaranteed not to call `callback` until `this` has been 155 - // properly initialized, because we require `dev` (i.e. the *bound* device) to 156 - // live at least as long as the returned `impl PinInit<Self, Error>`. 157 - to_result(unsafe { 158 - bindings::devm_add_action(dev.as_raw(), Some(*callback), inner.cast()) 159 - }).inspect_err(|_| { 160 - let inner = Opaque::cast_into(inner); 161 - 162 - // SAFETY: `inner` is a valid pointer to an `Inner<T>` and valid for both reads 163 - // and writes. 164 - unsafe { core::ptr::drop_in_place(inner) }; 165 - })?; 166 - }, 168 + callback, 169 + data, 167 170 }) 168 171 } 169 172 170 - fn inner(&self) -> &Inner<T> { 171 - // SAFETY: By the type invairants of `Self`, `inner` is properly initialized and always 172 - // accessed read-only. 173 - unsafe { &*self.inner.get() } 174 - } 175 - 176 173 fn data(&self) -> &Revocable<T> { 177 - &self.inner().data 174 + &self.data 178 175 } 179 176 180 177 #[allow(clippy::missing_safety_doc)] 181 178 unsafe extern "C" fn devres_callback(ptr: *mut kernel::ffi::c_void) { 182 - // SAFETY: In `Self::new` we've passed a valid pointer to `Inner` to `devm_add_action()`, 183 - // hence `ptr` must be a valid pointer to `Inner`. 184 - let inner = unsafe { &*ptr.cast::<Inner<T>>() }; 179 + // SAFETY: In `Self::new` we've passed a valid pointer of `Revocable<T>` to 180 + // `devm_add_action()`, hence `ptr` must be a valid pointer to `Revocable<T>`. 181 + let data = unsafe { Arc::from_raw(ptr.cast::<Revocable<T>>()) }; 185 182 186 - // Ensure that `inner` can't be used anymore after we signal completion of this callback. 187 - let inner = ScopeGuard::new_with_data(inner, |inner| inner.devm.complete_all()); 188 - 189 - if !inner.data.revoke() { 190 - // If `revoke()` returns false, it means that `Devres::drop` already started revoking 191 - // `data` for us. Hence we have to wait until `Devres::drop` signals that it 192 - // completed revoking `data`. 193 - inner.revoke.wait_for_completion(); 194 - } 183 + data.revoke(); 195 184 } 196 185 197 186 fn remove_action(&self) -> bool { ··· 177 218 bindings::devm_remove_action_nowarn( 178 219 self.dev.as_raw(), 179 220 Some(self.callback), 180 - core::ptr::from_ref(self.inner()).cast_mut().cast(), 221 + core::ptr::from_ref(self.data()).cast_mut().cast(), 181 222 ) 182 223 } == 0) 183 224 } ··· 200 241 /// # Examples 201 242 /// 202 243 /// ```no_run 203 - /// # #![cfg(CONFIG_PCI)] 204 - /// # use kernel::{device::Core, devres::Devres, pci}; 244 + /// #![cfg(CONFIG_PCI)] 245 + /// use kernel::{ 246 + /// device::Core, 247 + /// devres::Devres, 248 + /// io::{ 249 + /// Io, 250 + /// IoKnownSize, // 251 + /// }, 252 + /// pci, // 253 + /// }; 205 254 /// 206 255 /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result { 207 256 /// let bar = devres.access(dev.as_ref())?; ··· 256 289 // SAFETY: `Devres` can be shared with any task, if `T: Sync`. 257 290 unsafe impl<T: Send + Sync> Sync for Devres<T> {} 258 291 259 - #[pinned_drop] 260 - impl<T: Send> PinnedDrop for Devres<T> { 261 - fn drop(self: Pin<&mut Self>) { 292 + impl<T: Send> Drop for Devres<T> { 293 + fn drop(&mut self) { 262 294 // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data 263 295 // anymore, hence it is safe not to wait for the grace period to finish. 264 296 if unsafe { self.data().revoke_nosync() } { 265 297 // We revoked `self.data` before the devres action did, hence try to remove it. 266 - if !self.remove_action() { 267 - // We could not remove the devres action, which means that it now runs concurrently, 268 - // hence signal that `self.data` has been revoked by us successfully. 269 - self.inner().revoke.complete_all(); 270 - 271 - // Wait for `Self::devres_callback` to be done using this object. 272 - self.inner().devm.wait_for_completion(); 298 + if self.remove_action() { 299 + // SAFETY: In `Self::new` we have taken an additional reference count of `self.data` 300 + // for `devm_add_action()`. Since `remove_action()` was successful, we have to drop 301 + // this additional reference count. 302 + drop(unsafe { Arc::from_raw(Arc::as_ptr(&self.data)) }); 273 303 } 274 - } else { 275 - // `Self::devres_callback` revokes `self.data` for us, hence wait for it to be done 276 - // using this object. 277 - self.inner().devm.wait_for_completion(); 278 304 } 279 - 280 - // INVARIANT: At this point it is guaranteed that `inner` can't be accessed any more. 281 - // 282 - // SAFETY: `inner` is valid for dropping. 283 - unsafe { core::ptr::drop_in_place(self.inner.get()) }; 284 305 } 285 306 } 286 307 ··· 300 345 /// # Examples 301 346 /// 302 347 /// ```no_run 303 - /// use kernel::{device::{Bound, Device}, devres}; 348 + /// use kernel::{ 349 + /// device::{ 350 + /// Bound, 351 + /// Device, // 352 + /// }, 353 + /// devres, // 354 + /// }; 304 355 /// 305 356 /// /// Registration of e.g. a class device, IRQ, etc. 306 357 /// struct Registration;
+17
rust/kernel/dma.rs
··· 85 85 bindings::dma_set_mask_and_coherent(self.as_ref().as_raw(), mask.value()) 86 86 }) 87 87 } 88 + 89 + /// Set the maximum size of a single DMA segment the device may request. 90 + /// 91 + /// This method is usually called once from `probe()` as soon as the device capabilities are 92 + /// known. 93 + /// 94 + /// # Safety 95 + /// 96 + /// This method must not be called concurrently with any DMA allocation or mapping primitives, 97 + /// such as [`CoherentAllocation::alloc_attrs`]. 98 + unsafe fn dma_set_max_seg_size(&self, size: u32) { 99 + // SAFETY: 100 + // - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid. 101 + // - The safety requirement of this function guarantees that there are no concurrent calls 102 + // to DMA allocation and mapping primitives using this parameter. 103 + unsafe { bindings::dma_set_max_seg_size(self.as_ref().as_raw(), size) } 104 + } 88 105 } 89 106 90 107 /// A DMA mask that holds a bitmask with the lowest `n` bits set.
+8 -4
rust/kernel/driver.rs
··· 94 94 //! [`device_id`]: kernel::device_id 95 95 //! [`module_driver`]: kernel::module_driver 96 96 97 - use crate::error::{Error, Result}; 98 - use crate::{acpi, device, of, str::CStr, try_pin_init, types::Opaque, ThisModule}; 99 - use core::pin::Pin; 100 - use pin_init::{pin_data, pinned_drop, PinInit}; 97 + use crate::{ 98 + acpi, 99 + device, 100 + of, 101 + prelude::*, 102 + types::Opaque, 103 + ThisModule, // 104 + }; 101 105 102 106 /// Trait describing the layout of a specific device driver. 103 107 ///
+11 -2
rust/kernel/faux.rs
··· 6 6 //! 7 7 //! C header: [`include/linux/device/faux.h`](srctree/include/linux/device/faux.h) 8 8 9 - use crate::{bindings, device, error::code::*, prelude::*}; 10 - use core::ptr::{addr_of_mut, null, null_mut, NonNull}; 9 + use crate::{ 10 + bindings, 11 + device, 12 + prelude::*, // 13 + }; 14 + use core::ptr::{ 15 + addr_of_mut, 16 + null, 17 + null_mut, 18 + NonNull, // 19 + }; 11 20 12 21 /// The registration of a faux device. 13 22 ///
+402 -85
rust/kernel/io.rs
··· 32 32 /// By itself, the existence of an instance of this structure does not provide any guarantees that 33 33 /// the represented MMIO region does exist or is properly mapped. 34 34 /// 35 - /// Instead, the bus specific MMIO implementation must convert this raw representation into an `Io` 36 - /// instance providing the actual memory accessors. Only by the conversion into an `Io` structure 37 - /// any guarantees are given. 38 - pub struct IoRaw<const SIZE: usize = 0> { 35 + /// Instead, the bus specific MMIO implementation must convert this raw representation into an 36 + /// `Mmio` instance providing the actual memory accessors. Only by the conversion into an `Mmio` 37 + /// structure any guarantees are given. 38 + pub struct MmioRaw<const SIZE: usize = 0> { 39 39 addr: usize, 40 40 maxsize: usize, 41 41 } 42 42 43 - impl<const SIZE: usize> IoRaw<SIZE> { 44 - /// Returns a new `IoRaw` instance on success, an error otherwise. 43 + impl<const SIZE: usize> MmioRaw<SIZE> { 44 + /// Returns a new `MmioRaw` instance on success, an error otherwise. 45 45 pub fn new(addr: usize, maxsize: usize) -> Result<Self> { 46 46 if maxsize < SIZE { 47 47 return Err(EINVAL); ··· 81 81 /// ffi::c_void, 82 82 /// io::{ 83 83 /// Io, 84 - /// IoRaw, 84 + /// IoKnownSize, 85 + /// Mmio, 86 + /// MmioRaw, 85 87 /// PhysAddr, 86 88 /// }, 87 89 /// }; 88 90 /// use core::ops::Deref; 89 91 /// 90 - /// // See also [`pci::Bar`] for a real example. 91 - /// struct IoMem<const SIZE: usize>(IoRaw<SIZE>); 92 + /// // See also `pci::Bar` for a real example. 93 + /// struct IoMem<const SIZE: usize>(MmioRaw<SIZE>); 92 94 /// 93 95 /// impl<const SIZE: usize> IoMem<SIZE> { 94 96 /// /// # Safety ··· 105 103 /// return Err(ENOMEM); 106 104 /// } 107 105 /// 108 - /// Ok(IoMem(IoRaw::new(addr as usize, SIZE)?)) 106 + /// Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?)) 109 107 /// } 110 108 /// } 111 109 /// ··· 117 115 /// } 118 116 /// 119 117 /// impl<const SIZE: usize> Deref for IoMem<SIZE> { 120 - /// type Target = Io<SIZE>; 118 + /// type Target = Mmio<SIZE>; 121 119 /// 122 120 /// fn deref(&self) -> &Self::Target { 123 121 /// // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`. 124 - /// unsafe { Io::from_raw(&self.0) } 122 + /// unsafe { Mmio::from_raw(&self.0) } 125 123 /// } 126 124 /// } 127 125 /// ··· 135 133 /// # } 136 134 /// ``` 137 135 #[repr(transparent)] 138 - pub struct Io<const SIZE: usize = 0>(IoRaw<SIZE>); 136 + pub struct Mmio<const SIZE: usize = 0>(MmioRaw<SIZE>); 137 + 138 + /// Internal helper macros used to invoke C MMIO read functions. 139 + /// 140 + /// This macro is intended to be used by higher-level MMIO access macros (define_read) and provides 141 + /// a unified expansion for infallible vs. fallible read semantics. It emits a direct call into the 142 + /// corresponding C helper and performs the required cast to the Rust return type. 143 + /// 144 + /// # Parameters 145 + /// 146 + /// * `$c_fn` – The C function performing the MMIO read. 147 + /// * `$self` – The I/O backend object. 148 + /// * `$ty` – The type of the value to be read. 149 + /// * `$addr` – The MMIO address to read. 150 + /// 151 + /// This macro does not perform any validation; all invariants must be upheld by the higher-level 152 + /// abstraction invoking it. 153 + macro_rules! call_mmio_read { 154 + (infallible, $c_fn:ident, $self:ident, $type:ty, $addr:expr) => { 155 + // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 156 + unsafe { bindings::$c_fn($addr as *const c_void) as $type } 157 + }; 158 + 159 + (fallible, $c_fn:ident, $self:ident, $type:ty, $addr:expr) => {{ 160 + // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 161 + Ok(unsafe { bindings::$c_fn($addr as *const c_void) as $type }) 162 + }}; 163 + } 164 + 165 + /// Internal helper macros used to invoke C MMIO write functions. 166 + /// 167 + /// This macro is intended to be used by higher-level MMIO access macros (define_write) and provides 168 + /// a unified expansion for infallible vs. fallible write semantics. It emits a direct call into the 169 + /// corresponding C helper and performs the required cast to the Rust return type. 170 + /// 171 + /// # Parameters 172 + /// 173 + /// * `$c_fn` – The C function performing the MMIO write. 174 + /// * `$self` – The I/O backend object. 175 + /// * `$ty` – The type of the written value. 176 + /// * `$addr` – The MMIO address to write. 177 + /// * `$value` – The value to write. 178 + /// 179 + /// This macro does not perform any validation; all invariants must be upheld by the higher-level 180 + /// abstraction invoking it. 181 + macro_rules! call_mmio_write { 182 + (infallible, $c_fn:ident, $self:ident, $ty:ty, $addr:expr, $value:expr) => { 183 + // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 184 + unsafe { bindings::$c_fn($value, $addr as *mut c_void) } 185 + }; 186 + 187 + (fallible, $c_fn:ident, $self:ident, $ty:ty, $addr:expr, $value:expr) => {{ 188 + // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 189 + unsafe { bindings::$c_fn($value, $addr as *mut c_void) }; 190 + Ok(()) 191 + }}; 192 + } 139 193 140 194 macro_rules! define_read { 141 - ($(#[$attr:meta])* $name:ident, $try_name:ident, $c_fn:ident -> $type_name:ty) => { 195 + (infallible, $(#[$attr:meta])* $vis:vis $name:ident, $call_macro:ident($c_fn:ident) -> 196 + $type_name:ty) => { 142 197 /// Read IO data from a given offset known at compile time. 143 198 /// 144 199 /// Bound checks are performed on compile time, hence if the offset is not known at compile ··· 203 144 $(#[$attr])* 204 145 // Always inline to optimize out error path of `io_addr_assert`. 205 146 #[inline(always)] 206 - pub fn $name(&self, offset: usize) -> $type_name { 147 + $vis fn $name(&self, offset: usize) -> $type_name { 207 148 let addr = self.io_addr_assert::<$type_name>(offset); 208 149 209 - // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 210 - unsafe { bindings::$c_fn(addr as *const c_void) } 150 + // SAFETY: By the type invariant `addr` is a valid address for IO operations. 151 + $call_macro!(infallible, $c_fn, self, $type_name, addr) 211 152 } 153 + }; 212 154 155 + (fallible, $(#[$attr:meta])* $vis:vis $try_name:ident, $call_macro:ident($c_fn:ident) -> 156 + $type_name:ty) => { 213 157 /// Read IO data from a given offset. 214 158 /// 215 159 /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is 216 160 /// out of bounds. 217 161 $(#[$attr])* 218 - pub fn $try_name(&self, offset: usize) -> Result<$type_name> { 162 + $vis fn $try_name(&self, offset: usize) -> Result<$type_name> { 219 163 let addr = self.io_addr::<$type_name>(offset)?; 220 164 221 - // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 222 - Ok(unsafe { bindings::$c_fn(addr as *const c_void) }) 165 + // SAFETY: By the type invariant `addr` is a valid address for IO operations. 166 + $call_macro!(fallible, $c_fn, self, $type_name, addr) 223 167 } 224 168 }; 225 169 } 170 + pub(crate) use define_read; 226 171 227 172 macro_rules! define_write { 228 - ($(#[$attr:meta])* $name:ident, $try_name:ident, $c_fn:ident <- $type_name:ty) => { 173 + (infallible, $(#[$attr:meta])* $vis:vis $name:ident, $call_macro:ident($c_fn:ident) <- 174 + $type_name:ty) => { 229 175 /// Write IO data from a given offset known at compile time. 230 176 /// 231 177 /// Bound checks are performed on compile time, hence if the offset is not known at compile ··· 238 174 $(#[$attr])* 239 175 // Always inline to optimize out error path of `io_addr_assert`. 240 176 #[inline(always)] 241 - pub fn $name(&self, value: $type_name, offset: usize) { 177 + $vis fn $name(&self, value: $type_name, offset: usize) { 242 178 let addr = self.io_addr_assert::<$type_name>(offset); 243 179 244 - // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 245 - unsafe { bindings::$c_fn(value, addr as *mut c_void) } 180 + $call_macro!(infallible, $c_fn, self, $type_name, addr, value); 246 181 } 182 + }; 247 183 184 + (fallible, $(#[$attr:meta])* $vis:vis $try_name:ident, $call_macro:ident($c_fn:ident) <- 185 + $type_name:ty) => { 248 186 /// Write IO data from a given offset. 249 187 /// 250 188 /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is 251 189 /// out of bounds. 252 190 $(#[$attr])* 253 - pub fn $try_name(&self, value: $type_name, offset: usize) -> Result { 191 + $vis fn $try_name(&self, value: $type_name, offset: usize) -> Result { 254 192 let addr = self.io_addr::<$type_name>(offset)?; 255 193 256 - // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 257 - unsafe { bindings::$c_fn(value, addr as *mut c_void) } 258 - Ok(()) 194 + $call_macro!(fallible, $c_fn, self, $type_name, addr, value) 259 195 } 260 196 }; 261 197 } 198 + pub(crate) use define_write; 262 199 263 - impl<const SIZE: usize> Io<SIZE> { 264 - /// Converts an `IoRaw` into an `Io` instance, providing the accessors to the MMIO mapping. 265 - /// 266 - /// # Safety 267 - /// 268 - /// Callers must ensure that `addr` is the start of a valid I/O mapped memory region of size 269 - /// `maxsize`. 270 - pub unsafe fn from_raw(raw: &IoRaw<SIZE>) -> &Self { 271 - // SAFETY: `Io` is a transparent wrapper around `IoRaw`. 272 - unsafe { &*core::ptr::from_ref(raw).cast() } 200 + /// Checks whether an access of type `U` at the given `offset` 201 + /// is valid within this region. 202 + #[inline] 203 + const fn offset_valid<U>(offset: usize, size: usize) -> bool { 204 + let type_size = core::mem::size_of::<U>(); 205 + if let Some(end) = offset.checked_add(type_size) { 206 + end <= size && offset % type_size == 0 207 + } else { 208 + false 273 209 } 210 + } 274 211 212 + /// Marker trait indicating that an I/O backend supports operations of a certain type. 213 + /// 214 + /// Different I/O backends can implement this trait to expose only the operations they support. 215 + /// 216 + /// For example, a PCI configuration space may implement `IoCapable<u8>`, `IoCapable<u16>`, 217 + /// and `IoCapable<u32>`, but not `IoCapable<u64>`, while an MMIO region on a 64-bit 218 + /// system might implement all four. 219 + pub trait IoCapable<T> {} 220 + 221 + /// Types implementing this trait (e.g. MMIO BARs or PCI config regions) 222 + /// can perform I/O operations on regions of memory. 223 + /// 224 + /// This is an abstract representation to be implemented by arbitrary I/O 225 + /// backends (e.g. MMIO, PCI config space, etc.). 226 + /// 227 + /// The [`Io`] trait provides: 228 + /// - Base address and size information 229 + /// - Helper methods for offset validation and address calculation 230 + /// - Fallible (runtime checked) accessors for different data widths 231 + /// 232 + /// Which I/O methods are available depends on which [`IoCapable<T>`] traits 233 + /// are implemented for the type. 234 + /// 235 + /// # Examples 236 + /// 237 + /// For MMIO regions, all widths (u8, u16, u32, and u64 on 64-bit systems) are typically 238 + /// supported. For PCI configuration space, u8, u16, and u32 are supported but u64 is not. 239 + pub trait Io { 275 240 /// Returns the base address of this mapping. 276 - #[inline] 277 - pub fn addr(&self) -> usize { 278 - self.0.addr() 279 - } 241 + fn addr(&self) -> usize; 280 242 281 243 /// Returns the maximum size of this mapping. 282 - #[inline] 283 - pub fn maxsize(&self) -> usize { 284 - self.0.maxsize() 285 - } 244 + fn maxsize(&self) -> usize; 286 245 287 - #[inline] 288 - const fn offset_valid<U>(offset: usize, size: usize) -> bool { 289 - let type_size = core::mem::size_of::<U>(); 290 - if let Some(end) = offset.checked_add(type_size) { 291 - end <= size && offset % type_size == 0 292 - } else { 293 - false 294 - } 295 - } 296 - 246 + /// Returns the absolute I/O address for a given `offset`, 247 + /// performing runtime bound checks. 297 248 #[inline] 298 249 fn io_addr<U>(&self, offset: usize) -> Result<usize> { 299 - if !Self::offset_valid::<U>(offset, self.maxsize()) { 250 + if !offset_valid::<U>(offset, self.maxsize()) { 300 251 return Err(EINVAL); 301 252 } 302 253 ··· 320 241 self.addr().checked_add(offset).ok_or(EINVAL) 321 242 } 322 243 244 + /// Fallible 8-bit read with runtime bounds check. 245 + #[inline(always)] 246 + fn try_read8(&self, _offset: usize) -> Result<u8> 247 + where 248 + Self: IoCapable<u8>, 249 + { 250 + build_error!("Backend does not support fallible 8-bit read") 251 + } 252 + 253 + /// Fallible 16-bit read with runtime bounds check. 254 + #[inline(always)] 255 + fn try_read16(&self, _offset: usize) -> Result<u16> 256 + where 257 + Self: IoCapable<u16>, 258 + { 259 + build_error!("Backend does not support fallible 16-bit read") 260 + } 261 + 262 + /// Fallible 32-bit read with runtime bounds check. 263 + #[inline(always)] 264 + fn try_read32(&self, _offset: usize) -> Result<u32> 265 + where 266 + Self: IoCapable<u32>, 267 + { 268 + build_error!("Backend does not support fallible 32-bit read") 269 + } 270 + 271 + /// Fallible 64-bit read with runtime bounds check. 272 + #[inline(always)] 273 + fn try_read64(&self, _offset: usize) -> Result<u64> 274 + where 275 + Self: IoCapable<u64>, 276 + { 277 + build_error!("Backend does not support fallible 64-bit read") 278 + } 279 + 280 + /// Fallible 8-bit write with runtime bounds check. 281 + #[inline(always)] 282 + fn try_write8(&self, _value: u8, _offset: usize) -> Result 283 + where 284 + Self: IoCapable<u8>, 285 + { 286 + build_error!("Backend does not support fallible 8-bit write") 287 + } 288 + 289 + /// Fallible 16-bit write with runtime bounds check. 290 + #[inline(always)] 291 + fn try_write16(&self, _value: u16, _offset: usize) -> Result 292 + where 293 + Self: IoCapable<u16>, 294 + { 295 + build_error!("Backend does not support fallible 16-bit write") 296 + } 297 + 298 + /// Fallible 32-bit write with runtime bounds check. 299 + #[inline(always)] 300 + fn try_write32(&self, _value: u32, _offset: usize) -> Result 301 + where 302 + Self: IoCapable<u32>, 303 + { 304 + build_error!("Backend does not support fallible 32-bit write") 305 + } 306 + 307 + /// Fallible 64-bit write with runtime bounds check. 308 + #[inline(always)] 309 + fn try_write64(&self, _value: u64, _offset: usize) -> Result 310 + where 311 + Self: IoCapable<u64>, 312 + { 313 + build_error!("Backend does not support fallible 64-bit write") 314 + } 315 + 316 + /// Infallible 8-bit read with compile-time bounds check. 317 + #[inline(always)] 318 + fn read8(&self, _offset: usize) -> u8 319 + where 320 + Self: IoKnownSize + IoCapable<u8>, 321 + { 322 + build_error!("Backend does not support infallible 8-bit read") 323 + } 324 + 325 + /// Infallible 16-bit read with compile-time bounds check. 326 + #[inline(always)] 327 + fn read16(&self, _offset: usize) -> u16 328 + where 329 + Self: IoKnownSize + IoCapable<u16>, 330 + { 331 + build_error!("Backend does not support infallible 16-bit read") 332 + } 333 + 334 + /// Infallible 32-bit read with compile-time bounds check. 335 + #[inline(always)] 336 + fn read32(&self, _offset: usize) -> u32 337 + where 338 + Self: IoKnownSize + IoCapable<u32>, 339 + { 340 + build_error!("Backend does not support infallible 32-bit read") 341 + } 342 + 343 + /// Infallible 64-bit read with compile-time bounds check. 344 + #[inline(always)] 345 + fn read64(&self, _offset: usize) -> u64 346 + where 347 + Self: IoKnownSize + IoCapable<u64>, 348 + { 349 + build_error!("Backend does not support infallible 64-bit read") 350 + } 351 + 352 + /// Infallible 8-bit write with compile-time bounds check. 353 + #[inline(always)] 354 + fn write8(&self, _value: u8, _offset: usize) 355 + where 356 + Self: IoKnownSize + IoCapable<u8>, 357 + { 358 + build_error!("Backend does not support infallible 8-bit write") 359 + } 360 + 361 + /// Infallible 16-bit write with compile-time bounds check. 362 + #[inline(always)] 363 + fn write16(&self, _value: u16, _offset: usize) 364 + where 365 + Self: IoKnownSize + IoCapable<u16>, 366 + { 367 + build_error!("Backend does not support infallible 16-bit write") 368 + } 369 + 370 + /// Infallible 32-bit write with compile-time bounds check. 371 + #[inline(always)] 372 + fn write32(&self, _value: u32, _offset: usize) 373 + where 374 + Self: IoKnownSize + IoCapable<u32>, 375 + { 376 + build_error!("Backend does not support infallible 32-bit write") 377 + } 378 + 379 + /// Infallible 64-bit write with compile-time bounds check. 380 + #[inline(always)] 381 + fn write64(&self, _value: u64, _offset: usize) 382 + where 383 + Self: IoKnownSize + IoCapable<u64>, 384 + { 385 + build_error!("Backend does not support infallible 64-bit write") 386 + } 387 + } 388 + 389 + /// Trait for types with a known size at compile time. 390 + /// 391 + /// This trait is implemented by I/O backends that have a compile-time known size, 392 + /// enabling the use of infallible I/O accessors with compile-time bounds checking. 393 + /// 394 + /// Types implementing this trait can use the infallible methods in [`Io`] trait 395 + /// (e.g., `read8`, `write32`), which require `Self: IoKnownSize` bound. 396 + pub trait IoKnownSize: Io { 397 + /// Minimum usable size of this region. 398 + const MIN_SIZE: usize; 399 + 400 + /// Returns the absolute I/O address for a given `offset`, 401 + /// performing compile-time bound checks. 323 402 // Always inline to optimize out error path of `build_assert`. 324 403 #[inline(always)] 325 404 fn io_addr_assert<U>(&self, offset: usize) -> usize { 326 - build_assert!(Self::offset_valid::<U>(offset, SIZE)); 405 + build_assert!(offset_valid::<U>(offset, Self::MIN_SIZE)); 327 406 328 407 self.addr() + offset 329 408 } 409 + } 330 410 331 - define_read!(read8, try_read8, readb -> u8); 332 - define_read!(read16, try_read16, readw -> u16); 333 - define_read!(read32, try_read32, readl -> u32); 411 + // MMIO regions support 8, 16, and 32-bit accesses. 412 + impl<const SIZE: usize> IoCapable<u8> for Mmio<SIZE> {} 413 + impl<const SIZE: usize> IoCapable<u16> for Mmio<SIZE> {} 414 + impl<const SIZE: usize> IoCapable<u32> for Mmio<SIZE> {} 415 + 416 + // MMIO regions on 64-bit systems also support 64-bit accesses. 417 + #[cfg(CONFIG_64BIT)] 418 + impl<const SIZE: usize> IoCapable<u64> for Mmio<SIZE> {} 419 + 420 + impl<const SIZE: usize> Io for Mmio<SIZE> { 421 + /// Returns the base address of this mapping. 422 + #[inline] 423 + fn addr(&self) -> usize { 424 + self.0.addr() 425 + } 426 + 427 + /// Returns the maximum size of this mapping. 428 + #[inline] 429 + fn maxsize(&self) -> usize { 430 + self.0.maxsize() 431 + } 432 + 433 + define_read!(fallible, try_read8, call_mmio_read(readb) -> u8); 434 + define_read!(fallible, try_read16, call_mmio_read(readw) -> u16); 435 + define_read!(fallible, try_read32, call_mmio_read(readl) -> u32); 334 436 define_read!( 437 + fallible, 438 + #[cfg(CONFIG_64BIT)] 439 + try_read64, 440 + call_mmio_read(readq) -> u64 441 + ); 442 + 443 + define_write!(fallible, try_write8, call_mmio_write(writeb) <- u8); 444 + define_write!(fallible, try_write16, call_mmio_write(writew) <- u16); 445 + define_write!(fallible, try_write32, call_mmio_write(writel) <- u32); 446 + define_write!( 447 + fallible, 448 + #[cfg(CONFIG_64BIT)] 449 + try_write64, 450 + call_mmio_write(writeq) <- u64 451 + ); 452 + 453 + define_read!(infallible, read8, call_mmio_read(readb) -> u8); 454 + define_read!(infallible, read16, call_mmio_read(readw) -> u16); 455 + define_read!(infallible, read32, call_mmio_read(readl) -> u32); 456 + define_read!( 457 + infallible, 335 458 #[cfg(CONFIG_64BIT)] 336 459 read64, 337 - try_read64, 338 - readq -> u64 460 + call_mmio_read(readq) -> u64 339 461 ); 340 462 341 - define_read!(read8_relaxed, try_read8_relaxed, readb_relaxed -> u8); 342 - define_read!(read16_relaxed, try_read16_relaxed, readw_relaxed -> u16); 343 - define_read!(read32_relaxed, try_read32_relaxed, readl_relaxed -> u32); 344 - define_read!( 345 - #[cfg(CONFIG_64BIT)] 346 - read64_relaxed, 347 - try_read64_relaxed, 348 - readq_relaxed -> u64 349 - ); 350 - 351 - define_write!(write8, try_write8, writeb <- u8); 352 - define_write!(write16, try_write16, writew <- u16); 353 - define_write!(write32, try_write32, writel <- u32); 463 + define_write!(infallible, write8, call_mmio_write(writeb) <- u8); 464 + define_write!(infallible, write16, call_mmio_write(writew) <- u16); 465 + define_write!(infallible, write32, call_mmio_write(writel) <- u32); 354 466 define_write!( 467 + infallible, 355 468 #[cfg(CONFIG_64BIT)] 356 469 write64, 357 - try_write64, 358 - writeq <- u64 470 + call_mmio_write(writeq) <- u64 471 + ); 472 + } 473 + 474 + impl<const SIZE: usize> IoKnownSize for Mmio<SIZE> { 475 + const MIN_SIZE: usize = SIZE; 476 + } 477 + 478 + impl<const SIZE: usize> Mmio<SIZE> { 479 + /// Converts an `MmioRaw` into an `Mmio` instance, providing the accessors to the MMIO mapping. 480 + /// 481 + /// # Safety 482 + /// 483 + /// Callers must ensure that `addr` is the start of a valid I/O mapped memory region of size 484 + /// `maxsize`. 485 + pub unsafe fn from_raw(raw: &MmioRaw<SIZE>) -> &Self { 486 + // SAFETY: `Mmio` is a transparent wrapper around `MmioRaw`. 487 + unsafe { &*core::ptr::from_ref(raw).cast() } 488 + } 489 + 490 + define_read!(infallible, pub read8_relaxed, call_mmio_read(readb_relaxed) -> u8); 491 + define_read!(infallible, pub read16_relaxed, call_mmio_read(readw_relaxed) -> u16); 492 + define_read!(infallible, pub read32_relaxed, call_mmio_read(readl_relaxed) -> u32); 493 + define_read!( 494 + infallible, 495 + #[cfg(CONFIG_64BIT)] 496 + pub read64_relaxed, 497 + call_mmio_read(readq_relaxed) -> u64 359 498 ); 360 499 361 - define_write!(write8_relaxed, try_write8_relaxed, writeb_relaxed <- u8); 362 - define_write!(write16_relaxed, try_write16_relaxed, writew_relaxed <- u16); 363 - define_write!(write32_relaxed, try_write32_relaxed, writel_relaxed <- u32); 364 - define_write!( 500 + define_read!(fallible, pub try_read8_relaxed, call_mmio_read(readb_relaxed) -> u8); 501 + define_read!(fallible, pub try_read16_relaxed, call_mmio_read(readw_relaxed) -> u16); 502 + define_read!(fallible, pub try_read32_relaxed, call_mmio_read(readl_relaxed) -> u32); 503 + define_read!( 504 + fallible, 365 505 #[cfg(CONFIG_64BIT)] 366 - write64_relaxed, 367 - try_write64_relaxed, 368 - writeq_relaxed <- u64 506 + pub try_read64_relaxed, 507 + call_mmio_read(readq_relaxed) -> u64 508 + ); 509 + 510 + define_write!(infallible, pub write8_relaxed, call_mmio_write(writeb_relaxed) <- u8); 511 + define_write!(infallible, pub write16_relaxed, call_mmio_write(writew_relaxed) <- u16); 512 + define_write!(infallible, pub write32_relaxed, call_mmio_write(writel_relaxed) <- u32); 513 + define_write!( 514 + infallible, 515 + #[cfg(CONFIG_64BIT)] 516 + pub write64_relaxed, 517 + call_mmio_write(writeq_relaxed) <- u64 518 + ); 519 + 520 + define_write!(fallible, pub try_write8_relaxed, call_mmio_write(writeb_relaxed) <- u8); 521 + define_write!(fallible, pub try_write16_relaxed, call_mmio_write(writew_relaxed) <- u16); 522 + define_write!(fallible, pub try_write32_relaxed, call_mmio_write(writel_relaxed) <- u32); 523 + define_write!( 524 + fallible, 525 + #[cfg(CONFIG_64BIT)] 526 + pub try_write64_relaxed, 527 + call_mmio_write(writeq_relaxed) <- u64 369 528 ); 370 529 }
+21 -12
rust/kernel/io/mem.rs
··· 5 5 use core::ops::Deref; 6 6 7 7 use crate::{ 8 - c_str, 9 8 device::{ 10 9 Bound, 11 10 Device, // ··· 16 17 Region, 17 18 Resource, // 18 19 }, 19 - Io, 20 - IoRaw, // 20 + Mmio, 21 + MmioRaw, // 21 22 }, 22 23 prelude::*, 23 24 }; ··· 51 52 /// illustration purposes. 52 53 /// 53 54 /// ```no_run 54 - /// use kernel::{bindings, c_str, platform, of, device::Core}; 55 + /// use kernel::{ 56 + /// bindings, 57 + /// device::Core, 58 + /// of, 59 + /// platform, 60 + /// }; 55 61 /// struct SampleDriver; 56 62 /// 57 63 /// impl platform::Driver for SampleDriver { ··· 114 110 /// illustration purposes. 115 111 /// 116 112 /// ```no_run 117 - /// use kernel::{bindings, c_str, platform, of, device::Core}; 113 + /// use kernel::{ 114 + /// bindings, 115 + /// device::Core, 116 + /// of, 117 + /// platform, 118 + /// }; 118 119 /// struct SampleDriver; 119 120 /// 120 121 /// impl platform::Driver for SampleDriver { ··· 181 172 fn ioremap(resource: &Resource) -> Result<Self> { 182 173 let start = resource.start(); 183 174 let size = resource.size(); 184 - let name = resource.name().unwrap_or(c_str!("")); 175 + let name = resource.name().unwrap_or_default(); 185 176 186 177 let region = resource 187 178 .request_region( ··· 212 203 } 213 204 214 205 impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { 215 - type Target = Io<SIZE>; 206 + type Target = Mmio<SIZE>; 216 207 217 208 fn deref(&self) -> &Self::Target { 218 209 &self.iomem ··· 226 217 /// 227 218 /// # Invariants 228 219 /// 229 - /// [`IoMem`] always holds an [`IoRaw`] instance that holds a valid pointer to the 220 + /// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid pointer to the 230 221 /// start of the I/O memory mapped region. 231 222 pub struct IoMem<const SIZE: usize = 0> { 232 - io: IoRaw<SIZE>, 223 + io: MmioRaw<SIZE>, 233 224 } 234 225 235 226 impl<const SIZE: usize> IoMem<SIZE> { ··· 264 255 return Err(ENOMEM); 265 256 } 266 257 267 - let io = IoRaw::new(addr as usize, size)?; 258 + let io = MmioRaw::new(addr as usize, size)?; 268 259 let io = IoMem { io }; 269 260 270 261 Ok(io) ··· 287 278 } 288 279 289 280 impl<const SIZE: usize> Deref for IoMem<SIZE> { 290 - type Target = Io<SIZE>; 281 + type Target = Mmio<SIZE>; 291 282 292 283 fn deref(&self) -> &Self::Target { 293 284 // SAFETY: Safe as by the invariant of `IoMem`. 294 - unsafe { Io::from_raw(&self.io) } 285 + unsafe { Mmio::from_raw(&self.io) } 295 286 } 296 287 }
+12 -4
rust/kernel/io/poll.rs
··· 45 45 /// # Examples 46 46 /// 47 47 /// ```no_run 48 - /// use kernel::io::{Io, poll::read_poll_timeout}; 48 + /// use kernel::io::{ 49 + /// Io, 50 + /// Mmio, 51 + /// poll::read_poll_timeout, // 52 + /// }; 49 53 /// use kernel::time::Delta; 50 54 /// 51 55 /// const HW_READY: u16 = 0x01; 52 56 /// 53 - /// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result { 57 + /// fn wait_for_hardware<const SIZE: usize>(io: &Mmio<SIZE>) -> Result { 54 58 /// read_poll_timeout( 55 59 /// // The `op` closure reads the value of a specific status register. 56 60 /// || io.try_read16(0x1000), ··· 132 128 /// # Examples 133 129 /// 134 130 /// ```no_run 135 - /// use kernel::io::{poll::read_poll_timeout_atomic, Io}; 131 + /// use kernel::io::{ 132 + /// Io, 133 + /// Mmio, 134 + /// poll::read_poll_timeout_atomic, // 135 + /// }; 136 136 /// use kernel::time::Delta; 137 137 /// 138 138 /// const HW_READY: u16 = 0x01; 139 139 /// 140 - /// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result { 140 + /// fn wait_for_hardware<const SIZE: usize>(io: &Mmio<SIZE>) -> Result { 141 141 /// read_poll_timeout_atomic( 142 142 /// // The `op` closure reads the value of a specific status register. 143 143 /// || io.try_read16(0x1000),
+2 -4
rust/kernel/irq/request.rs
··· 139 139 /// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion 140 140 /// 141 141 /// ``` 142 - /// use kernel::c_str; 143 142 /// use kernel::device::{Bound, Device}; 144 143 /// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration}; 145 144 /// use kernel::prelude::*; ··· 166 167 /// handler: impl PinInit<Data, Error>, 167 168 /// request: IrqRequest<'_>, 168 169 /// ) -> Result<Arc<Registration<Data>>> { 169 - /// let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler); 170 + /// let registration = Registration::new(request, Flags::SHARED, c"my_device", handler); 170 171 /// 171 172 /// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 172 173 /// ··· 339 340 /// [`Mutex`](kernel::sync::Mutex) to provide interior mutability. 340 341 /// 341 342 /// ``` 342 - /// use kernel::c_str; 343 343 /// use kernel::device::{Bound, Device}; 344 344 /// use kernel::irq::{ 345 345 /// self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn, ··· 379 381 /// request: IrqRequest<'_>, 380 382 /// ) -> Result<Arc<ThreadedRegistration<Data>>> { 381 383 /// let registration = 382 - /// ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler); 384 + /// ThreadedRegistration::new(request, Flags::SHARED, c"my_device", handler); 383 385 /// 384 386 /// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 385 387 ///
+2
rust/kernel/lib.rs
··· 142 142 pub mod seq_file; 143 143 pub mod sizes; 144 144 pub mod slice; 145 + #[cfg(CONFIG_SOC_BUS)] 146 + pub mod soc; 145 147 mod static_assert; 146 148 #[doc(hidden)] 147 149 pub mod std_vendor;
+9 -2
rust/kernel/pci.rs
··· 40 40 ClassMask, 41 41 Vendor, // 42 42 }; 43 - pub use self::io::Bar; 43 + pub use self::io::{ 44 + Bar, 45 + ConfigSpace, 46 + ConfigSpaceKind, 47 + ConfigSpaceSize, 48 + Extended, 49 + Normal, // 50 + }; 44 51 pub use self::irq::{ 45 52 IrqType, 46 53 IrqTypes, ··· 358 351 /// // Get an instance of `Vendor`. 359 352 /// let vendor = pdev.vendor_id(); 360 353 /// dev_info!( 361 - /// pdev.as_ref(), 354 + /// pdev, 362 355 /// "Device: Vendor={}, Device=0x{:x}\n", 363 356 /// vendor, 364 357 /// pdev.device_id()
+1 -1
rust/kernel/pci/id.rs
··· 22 22 /// fn probe_device(pdev: &pci::Device<Core>) -> Result { 23 23 /// let pci_class = pdev.pci_class(); 24 24 /// dev_info!( 25 - /// pdev.as_ref(), 25 + /// pdev, 26 26 /// "Detected PCI class: {}\n", 27 27 /// pci_class 28 28 /// );
+204 -6
rust/kernel/pci/io.rs
··· 8 8 device, 9 9 devres::Devres, 10 10 io::{ 11 + define_read, 12 + define_write, 11 13 Io, 12 - IoRaw, // 14 + IoCapable, 15 + IoKnownSize, 16 + Mmio, 17 + MmioRaw, // 13 18 }, 14 19 prelude::*, 15 20 sync::aref::ARef, // 16 21 }; 17 - use core::ops::Deref; 22 + use core::{ 23 + marker::PhantomData, 24 + ops::Deref, // 25 + }; 26 + 27 + /// Represents the size of a PCI configuration space. 28 + /// 29 + /// PCI devices can have either a *normal* (legacy) configuration space of 256 bytes, 30 + /// or an *extended* configuration space of 4096 bytes as defined in the PCI Express 31 + /// specification. 32 + #[repr(usize)] 33 + #[derive(Eq, PartialEq)] 34 + pub enum ConfigSpaceSize { 35 + /// 256-byte legacy PCI configuration space. 36 + Normal = 256, 37 + 38 + /// 4096-byte PCIe extended configuration space. 39 + Extended = 4096, 40 + } 41 + 42 + impl ConfigSpaceSize { 43 + /// Get the raw value of this enum. 44 + #[inline(always)] 45 + pub const fn into_raw(self) -> usize { 46 + // CAST: PCI configuration space size is at most 4096 bytes, so the value always fits 47 + // within `usize` without truncation or sign change. 48 + self as usize 49 + } 50 + } 51 + 52 + /// Marker type for normal (256-byte) PCI configuration space. 53 + pub struct Normal; 54 + 55 + /// Marker type for extended (4096-byte) PCIe configuration space. 56 + pub struct Extended; 57 + 58 + /// Trait for PCI configuration space size markers. 59 + /// 60 + /// This trait is implemented by [`Normal`] and [`Extended`] to provide 61 + /// compile-time knowledge of the configuration space size. 62 + pub trait ConfigSpaceKind { 63 + /// The size of this configuration space in bytes. 64 + const SIZE: usize; 65 + } 66 + 67 + impl ConfigSpaceKind for Normal { 68 + const SIZE: usize = 256; 69 + } 70 + 71 + impl ConfigSpaceKind for Extended { 72 + const SIZE: usize = 4096; 73 + } 74 + 75 + /// The PCI configuration space of a device. 76 + /// 77 + /// Provides typed read and write accessors for configuration registers 78 + /// using the standard `pci_read_config_*` and `pci_write_config_*` helpers. 79 + /// 80 + /// The generic parameter `S` indicates the maximum size of the configuration space. 81 + /// Use [`Normal`] for 256-byte legacy configuration space or [`Extended`] for 82 + /// 4096-byte PCIe extended configuration space (default). 83 + pub struct ConfigSpace<'a, S: ConfigSpaceKind = Extended> { 84 + pub(crate) pdev: &'a Device<device::Bound>, 85 + _marker: PhantomData<S>, 86 + } 87 + 88 + /// Internal helper macros used to invoke C PCI configuration space read functions. 89 + /// 90 + /// This macro is intended to be used by higher-level PCI configuration space access macros 91 + /// (define_read) and provides a unified expansion for infallible vs. fallible read semantics. It 92 + /// emits a direct call into the corresponding C helper and performs the required cast to the Rust 93 + /// return type. 94 + /// 95 + /// # Parameters 96 + /// 97 + /// * `$c_fn` – The C function performing the PCI configuration space write. 98 + /// * `$self` – The I/O backend object. 99 + /// * `$ty` – The type of the value to read. 100 + /// * `$addr` – The PCI configuration space offset to read. 101 + /// 102 + /// This macro does not perform any validation; all invariants must be upheld by the higher-level 103 + /// abstraction invoking it. 104 + macro_rules! call_config_read { 105 + (infallible, $c_fn:ident, $self:ident, $ty:ty, $addr:expr) => {{ 106 + let mut val: $ty = 0; 107 + // SAFETY: By the type invariant `$self.pdev` is a valid address. 108 + // CAST: The offset is cast to `i32` because the C functions expect a 32-bit signed offset 109 + // parameter. PCI configuration space size is at most 4096 bytes, so the value always fits 110 + // within `i32` without truncation or sign change. 111 + // Return value from C function is ignored in infallible accessors. 112 + let _ret = unsafe { bindings::$c_fn($self.pdev.as_raw(), $addr as i32, &mut val) }; 113 + val 114 + }}; 115 + } 116 + 117 + /// Internal helper macros used to invoke C PCI configuration space write functions. 118 + /// 119 + /// This macro is intended to be used by higher-level PCI configuration space access macros 120 + /// (define_write) and provides a unified expansion for infallible vs. fallible read semantics. It 121 + /// emits a direct call into the corresponding C helper and performs the required cast to the Rust 122 + /// return type. 123 + /// 124 + /// # Parameters 125 + /// 126 + /// * `$c_fn` – The C function performing the PCI configuration space write. 127 + /// * `$self` – The I/O backend object. 128 + /// * `$ty` – The type of the written value. 129 + /// * `$addr` – The configuration space offset to write. 130 + /// * `$value` – The value to write. 131 + /// 132 + /// This macro does not perform any validation; all invariants must be upheld by the higher-level 133 + /// abstraction invoking it. 134 + macro_rules! call_config_write { 135 + (infallible, $c_fn:ident, $self:ident, $ty:ty, $addr:expr, $value:expr) => { 136 + // SAFETY: By the type invariant `$self.pdev` is a valid address. 137 + // CAST: The offset is cast to `i32` because the C functions expect a 32-bit signed offset 138 + // parameter. PCI configuration space size is at most 4096 bytes, so the value always fits 139 + // within `i32` without truncation or sign change. 140 + // Return value from C function is ignored in infallible accessors. 141 + let _ret = unsafe { bindings::$c_fn($self.pdev.as_raw(), $addr as i32, $value) }; 142 + }; 143 + } 144 + 145 + // PCI configuration space supports 8, 16, and 32-bit accesses. 146 + impl<'a, S: ConfigSpaceKind> IoCapable<u8> for ConfigSpace<'a, S> {} 147 + impl<'a, S: ConfigSpaceKind> IoCapable<u16> for ConfigSpace<'a, S> {} 148 + impl<'a, S: ConfigSpaceKind> IoCapable<u32> for ConfigSpace<'a, S> {} 149 + 150 + impl<'a, S: ConfigSpaceKind> Io for ConfigSpace<'a, S> { 151 + /// Returns the base address of the I/O region. It is always 0 for configuration space. 152 + #[inline] 153 + fn addr(&self) -> usize { 154 + 0 155 + } 156 + 157 + /// Returns the maximum size of the configuration space. 158 + #[inline] 159 + fn maxsize(&self) -> usize { 160 + self.pdev.cfg_size().into_raw() 161 + } 162 + 163 + // PCI configuration space does not support fallible operations. 164 + // The default implementations from the Io trait are not used. 165 + 166 + define_read!(infallible, read8, call_config_read(pci_read_config_byte) -> u8); 167 + define_read!(infallible, read16, call_config_read(pci_read_config_word) -> u16); 168 + define_read!(infallible, read32, call_config_read(pci_read_config_dword) -> u32); 169 + 170 + define_write!(infallible, write8, call_config_write(pci_write_config_byte) <- u8); 171 + define_write!(infallible, write16, call_config_write(pci_write_config_word) <- u16); 172 + define_write!(infallible, write32, call_config_write(pci_write_config_dword) <- u32); 173 + } 174 + 175 + impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'a, S> { 176 + const MIN_SIZE: usize = S::SIZE; 177 + } 18 178 19 179 /// A PCI BAR to perform I/O-Operations on. 180 + /// 181 + /// I/O backend assumes that the device is little-endian and will automatically 182 + /// convert from little-endian to CPU endianness. 20 183 /// 21 184 /// # Invariants 22 185 /// ··· 187 24 /// memory mapped PCI BAR and its size. 188 25 pub struct Bar<const SIZE: usize = 0> { 189 26 pdev: ARef<Device>, 190 - io: IoRaw<SIZE>, 27 + io: MmioRaw<SIZE>, 191 28 num: i32, 192 29 } 193 30 ··· 223 60 return Err(ENOMEM); 224 61 } 225 62 226 - let io = match IoRaw::new(ioptr, len as usize) { 63 + let io = match MmioRaw::new(ioptr, len as usize) { 227 64 Ok(io) => io, 228 65 Err(err) => { 229 66 // SAFETY: ··· 277 114 } 278 115 279 116 impl<const SIZE: usize> Deref for Bar<SIZE> { 280 - type Target = Io<SIZE>; 117 + type Target = Mmio<SIZE>; 281 118 282 119 fn deref(&self) -> &Self::Target { 283 120 // SAFETY: By the type invariant of `Self`, the MMIO range in `self.io` is properly mapped. 284 - unsafe { Io::from_raw(&self.io) } 121 + unsafe { Mmio::from_raw(&self.io) } 285 122 } 286 123 } 287 124 ··· 303 140 name: &'a CStr, 304 141 ) -> impl PinInit<Devres<Bar>, Error> + 'a { 305 142 self.iomap_region_sized::<0>(bar, name) 143 + } 144 + 145 + /// Returns the size of configuration space. 146 + pub fn cfg_size(&self) -> ConfigSpaceSize { 147 + // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. 148 + let size = unsafe { (*self.as_raw()).cfg_size }; 149 + match size { 150 + 256 => ConfigSpaceSize::Normal, 151 + 4096 => ConfigSpaceSize::Extended, 152 + _ => { 153 + // PANIC: The PCI subsystem only ever reports the configuration space size as either 154 + // `ConfigSpaceSize::Normal` or `ConfigSpaceSize::Extended`. 155 + unreachable!(); 156 + } 157 + } 158 + } 159 + 160 + /// Return an initialized normal (256-byte) config space object. 161 + pub fn config_space<'a>(&'a self) -> ConfigSpace<'a, Normal> { 162 + ConfigSpace { 163 + pdev: self, 164 + _marker: PhantomData, 165 + } 166 + } 167 + 168 + /// Return an initialized extended (4096-byte) config space object. 169 + pub fn config_space_extended<'a>(&'a self) -> Result<ConfigSpace<'a, Extended>> { 170 + if self.cfg_size() != ConfigSpaceSize::Extended { 171 + return Err(EINVAL); 172 + } 173 + 174 + Ok(ConfigSpace { 175 + pdev: self, 176 + _marker: PhantomData, 177 + }) 306 178 } 307 179 }
+34 -12
rust/kernel/platform.rs
··· 5 5 //! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h) 6 6 7 7 use crate::{ 8 - acpi, bindings, container_of, 9 - device::{self, Bound}, 8 + acpi, 9 + bindings, 10 + container_of, 11 + device::{ 12 + self, 13 + Bound, // 14 + }, 10 15 driver, 11 - error::{from_result, to_result, Result}, 12 - io::{mem::IoRequest, Resource}, 13 - irq::{self, IrqRequest}, 16 + error::{ 17 + from_result, 18 + to_result, // 19 + }, 20 + io::{ 21 + mem::IoRequest, 22 + Resource, // 23 + }, 24 + irq::{ 25 + self, 26 + IrqRequest, // 27 + }, 14 28 of, 15 29 prelude::*, 16 30 types::Opaque, 17 - ThisModule, 31 + ThisModule, // 18 32 }; 19 33 20 34 use core::{ 21 35 marker::PhantomData, 22 36 mem::offset_of, 23 - ptr::{addr_of_mut, NonNull}, 37 + ptr::{ 38 + addr_of_mut, 39 + NonNull, // 40 + }, 24 41 }; 25 42 26 43 /// An adapter for the registration of platform drivers. ··· 112 95 // SAFETY: The platform bus only ever calls the remove callback with a valid pointer to a 113 96 // `struct platform_device`. 114 97 // 115 - // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. 98 + // INVARIANT: `pdev` is valid for the duration of `remove_callback()`. 116 99 let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; 117 100 118 101 // SAFETY: `remove_callback` is only ever called after a successful call to ··· 163 146 /// # Examples 164 147 /// 165 148 ///``` 166 - /// # use kernel::{acpi, bindings, c_str, device::Core, of, platform}; 167 - /// 149 + /// # use kernel::{ 150 + /// # acpi, 151 + /// # bindings, 152 + /// # device::Core, 153 + /// # of, 154 + /// # platform, 155 + /// # }; 168 156 /// struct MyDriver; 169 157 /// 170 158 /// kernel::of_device_table!( ··· 177 155 /// MODULE_OF_TABLE, 178 156 /// <MyDriver as platform::Driver>::IdInfo, 179 157 /// [ 180 - /// (of::DeviceId::new(c_str!("test,device")), ()) 158 + /// (of::DeviceId::new(c"test,device"), ()) 181 159 /// ] 182 160 /// ); 183 161 /// ··· 186 164 /// MODULE_ACPI_TABLE, 187 165 /// <MyDriver as platform::Driver>::IdInfo, 188 166 /// [ 189 - /// (acpi::DeviceId::new(c_str!("LNUXBEEF")), ()) 167 + /// (acpi::DeviceId::new(c"LNUXBEEF"), ()) 190 168 /// ] 191 169 /// ); 192 170 ///
+2 -1
rust/kernel/scatterlist.rs
··· 38 38 io::ResourceSize, 39 39 page, 40 40 prelude::*, 41 - types::{ARef, Opaque}, 41 + sync::aref::ARef, 42 + types::Opaque, 42 43 }; 43 44 use core::{ops::Deref, ptr::NonNull}; 44 45
+135
rust/kernel/soc.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + // Copyright (C) 2025 Google LLC. 4 + 5 + //! SoC Driver Abstraction. 6 + //! 7 + //! C header: [`include/linux/sys_soc.h`](srctree/include/linux/sys_soc.h) 8 + 9 + use crate::{ 10 + bindings, 11 + error, 12 + prelude::*, 13 + str::CString, 14 + types::Opaque, // 15 + }; 16 + use core::ptr::NonNull; 17 + 18 + /// Attributes for a SoC device. 19 + /// 20 + /// These are both exported to userspace under /sys/devices/socX and provided to other drivers to 21 + /// match against via `soc_device_match` (not yet available in Rust) to enable quirks or 22 + /// device-specific support where necessary. 23 + /// 24 + /// All fields are freeform - they have no specific formatting, just defined meanings. 25 + /// For example, the [`machine`](`Attributes::machine`) field could be "DB8500" or 26 + /// "Qualcomm Technologies, Inc. SM8560 HDK", but regardless it should identify a board or product. 27 + pub struct Attributes { 28 + /// Should generally be a board ID or product ID. Examples 29 + /// include DB8500 (ST-Ericsson) or "Qualcomm Technologies, inc. SM8560 HDK". 30 + /// 31 + /// If this field is not populated, the SoC infrastructure will try to populate it from 32 + /// `/model` in the device tree. 33 + pub machine: Option<CString>, 34 + /// The broader class this SoC belongs to. Examples include ux500 35 + /// (for DB8500) or Snapdragon (for SM8650). 36 + /// 37 + /// On chips with ARM firmware supporting SMCCC v1.2+, this may be a JEDEC JEP106 manufacturer 38 + /// identification. 39 + pub family: Option<CString>, 40 + /// The manufacturing revision of the part. Frequently this is MAJOR.MINOR, but not always. 41 + pub revision: Option<CString>, 42 + /// Serial Number - uniquely identifies a specific SoC. If present, should be unique (buying a 43 + /// replacement part should change it if present). This field cannot be matched on and is 44 + /// solely present to export through /sys. 45 + pub serial_number: Option<CString>, 46 + /// SoC ID - identifies a specific SoC kind in question, sometimes more specifically than 47 + /// `machine` if the same SoC is used in multiple products. Some devices use this to specify a 48 + /// SoC name, e.g. "I.MX??", and others just print an ID number (e.g. Tegra and Qualcomm). 49 + /// 50 + /// On chips with ARM firmware supporting SMCCC v1.2+, this may be a JEDEC JEP106 manufacturer 51 + /// identification (the family value) followed by a colon and then a 4-digit ID value. 52 + pub soc_id: Option<CString>, 53 + } 54 + 55 + struct BuiltAttributes { 56 + // While `inner` has pointers to `_backing`, it is to the interior of the `CStrings`, not 57 + // `backing` itself, so it does not need to be pinned. 58 + _backing: Attributes, 59 + // `Opaque` makes us `!Unpin`, as the registration holds a pointer to `inner` when used. 60 + inner: Opaque<bindings::soc_device_attribute>, 61 + } 62 + 63 + fn cstring_to_c(mcs: &Option<CString>) -> *const kernel::ffi::c_char { 64 + mcs.as_ref() 65 + .map(|cs| cs.as_char_ptr()) 66 + .unwrap_or(core::ptr::null()) 67 + } 68 + 69 + impl BuiltAttributes { 70 + fn as_mut_ptr(&self) -> *mut bindings::soc_device_attribute { 71 + self.inner.get() 72 + } 73 + } 74 + 75 + impl Attributes { 76 + fn build(self) -> BuiltAttributes { 77 + BuiltAttributes { 78 + inner: Opaque::new(bindings::soc_device_attribute { 79 + machine: cstring_to_c(&self.machine), 80 + family: cstring_to_c(&self.family), 81 + revision: cstring_to_c(&self.revision), 82 + serial_number: cstring_to_c(&self.serial_number), 83 + soc_id: cstring_to_c(&self.soc_id), 84 + data: core::ptr::null(), 85 + custom_attr_group: core::ptr::null(), 86 + }), 87 + _backing: self, 88 + } 89 + } 90 + } 91 + 92 + #[pin_data(PinnedDrop)] 93 + /// Registration handle for your soc_dev. If you let it go out of scope, your soc_dev will be 94 + /// unregistered. 95 + pub struct Registration { 96 + #[pin] 97 + attr: BuiltAttributes, 98 + soc_dev: NonNull<bindings::soc_device>, 99 + } 100 + 101 + // SAFETY: We provide no operations through `&Registration`. 102 + unsafe impl Sync for Registration {} 103 + 104 + // SAFETY: All pointers are normal allocations, not thread-specific. 105 + unsafe impl Send for Registration {} 106 + 107 + #[pinned_drop] 108 + impl PinnedDrop for Registration { 109 + fn drop(self: Pin<&mut Self>) { 110 + // SAFETY: Device always contains a live pointer to a soc_device that can be unregistered 111 + unsafe { bindings::soc_device_unregister(self.soc_dev.as_ptr()) } 112 + } 113 + } 114 + 115 + impl Registration { 116 + /// Register a new SoC device 117 + pub fn new(attr: Attributes) -> impl PinInit<Self, Error> { 118 + try_pin_init!(Self { 119 + attr: attr.build(), 120 + soc_dev: { 121 + // SAFETY: 122 + // * The struct provided through attr is backed by pinned data next to it, 123 + // so as long as attr lives, the strings pointed to by the struct will too. 124 + // * `attr` is pinned, so the pinned data won't move. 125 + // * If it returns a device, and so others may try to read this data, by 126 + // caller invariant, `attr` won't be released until the device is. 127 + let raw_soc = error::from_err_ptr(unsafe { 128 + bindings::soc_device_register(attr.as_mut_ptr()) 129 + })?; 130 + 131 + NonNull::new(raw_soc).ok_or(EINVAL)? 132 + }, 133 + }? Error) 134 + } 135 + }
+11
samples/rust/Kconfig
··· 161 161 162 162 If unsure, say N. 163 163 164 + config SAMPLE_RUST_SOC 165 + tristate "SoC Driver" 166 + select SOC_BUS 167 + help 168 + This option builds the Rust SoC driver sample. 169 + 170 + To compile this as a module, choose M here: 171 + the module will be called rust_soc. 172 + 173 + If unsure, say N. 174 + 164 175 config SAMPLE_RUST_HOSTPROGS 165 176 bool "Host programs" 166 177 help
+1
samples/rust/Makefile
··· 15 15 obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) += rust_driver_faux.o 16 16 obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY) += rust_driver_auxiliary.o 17 17 obj-$(CONFIG_SAMPLE_RUST_CONFIGFS) += rust_configfs.o 18 + obj-$(CONFIG_SAMPLE_RUST_SOC) += rust_soc.o 18 19 19 20 rust_print-y := rust_print_main.o rust_print_events.o 20 21
+30 -16
samples/rust/rust_debugfs.rs
··· 32 32 //! ``` 33 33 34 34 use core::str::FromStr; 35 - use kernel::c_str; 36 - use kernel::debugfs::{Dir, File}; 37 - use kernel::new_mutex; 38 - use kernel::prelude::*; 39 - use kernel::sizes::*; 40 - use kernel::sync::atomic::{Atomic, Relaxed}; 41 - use kernel::sync::Mutex; 42 - use kernel::{acpi, device::Core, of, platform, str::CString, types::ARef}; 35 + use kernel::{ 36 + acpi, 37 + debugfs::{ 38 + Dir, 39 + File, // 40 + }, 41 + device::Core, 42 + new_mutex, 43 + of, 44 + platform, 45 + prelude::*, 46 + sizes::*, 47 + str::CString, 48 + sync::{ 49 + aref::ARef, 50 + atomic::{ 51 + Atomic, 52 + Relaxed, // 53 + }, 54 + Mutex, 55 + }, // 56 + }; 43 57 44 58 kernel::module_platform_driver! { 45 59 type: RustDebugFs, ··· 112 98 ACPI_TABLE, 113 99 MODULE_ACPI_TABLE, 114 100 <RustDebugFs as platform::Driver>::IdInfo, 115 - [(acpi::DeviceId::new(c_str!("LNUXBEEF")), ())] 101 + [(acpi::DeviceId::new(c"LNUXBEEF"), ())] 116 102 ); 117 103 118 104 impl platform::Driver for RustDebugFs { ··· 139 125 140 126 impl RustDebugFs { 141 127 fn build_counter(dir: &Dir) -> impl PinInit<File<Atomic<usize>>> + '_ { 142 - dir.read_write_file(c_str!("counter"), Atomic::<usize>::new(0)) 128 + dir.read_write_file(c"counter", Atomic::<usize>::new(0)) 143 129 } 144 130 145 131 fn build_inner(dir: &Dir) -> impl PinInit<File<Mutex<Inner>>> + '_ { 146 - dir.read_write_file(c_str!("pair"), new_mutex!(Inner { x: 3, y: 10 })) 132 + dir.read_write_file(c"pair", new_mutex!(Inner { x: 3, y: 10 })) 147 133 } 148 134 149 135 fn new(pdev: &platform::Device<Core>) -> impl PinInit<Self, Error> + '_ { 150 - let debugfs = Dir::new(c_str!("sample_debugfs")); 136 + let debugfs = Dir::new(c"sample_debugfs"); 151 137 let dev = pdev.as_ref(); 152 138 153 139 try_pin_init! { 154 140 Self { 155 141 _compatible <- debugfs.read_only_file( 156 - c_str!("compatible"), 142 + c"compatible", 157 143 dev.fwnode() 158 144 .ok_or(ENOENT)? 159 - .property_read::<CString>(c_str!("compatible")) 145 + .property_read::<CString>(c"compatible") 160 146 .required_by(dev)?, 161 147 ), 162 148 counter <- Self::build_counter(&debugfs), 163 149 inner <- Self::build_inner(&debugfs), 164 150 array_blob <- debugfs.read_write_binary_file( 165 - c_str!("array_blob"), 151 + c"array_blob", 166 152 new_mutex!([0x62, 0x6c, 0x6f, 0x62]), 167 153 ), 168 154 vector_blob <- debugfs.read_write_binary_file( 169 - c_str!("vector_blob"), 155 + c"vector_blob", 170 156 new_mutex!(kernel::kvec!(0x42; SZ_4K)?), 171 157 ), 172 158 _debugfs: debugfs,
+21 -17
samples/rust/rust_debugfs_scoped.rs
··· 6 6 //! `Scope::dir` to create a variety of files without the need to separately 7 7 //! track them all. 8 8 9 - use kernel::debugfs::{Dir, Scope}; 10 - use kernel::prelude::*; 11 - use kernel::sizes::*; 12 - use kernel::sync::atomic::Atomic; 13 - use kernel::sync::Mutex; 14 - use kernel::{c_str, new_mutex, str::CString}; 9 + use kernel::{ 10 + debugfs::{ 11 + Dir, 12 + Scope, // 13 + }, 14 + new_mutex, 15 + prelude::*, 16 + sizes::*, 17 + str::CString, 18 + sync::{ 19 + atomic::Atomic, 20 + Mutex, // 21 + }, 22 + }; 15 23 16 24 module! { 17 25 type: RustScopedDebugFs, ··· 88 80 }; 89 81 dir.read_write_file(&name, val); 90 82 } 91 - dir.read_write_binary_file(c_str!("blob"), &dev_data.blob); 83 + dir.read_write_binary_file(c"blob", &dev_data.blob); 92 84 }, 93 85 ), 94 86 GFP_KERNEL, ··· 127 119 } 128 120 129 121 fn init_control(base_dir: &Dir, dyn_dirs: Dir) -> impl PinInit<Scope<ModuleData>> + '_ { 130 - base_dir.scope( 131 - ModuleData::init(dyn_dirs), 132 - c_str!("control"), 133 - |data, dir| { 134 - dir.write_only_callback_file(c_str!("create"), data, &create_file_write); 135 - dir.write_only_callback_file(c_str!("remove"), data, &remove_file_write); 136 - }, 137 - ) 122 + base_dir.scope(ModuleData::init(dyn_dirs), c"control", |data, dir| { 123 + dir.write_only_callback_file(c"create", data, &create_file_write); 124 + dir.write_only_callback_file(c"remove", data, &remove_file_write); 125 + }) 138 126 } 139 127 140 128 impl kernel::Module for RustScopedDebugFs { 141 129 fn init(_module: &'static kernel::ThisModule) -> Result<Self> { 142 - let base_dir = Dir::new(c_str!("rust_scoped_debugfs")); 143 - let dyn_dirs = base_dir.subdir(c_str!("dynamic")); 130 + let base_dir = Dir::new(c"rust_scoped_debugfs"); 131 + let dyn_dirs = base_dir.subdir(c"dynamic"); 144 132 Ok(Self { 145 133 _data: KBox::pin_init(init_control(&base_dir, dyn_dirs), GFP_KERNEL)?, 146 134 })
+8 -5
samples/rust/rust_dma.rs
··· 57 57 58 58 fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { 59 59 pin_init::pin_init_scope(move || { 60 - dev_info!(pdev.as_ref(), "Probe DMA test driver.\n"); 60 + dev_info!(pdev, "Probe DMA test driver.\n"); 61 61 62 62 let mask = DmaMask::new::<64>(); 63 63 ··· 88 88 #[pinned_drop] 89 89 impl PinnedDrop for DmaSampleDriver { 90 90 fn drop(self: Pin<&mut Self>) { 91 - let dev = self.pdev.as_ref(); 92 - 93 - dev_info!(dev, "Unload DMA test driver.\n"); 91 + dev_info!(self.pdev, "Unload DMA test driver.\n"); 94 92 95 93 for (i, value) in TEST_VALUES.into_iter().enumerate() { 96 94 let val0 = kernel::dma_read!(self.ca[i].h); ··· 105 107 } 106 108 107 109 for (i, entry) in self.sgt.iter().enumerate() { 108 - dev_info!(dev, "Entry[{}]: DMA address: {:#x}", i, entry.dma_address()); 110 + dev_info!( 111 + self.pdev, 112 + "Entry[{}]: DMA address: {:#x}", 113 + i, 114 + entry.dma_address(), 115 + ); 109 116 } 110 117 } 111 118 }
+8 -6
samples/rust/rust_driver_auxiliary.rs
··· 5 5 //! To make this driver probe, QEMU must be run with `-device pci-testdev`. 6 6 7 7 use kernel::{ 8 - auxiliary, c_str, 9 - device::{Bound, Core}, 8 + auxiliary, 9 + device::{ 10 + Bound, 11 + Core, // 12 + }, 10 13 devres::Devres, 11 14 driver, 12 - error::Error, 13 15 pci, 14 16 prelude::*, 15 - InPlaceModule, 17 + InPlaceModule, // 16 18 }; 17 19 18 20 use core::any::TypeId; 19 21 20 22 const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME; 21 - const AUXILIARY_NAME: &CStr = c_str!("auxiliary"); 23 + const AUXILIARY_NAME: &CStr = c"auxiliary"; 22 24 23 25 struct AuxiliaryDriver; 24 26 ··· 38 36 39 37 fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { 40 38 dev_info!( 41 - adev.as_ref(), 39 + adev, 42 40 "Probing auxiliary driver for auxiliary device with id={}\n", 43 41 adev.id() 44 42 );
+7 -3
samples/rust/rust_driver_faux.rs
··· 2 2 3 3 //! Rust faux device sample. 4 4 5 - use kernel::{c_str, faux, prelude::*, Module}; 5 + use kernel::{ 6 + faux, 7 + prelude::*, 8 + Module, // 9 + }; 6 10 7 11 module! { 8 12 type: SampleModule, ··· 24 20 fn init(_module: &'static ThisModule) -> Result<Self> { 25 21 pr_info!("Initialising Rust Faux Device Sample\n"); 26 22 27 - let reg = faux::Registration::new(c_str!("rust-faux-sample-device"), None)?; 23 + let reg = faux::Registration::new(c"rust-faux-sample-device", None)?; 28 24 29 - dev_info!(reg.as_ref(), "Hello from faux device!\n"); 25 + dev_info!(reg, "Hello from faux device!\n"); 30 26 31 27 Ok(Self { _reg: reg }) 32 28 }
+38 -5
samples/rust/rust_driver_pci.rs
··· 4 4 //! 5 5 //! To make this driver probe, QEMU must be run with `-device pci-testdev`. 6 6 7 - use kernel::{c_str, device::Core, devres::Devres, pci, prelude::*, sync::aref::ARef}; 7 + use kernel::{ 8 + device::Bound, 9 + device::Core, 10 + devres::Devres, 11 + io::Io, 12 + pci, 13 + prelude::*, 14 + sync::aref::ARef, // 15 + }; 8 16 9 17 struct Regs; 10 18 ··· 66 58 67 59 Ok(bar.read32(Regs::COUNT)) 68 60 } 61 + 62 + fn config_space(pdev: &pci::Device<Bound>) { 63 + let config = pdev.config_space(); 64 + 65 + // TODO: use the register!() macro for defining PCI configuration space registers once it 66 + // has been move out of nova-core. 67 + dev_info!( 68 + pdev, 69 + "pci-testdev config space read8 rev ID: {:x}\n", 70 + config.read8(0x8) 71 + ); 72 + 73 + dev_info!( 74 + pdev, 75 + "pci-testdev config space read16 vendor ID: {:x}\n", 76 + config.read16(0) 77 + ); 78 + 79 + dev_info!( 80 + pdev, 81 + "pci-testdev config space read32 BAR 0: {:x}\n", 82 + config.read32(0x10) 83 + ); 84 + } 69 85 } 70 86 71 87 impl pci::Driver for SampleDriver { ··· 101 69 pin_init::pin_init_scope(move || { 102 70 let vendor = pdev.vendor_id(); 103 71 dev_dbg!( 104 - pdev.as_ref(), 72 + pdev, 105 73 "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", 106 74 vendor, 107 75 pdev.device_id() ··· 111 79 pdev.set_master(); 112 80 113 81 Ok(try_pin_init!(Self { 114 - bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci")), 82 + bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c"rust_driver_pci"), 115 83 index: *info, 116 84 _: { 117 85 let bar = bar.access(pdev.as_ref())?; 118 86 119 87 dev_info!( 120 - pdev.as_ref(), 88 + pdev, 121 89 "pci-testdev data-match count: {}\n", 122 90 Self::testdev(info, bar)? 123 91 ); 92 + Self::config_space(pdev); 124 93 }, 125 94 pdev: pdev.into(), 126 95 })) ··· 139 106 #[pinned_drop] 140 107 impl PinnedDrop for SampleDriver { 141 108 fn drop(self: Pin<&mut Self>) { 142 - dev_dbg!(self.pdev.as_ref(), "Remove Rust PCI driver sample.\n"); 109 + dev_dbg!(self.pdev, "Remove Rust PCI driver sample.\n"); 143 110 } 144 111 } 145 112
+22 -20
samples/rust/rust_driver_platform.rs
··· 63 63 //! 64 64 65 65 use kernel::{ 66 - acpi, c_str, 66 + acpi, 67 67 device::{ 68 68 self, 69 - property::{FwNodeReferenceArgs, NArgs}, 69 + property::{ 70 + FwNodeReferenceArgs, 71 + NArgs, // 72 + }, 70 73 Core, 71 74 }, 72 - of, platform, 75 + of, 76 + platform, 73 77 prelude::*, 74 78 str::CString, 75 - sync::aref::ARef, 79 + sync::aref::ARef, // 76 80 }; 77 81 78 82 struct SampleDriver { ··· 89 85 OF_TABLE, 90 86 MODULE_OF_TABLE, 91 87 <SampleDriver as platform::Driver>::IdInfo, 92 - [(of::DeviceId::new(c_str!("test,rust-device")), Info(42))] 88 + [(of::DeviceId::new(c"test,rust-device"), Info(42))] 93 89 ); 94 90 95 91 kernel::acpi_device_table!( 96 92 ACPI_TABLE, 97 93 MODULE_ACPI_TABLE, 98 94 <SampleDriver as platform::Driver>::IdInfo, 99 - [(acpi::DeviceId::new(c_str!("LNUXBEEF")), Info(0))] 95 + [(acpi::DeviceId::new(c"LNUXBEEF"), Info(0))] 100 96 ); 101 97 102 98 impl platform::Driver for SampleDriver { ··· 128 124 fn properties_parse(dev: &device::Device) -> Result { 129 125 let fwnode = dev.fwnode().ok_or(ENOENT)?; 130 126 131 - if let Ok(idx) = 132 - fwnode.property_match_string(c_str!("compatible"), c_str!("test,rust-device")) 133 - { 127 + if let Ok(idx) = fwnode.property_match_string(c"compatible", c"test,rust-device") { 134 128 dev_info!(dev, "matched compatible string idx = {}\n", idx); 135 129 } 136 130 137 - let name = c_str!("compatible"); 131 + let name = c"compatible"; 138 132 let prop = fwnode.property_read::<CString>(name).required_by(dev)?; 139 133 dev_info!(dev, "'{name}'='{prop:?}'\n"); 140 134 141 - let name = c_str!("test,bool-prop"); 142 - let prop = fwnode.property_read_bool(c_str!("test,bool-prop")); 135 + let name = c"test,bool-prop"; 136 + let prop = fwnode.property_read_bool(c"test,bool-prop"); 143 137 dev_info!(dev, "'{name}'='{prop}'\n"); 144 138 145 - if fwnode.property_present(c_str!("test,u32-prop")) { 139 + if fwnode.property_present(c"test,u32-prop") { 146 140 dev_info!(dev, "'test,u32-prop' is present\n"); 147 141 } 148 142 149 - let name = c_str!("test,u32-optional-prop"); 143 + let name = c"test,u32-optional-prop"; 150 144 let prop = fwnode.property_read::<u32>(name).or(0x12); 151 145 dev_info!(dev, "'{name}'='{prop:#x}' (default = 0x12)\n"); 152 146 153 147 // A missing required property will print an error. Discard the error to 154 148 // prevent properties_parse from failing in that case. 155 - let name = c_str!("test,u32-required-prop"); 149 + let name = c"test,u32-required-prop"; 156 150 let _ = fwnode.property_read::<u32>(name).required_by(dev); 157 151 158 - let name = c_str!("test,u32-prop"); 152 + let name = c"test,u32-prop"; 159 153 let prop: u32 = fwnode.property_read(name).required_by(dev)?; 160 154 dev_info!(dev, "'{name}'='{prop:#x}'\n"); 161 155 162 - let name = c_str!("test,i16-array"); 156 + let name = c"test,i16-array"; 163 157 let prop: [i16; 4] = fwnode.property_read(name).required_by(dev)?; 164 158 dev_info!(dev, "'{name}'='{prop:?}'\n"); 165 159 let len = fwnode.property_count_elem::<u16>(name)?; 166 160 dev_info!(dev, "'{name}' length is {len}\n"); 167 161 168 - let name = c_str!("test,i16-array"); 162 + let name = c"test,i16-array"; 169 163 let prop: KVec<i16> = fwnode.property_read_array_vec(name, 4)?.required_by(dev)?; 170 164 dev_info!(dev, "'{name}'='{prop:?}' (KVec)\n"); 171 165 172 166 for child in fwnode.children() { 173 - let name = c_str!("test,ref-arg"); 167 + let name = c"test,ref-arg"; 174 168 let nargs = NArgs::N(2); 175 169 let prop: FwNodeReferenceArgs = child.property_get_reference_args(name, nargs, 0)?; 176 170 dev_info!(dev, "'{name}'='{prop:?}'\n"); ··· 180 178 181 179 impl Drop for SampleDriver { 182 180 fn drop(&mut self) { 183 - dev_dbg!(self.pdev.as_ref(), "Remove Rust Platform driver sample.\n"); 181 + dev_dbg!(self.pdev, "Remove Rust Platform driver sample.\n"); 184 182 } 185 183 } 186 184
+79
samples/rust/rust_soc.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Rust SoC Platform driver sample. 4 + 5 + use kernel::{ 6 + acpi, 7 + device::Core, 8 + of, 9 + platform, 10 + prelude::*, 11 + soc, 12 + str::CString, 13 + sync::aref::ARef, // 14 + }; 15 + use pin_init::pin_init_scope; 16 + 17 + #[pin_data] 18 + struct SampleSocDriver { 19 + pdev: ARef<platform::Device>, 20 + #[pin] 21 + _dev_reg: soc::Registration, 22 + } 23 + 24 + kernel::of_device_table!( 25 + OF_TABLE, 26 + MODULE_OF_TABLE, 27 + <SampleSocDriver as platform::Driver>::IdInfo, 28 + [(of::DeviceId::new(c"test,rust-device"), ())] 29 + ); 30 + 31 + kernel::acpi_device_table!( 32 + ACPI_TABLE, 33 + MODULE_ACPI_TABLE, 34 + <SampleSocDriver as platform::Driver>::IdInfo, 35 + [(acpi::DeviceId::new(c"LNUXBEEF"), ())] 36 + ); 37 + 38 + impl platform::Driver for SampleSocDriver { 39 + type IdInfo = (); 40 + const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); 41 + const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); 42 + 43 + fn probe( 44 + pdev: &platform::Device<Core>, 45 + _info: Option<&Self::IdInfo>, 46 + ) -> impl PinInit<Self, Error> { 47 + dev_dbg!(pdev, "Probe Rust SoC driver sample.\n"); 48 + 49 + let pdev = pdev.into(); 50 + pin_init_scope(move || { 51 + let machine = CString::try_from(c"My cool ACME15 dev board")?; 52 + let family = CString::try_from(c"ACME")?; 53 + let revision = CString::try_from(c"1.2")?; 54 + let serial_number = CString::try_from(c"12345")?; 55 + let soc_id = CString::try_from(c"ACME15")?; 56 + 57 + let attr = soc::Attributes { 58 + machine: Some(machine), 59 + family: Some(family), 60 + revision: Some(revision), 61 + serial_number: Some(serial_number), 62 + soc_id: Some(soc_id), 63 + }; 64 + 65 + Ok(try_pin_init!(SampleSocDriver { 66 + pdev: pdev, 67 + _dev_reg <- soc::Registration::new(attr), 68 + }? Error)) 69 + }) 70 + } 71 + } 72 + 73 + kernel::module_platform_driver! { 74 + type: SampleSocDriver, 75 + name: "rust_soc", 76 + authors: ["Matthew Maurer"], 77 + description: "Rust SoC Driver", 78 + license: "GPL", 79 + }