diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-19 10:42:18 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-19 10:42:18 -0700 |
| commit | 59e6295fac26b8e85c1ea859cdd89fa1e47519d7 (patch) | |
| tree | 7c071f8bab440eddbb569e84e9f31c80f8a4e529 /drivers/gpu | |
| parent | c6cf4441a3a05bb7273ed022f3e56c4fc591da08 (diff) | |
| parent | 3b5ea0f078e1b72276e99c237f3dfc2fd72938bb (diff) | |
Merge tag 'driver-core-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core
Pull driver core updates from Danilo Krummrich:
"container_of:
- Apply typeof_member(), remove the local __mptr variable to
eliminate variable shadowing warnings on nested container_of()
calls, and remove unnecessary parentheses
core:
- Add driver name to probe debug print for initcall_debug
- Avoid repeatedly printing the same 'Fixed dependency cycle' log
- Unwind device_add() on attribute creation failure in
attribute_container_add_class_device()
- Remove statistics group if encryption group creation fails in
transport_add_class_device()
debugfs:
- Fix lockdown check for mmap_prepare()
- Warn if file creation failed due to uninitialized debugfs
device property:
- Implement fw_devlink support for software nodes by adding
software_node_add_links(), which creates fwnode links from
DEV_PROP_REF properties to enable automatic probe ordering. Add
kunit-managed fwnode helpers and test coverage
- Fix infinite loop in fwnode_for_each_child_node() when the
secondary fwnode has more than one child. Add test cases
- Fix out-of-bounds access in software_node_get_reference_args() when
called with index -1 (UINT_MAX)
- Refactor to use RAII approach with __free()
- Add Bartosz Golaszewski as software node reviewer
firmware loader:
- Fix race where a sysfs fallback request can complete before being
queued as pending, leading to a use-after-free on the next fallback
request
- Reject 0-size built-in firmware and fail the build on empty
firmware files in CONFIG_EXTRA_FIRMWARE
kobject:
- Provide __KOBJ_ATTR() and __KOBJ_ATTR_RO/WO() initialization macros
and allow the constification of kobject attributes, enabling them
to reside in read-only memory
platform:
- Provide platform_device_set_of_node(), platform_device_set_fwnode(),
and platform_device_set_of_node_from_dev() helpers that encapsulate
firmware node reference counting for dynamically allocated platform
devices
Convert all in-tree users that manually assigned dev.of_node or
dev.fwnode, fixing a pre-existing refcount bug in powermac. Switch
to counting references of all firmware node types, not only OF
nodes
- Unify the release path for dynamically allocated platform devices
by removing platform_device_release_full(). Amend the fwnode setter
API contract to warn if a primary software node is overwritten. Add
KUnit tests for correct software node removal on device
unregistration
Rust:
- Auxiliary:
- Add registration_data_with() closure-based API for invariant
ForLt types
- Debugfs:
- Migrate BinaryWriter and BinaryReaderMut trait requirements
from kernel::transmute traits to zerocopy traits
- Device:
- Add BoundInternal device context and InternalBoundContext trait
for bus abstractions that need internal access to a bound
device.
- Make the lifetime on Core and CoreInternal invariant to prevent
coercion to shorter lifetimes
- Devres:
- Fix race between concurrent revokers where the losing revoker
could return before the winning revoker finished dropping the
inner data, causing use-after-free.
- Ensure revocation is complete before the device finishes
unbinding by making the synchronization bidirectional.
- Add DevresLt<F: ForLt>, a wrapper around Devres that shortens
'static back to the caller's borrow scope. Implement ForLt and
CovariantForLt for Bar, IoMem, and ExclusiveIoMem
- Driver:
- Switch from index-based to pointer-based device ID info lookup,
storing static references in driver_data. Centralize device ID
handling in device_id.rs, removing the open-coded ACPI/OF
matching logic and duplicate ID table from driver.rs
- I/O:
- Make I/O regions typed (with a dynamically-sized Region type
for the existing untyped case), create view types representing
subregions of a mapped I/O region, and add io_project!() for
safely creating subviews.
- Split Io into a base trait (IoBase) and an extension trait (Io)
with a blanket implementation, preventing implementers from
overriding provided methods that unsafe code relies on.
- Add a SysMem backend for shared system memory with volatile
access, and make Coherent implement Io via an I/O view type.
Add IoSysMap as sum type of Mmio and SysMem. Add copying
methods (memcpy_{from,to}io()) and read_val()/write_val() for
typed access.
- Replace dma_read!()/dma_write!() with io_read!()/io_write!()
for primitives and copying methods for aggregates; drop the old
macros. Convert nova-core to use I/O projection.
- Fix internal shortcut rule dispatch in the register!() macro,
remove unused rule arguments, and use path fragments for alias
destinations
- IRQ:
- Make irq::Registration compatible with lifetime-bound drivers
by removing the 'static bound on Handler/ThreadedHandler and
replacing Devres<RegistrationInner> with direct
request_irq()/free_irq() calls. Handlers can now directly own
lifetime-bound device resources
- PCI:
- Convert IrqVectorRegistration to a lifetime-annotated owning
type, giving drivers explicit control over the allocation
lifetime. IrqVector embeds a resolved IrqRequest, making the
conversion infallible. Remove the redundant
request_irq()/request_threaded_irq() wrappers from pci::Device.
- Add pci_irq_type() C helper and expose it via irq_type() on
IrqVectorRegistration and IrqVector, returning PCI_IRQ_MSIX,
PCI_IRQ_MSI, or PCI_IRQ_INTX.
- Mark pci::Device refcount methods inline
- Serdev:
- Add Rust abstractions for the serial device bus, including
serdev::Driver trait, serdev::Device wrapping struct
serdev_device, and serdev::Adapter implementing
RegistrationOps. Includes a sample driver. Markus Probst takes
over as serdev maintainer for both C and Rust code
- Misc:
- Split ForLt into a base trait (providing the Of<'a> GAT) and an
unsafe CovariantForLt subtrait guaranteeing covariance,
enabling invariant types (e.g. those containing Mutex<&'bound T>)
to participate in the ForLt abstraction.
- Fix Coherent read past EOF returning -ERANGE instead of zero.
- Fix firmware example UB by avoiding null-pointer ARef
misc:
- Avoid iattr allocation in kernfs listxattr by using
kernfs_iattrs_noalloc().
- Unregister SoC bus on early device registration failure.
- Remove unused DMA_FENCE_TRACE Kconfig symbol.
- Fix /sys/module path in comment.
- Refactor ISA bus init to remove nested blocks.
- Remove redundant nodemask clears in numa_init().
- Add kernel-doc for fwnode_operations and sys_soc.h, mark
internal property data as private for kernel-doc, and add
property.h/fwnode.h to driver-api infrastructure docs.
- Add MAINTAINERS entry for sys_soc.h"
* tag 'driver-core-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: (129 commits)
rust: pci: expose the allocated interrupt type
PCI: Add pci_irq_type() to query the allocated interrupt type
rust: pci: remove request_irq() and request_threaded_irq() from Device
rust: pci: resolve IRQ in index() and embed IrqRequest in IrqVector
rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type
kernfs: avoid iattr allocation in listxattr
rust: serdev: use ThisModule::as_ptr() instead of field access
ACPI/IORT: use platform_device_set_fwnode()
ACPI/APMT: use platform_device_set_fwnode()
firmware_loader: do not queue completed sysfs fallback requests
rust: pci: Mark Device refcount methods inline
rust: irq: make Registration compatible with lifetime-bound drivers
rust: net/phy: remove expansion from doc
rust: dma: return zero for Coherent reads past EOF
rust: io: register: use path fragment for alias destination
rust: io: register: remove unused rule arguments
rust: io: register: dispatch shortcut rules internally
MAINTAINERS: add sys_soc.h to DRIVER CORE
rust: debugfs: remove unsafe blocks from traits impl for Vec
rust: debugfs: migrate debugfs traits requirements to zerocopy
...
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/nova/driver.rs | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/tyr/driver.rs | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/xe/xe_i2c.c | 22 | ||||
| -rw-r--r-- | drivers/gpu/drm/xe/xe_i2c.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/nova-core/driver.rs | 7 | ||||
| -rw-r--r-- | drivers/gpu/nova-core/gpu.rs | 6 | ||||
| -rw-r--r-- | drivers/gpu/nova-core/gsp.rs | 53 | ||||
| -rw-r--r-- | drivers/gpu/nova-core/gsp/cmdq.rs | 66 | ||||
| -rw-r--r-- | drivers/gpu/nova-core/gsp/fw.rs | 82 |
9 files changed, 104 insertions, 135 deletions
diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs index 48933d86ddda..43f15cdfeb09 100644 --- a/drivers/gpu/drm/nova/driver.rs +++ b/drivers/gpu/drm/nova/driver.rs @@ -43,7 +43,6 @@ const AUXILIARY_NAME: &CStr = c"nova-drm"; kernel::auxiliary_device_table!( AUX_TABLE, - MODULE_AUX_TABLE, <NovaDriver as auxiliary::Driver>::IdInfo, [( auxiliary::DeviceId::new(NOVA_CORE_MODULE_NAME, AUXILIARY_NAME), diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index d063bc664cc1..218e9af899c7 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -87,7 +87,6 @@ fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result { kernel::of_device_table!( OF_TABLE, - MODULE_OF_TABLE, <TyrPlatformDriver as platform::Driver>::IdInfo, [ (of::DeviceId::new(c"rockchip,rk3588-mali"), ()), diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c index f05f23221c1b..c61d5db07309 100644 --- a/drivers/gpu/drm/xe/xe_i2c.c +++ b/drivers/gpu/drm/xe/xe_i2c.c @@ -93,14 +93,9 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c) { struct pci_dev *pci = to_pci_dev(i2c->drm_dev); struct platform_device *pdev; - struct fwnode_handle *fwnode; int ret; u32 id; - fwnode = fwnode_create_software_node(xe_i2c_adapter_properties, NULL); - if (IS_ERR(fwnode)) - return PTR_ERR(fwnode); - id = (pci_domain_nr(pci->bus) << 16) | pci_dev_id(pci); /* @@ -110,10 +105,14 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c) * platform_device_register_full() is done. */ pdev = platform_device_alloc(adapter_name, id); - if (!pdev) { - ret = -ENOMEM; - goto err_fwnode_remove; - } + if (!pdev) + return -ENOMEM; + + ret = device_create_managed_software_node(&pdev->dev, + xe_i2c_adapter_properties, + NULL); + if (ret) + goto err_pdev_put; if (i2c->adapter_irq) { struct resource res; @@ -126,8 +125,6 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c) } pdev->dev.parent = i2c->drm_dev; - pdev->dev.fwnode = fwnode; - i2c->adapter_node = fwnode; i2c->pdev = pdev; ret = platform_device_add(pdev); @@ -138,8 +135,6 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c) err_pdev_put: platform_device_put(pdev); -err_fwnode_remove: - fwnode_remove_software_node(fwnode); return ret; } @@ -147,7 +142,6 @@ err_fwnode_remove: static void xe_i2c_unregister_adapter(struct xe_i2c *i2c) { platform_device_unregister(i2c->pdev); - fwnode_remove_software_node(i2c->adapter_node); } /** diff --git a/drivers/gpu/drm/xe/xe_i2c.h b/drivers/gpu/drm/xe/xe_i2c.h index 425d8160835f..b28229f056c5 100644 --- a/drivers/gpu/drm/xe/xe_i2c.h +++ b/drivers/gpu/drm/xe/xe_i2c.h @@ -30,7 +30,6 @@ struct xe_i2c_endpoint { }; struct xe_i2c { - struct fwnode_handle *adapter_node; struct platform_device *pdev; struct i2c_adapter *adapter; struct i2c_client *client[XE_I2C_MAX_CLIENTS]; diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 5738d4ac521b..bbd93959e0b2 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -15,7 +15,7 @@ use kernel::{ Atomic, Relaxed, // }, - types::ForLt, + types::CovariantForLt, }; use crate::gpu::Gpu; @@ -29,7 +29,7 @@ pub(crate) struct NovaCore<'bound> { pub(crate) gpu: Gpu<'bound>, bar: pci::Bar<'bound, BAR0_SIZE>, #[allow(clippy::type_complexity)] - _reg: auxiliary::Registration<'bound, ForLt!(())>, + _reg: auxiliary::Registration<'bound, CovariantForLt!(())>, } pub(crate) struct NovaCoreDriver; @@ -40,7 +40,6 @@ pub(crate) type Bar0<'a> = &'a pci::Bar<'a, BAR0_SIZE>; kernel::pci_device_table!( PCI_TABLE, - MODULE_PCI_TABLE, <NovaCoreDriver as pci::Driver>::IdInfo, [ // Modern NVIDIA GPUs will show up as either VGA or 3D controllers. @@ -70,7 +69,7 @@ impl pci::Driver for NovaCoreDriver { fn probe<'bound>( pdev: &'bound pci::Device<Core<'_>>, - _info: &'bound Self::IdInfo, + _info: Option<&'bound Self::IdInfo>, ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { pin_init::pin_init_scope(move || { dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index b3c91731db45..b603b0bd2692 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -285,10 +285,10 @@ pub(crate) struct Gpu<'gpu> { } impl<'gpu> Gpu<'gpu> { - pub(crate) fn new( - pdev: &'gpu pci::Device<device::Core<'_>>, + pub(crate) fn new<'a>( + pdev: &'gpu pci::Device<device::Core<'a>>, bar: Bar0<'gpu>, - ) -> impl PinInit<Self, Error> + 'gpu { + ) -> impl PinInit<Self, Error> + use<'gpu, 'a> { try_pin_init!(Self { device: pdev.as_ref(), spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| { diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 69175ca3315c..cfa7553cd820 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -9,14 +9,16 @@ use kernel::{ dma::{ Coherent, CoherentBox, + CoherentView, DmaAddress, // }, + io::{ + io_project, + io_write, + Io, // + }, pci, - prelude::*, - transmute::{ - AsBytes, - FromBytes, // - }, // + prelude::*, // }; pub(crate) mod cmdq; @@ -48,21 +50,21 @@ const LOG_BUFFER_SIZE: usize = RM_LOG_BUFFER_NUM_PAGES * GSP_PAGE_SIZE; /// Array of page table entries, as understood by the GSP bootloader. #[repr(C)] +#[derive(FromBytes, IntoBytes)] struct PteArray<const NUM_ENTRIES: usize>([u64; NUM_ENTRIES]); -/// SAFETY: arrays of `u64` implement `FromBytes` and we are but a wrapper around one. -unsafe impl<const NUM_ENTRIES: usize> FromBytes for PteArray<NUM_ENTRIES> {} - -/// SAFETY: arrays of `u64` implement `AsBytes` and we are but a wrapper around one. -unsafe impl<const NUM_ENTRIES: usize> AsBytes for PteArray<NUM_ENTRIES> {} - impl<const NUM_PAGES: usize> PteArray<NUM_PAGES> { - /// Returns the page table entry for `index`, for a mapping starting at `start`. - // TODO: Replace with `IoView` projection once available. - fn entry(start: DmaAddress, index: usize) -> Result<u64> { - start - .checked_add(num::usize_as_u64(index) << GSP_PAGE_SHIFT) - .ok_or(EOVERFLOW) + /// Initialize a new page table array mapping `NUM_PAGES` GSP pages starting at address `start`. + fn init(view: CoherentView<'_, Self>, start: DmaAddress) -> Result<()> { + for i in 0..NUM_PAGES { + io_write!(view, .0[build: i], + start + .checked_add(num::usize_as_u64(i) << GSP_PAGE_SHIFT) + .ok_or(EOVERFLOW)? + ); + } + + Ok(()) } } @@ -89,17 +91,12 @@ impl LogBuffer { let start_addr = obj.0.dma_handle(); - // SAFETY: `obj` has just been created and we are its sole user. - let pte_region = unsafe { - &mut obj.0.as_mut()[size_of::<u64>()..][..RM_LOG_BUFFER_NUM_PAGES * size_of::<u64>()] - }; - - // Write values one by one to avoid an on-stack instance of `PteArray`. - for (i, chunk) in pte_region.chunks_exact_mut(size_of::<u64>()).enumerate() { - let pte_value = PteArray::<0>::entry(start_addr, i)?; - - chunk.copy_from_slice(&pte_value.to_ne_bytes()); - } + let pte_view = io_project!( + obj.0, + [build: size_of::<u64>()..][build: ..RM_LOG_BUFFER_NUM_PAGES * size_of::<u64>()] + ) + .try_cast::<PteArray<RM_LOG_BUFFER_NUM_PAGES>>()?; + PteArray::init(pte_view, start_addr)?; Ok(obj) } diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs index 3c68a66770d3..9349717b982b 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -2,16 +2,23 @@ mod continuation; -use core::mem; +use core::{ + mem, + sync::atomic::{ + fence, + Ordering, // + }, +}; use kernel::{ device, dma::{ Coherent, + CoherentBox, DmaAddress, // }, - dma_write, io::{ + io_project, poll::read_poll_timeout, Io, // }, @@ -171,20 +178,18 @@ static_assert!(align_of::<MsgqData>() == GSP_PAGE_SIZE); #[repr(C)] // There is no struct defined for this in the open-gpu-kernel-source headers. // Instead it is defined by code in `GspMsgQueuesInit()`. -// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module. -pub(super) struct Msgq { +struct Msgq { /// Header for sending messages, including the write pointer. - pub(super) tx: MsgqTxHeader, + tx: MsgqTxHeader, /// Header for receiving messages, including the read pointer. - pub(super) rx: MsgqRxHeader, + rx: MsgqRxHeader, /// The message queue proper. msgq: MsgqData, } /// Structure shared between the driver and the GSP and containing the command and message queues. #[repr(C)] -// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module. -pub(super) struct GspMem { +struct GspMem { /// Self-mapping page table entries. ptes: PteArray<{ Self::PTE_ARRAY_SIZE }>, /// CPU queue: the driver writes commands here, and the GSP reads them. It also contains the @@ -192,13 +197,13 @@ pub(super) struct GspMem { /// index into the GSP queue. /// /// This member is read-only for the GSP. - pub(super) cpuq: Msgq, + cpuq: Msgq, /// GSP queue: the GSP writes messages here, and the driver reads them. It also contains the /// write and read pointers that the GSP updates. This means that the read pointer here is an /// index into the CPU queue. /// /// This member is read-only for the driver. - pub(super) gspq: Msgq, + gspq: Msgq, } impl GspMem { @@ -232,20 +237,12 @@ impl DmaGspMem { const MSGQ_SIZE: u32 = num::usize_into_u32::<{ size_of::<Msgq>() }>(); const RX_HDR_OFF: u32 = num::usize_into_u32::<{ mem::offset_of!(Msgq, rx) }>(); - let gsp_mem = Coherent::<GspMem>::zeroed(dev, GFP_KERNEL)?; - - let start = gsp_mem.dma_handle(); - // Write values one by one to avoid an on-stack instance of `PteArray`. - for i in 0..GspMem::PTE_ARRAY_SIZE { - dma_write!(gsp_mem, .ptes.0[build: i], PteArray::<0>::entry(start, i)?); - } + let mut gsp_mem = CoherentBox::<GspMem>::zeroed(dev, GFP_KERNEL)?; + gsp_mem.cpuq.tx = MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES); + gsp_mem.cpuq.rx = MsgqRxHeader::new(); - dma_write!( - gsp_mem, - .cpuq.tx, - MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES) - ); - dma_write!(gsp_mem, .cpuq.rx, MsgqRxHeader::new()); + let gsp_mem: Coherent<_> = gsp_mem.into(); + PteArray::init(io_project!(gsp_mem, .ptes), gsp_mem.dma_handle())?; Ok(Self(gsp_mem)) } @@ -406,7 +403,7 @@ impl DmaGspMem { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn gsp_write_ptr(&self) -> u32 { - super::fw::gsp_mem::gsp_write_ptr(&self.0) + MsgqTxHeader::write_ptr(io_project!(self.0, .gspq.tx)) % MSGQ_NUM_PAGES } // Returns the index of the memory page the GSP will read the next command from. @@ -415,7 +412,7 @@ impl DmaGspMem { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn gsp_read_ptr(&self) -> u32 { - super::fw::gsp_mem::gsp_read_ptr(&self.0) + MsgqRxHeader::read_ptr(io_project!(self.0, .gspq.rx)) % MSGQ_NUM_PAGES } // Returns the index of the memory page the CPU can read the next message from. @@ -424,12 +421,18 @@ impl DmaGspMem { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn cpu_read_ptr(&self) -> u32 { - super::fw::gsp_mem::cpu_read_ptr(&self.0) + MsgqRxHeader::read_ptr(io_project!(self.0, .cpuq.rx)) % MSGQ_NUM_PAGES } // Informs the GSP that it can send `elem_count` new pages into the message queue. fn advance_cpu_read_ptr(&mut self, elem_count: u32) { - super::fw::gsp_mem::advance_cpu_read_ptr(&self.0, elem_count) + let rx = io_project!(self.0, .cpuq.rx); + let rptr = MsgqRxHeader::read_ptr(rx).wrapping_add(elem_count) % MSGQ_NUM_PAGES; + + // Ensure read pointer is properly ordered. + fence(Ordering::SeqCst); + + MsgqRxHeader::set_read_ptr(rx, rptr) } // Returns the index of the memory page the CPU can write the next command to. @@ -438,12 +441,17 @@ impl DmaGspMem { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn cpu_write_ptr(&self) -> u32 { - super::fw::gsp_mem::cpu_write_ptr(&self.0) + MsgqTxHeader::write_ptr(io_project!(self.0, .cpuq.tx)) % MSGQ_NUM_PAGES } // Informs the GSP that it can process `elem_count` new pages from the command queue. fn advance_cpu_write_ptr(&mut self, elem_count: u32) { - super::fw::gsp_mem::advance_cpu_write_ptr(&self.0, elem_count) + let tx = io_project!(self.0, .cpuq.tx); + let wptr = MsgqTxHeader::write_ptr(tx).wrapping_add(elem_count) % MSGQ_NUM_PAGES; + MsgqTxHeader::set_write_ptr(tx, wptr); + + // Ensure all command data is visible before triggering the GSP read. + fence(Ordering::SeqCst); } } diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index 4db0cfa4dc4d..b0e7de328eaf 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -10,7 +10,14 @@ use r570_144 as bindings; use core::ops::Range; use kernel::{ - dma::Coherent, + dma::{ + Coherent, + CoherentView, // + }, + io::{ + io_read, + io_write, // + }, prelude::*, ptr::{ Alignable, @@ -44,59 +51,6 @@ use crate::{ }, }; -// TODO: Replace with `IoView` projections once available. -pub(super) mod gsp_mem { - use core::sync::atomic::{ - fence, - Ordering, // - }; - - use kernel::{ - dma::Coherent, - dma_read, - dma_write, // - }; - - use crate::gsp::cmdq::{ - GspMem, - MSGQ_NUM_PAGES, // - }; - - pub(in crate::gsp) fn gsp_write_ptr(qs: &Coherent<GspMem>) -> u32 { - dma_read!(qs, .gspq.tx.0.writePtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn gsp_read_ptr(qs: &Coherent<GspMem>) -> u32 { - dma_read!(qs, .gspq.rx.0.readPtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn cpu_read_ptr(qs: &Coherent<GspMem>) -> u32 { - dma_read!(qs, .cpuq.rx.0.readPtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn advance_cpu_read_ptr(qs: &Coherent<GspMem>, count: u32) { - let rptr = cpu_read_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES; - - // Ensure read pointer is properly ordered. - fence(Ordering::SeqCst); - - dma_write!(qs, .cpuq.rx.0.readPtr, rptr); - } - - pub(in crate::gsp) fn cpu_write_ptr(qs: &Coherent<GspMem>) -> u32 { - dma_read!(qs, .cpuq.tx.0.writePtr) % MSGQ_NUM_PAGES - } - - pub(in crate::gsp) fn advance_cpu_write_ptr(qs: &Coherent<GspMem>, count: u32) { - let wptr = cpu_write_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES; - - dma_write!(qs, .cpuq.tx.0.writePtr, wptr); - - // Ensure all command data is visible before triggering the GSP read. - fence(Ordering::SeqCst); - } -} - /// Maximum size of a single GSP message queue element in bytes. pub(crate) const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: usize = num::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX); @@ -720,6 +674,16 @@ impl MsgqTxHeader { entryOff: num::usize_into_u32::<GSP_PAGE_SIZE>(), }) } + + /// Returns the value of the write pointer for this queue. + pub(crate) fn write_ptr(this: CoherentView<'_, Self>) -> u32 { + io_read!(this, .0.writePtr) + } + + /// Sets the value of the write pointer for this queue. + pub(crate) fn set_write_ptr(this: CoherentView<'_, Self>, val: u32) { + io_write!(this, .0.writePtr, val) + } } // SAFETY: Padding is explicit and does not contain uninitialized data. @@ -735,6 +699,16 @@ impl MsgqRxHeader { pub(crate) fn new() -> Self { Self(Default::default()) } + + /// Returns the value of the read pointer for this queue. + pub(crate) fn read_ptr(this: CoherentView<'_, Self>) -> u32 { + io_read!(this, .0.readPtr) + } + + /// Sets the value of the read pointer for this queue. + pub(crate) fn set_read_ptr(this: CoherentView<'_, Self>, val: u32) { + io_write!(this, .0.readPtr, val) + } } // SAFETY: Padding is explicit and does not contain uninitialized data. |
