Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/nova-core/fb.rs
48888 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
use core::ops::Range;
4
5
use kernel::{
6
device,
7
prelude::*,
8
ptr::{
9
Alignable,
10
Alignment, //
11
},
12
sizes::*,
13
sync::aref::ARef, //
14
};
15
16
use crate::{
17
dma::DmaObject,
18
driver::Bar0,
19
firmware::gsp::GspFirmware,
20
gpu::Chipset,
21
gsp,
22
num::{
23
usize_as_u64,
24
FromSafeCast, //
25
},
26
regs,
27
};
28
29
mod hal;
30
31
/// Type holding the sysmem flush memory page, a page of memory to be written into the
32
/// `NV_PFB_NISO_FLUSH_SYSMEM_ADDR*` registers and used to maintain memory coherency.
33
///
34
/// A system memory page is required for `sysmembar`, which is a GPU-initiated hardware
35
/// memory-barrier operation that flushes all pending GPU-side memory writes that were done through
36
/// PCIE to system memory. It is required for falcons to be reset as the reset operation involves a
37
/// reset handshake. When the falcon acknowledges a reset, it writes into system memory. To ensure
38
/// this write is visible to the host and prevent driver timeouts, the falcon must perform a
39
/// sysmembar operation to flush its writes.
40
///
41
/// Because of this, the sysmem flush memory page must be registered as early as possible during
42
/// driver initialization, and before any falcon is reset.
43
///
44
/// Users are responsible for manually calling [`Self::unregister`] before dropping this object,
45
/// otherwise the GPU might still use it even after it has been freed.
46
pub(crate) struct SysmemFlush {
47
/// Chipset we are operating on.
48
chipset: Chipset,
49
device: ARef<device::Device>,
50
/// Keep the page alive as long as we need it.
51
page: DmaObject,
52
}
53
54
impl SysmemFlush {
55
/// Allocate a memory page and register it as the sysmem flush page.
56
pub(crate) fn register(
57
dev: &device::Device<device::Bound>,
58
bar: &Bar0,
59
chipset: Chipset,
60
) -> Result<Self> {
61
let page = DmaObject::new(dev, kernel::page::PAGE_SIZE)?;
62
63
hal::fb_hal(chipset).write_sysmem_flush_page(bar, page.dma_handle())?;
64
65
Ok(Self {
66
chipset,
67
device: dev.into(),
68
page,
69
})
70
}
71
72
/// Unregister the managed sysmem flush page.
73
///
74
/// In order to gracefully tear down the GPU, users must make sure to call this method before
75
/// dropping the object.
76
pub(crate) fn unregister(&self, bar: &Bar0) {
77
let hal = hal::fb_hal(self.chipset);
78
79
if hal.read_sysmem_flush_page(bar) == self.page.dma_handle() {
80
let _ = hal.write_sysmem_flush_page(bar, 0).inspect_err(|e| {
81
dev_warn!(
82
&self.device,
83
"failed to unregister sysmem flush page: {:?}",
84
e
85
)
86
});
87
} else {
88
// Another page has been registered after us for some reason - warn as this is a bug.
89
dev_warn!(
90
&self.device,
91
"attempt to unregister a sysmem flush page that is not active\n"
92
);
93
}
94
}
95
}
96
97
/// Layout of the GPU framebuffer memory.
98
///
99
/// Contains ranges of GPU memory reserved for a given purpose during the GSP boot process.
100
#[derive(Debug)]
101
pub(crate) struct FbLayout {
102
/// Range of the framebuffer. Starts at `0`.
103
pub(crate) fb: Range<u64>,
104
/// VGA workspace, small area of reserved memory at the end of the framebuffer.
105
pub(crate) vga_workspace: Range<u64>,
106
/// FRTS range.
107
pub(crate) frts: Range<u64>,
108
/// Memory area containing the GSP bootloader image.
109
pub(crate) boot: Range<u64>,
110
/// Memory area containing the GSP firmware image.
111
pub(crate) elf: Range<u64>,
112
/// WPR2 heap.
113
pub(crate) wpr2_heap: Range<u64>,
114
/// WPR2 region range, starting with an instance of `GspFwWprMeta`.
115
pub(crate) wpr2: Range<u64>,
116
pub(crate) heap: Range<u64>,
117
pub(crate) vf_partition_count: u8,
118
}
119
120
impl FbLayout {
121
/// Computes the FB layout for `chipset` required to run the `gsp_fw` GSP firmware.
122
pub(crate) fn new(chipset: Chipset, bar: &Bar0, gsp_fw: &GspFirmware) -> Result<Self> {
123
let hal = hal::fb_hal(chipset);
124
125
let fb = {
126
let fb_size = hal.vidmem_size(bar);
127
128
0..fb_size
129
};
130
131
let vga_workspace = {
132
let vga_base = {
133
const NV_PRAMIN_SIZE: u64 = usize_as_u64(SZ_1M);
134
let base = fb.end - NV_PRAMIN_SIZE;
135
136
if hal.supports_display(bar) {
137
match regs::NV_PDISP_VGA_WORKSPACE_BASE::read(bar).vga_workspace_addr() {
138
Some(addr) => {
139
if addr < base {
140
const VBIOS_WORKSPACE_SIZE: u64 = usize_as_u64(SZ_128K);
141
142
// Point workspace address to end of framebuffer.
143
fb.end - VBIOS_WORKSPACE_SIZE
144
} else {
145
addr
146
}
147
}
148
None => base,
149
}
150
} else {
151
base
152
}
153
};
154
155
vga_base..fb.end
156
};
157
158
let frts = {
159
const FRTS_DOWN_ALIGN: Alignment = Alignment::new::<SZ_128K>();
160
const FRTS_SIZE: u64 = usize_as_u64(SZ_1M);
161
let frts_base = vga_workspace.start.align_down(FRTS_DOWN_ALIGN) - FRTS_SIZE;
162
163
frts_base..frts_base + FRTS_SIZE
164
};
165
166
let boot = {
167
const BOOTLOADER_DOWN_ALIGN: Alignment = Alignment::new::<SZ_4K>();
168
let bootloader_size = u64::from_safe_cast(gsp_fw.bootloader.ucode.size());
169
let bootloader_base = (frts.start - bootloader_size).align_down(BOOTLOADER_DOWN_ALIGN);
170
171
bootloader_base..bootloader_base + bootloader_size
172
};
173
174
let elf = {
175
const ELF_DOWN_ALIGN: Alignment = Alignment::new::<SZ_64K>();
176
let elf_size = u64::from_safe_cast(gsp_fw.size);
177
let elf_addr = (boot.start - elf_size).align_down(ELF_DOWN_ALIGN);
178
179
elf_addr..elf_addr + elf_size
180
};
181
182
let wpr2_heap = {
183
const WPR2_HEAP_DOWN_ALIGN: Alignment = Alignment::new::<SZ_1M>();
184
let wpr2_heap_size =
185
gsp::LibosParams::from_chipset(chipset).wpr_heap_size(chipset, fb.end);
186
let wpr2_heap_addr = (elf.start - wpr2_heap_size).align_down(WPR2_HEAP_DOWN_ALIGN);
187
188
wpr2_heap_addr..(elf.start).align_down(WPR2_HEAP_DOWN_ALIGN)
189
};
190
191
let wpr2 = {
192
const WPR2_DOWN_ALIGN: Alignment = Alignment::new::<SZ_1M>();
193
let wpr2_addr = (wpr2_heap.start - u64::from_safe_cast(size_of::<gsp::GspFwWprMeta>()))
194
.align_down(WPR2_DOWN_ALIGN);
195
196
wpr2_addr..frts.end
197
};
198
199
let heap = {
200
const HEAP_SIZE: u64 = usize_as_u64(SZ_1M);
201
202
wpr2.start - HEAP_SIZE..wpr2.start
203
};
204
205
Ok(Self {
206
fb,
207
vga_workspace,
208
frts,
209
boot,
210
elf,
211
wpr2_heap,
212
wpr2,
213
heap,
214
vf_partition_count: 0,
215
})
216
}
217
}
218
219