Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion drivers/gpu/drm/asahi/mmu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3364,7 +3364,7 @@ impl Uat {
}

/// Discards the CPU's cached lines of the no-map table regions after the firmware built its
/// root there during boot, before the first host edit (`UatQuirks::reserved_tables`).
/// root there during boot (`UatQuirks::reserved_tables`; see `ReservedTables::invalidate`).
pub(crate) fn invalidate_reserved_tables(&self) {
if let Some(reserved) = self.inner.reserved.as_ref() {
reserved.invalidate();
Expand Down
23 changes: 20 additions & 3 deletions drivers/gpu/drm/asahi/pgtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ impl ReservedTables {

/// Drops the CPU's cached lines of every region, so that later reads see what the firmware
/// wrote while booting. Lines the host dirtied are written back first, never discarded.
///
/// This runs once, after the firmware booted. The host has written table entries by then
/// (fixed kernel objects are mapped before the boot), but the T6040, the only SoC with
/// reserved tables, also sets `UatQuirks::clean_tables`: every host table store is cleaned
/// to the PoC as it is made, so this drops only clean lines and loses no host write.
///
/// The regions are not invalidated again, which assumes the firmware no longer writes the
/// tables the host walks once it has booted. That is not proven by a trace; the J616s has
/// run this way since its GPU came up without a fault traced to a stale table.
pub(crate) fn invalidate(&self) {
for map in self.regions.iter() {
clean_invalidate_poc(map.ptr(), map.size());
Expand All @@ -192,7 +201,9 @@ impl ReservedTables {
}

/// Runs `f` on a pointer to `len` bytes at `offset` in the page-table page at `phys`, through the
/// reserved mapping when the page lies in a reserved region, else through `struct page`.
/// reserved mapping when the page lies in a reserved region, else through `struct page`. With
/// reserved regions, a page outside them that is not System RAM with a `struct page` (other
/// no-map memory) is refused with `EIO`.
///
/// # Safety
///
Expand All @@ -211,8 +222,14 @@ unsafe fn with_table<T>(
// SAFETY: lookup() checked that the whole page is mapped.
return f(unsafe { base.add(offset) });
}
// SAFETY: The caller guarantees an allocated page-table page in RAM.
let page = unsafe { Page::borrow_phys_unchecked(&phys) };
let page = if reserved.is_some() {
// SAFETY: The caller guarantees the page stays allocated; borrow_phys() checks that it
// is System RAM with a struct page.
unsafe { Page::borrow_phys(&phys) }.ok_or(EIO)?
} else {
// SAFETY: The caller guarantees an allocated page-table page in RAM.
unsafe { Page::borrow_phys_unchecked(&phys) }
};
page.with_pointer_into_page(offset, len, f)
}

Expand Down