intel/gpu: allocate aperture on demand

in order to support running intel/gpu next to boot_fb, which has access
to part of the mmio aperture. The aperture is tried to be accessed not
before a Platform client (intel/display) or the first GPU client
appears.

Fixes #5497
This commit is contained in:
Alexander Boettcher 2025-03-28 10:54:55 +01:00 committed by Norman Feske
parent aa9ff3894c
commit 14cfc765c6
2 changed files with 137 additions and 64 deletions

View File

@ -1187,7 +1187,9 @@ struct Igd::Device
_active_vgpu->rcs.with_context_ring([&](auto &context, auto &ring) {
context.dump();
_hw_status_page->dump();
with_hw_status_page([&](auto & hw_status) {
hw_status.dump(); });
ring.update_head(context.head_offset());
ring.dump(4096, context.tail_offset() * 2,
@ -1286,12 +1288,12 @@ struct Igd::Device
{
using namespace Genode;
_resources.with_mmio_gmadr([&](auto &mmio, auto &gmadr) {
_resources.with_mmio([&](auto &mmio) {
_resources.with_platform([&](auto &plat_con) {
auto const ggtt_base = mmio.base() + (mmio.size() / 2);
_ggtt.construct(plat_con, mmio, ggtt_base,
_ggtt_size(gmch_ctl), gmadr.size(),
_ggtt_size(gmch_ctl), _resources.aperture_size(),
_resources.aperture_reserved());
if (!_supported(mmio, supported, device_id, revision))
@ -1299,7 +1301,7 @@ struct Igd::Device
_ggtt->dump();
_vgpu_avail = (gmadr.size() - _resources.aperture_reserved())
_vgpu_avail = (_resources.aperture_size() - _resources.aperture_reserved())
/ Vgpu::DUMMY_MESA_APERTURE_SIZE;
reinit(mmio);
@ -1320,12 +1322,6 @@ struct Igd::Device
/* setup global hardware status page */
if (!_hw_status_ctx.constructed())
_hw_status_ctx.construct(_md_alloc, *this, 1, 0);
if (!_hw_status_page.constructed()) {
/* global hw_status_ctx becomes never invalid up to now, so using vrange is ok */
_hw_status_ctx->with_vrange([&](Byte_range_ptr const &vrange) {
_hw_status_page.construct(vrange);
});
}
Mmio::HWS_PGA_RCSUNIT::access_t const addr = _hw_status_ctx->gmaddr();
mmio.write_post<Igd::Mmio::HWS_PGA_RCSUNIT>(addr);
@ -1567,18 +1563,42 @@ struct Igd::Device
return hw_status_page_gmaddr() + Hardware_status_page::Semaphore::OFFSET;
}
void with_hw_status_page(auto const &fn)
{
if (!_hw_status_ctx.constructed())
return;
if (!_hw_status_page.constructed()) {
/* global hw_status_ctx becomes never invalid up to now, so using vrange is ok */
_hw_status_ctx->with_vrange([&](Byte_range_ptr const &vrange) {
_hw_status_page.construct(vrange);
});
}
if (!_hw_status_page.constructed())
return;
fn(*_hw_status_page);
}
/*
* Pause the physical ring by setting semaphore value programmed by
* 'setup_ring_vram' to 1, causing GPU to spin.
*/
void hw_status_page_pause_ring(bool pause)
{
_hw_status_page->semaphore(pause ? 1 : 0);
with_hw_status_page([&](auto & hw_status) {
hw_status.semaphore(pause ? 1 : 0); });
}
uint64_t seqno()
{
return _hw_status_page->sequence_number();
uint64_t seq = 0;
with_hw_status_page([&](auto & hw_status) {
seq = hw_status.sequence_number(); });
return seq;
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2021-2024 Genode Labs GmbH
* Copyright (C) 2021-2025 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -400,9 +400,10 @@ class Platform::Resources : Noncopyable, public Hw_ready_state
Reconstructible<Platform::Device> _device { _platform };
Reconstructible<Platform::Device::Irq> _irq { *_device };
Reconstructible<Igd::Mmio> _mmio { *_device, _env };
Reconstructible<Platform::Device::Mmio<0> > _gmadr { *_device, Platform::Device::Mmio<0>::Index(1) };
Reconstructible<Attached_dataspace> _gmadr_mem { _env.rm(), _gmadr->cap() };
Constructible<Platform::Device::Mmio<0> > _gmadr { };
Constructible<Attached_dataspace> _gmadr_mem { };
uint64_t const _aperture_size;
uint64_t const _aperture_reserved;
Region_map_client _rm_gttmm;
@ -412,7 +413,7 @@ class Platform::Resources : Noncopyable, public Hw_ready_state
void _reinit()
{
with_mmio_gmadr([&](auto &mmio, auto &gmadr) {
with_mmio([&](auto &mmio) {
using namespace Igd;
@ -451,42 +452,84 @@ class Platform::Resources : Noncopyable, public Hw_ready_state
.writeable = true
}).failed()) error("failed to re-attach mmio at gtt offset to gttmm");
_rm_gmadr.detach(0ul);
if (_rm_gmadr.attach(gmadr.cap(), {
.size = size_t(aperture_reserved()),
.offset = { },
.use_at = true,
.at = 0,
.executable = { },
.writeable = true
}).failed()) error("failed to re-attach gmadr");
}, []() {
error("reinit failed");
});
}
Number_of_bytes _sanitized_aperture_size() const
/*
* Always try to reserve 32 MiB for the multiplexer itself but
* we also make sure that 32 MiB are available for the display
* driver (or at least all of the available aperture). We
* prioritize a working display over having the GPU service
* available because investigating the later is futil without
* the former.
*/
static auto constexpr GPU_SERVICE_APERTURE = (32ull << 20);
static auto constexpr DISPLAY_MIN_APERTURE = (32ull << 20);
Number_of_bytes _sanitized_aperture_size()
{
/*
* Always try to reserve 32 MiB for the multiplexer itself but
* we also make sure that 32 MiB are available for the display
* driver (or at least all of the available aperture). We
* prioritize a working display over having the GPU service
* available because investigating the later is futil without
* the former.
*/
auto constexpr GPU_SERVICE_APERTURE = (32ull << 20);
auto constexpr DISPLAY_MIN_APERTURE = (32ull << 20);
if (_gmadr->size() <= DISPLAY_MIN_APERTURE)
return _gmadr->size();
auto apert_reserved = _aperture_size;
if (_aperture_size <= DISPLAY_MIN_APERTURE)
apert_reserved = _aperture_size;
else
/* guard against non 2^x aperture size */
if ((_gmadr->size() - GPU_SERVICE_APERTURE) < DISPLAY_MIN_APERTURE)
return DISPLAY_MIN_APERTURE;
if ((_aperture_size - GPU_SERVICE_APERTURE) < DISPLAY_MIN_APERTURE)
apert_reserved = DISPLAY_MIN_APERTURE;
else
apert_reserved = _aperture_size - GPU_SERVICE_APERTURE;
return _gmadr->size() - GPU_SERVICE_APERTURE;
log("Aperture max: ", Number_of_bytes(_aperture_size),
" display: ", Number_of_bytes(apert_reserved));
/* reserved space is used to calculate vGPU available */
if (_aperture_size == apert_reserved)
warning("GPU service not usable due to insufficient aperture space");
return apert_reserved;
}
Number_of_bytes _aperture_size_via_device_rom()
{
auto apert_size = DISPLAY_MIN_APERTURE;
_platform.with_xml([&](auto const &node) {
node.for_each_sub_node("device", [&] (Xml_node const &dev) {
dev.for_each_sub_node("pci-config", [&] (Xml_node const &cfg) {
if (cfg.attribute_value("vendor_id", 0) != 0x8086)
return;
dev.for_each_sub_node("io_mem", [&] (Xml_node const &mem) {
if (mem.attribute_value("pci_bar", ~0u) != 2)
return;
apert_size = mem.attribute_value("size", apert_size);
});
});
});
});
return apert_size;
}
bool _make_aperture_accessible()
{
bool reconstructed = false;
if (_device.constructed() && !_gmadr.constructed()) {
_gmadr.construct(*_device, Platform::Device::Mmio<0>::Index(1));
reconstructed = true;
}
if (_gmadr.constructed() && !_gmadr_mem.constructed()) {
_gmadr_mem.construct(_env.rm(), _gmadr->cap());
reconstructed = true;
}
return reconstructed;
}
public:
@ -495,19 +538,13 @@ class Platform::Resources : Noncopyable, public Hw_ready_state
:
_env(env),
_irq_cap(irq),
_aperture_size(_aperture_size_via_device_rom()),
_aperture_reserved(_sanitized_aperture_size()),
_rm_gttmm(rm.create(_mmio->size())),
_rm_gmadr(rm.create(aperture_reserved())),
_range_gttmm(1ul << 30, _mmio->size()),
_range_gmadr(1ul << 29, aperture_reserved())
{
log("Aperture max: ", Number_of_bytes(_gmadr->size()),
" display: ", Number_of_bytes(_aperture_reserved));
/* reserved space is used to calculate vGPU available */
if (_gmadr->size() == _aperture_reserved)
warning("GPU service not usable due to insufficient aperture space");
_irq->sigh(_irq_cap);
/* GTT starts at half of the mmio memory */
@ -554,18 +591,10 @@ class Platform::Resources : Noncopyable, public Hw_ready_state
}
}
void with_mmio_gmadr(auto const &fn, auto const &fn_error)
{
if (!_mmio.constructed() || !_gmadr.constructed()) {
fn_error();
return;
}
fn(*_mmio, *_gmadr);
}
void with_gmadr(auto const offset, auto const &fn, auto const &fn_error)
{
_make_aperture_accessible();
if (!_gmadr.constructed() || !_gmadr_mem.constructed()) {
fn_error();
return;
@ -592,6 +621,23 @@ class Platform::Resources : Noncopyable, public Hw_ready_state
void with_gttm_gmadr(auto const &fn)
{
bool attach_required = _make_aperture_accessible();
if (attach_required) {
_rm_gmadr.detach(0ul);
if (_rm_gmadr.attach(_gmadr->cap(), {
.size = size_t(aperture_reserved()),
.offset = { },
.use_at = true,
.at = 0,
.executable = { },
.writeable = true
}).failed()) {
error("failed to re-attach gmadr");
return;
}
}
fn(_platform, _rm_gttmm, _range_gttmm, _rm_gmadr, _range_gmadr);
}
@ -605,25 +651,30 @@ class Platform::Resources : Noncopyable, public Hw_ready_state
_irq->sigh(_irq_cap);
_mmio.construct(*_device, _env);
_gmadr.construct(*_device, Platform::Device::Mmio<0>::Index(1));
_gmadr_mem.construct(_env.rm(), _gmadr->cap());
_reinit();
}
void release_device()
{
_gmadr_mem.destruct();
_gmadr.destruct();
release_aperture_access();
_mmio.destruct();
_irq.destruct();
_device.destruct();
}
void release_aperture_access()
{
_gmadr_mem.destruct();
_gmadr.destruct();
}
/*
* Reserved aperture for platform service
*/
uint64_t aperture_reserved() const { return _aperture_reserved; }
uint64_t aperture_size() const { return _aperture_size; }
uint64_t gtt_reserved() const
{
@ -695,6 +746,8 @@ class Platform::Root : public Root_component<Session_component, Genode::Single_c
{
if (_session.constructed())
_session.destruct();
_resources.release_aperture_access();
}
bool handle_irq()