mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
gpu: nova-core: use I/O projection for cleaner encapsulation
Use `io_project!` for PTE array and message queues to restore the proper encapsulation. The remaining `dma_read!` and `dma_write!` is now only acting on primitives; thus replace by `io_read!` and `io_write!`. Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260706-io_projection-v6-17-72cd5d055d54@garyguo.net Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
parent
89814c42c1
commit
0722567f50
|
|
@ -9,14 +9,16 @@
|
|||
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 @@
|
|||
|
||||
/// 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 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
|
|||
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 @@ struct MsgqData {
|
|||
#[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 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
|
|||
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 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();
|
||||
|
||||
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)?);
|
||||
}
|
||||
|
||||
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 @@ fn allocate_command(&mut self, size: usize, timeout: Delta) -> Result<GspCommand
|
|||
//
|
||||
// - 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 @@ fn gsp_write_ptr(&self) -> u32 {
|
|||
//
|
||||
// - 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 @@ fn gsp_read_ptr(&self) -> u32 {
|
|||
//
|
||||
// - 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 @@ fn advance_cpu_read_ptr(&mut self, elem_count: u32) {
|
|||
//
|
||||
// - 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,14 @@
|
|||
use core::ops::Range;
|
||||
|
||||
use kernel::{
|
||||
dma::Coherent,
|
||||
dma::{
|
||||
Coherent,
|
||||
CoherentView, //
|
||||
},
|
||||
io::{
|
||||
io_read,
|
||||
io_write, //
|
||||
},
|
||||
prelude::*,
|
||||
ptr::{
|
||||
Alignable,
|
||||
|
|
@ -44,59 +51,6 @@
|
|||
},
|
||||
};
|
||||
|
||||
// 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 @@ pub(crate) fn new(msgq_size: u32, rx_hdr_offset: u32, msg_count: u32) -> Self {
|
|||
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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user