226 lines · 7.5 KB · Rust
RawDownload
// SPDX-License-Identifier: GPL-2.0 mod boot;mod hal; use kernel::{    debugfs,    device,    dma::{        Coherent,        CoherentBox,        CoherentView,        DmaAddress, //    },    io::{        io_project,        io_write,        Io, //    },    pci,    prelude::*, //}; pub(crate) mod cmdq;pub(crate) mod commands;mod fw;mod regs;mod sequencer; pub(crate) use fw::{    GspFmcBootParams,    GspFwWprMeta,    LibosMemoryRegionInitArgument,    LibosParams, //};pub(crate) use hal::boot_firmware_files; use crate::{    driver::Bar0,    falcon::{        gsp::Gsp as GspFalcon,        sec2::Sec2 as Sec2Falcon,        Falcon, //    },    fsp::Fsp,    gpu::Chipset,    gsp::{        cmdq::Cmdq,        fw::GspArgumentsPadded, //    },    num,    vgpu::VgpuManager, //}; pub(crate) const GSP_PAGE_SHIFT: usize = 12;pub(crate) const GSP_PAGE_SIZE: usize = 1 << GSP_PAGE_SHIFT; /// Common context for the GSP boot process.////// It carries two distinct lifetimes:////// - `'gpu` is the lifetime of the bound GPU device, as captured by the GPU subdevices./// - `'ctx` is a shorter lifetime during which this context borrows those subdevices.pub(crate) struct GspBootContext<'ctx, 'gpu> {    pub(crate) pdev: &'gpu pci::Device<device::Bound>,    pub(crate) bar: Bar0<'gpu>,    pub(crate) chipset: Chipset,    pub(crate) gsp_falcon: &'ctx Falcon<'gpu, GspFalcon>,    pub(crate) sec2_falcon: &'ctx Falcon<'gpu, Sec2Falcon>,    pub(crate) fsp: Option<&'ctx mut Fsp<'gpu>>,    pub(crate) vgpu: &'ctx VgpuManager,} impl<'ctx, 'gpu> GspBootContext<'ctx, 'gpu> {    pub(crate) fn dev(&self) -> &'gpu device::Device<device::Bound> {        self.pdev.as_ref()    }} /// Number of GSP pages to use in a RM log buffer.const RM_LOG_BUFFER_NUM_PAGES: usize = 0x10;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]); impl<const NUM_PAGES: usize> PteArray<NUM_PAGES> {    /// 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(())    }} /// The logging buffers are byte queues that contain encoded printf-like/// messages from GSP-RM.  They need to be decoded by a special application/// that can parse the buffers.////// The 'loginit' buffer contains logs from early GSP-RM init and/// exception dumps.  The 'logrm' buffer contains the subsequent logs. Both are/// written to directly by GSP-RM and can be any multiple of GSP_PAGE_SIZE.////// The physical address map for the log buffer is stored in the buffer/// itself, starting with offset 1. Offset 0 contains the "put" pointer (pp)./// Initially, pp is equal to 0. If the buffer has valid logging data in it,/// then pp points to index into the buffer where the next logging entry will/// be written. Therefore, the logging data is valid if:///   1 <= pp < sizeof(buffer)/sizeof(u64)struct LogBuffer(Coherent<[u8; LOG_BUFFER_SIZE]>); impl LogBuffer {    /// Creates a new `LogBuffer` mapped on `dev`.    fn new(dev: &device::Device<device::Bound>) -> Result<Self> {        let obj = Self(Coherent::zeroed(dev, GFP_KERNEL)?);         let start_addr = obj.0.dma_address();         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)    }} struct LogBuffers {    /// Init log buffer.    loginit: LogBuffer,    /// Interrupts log buffer.    logintr: LogBuffer,    /// RM log buffer.    logrm: LogBuffer,} /// GSP runtime data.#[pin_data]pub(crate) struct Gsp {    /// Libos arguments.    pub(crate) libos: Coherent<[LibosMemoryRegionInitArgument]>,    /// Log buffers, optionally exposed via debugfs.    #[pin]    logs: debugfs::Scope<LogBuffers>,    /// Command queue.    #[pin]    pub(crate) cmdq: Cmdq,    /// RM arguments.    rmargs: Coherent<GspArgumentsPadded>,} impl Gsp {    // Creates an in-place initializer for a `Gsp` manager for `pdev`.    pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> impl PinInit<Self, Error> + '_ {        pin_init::pin_init_scope(move || {            let dev = pdev.as_ref();             let loginit = LogBuffer::new(dev)?;            let logintr = LogBuffer::new(dev)?;            let logrm = LogBuffer::new(dev)?;             // Initialise the logging structures. The OpenRM equivalents are in:            // _kgspInitLibosLoggingStructures (allocates memory for buffers)            // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array)            Ok(try_pin_init!(Self {                cmdq <- Cmdq::new(dev),                rmargs: Coherent::init(dev, GFP_KERNEL, GspArgumentsPadded::new(&cmdq))?,                libos: {                    let mut libos = CoherentBox::zeroed_slice(                        dev,                        GSP_PAGE_SIZE / size_of::<LibosMemoryRegionInitArgument>(),                        GFP_KERNEL,                    )?;                     libos.init_at(0, LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0))?;                    libos.init_at(1, LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0))?;                    libos.init_at(2, LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0))?;                    libos.init_at(3, LibosMemoryRegionInitArgument::new("RMARGS", rmargs))?;                     libos.into()                },                logs <- {                    let log_buffers = LogBuffers {                        loginit,                        logintr,                        logrm,                    };                     #[allow(static_mut_refs)]                    // SAFETY: `DEBUGFS_ROOT` is created before driver registration and cleared                    // after driver unregistration, so no probe() can race with its modification.                    //                    // PANIC: `DEBUGFS_ROOT` cannot be `None` here.  It is set before driver                    // registration and cleared after driver unregistration, so it is always                    // `Some` for the entire lifetime that probe() can be called.                    let log_parent: &debugfs::Dir = unsafe { crate::DEBUGFS_ROOT.as_ref() }                        .expect("DEBUGFS_ROOT not initialized");                     log_parent.scope(log_buffers, dev.name(), |logs, dir| {                        dir.read_binary_file(c"loginit", &logs.loginit.0);                        dir.read_binary_file(c"logintr", &logs.logintr.0);                        dir.read_binary_file(c"logrm", &logs.logrm.0);                    })                },            }))        })    }     /// Query the GSP for the static GPU information.    pub(crate) fn get_static_info(&self, bar: Bar0<'_>) -> Result<commands::GetGspStaticInfoReply> {        self.cmdq.send_command(bar, commands::GetGspStaticInfo)    }} /// Opaque bundle required to unload the GSP. Created by [`Gsp::boot`], consumed by [`Gsp::unload`].pub(crate) struct UnloadBundle(KBox<dyn hal::UnloadBundle>);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t