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.

rust: dma: add generalized container for types other than slices

Currently, `CoherentAllocation` is concecptually a DMA coherent container
of a slice of `[T]` of runtime-checked length. Generalize it by creating
`dma::Coherent<T>` which can hold any value of `T`.
`Coherent::alloc_with_attrs` is implemented but not yet exposed, as I
believe we should not expose the way to obtain an uninitialized coherent
region.

`Coherent<[T]>` provides a `len` method instead of the previous `count()`
method to be consistent with methods on slices.

The existing type is re-defined as a type alias of `Coherent<[T]>` to ease
transition. Methods in use are not yet removed.

Signed-off-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Link: https://patch.msgid.link/20260320194626.36263-3-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

authored by

Gary Guo and committed by
Danilo Krummrich
d9aee73c 7ea1a611

+234 -147
+2 -2
rust/kernel/device.rs
··· 575 575 /// The bound context indicates that for the entire duration of the lifetime of a [`Device<Bound>`] 576 576 /// reference, the [`Device`] is guaranteed to be bound to a driver. 577 577 /// 578 - /// Some APIs, such as [`dma::CoherentAllocation`] or [`Devres`] rely on the [`Device`] to be bound, 578 + /// Some APIs, such as [`dma::Coherent`] or [`Devres`] rely on the [`Device`] to be bound, 579 579 /// which can be proven with the [`Bound`] device context. 580 580 /// 581 581 /// Any abstraction that can guarantee a scope where the corresponding bus device is bound, should ··· 584 584 /// 585 585 /// [`Devres`]: kernel::devres::Devres 586 586 /// [`Devres::access`]: kernel::devres::Devres::access 587 - /// [`dma::CoherentAllocation`]: kernel::dma::CoherentAllocation 587 + /// [`dma::Coherent`]: kernel::dma::Coherent 588 588 pub struct Bound; 589 589 590 590 mod private {
+232 -145
rust/kernel/dma.rs
··· 6 6 7 7 use crate::{ 8 8 bindings, 9 - build_assert, 10 9 device::{ 11 10 self, 12 11 Bound, ··· 13 14 }, 14 15 error::to_result, 15 16 prelude::*, 17 + ptr::KnownSize, 16 18 sync::aref::ARef, 17 19 transmute::{ 18 20 AsBytes, ··· 357 357 /// This is an abstraction around the `dma_alloc_coherent` API which is used to allocate and map 358 358 /// large coherent DMA regions. 359 359 /// 360 - /// A [`CoherentAllocation`] instance contains a pointer to the allocated region (in the 360 + /// A [`Coherent`] instance contains a pointer to the allocated region (in the 361 361 /// processor's virtual address space) and the device address which can be given to the device 362 - /// as the DMA address base of the region. The region is released once [`CoherentAllocation`] 362 + /// as the DMA address base of the region. The region is released once [`Coherent`] 363 363 /// is dropped. 364 364 /// 365 365 /// # Invariants 366 366 /// 367 - /// - For the lifetime of an instance of [`CoherentAllocation`], the `cpu_addr` is a valid pointer 367 + /// - For the lifetime of an instance of [`Coherent`], the `cpu_addr` is a valid pointer 368 368 /// to an allocated region of coherent memory and `dma_handle` is the DMA address base of the 369 369 /// region. 370 - /// - The size in bytes of the allocation is equal to `size_of::<T> * count`. 371 - /// - `size_of::<T> * count` fits into a `usize`. 370 + /// - The size in bytes of the allocation is equal to size information via pointer. 372 371 // TODO 373 372 // 374 373 // DMA allocations potentially carry device resources (e.g.IOMMU mappings), hence for soundness ··· 378 379 // allocation from surviving device unbind; it would require RCU read side critical sections to 379 380 // access the memory, which may require subsequent unnecessary copies. 380 381 // 381 - // Hence, find a way to revoke the device resources of a `CoherentAllocation`, but not the 382 - // entire `CoherentAllocation` including the allocated memory itself. 383 - pub struct CoherentAllocation<T: AsBytes + FromBytes> { 382 + // Hence, find a way to revoke the device resources of a `Coherent`, but not the 383 + // entire `Coherent` including the allocated memory itself. 384 + pub struct Coherent<T: KnownSize + ?Sized> { 384 385 dev: ARef<device::Device>, 385 386 dma_handle: DmaAddress, 386 - count: usize, 387 387 cpu_addr: NonNull<T>, 388 388 dma_attrs: Attrs, 389 389 } 390 + 391 + impl<T: KnownSize + ?Sized> Coherent<T> { 392 + /// Returns the size in bytes of this allocation. 393 + #[inline] 394 + pub fn size(&self) -> usize { 395 + T::size(self.cpu_addr.as_ptr()) 396 + } 397 + 398 + /// Returns the raw pointer to the allocated region in the CPU's virtual address space. 399 + #[inline] 400 + pub fn as_ptr(&self) -> *const T { 401 + self.cpu_addr.as_ptr() 402 + } 403 + 404 + /// Returns the raw pointer to the allocated region in the CPU's virtual address space as 405 + /// a mutable pointer. 406 + #[inline] 407 + pub fn as_mut_ptr(&self) -> *mut T { 408 + self.cpu_addr.as_ptr() 409 + } 410 + 411 + /// Returns a DMA handle which may be given to the device as the DMA address base of 412 + /// the region. 413 + #[inline] 414 + pub fn dma_handle(&self) -> DmaAddress { 415 + self.dma_handle 416 + } 417 + 418 + /// Returns a reference to the data in the region. 419 + /// 420 + /// # Safety 421 + /// 422 + /// * Callers must ensure that the device does not read/write to/from memory while the returned 423 + /// slice is live. 424 + /// * Callers must ensure that this call does not race with a write to the same region while 425 + /// the returned slice is live. 426 + #[inline] 427 + pub unsafe fn as_ref(&self) -> &T { 428 + // SAFETY: per safety requirement. 429 + unsafe { &*self.as_ptr() } 430 + } 431 + 432 + /// Returns a mutable reference to the data in the region. 433 + /// 434 + /// # Safety 435 + /// 436 + /// * Callers must ensure that the device does not read/write to/from memory while the returned 437 + /// slice is live. 438 + /// * Callers must ensure that this call does not race with a read or write to the same region 439 + /// while the returned slice is live. 440 + #[expect(clippy::mut_from_ref, reason = "unsafe to use API")] 441 + #[inline] 442 + pub unsafe fn as_mut(&self) -> &mut T { 443 + // SAFETY: per safety requirement. 444 + unsafe { &mut *self.as_mut_ptr() } 445 + } 446 + 447 + /// Reads the value of `field` and ensures that its type is [`FromBytes`]. 448 + /// 449 + /// # Safety 450 + /// 451 + /// This must be called from the [`dma_read`] macro which ensures that the `field` pointer is 452 + /// validated beforehand. 453 + /// 454 + /// Public but hidden since it should only be used from [`dma_read`] macro. 455 + #[doc(hidden)] 456 + pub unsafe fn field_read<F: FromBytes>(&self, field: *const F) -> F { 457 + // SAFETY: 458 + // - By the safety requirements field is valid. 459 + // - Using read_volatile() here is not sound as per the usual rules, the usage here is 460 + // a special exception with the following notes in place. When dealing with a potential 461 + // race from a hardware or code outside kernel (e.g. user-space program), we need that 462 + // read on a valid memory is not UB. Currently read_volatile() is used for this, and the 463 + // rationale behind is that it should generate the same code as READ_ONCE() which the 464 + // kernel already relies on to avoid UB on data races. Note that the usage of 465 + // read_volatile() is limited to this particular case, it cannot be used to prevent 466 + // the UB caused by racing between two kernel functions nor do they provide atomicity. 467 + unsafe { field.read_volatile() } 468 + } 469 + 470 + /// Writes a value to `field` and ensures that its type is [`AsBytes`]. 471 + /// 472 + /// # Safety 473 + /// 474 + /// This must be called from the [`dma_write`] macro which ensures that the `field` pointer is 475 + /// validated beforehand. 476 + /// 477 + /// Public but hidden since it should only be used from [`dma_write`] macro. 478 + #[doc(hidden)] 479 + pub unsafe fn field_write<F: AsBytes>(&self, field: *mut F, val: F) { 480 + // SAFETY: 481 + // - By the safety requirements field is valid. 482 + // - Using write_volatile() here is not sound as per the usual rules, the usage here is 483 + // a special exception with the following notes in place. When dealing with a potential 484 + // race from a hardware or code outside kernel (e.g. user-space program), we need that 485 + // write on a valid memory is not UB. Currently write_volatile() is used for this, and the 486 + // rationale behind is that it should generate the same code as WRITE_ONCE() which the 487 + // kernel already relies on to avoid UB on data races. Note that the usage of 488 + // write_volatile() is limited to this particular case, it cannot be used to prevent 489 + // the UB caused by racing between two kernel functions nor do they provide atomicity. 490 + unsafe { field.write_volatile(val) } 491 + } 492 + } 493 + 494 + impl<T: AsBytes + FromBytes> Coherent<T> { 495 + /// Allocates a region of `T` of coherent memory. 496 + #[expect(unused)] 497 + fn alloc_with_attrs( 498 + dev: &device::Device<Bound>, 499 + gfp_flags: kernel::alloc::Flags, 500 + dma_attrs: Attrs, 501 + ) -> Result<Self> { 502 + const { 503 + assert!( 504 + core::mem::size_of::<T>() > 0, 505 + "It doesn't make sense for the allocated type to be a ZST" 506 + ); 507 + } 508 + 509 + let mut dma_handle = 0; 510 + // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`. 511 + let addr = unsafe { 512 + bindings::dma_alloc_attrs( 513 + dev.as_raw(), 514 + core::mem::size_of::<T>(), 515 + &mut dma_handle, 516 + gfp_flags.as_raw(), 517 + dma_attrs.as_raw(), 518 + ) 519 + }; 520 + let cpu_addr = NonNull::new(addr.cast()).ok_or(ENOMEM)?; 521 + // INVARIANT: 522 + // - We just successfully allocated a coherent region which is adequately sized for `T`, 523 + // hence the cpu address is valid. 524 + // - We also hold a refcounted reference to the device. 525 + Ok(Self { 526 + dev: dev.into(), 527 + dma_handle, 528 + cpu_addr, 529 + dma_attrs, 530 + }) 531 + } 532 + 533 + /// Allocates a region of `[T; len]` of coherent memory. 534 + fn alloc_slice_with_attrs( 535 + dev: &device::Device<Bound>, 536 + len: usize, 537 + gfp_flags: kernel::alloc::Flags, 538 + dma_attrs: Attrs, 539 + ) -> Result<Coherent<[T]>> { 540 + const { 541 + assert!( 542 + core::mem::size_of::<T>() > 0, 543 + "It doesn't make sense for the allocated type to be a ZST" 544 + ); 545 + } 546 + 547 + // `dma_alloc_attrs` cannot handle zero-length allocation, bail early. 548 + if len == 0 { 549 + Err(EINVAL)?; 550 + } 551 + 552 + let size = core::mem::size_of::<T>().checked_mul(len).ok_or(ENOMEM)?; 553 + let mut dma_handle = 0; 554 + // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`. 555 + let addr = unsafe { 556 + bindings::dma_alloc_attrs( 557 + dev.as_raw(), 558 + size, 559 + &mut dma_handle, 560 + gfp_flags.as_raw(), 561 + dma_attrs.as_raw(), 562 + ) 563 + }; 564 + let cpu_addr = NonNull::slice_from_raw_parts(NonNull::new(addr.cast()).ok_or(ENOMEM)?, len); 565 + // INVARIANT: 566 + // - We just successfully allocated a coherent region which is adequately sized for 567 + // `[T; len]`, hence the cpu address is valid. 568 + // - We also hold a refcounted reference to the device. 569 + Ok(Coherent { 570 + dev: dev.into(), 571 + dma_handle, 572 + cpu_addr, 573 + dma_attrs, 574 + }) 575 + } 576 + } 577 + 578 + impl<T> Coherent<[T]> { 579 + /// Returns the number of elements `T` in this allocation. 580 + /// 581 + /// Note that this is not the size of the allocation in bytes, which is provided by 582 + /// [`Self::size`]. 583 + #[inline] 584 + #[expect(clippy::len_without_is_empty, reason = "Coherent slice is never empty")] 585 + pub fn len(&self) -> usize { 586 + self.cpu_addr.len() 587 + } 588 + } 589 + 590 + // Type alias for compatibility. 591 + #[doc(hidden)] 592 + pub type CoherentAllocation<T> = Coherent<[T]>; 390 593 391 594 impl<T: AsBytes + FromBytes> CoherentAllocation<T> { 392 595 /// Allocates a region of `size_of::<T> * count` of coherent memory. ··· 610 409 gfp_flags: kernel::alloc::Flags, 611 410 dma_attrs: Attrs, 612 411 ) -> Result<CoherentAllocation<T>> { 613 - build_assert!( 614 - core::mem::size_of::<T>() > 0, 615 - "It doesn't make sense for the allocated type to be a ZST" 616 - ); 617 - 618 - let size = count 619 - .checked_mul(core::mem::size_of::<T>()) 620 - .ok_or(EOVERFLOW)?; 621 - let mut dma_handle = 0; 622 - // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`. 623 - let addr = unsafe { 624 - bindings::dma_alloc_attrs( 625 - dev.as_raw(), 626 - size, 627 - &mut dma_handle, 628 - gfp_flags.as_raw(), 629 - dma_attrs.as_raw(), 630 - ) 631 - }; 632 - let addr = NonNull::new(addr).ok_or(ENOMEM)?; 633 - // INVARIANT: 634 - // - We just successfully allocated a coherent region which is accessible for 635 - // `count` elements, hence the cpu address is valid. We also hold a refcounted reference 636 - // to the device. 637 - // - The allocated `size` is equal to `size_of::<T> * count`. 638 - // - The allocated `size` fits into a `usize`. 639 - Ok(Self { 640 - dev: dev.into(), 641 - dma_handle, 642 - count, 643 - cpu_addr: addr.cast(), 644 - dma_attrs, 645 - }) 412 + Coherent::alloc_slice_with_attrs(dev, count, gfp_flags, dma_attrs) 646 413 } 647 414 648 415 /// Performs the same functionality as [`CoherentAllocation::alloc_attrs`], except the ··· 623 454 CoherentAllocation::alloc_attrs(dev, count, gfp_flags, Attrs(0)) 624 455 } 625 456 626 - /// Returns the number of elements `T` in this allocation. 627 - /// 628 - /// Note that this is not the size of the allocation in bytes, which is provided by 629 - /// [`Self::size`]. 630 - pub fn count(&self) -> usize { 631 - self.count 632 - } 633 - 634 - /// Returns the size in bytes of this allocation. 635 - pub fn size(&self) -> usize { 636 - // INVARIANT: The type invariant of `Self` guarantees that `size_of::<T> * count` fits into 637 - // a `usize`. 638 - self.count * core::mem::size_of::<T>() 639 - } 640 - 641 - /// Returns the raw pointer to the allocated region in the CPU's virtual address space. 642 - #[inline] 643 - pub fn as_ptr(&self) -> *const [T] { 644 - core::ptr::slice_from_raw_parts(self.cpu_addr.as_ptr(), self.count) 645 - } 646 - 647 - /// Returns the raw pointer to the allocated region in the CPU's virtual address space as 648 - /// a mutable pointer. 649 - #[inline] 650 - pub fn as_mut_ptr(&self) -> *mut [T] { 651 - core::ptr::slice_from_raw_parts_mut(self.cpu_addr.as_ptr(), self.count) 652 - } 653 - 654 457 /// Returns the base address to the allocated region in the CPU's virtual address space. 655 458 pub fn start_ptr(&self) -> *const T { 656 - self.cpu_addr.as_ptr() 459 + self.as_ptr().cast() 657 460 } 658 461 659 462 /// Returns the base address to the allocated region in the CPU's virtual address space as 660 463 /// a mutable pointer. 661 464 pub fn start_ptr_mut(&mut self) -> *mut T { 662 - self.cpu_addr.as_ptr() 663 - } 664 - 665 - /// Returns a DMA handle which may be given to the device as the DMA address base of 666 - /// the region. 667 - pub fn dma_handle(&self) -> DmaAddress { 668 - self.dma_handle 465 + self.as_mut_ptr().cast() 669 466 } 670 467 671 468 /// Returns a DMA handle starting at `offset` (in units of `T`) which may be given to the ··· 639 504 /// 640 505 /// Returns `EINVAL` if `offset` is not within the bounds of the allocation. 641 506 pub fn dma_handle_with_offset(&self, offset: usize) -> Result<DmaAddress> { 642 - if offset >= self.count { 507 + if offset >= self.len() { 643 508 Err(EINVAL) 644 509 } else { 645 - // INVARIANT: The type invariant of `Self` guarantees that `size_of::<T> * count` fits 646 - // into a `usize`, and `offset` is inferior to `count`. 647 510 Ok(self.dma_handle + (offset * core::mem::size_of::<T>()) as DmaAddress) 648 511 } 649 512 } ··· 649 516 /// Common helper to validate a range applied from the allocated region in the CPU's virtual 650 517 /// address space. 651 518 fn validate_range(&self, offset: usize, count: usize) -> Result { 652 - if offset.checked_add(count).ok_or(EOVERFLOW)? > self.count { 519 + if offset.checked_add(count).ok_or(EOVERFLOW)? > self.len() { 653 520 return Err(EINVAL); 654 521 } 655 522 Ok(()) ··· 734 601 }; 735 602 Ok(()) 736 603 } 737 - 738 - /// Reads the value of `field` and ensures that its type is [`FromBytes`]. 739 - /// 740 - /// # Safety 741 - /// 742 - /// This must be called from the [`dma_read`] macro which ensures that the `field` pointer is 743 - /// validated beforehand. 744 - /// 745 - /// Public but hidden since it should only be used from [`dma_read`] macro. 746 - #[doc(hidden)] 747 - pub unsafe fn field_read<F: FromBytes>(&self, field: *const F) -> F { 748 - // SAFETY: 749 - // - By the safety requirements field is valid. 750 - // - Using read_volatile() here is not sound as per the usual rules, the usage here is 751 - // a special exception with the following notes in place. When dealing with a potential 752 - // race from a hardware or code outside kernel (e.g. user-space program), we need that 753 - // read on a valid memory is not UB. Currently read_volatile() is used for this, and the 754 - // rationale behind is that it should generate the same code as READ_ONCE() which the 755 - // kernel already relies on to avoid UB on data races. Note that the usage of 756 - // read_volatile() is limited to this particular case, it cannot be used to prevent 757 - // the UB caused by racing between two kernel functions nor do they provide atomicity. 758 - unsafe { field.read_volatile() } 759 - } 760 - 761 - /// Writes a value to `field` and ensures that its type is [`AsBytes`]. 762 - /// 763 - /// # Safety 764 - /// 765 - /// This must be called from the [`dma_write`] macro which ensures that the `field` pointer is 766 - /// validated beforehand. 767 - /// 768 - /// Public but hidden since it should only be used from [`dma_write`] macro. 769 - #[doc(hidden)] 770 - pub unsafe fn field_write<F: AsBytes>(&self, field: *mut F, val: F) { 771 - // SAFETY: 772 - // - By the safety requirements field is valid. 773 - // - Using write_volatile() here is not sound as per the usual rules, the usage here is 774 - // a special exception with the following notes in place. When dealing with a potential 775 - // race from a hardware or code outside kernel (e.g. user-space program), we need that 776 - // write on a valid memory is not UB. Currently write_volatile() is used for this, and the 777 - // rationale behind is that it should generate the same code as WRITE_ONCE() which the 778 - // kernel already relies on to avoid UB on data races. Note that the usage of 779 - // write_volatile() is limited to this particular case, it cannot be used to prevent 780 - // the UB caused by racing between two kernel functions nor do they provide atomicity. 781 - unsafe { field.write_volatile(val) } 782 - } 783 604 } 784 605 785 606 /// Note that the device configured to do DMA must be halted before this object is dropped. 786 - impl<T: AsBytes + FromBytes> Drop for CoherentAllocation<T> { 607 + impl<T: KnownSize + ?Sized> Drop for Coherent<T> { 787 608 fn drop(&mut self) { 788 - let size = self.count * core::mem::size_of::<T>(); 609 + let size = T::size(self.cpu_addr.as_ptr()); 789 610 // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`. 790 611 // The cpu address, and the dma handle are valid due to the type invariants on 791 - // `CoherentAllocation`. 612 + // `Coherent`. 792 613 unsafe { 793 614 bindings::dma_free_attrs( 794 615 self.dev.as_raw(), 795 616 size, 796 - self.start_ptr_mut().cast(), 617 + self.cpu_addr.as_ptr().cast(), 797 618 self.dma_handle, 798 619 self.dma_attrs.as_raw(), 799 620 ) ··· 755 668 } 756 669 } 757 670 758 - // SAFETY: It is safe to send a `CoherentAllocation` to another thread if `T` 671 + // SAFETY: It is safe to send a `Coherent` to another thread if `T` 759 672 // can be sent to another thread. 760 - unsafe impl<T: AsBytes + FromBytes + Send> Send for CoherentAllocation<T> {} 673 + unsafe impl<T: KnownSize + Send + ?Sized> Send for Coherent<T> {} 761 674 762 675 /// Reads a field of an item from an allocated region of structs. 763 676 /// 764 677 /// The syntax is of the form `kernel::dma_read!(dma, proj)` where `dma` is an expression evaluating 765 - /// to a [`CoherentAllocation`] and `proj` is a [projection specification](kernel::ptr::project!). 678 + /// to a [`Coherent`] and `proj` is a [projection specification](kernel::ptr::project!). 766 679 /// 767 680 /// # Examples 768 681 /// 769 682 /// ``` 770 683 /// use kernel::device::Device; 771 - /// use kernel::dma::{attrs::*, CoherentAllocation}; 684 + /// use kernel::dma::{attrs::*, Coherent}; 772 685 /// 773 686 /// struct MyStruct { field: u32, } 774 687 /// ··· 777 690 /// // SAFETY: Instances of `MyStruct` have no uninitialized portions. 778 691 /// unsafe impl kernel::transmute::AsBytes for MyStruct{}; 779 692 /// 780 - /// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result { 693 + /// # fn test(alloc: &kernel::dma::Coherent<[MyStruct]>) -> Result { 781 694 /// let whole = kernel::dma_read!(alloc, [2]?); 782 695 /// let field = kernel::dma_read!(alloc, [1]?.field); 783 696 /// # Ok::<(), Error>(()) } ··· 787 700 ($dma:expr, $($proj:tt)*) => {{ 788 701 let dma = &$dma; 789 702 let ptr = $crate::ptr::project!( 790 - $crate::dma::CoherentAllocation::as_ptr(dma), $($proj)* 703 + $crate::dma::Coherent::as_ptr(dma), $($proj)* 791 704 ); 792 705 // SAFETY: The pointer created by the projection is within the DMA region. 793 - unsafe { $crate::dma::CoherentAllocation::field_read(dma, ptr) } 706 + unsafe { $crate::dma::Coherent::field_read(dma, ptr) } 794 707 }}; 795 708 } 796 709 797 710 /// Writes to a field of an item from an allocated region of structs. 798 711 /// 799 712 /// The syntax is of the form `kernel::dma_write!(dma, proj, val)` where `dma` is an expression 800 - /// evaluating to a [`CoherentAllocation`], `proj` is a 713 + /// evaluating to a [`Coherent`], `proj` is a 801 714 /// [projection specification](kernel::ptr::project!), and `val` is the value to be written to the 802 715 /// projected location. 803 716 /// ··· 805 718 /// 806 719 /// ``` 807 720 /// use kernel::device::Device; 808 - /// use kernel::dma::{attrs::*, CoherentAllocation}; 721 + /// use kernel::dma::{attrs::*, Coherent}; 809 722 /// 810 723 /// struct MyStruct { member: u32, } 811 724 /// ··· 814 727 /// // SAFETY: Instances of `MyStruct` have no uninitialized portions. 815 728 /// unsafe impl kernel::transmute::AsBytes for MyStruct{}; 816 729 /// 817 - /// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result { 730 + /// # fn test(alloc: &kernel::dma::Coherent<[MyStruct]>) -> Result { 818 731 /// kernel::dma_write!(alloc, [2]?.member, 0xf); 819 732 /// kernel::dma_write!(alloc, [1]?, MyStruct { member: 0xf }); 820 733 /// # Ok::<(), Error>(()) } ··· 824 737 (@parse [$dma:expr] [$($proj:tt)*] [, $val:expr]) => {{ 825 738 let dma = &$dma; 826 739 let ptr = $crate::ptr::project!( 827 - mut $crate::dma::CoherentAllocation::as_mut_ptr(dma), $($proj)* 740 + mut $crate::dma::Coherent::as_mut_ptr(dma), $($proj)* 828 741 ); 829 742 let val = $val; 830 743 // SAFETY: The pointer created by the projection is within the DMA region. 831 - unsafe { $crate::dma::CoherentAllocation::field_write(dma, ptr, val) } 744 + unsafe { $crate::dma::Coherent::field_write(dma, ptr, val) } 832 745 }}; 833 746 (@parse [$dma:expr] [$($proj:tt)*] [.$field:tt $($rest:tt)*]) => { 834 747 $crate::dma_write!(@parse [$dma] [$($proj)* .$field] [$($rest)*])