Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
use kernel::prelude::*;
use crate::{
driver::Bar0,
gpu::{
Architecture,
Chipset, //
},
};
mod ga100;
mod ga102;
mod gb100;
mod gb202;
mod gh100;
mod tu102;
pub(crate) trait FbHal {
/// Returns the address of the currently-registered sysmem flush page.
fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64;
/// Register `addr` as the address of the sysmem flush page.
///
/// This might fail if the address is too large for the receiving register.
fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result;
/// Returns `true` is display is supported.
fn supports_display(&self, bar: Bar0<'_>) -> bool;
/// Returns the VRAM size, in bytes.
fn vidmem_size(&self, bar: Bar0<'_>) -> u64;
/// Returns the amount of VRAM to reserve for the PMU.
fn pmu_reserved_size(&self) -> u32;
/// Returns the non-WPR heap size for this chipset, in bytes.
fn non_wpr_heap_size(&self) -> u32;
/// Returns the FRTS size, in bytes.
fn frts_size(&self) -> u64;
}
/// Returns the HAL corresponding to `chipset`.
pub(super) fn fb_hal(chipset: Chipset) -> &'static dyn FbHal {
match chipset.arch() {
Architecture::Turing => tu102::TU102_HAL,
Architecture::Ampere if chipset == Chipset::GA100 => ga100::GA100_HAL,
Architecture::Ampere | Architecture::Ada => ga102::GA102_HAL,
Architecture::Hopper => gh100::GH100_HAL,
Architecture::BlackwellGB10x => gb100::GB100_HAL,
Architecture::BlackwellGB20x => gb202::GB202_HAL,
}
}
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
use kernel::{
io::Io,
num::Bounded,
prelude::*, //
};
use crate::{
driver::Bar0,
fb::hal::FbHal,
regs, //
};
use super::tu102::FLUSH_SYSMEM_ADDR_SHIFT;
struct Ga100;
pub(super) fn read_sysmem_flush_page_ga100(bar: Bar0<'_>) -> u64 {
u64::from(bar.read(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR).adr_39_08()) << FLUSH_SYSMEM_ADDR_SHIFT
| u64::from(bar.read(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI).adr_63_40())
<< FLUSH_SYSMEM_ADDR_SHIFT_HI
}
pub(super) fn write_sysmem_flush_page_ga100(bar: Bar0<'_>, addr: u64) {
bar.write_reg(
regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr_63_40(
Bounded::<u64, _>::from(addr)
.shr::<FLUSH_SYSMEM_ADDR_SHIFT_HI, _>()
.cast(),
),
);
bar.write_reg(
regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::zeroed()
// CAST: `as u32` is used on purpose since we want to strip the upper bits that have
// been written to `NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI`.
.with_adr_39_08((addr >> FLUSH_SYSMEM_ADDR_SHIFT) as u32),
);
}
pub(super) fn display_enabled_ga100(bar: Bar0<'_>) -> bool {
!bar.read(regs::ga100::NV_FUSE_STATUS_OPT_DISPLAY)
.display_disabled()
}
/// Shift applied to the sysmem address before it is written into
/// `NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI`,
const FLUSH_SYSMEM_ADDR_SHIFT_HI: u32 = 40;
impl FbHal for Ga100 {
fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64 {
read_sysmem_flush_page_ga100(bar)
}
fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result {
write_sysmem_flush_page_ga100(bar, addr);
Ok(())
}
fn supports_display(&self, bar: Bar0<'_>) -> bool {
display_enabled_ga100(bar)
}
fn vidmem_size(&self, bar: Bar0<'_>) -> u64 {
super::tu102::vidmem_size_gp102(bar)
}
fn pmu_reserved_size(&self) -> u32 {
super::tu102::pmu_reserved_size_tu102()
}
fn non_wpr_heap_size(&self) -> u32 {
super::tu102::non_wpr_heap_size_tu102()
}
// GA100 is a special case where its FRTS region exists, but is empty. We
// return a size of 0 because we still need to record where the region starts.
fn frts_size(&self) -> u64 {
0
}
}
const GA100: Ga100 = Ga100;
pub(super) const GA100_HAL: &dyn FbHal = &GA100;
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
use kernel::{
io::Io,
prelude::*, //
};
use crate::{
driver::Bar0,
fb::hal::FbHal,
regs, //
};
pub(super) fn vidmem_size_ga102(bar: Bar0<'_>) -> u64 {
bar.read(regs::NV_USABLE_FB_SIZE_IN_MB).usable_fb_size()
}
struct Ga102;
impl FbHal for Ga102 {
fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64 {
super::ga100::read_sysmem_flush_page_ga100(bar)
}
fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result {
super::ga100::write_sysmem_flush_page_ga100(bar, addr);
Ok(())
}
fn supports_display(&self, bar: Bar0<'_>) -> bool {
super::ga100::display_enabled_ga100(bar)
}
fn vidmem_size(&self, bar: Bar0<'_>) -> u64 {
vidmem_size_ga102(bar)
}
fn pmu_reserved_size(&self) -> u32 {
super::tu102::pmu_reserved_size_tu102()
}
fn non_wpr_heap_size(&self) -> u32 {
super::tu102::non_wpr_heap_size_tu102()
}
fn frts_size(&self) -> u64 {
super::tu102::frts_size_tu102()
}
}
const GA102: Ga102 = Ga102;
pub(super) const GA102_HAL: &dyn FbHal = &GA102;
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
//! Blackwell GB10x framebuffer HAL.
use kernel::{
io::{
register::{
RegisterBase,
WithBase, //
},
Io, //
},
num::Bounded,
prelude::*,
ptr::{
const_align_up,
Alignment, //
},
sizes::*, //
};
use crate::{
driver::Bar0,
fb::hal::FbHal,
num::usize_into_u32,
regs, //
};
struct Gb100;
impl RegisterBase<regs::Hshub0Base> for Gb100 {
const BASE: usize = 0x0087_0000;
}
fn read_sysmem_flush_page_gb100(bar: Bar0<'_>) -> u64 {
let lo = u64::from(
bar.read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>())
.adr(),
);
let hi = u64::from(
bar.read(regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>())
.adr(),
);
lo | (hi << 32)
}
/// Write the sysmem flush page address through the GB10x HSHUB0 registers.
///
/// Both the primary and EG (egress) register pairs must be programmed to the same address,
/// as required by hardware.
fn write_sysmem_flush_page_gb100(bar: Bar0<'_>, addr: Bounded<u64, 52>) {
// CAST: lower 32 bits. Hardware ignores bits 7:0.
let addr_lo = *addr as u32;
let addr_hi = addr.shr::<32, 20>().cast::<u32>();
// Write HI first. The hardware will trigger the flush on the LO write.
// Primary HSHUB pair.
bar.write(
regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>(),
regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr(addr_hi),
);
bar.write(
regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>(),
regs::NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr(addr_lo),
);
// EG (egress) pair -- must match the primary pair.
bar.write(
regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb100>(),
regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed().with_adr(addr_hi),
);
bar.write(
regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb100>(),
regs::NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr(addr_lo),
);
}
pub(super) const fn pmu_reserved_size_gb100() -> u32 {
usize_into_u32::<{ const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::<SZ_128K>()).unwrap() }>(
)
}
impl FbHal for Gb100 {
fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64 {
read_sysmem_flush_page_gb100(bar)
}
fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result {
let addr = Bounded::<u64, 52>::try_new(addr).ok_or(EINVAL)?;
write_sysmem_flush_page_gb100(bar, addr);
Ok(())
}
fn supports_display(&self, bar: Bar0<'_>) -> bool {
super::ga100::display_enabled_ga100(bar)
}
fn vidmem_size(&self, bar: Bar0<'_>) -> u64 {
super::ga102::vidmem_size_ga102(bar)
}
fn pmu_reserved_size(&self) -> u32 {
pmu_reserved_size_gb100()
}
fn non_wpr_heap_size(&self) -> u32 {
// Non-WPR heap for GB10x (see Open RM: kgspGetNonWprHeapSize, GB100/GB102).
u32::SZ_2M
}
fn frts_size(&self) -> u64 {
super::tu102::frts_size_tu102()
}
}
const GB100: Gb100 = Gb100;
pub(super) const GB100_HAL: &dyn FbHal = &GB100;
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
//! Blackwell GB20x framebuffer HAL.
use kernel::{
io::{
register::{
RegisterBase,
WithBase, //
},
Io, //
},
num::Bounded,
prelude::*,
sizes::SizeConstants, //
};
use crate::{
driver::Bar0,
fb::hal::FbHal,
regs, //
};
struct Gb202;
impl RegisterBase<regs::Fbhub0Base> for Gb202 {
const BASE: usize = 0x008a_0000;
}
fn read_sysmem_flush_page_gb202(bar: Bar0<'_>) -> u64 {
let lo = u64::from(
bar.read(regs::NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb202>())
.adr(),
);
let hi = u64::from(
bar.read(regs::NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb202>())
.adr(),
);
lo | (hi << 32)
}
/// Write the sysmem flush page address through the GB20x FBHUB0 registers.
fn write_sysmem_flush_page_gb202(bar: Bar0<'_>, addr: Bounded<u64, 52>) {
// Write HI first. The hardware will trigger the flush on the LO write.
bar.write(
regs::NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::of::<Gb202>(),
regs::NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_HI::zeroed()
.with_adr(addr.shr::<32, 20>().cast::<u32>()),
);
bar.write(
regs::NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::of::<Gb202>(),
// CAST: lower 32 bits. Hardware ignores bits 7:0.
regs::NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_LO::zeroed().with_adr(*addr as u32),
);
}
impl FbHal for Gb202 {
fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64 {
read_sysmem_flush_page_gb202(bar)
}
fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result {
let addr = Bounded::<u64, 52>::try_new(addr).ok_or(EINVAL)?;
write_sysmem_flush_page_gb202(bar, addr);
Ok(())
}
fn supports_display(&self, bar: Bar0<'_>) -> bool {
super::ga100::display_enabled_ga100(bar)
}
fn vidmem_size(&self, bar: Bar0<'_>) -> u64 {
super::ga102::vidmem_size_ga102(bar)
}
fn pmu_reserved_size(&self) -> u32 {
super::gb100::pmu_reserved_size_gb100()
}
fn non_wpr_heap_size(&self) -> u32 {
// Non-WPR heap for GB20x (see Open RM: kgspGetNonWprHeapSize, GB202+).
u32::SZ_2M + u32::SZ_128K
}
fn frts_size(&self) -> u64 {
super::tu102::frts_size_tu102()
}
}
const GB202: Gb202 = Gb202;
pub(super) const GB202_HAL: &dyn FbHal = &GB202;
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
use kernel::{
prelude::*,
sizes::SizeConstants, //
};
use crate::{
driver::Bar0,
fb::hal::FbHal, //
};
struct Gh100;
impl FbHal for Gh100 {
fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64 {
super::ga100::read_sysmem_flush_page_ga100(bar)
}
fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result {
super::ga100::write_sysmem_flush_page_ga100(bar, addr);
Ok(())
}
fn supports_display(&self, bar: Bar0<'_>) -> bool {
super::ga100::display_enabled_ga100(bar)
}
fn vidmem_size(&self, bar: Bar0<'_>) -> u64 {
super::ga102::vidmem_size_ga102(bar)
}
fn pmu_reserved_size(&self) -> u32 {
super::tu102::pmu_reserved_size_tu102()
}
fn non_wpr_heap_size(&self) -> u32 {
// Non-WPR heap for Hopper (see Open RM: kgspCalculateFbLayout_GH100).
u32::SZ_2M
}
fn frts_size(&self) -> u64 {
super::tu102::frts_size_tu102()
}
}
const GH100: Gh100 = Gh100;
pub(super) const GH100_HAL: &dyn FbHal = &GH100;
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
use kernel::{
io::Io,
prelude::*,
sizes::*, //
};
use crate::{
driver::Bar0,
fb::hal::FbHal,
regs, //
};
/// Shift applied to the sysmem address before it is written into `NV_PFB_NISO_FLUSH_SYSMEM_ADDR`,
/// to be used by HALs.
pub(super) const FLUSH_SYSMEM_ADDR_SHIFT: u32 = 8;
pub(super) fn read_sysmem_flush_page_gm107(bar: Bar0<'_>) -> u64 {
u64::from(bar.read(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR).adr_39_08()) << FLUSH_SYSMEM_ADDR_SHIFT
}
pub(super) fn write_sysmem_flush_page_gm107(bar: Bar0<'_>, addr: u64) -> Result {
// Check that the address doesn't overflow the receiving 32-bit register.
u32::try_from(addr >> FLUSH_SYSMEM_ADDR_SHIFT)
.map_err(|_| EINVAL)
.map(|addr| {
bar.write_reg(regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::zeroed().with_adr_39_08(addr))
})
}
pub(super) fn display_enabled_gm107(bar: Bar0<'_>) -> bool {
!bar.read(regs::gm107::NV_FUSE_STATUS_OPT_DISPLAY)
.display_disabled()
}
pub(super) fn vidmem_size_gp102(bar: Bar0<'_>) -> u64 {
bar.read(regs::NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE)
.usable_fb_size()
}
pub(super) const fn pmu_reserved_size_tu102() -> u32 {
0
}
pub(super) const fn non_wpr_heap_size_tu102() -> u32 {
u32::SZ_1M
}
pub(super) const fn frts_size_tu102() -> u64 {
u64::SZ_1M
}
struct Tu102;
impl FbHal for Tu102 {
fn read_sysmem_flush_page(&self, bar: Bar0<'_>) -> u64 {
read_sysmem_flush_page_gm107(bar)
}
fn write_sysmem_flush_page(&self, bar: Bar0<'_>, addr: u64) -> Result {
write_sysmem_flush_page_gm107(bar, addr)
}
fn supports_display(&self, bar: Bar0<'_>) -> bool {
display_enabled_gm107(bar)
}
fn vidmem_size(&self, bar: Bar0<'_>) -> u64 {
vidmem_size_gp102(bar)
}
fn pmu_reserved_size(&self) -> u32 {
pmu_reserved_size_tu102()
}
fn non_wpr_heap_size(&self) -> u32 {
non_wpr_heap_size_tu102()
}
fn frts_size(&self) -> u64 {
frts_size_tu102()
}
}
const TU102: Tu102 = Tu102;
pub(super) const TU102_HAL: &dyn FbHal = &TU102;