gpu/intel: free DMA, clear ggtt

* free DMA caps in case platform client's session is closed
* clear GGTT of platform client upon session close

issue #4233
This commit is contained in:
Sebastian Sumpf 2021-07-23 14:21:44 +02:00 committed by Christian Helmuth
parent 6c003a13d2
commit 1727de30b7
3 changed files with 154 additions and 95 deletions

View File

@ -85,23 +85,8 @@ struct Igd::Device
Env &_env; Env &_env;
Allocator &_md_alloc; Allocator &_md_alloc;
/***********
** Timer **
***********/
Timer::Connection _timer { _env };
enum { WATCHDOG_TIMEOUT = 1*1000*1000, }; enum { WATCHDOG_TIMEOUT = 1*1000*1000, };
struct Timer_delayer : Genode::Mmio::Delayer
{
Timer::Connection &_timer;
Timer_delayer(Timer::Connection &timer) : _timer(timer) { }
void usleep(uint64_t us) override { _timer.usleep(us); }
} _delayer { _timer };
/********* /*********
** PCI ** ** PCI **
*********/ *********/
@ -193,7 +178,7 @@ struct Igd::Device
** MMIO ** ** MMIO **
**********/ **********/
Genode::Constructible<Igd::Mmio> _mmio { }; Igd::Mmio &_mmio { _resources.mmio() };
/************ /************
** MEMORY ** ** MEMORY **
@ -732,7 +717,7 @@ struct Igd::Device
{ {
Execlist &el = *engine.execlist; Execlist &el = *engine.execlist;
int const port = _mmio->read<Igd::Mmio::EXECLIST_STATUS_RSCUNIT::Execlist_write_pointer>(); int const port = _mmio.read<Igd::Mmio::EXECLIST_STATUS_RSCUNIT::Execlist_write_pointer>();
el.schedule(port); el.schedule(port);
@ -742,10 +727,10 @@ struct Igd::Device
desc[1] = el.elem0().high(); desc[1] = el.elem0().high();
desc[0] = el.elem0().low(); desc[0] = el.elem0().low();
_mmio->write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[3]); _mmio.write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[3]);
_mmio->write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[2]); _mmio.write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[2]);
_mmio->write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[1]); _mmio.write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[1]);
_mmio->write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[0]); _mmio.write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[0]);
} }
Vgpu *_unschedule_current_vgpu() Vgpu *_unschedule_current_vgpu()
@ -774,19 +759,19 @@ struct Igd::Device
Engine<Rcs_context> &rcs = gpu->rcs; Engine<Rcs_context> &rcs = gpu->rcs;
_mmio->flush_gfx_tlb(); _mmio.flush_gfx_tlb();
/* /*
* XXX check if HWSP is shared across contexts and if not when * XXX check if HWSP is shared across contexts and if not when
* we actually need to write the register * we actually need to write the register
*/ */
Mmio::HWS_PGA_RCSUNIT::access_t const addr = rcs.hw_status_page(); Mmio::HWS_PGA_RCSUNIT::access_t const addr = rcs.hw_status_page();
_mmio->write_post<Igd::Mmio::HWS_PGA_RCSUNIT>(addr); _mmio.write_post<Igd::Mmio::HWS_PGA_RCSUNIT>(addr);
_submit_execlist(rcs); _submit_execlist(rcs);
_active_vgpu = gpu; _active_vgpu = gpu;
_timer.trigger_once(WATCHDOG_TIMEOUT); _resources.timer().trigger_once(WATCHDOG_TIMEOUT);
} }
/********** /**********
@ -795,7 +780,7 @@ struct Igd::Device
void _clear_rcs_iir(Mmio::GT_0_INTERRUPT_IIR::access_t const v) void _clear_rcs_iir(Mmio::GT_0_INTERRUPT_IIR::access_t const v)
{ {
_mmio->write_post<Mmio::GT_0_INTERRUPT_IIR>(v); _mmio.write_post<Mmio::GT_0_INTERRUPT_IIR>(v);
} }
/** /**
@ -830,7 +815,7 @@ struct Igd::Device
uint32_t _get_free_fence() uint32_t _get_free_fence()
{ {
return _mmio->find_free_fence(); return _mmio.find_free_fence();
} }
uint32_t _update_fence(uint32_t const id, uint32_t _update_fence(uint32_t const id,
@ -839,12 +824,12 @@ struct Igd::Device
uint32_t const pitch, uint32_t const pitch,
bool const tile_x) bool const tile_x)
{ {
return _mmio->update_fence(id, lower, upper, pitch, tile_x); return _mmio.update_fence(id, lower, upper, pitch, tile_x);
} }
void _clear_fence(uint32_t const id) void _clear_fence(uint32_t const id)
{ {
_mmio->clear_fence(id); _mmio.clear_fence(id);
} }
/********************** /**********************
@ -857,10 +842,10 @@ struct Igd::Device
Genode::error("watchdog triggered: engine stuck," Genode::error("watchdog triggered: engine stuck,"
" vGPU=", _active_vgpu->id()); " vGPU=", _active_vgpu->id());
_mmio->dump(); _mmio.dump();
_mmio->error_dump(); _mmio.error_dump();
_mmio->fault_dump(); _mmio.fault_dump();
_mmio->execlist_status_dump(); _mmio.execlist_status_dump();
_active_vgpu->rcs.context->dump(); _active_vgpu->rcs.context->dump();
_active_vgpu->rcs.context->dump_hw_status_page(); _active_vgpu->rcs.context->dump_hw_status_page();
@ -883,11 +868,11 @@ struct Igd::Device
void _device_reset_and_init() void _device_reset_and_init()
{ {
_mmio->reset(); _mmio.reset();
_mmio->clear_errors(); _mmio.clear_errors();
_mmio->init(); _mmio.init();
_mmio->enable_intr(); _mmio.enable_intr();
_mmio->forcewake_enable(); _mmio.forcewake_enable();
} }
/** /**
@ -928,11 +913,9 @@ struct Igd::Device
/* map PCI resources */ /* map PCI resources */
addr_t gttmmadr_base = _resources.map_gttmmadr(); addr_t gttmmadr_base = _resources.map_gttmmadr();
_mmio.construct(_delayer, gttmmadr_base);
/* GGTT */ /* GGTT */
Ram_dataspace_capability scratch_page_ds = _pci_backend_alloc.alloc(PAGE_SIZE); addr_t const scratch_page = _resources.scratch_page();
addr_t const scratch_page = Dataspace_client(scratch_page_ds).phys_addr();
/* reserverd size for framebuffer */ /* reserverd size for framebuffer */
size_t const aperture_reserved = resources.gmadr_platform_size(); size_t const aperture_reserved = resources.gmadr_platform_size();
@ -940,18 +923,17 @@ struct Igd::Device
size_t const ggtt_size = (1u << MGGC_0_2_0_PCI::Gtt_graphics_memory_size::get(v)) << 20; size_t const ggtt_size = (1u << MGGC_0_2_0_PCI::Gtt_graphics_memory_size::get(v)) << 20;
addr_t const ggtt_base = gttmmadr_base + (_resources.gttmmadr_size() / 2); addr_t const ggtt_base = gttmmadr_base + (_resources.gttmmadr_size() / 2);
size_t const gmadr_size = _resources.gmadr_size(); size_t const gmadr_size = _resources.gmadr_size();
_ggtt.construct(*_mmio, ggtt_base, ggtt_size, gmadr_size, scratch_page, aperture_reserved); _ggtt.construct(_mmio, ggtt_base, ggtt_size, gmadr_size, scratch_page, aperture_reserved);
_ggtt->dump(); _ggtt->dump();
_vgpu_avail = (gmadr_size - aperture_reserved) / Vgpu::APERTURE_SIZE; _vgpu_avail = (gmadr_size - aperture_reserved) / Vgpu::APERTURE_SIZE;
_device_reset_and_init(); _device_reset_and_init();
_mmio.dump();
_mmio.context_status_pointer_dump();
_mmio->dump(); _resources.timer().sigh(_watchdog_timeout_sigh);
_mmio->context_status_pointer_dump();
_timer.sigh(_watchdog_timeout_sigh);
} }
/********************* /*********************
@ -1105,7 +1087,7 @@ struct Igd::Device
uint32_t set_tiling(Ggtt::Offset const start, size_t const size, uint32_t set_tiling(Ggtt::Offset const start, size_t const size,
uint32_t const mode) uint32_t const mode)
{ {
uint32_t const id = _mmio->find_free_fence(); uint32_t const id = _mmio.find_free_fence();
if (id == INVALID_FENCE) { if (id == INVALID_FENCE) {
Genode::warning("could not find free FENCE"); Genode::warning("could not find free FENCE");
return id; return id;
@ -1130,15 +1112,15 @@ struct Igd::Device
unsigned handle_irq() unsigned handle_irq()
{ {
Mmio::MASTER_INT_CTL::access_t master = _mmio->read<Mmio::MASTER_INT_CTL>(); Mmio::MASTER_INT_CTL::access_t master = _mmio.read<Mmio::MASTER_INT_CTL>();
/* handle render interrupts only */ /* handle render interrupts only */
if (Mmio::MASTER_INT_CTL::Render_interrupts_pending::get(master) == 0) if (Mmio::MASTER_INT_CTL::Render_interrupts_pending::get(master) == 0)
return master; return master;
_mmio->disable_master_irq(); _mmio.disable_master_irq();
Mmio::GT_0_INTERRUPT_IIR::access_t const v = _mmio->read<Mmio::GT_0_INTERRUPT_IIR>(); Mmio::GT_0_INTERRUPT_IIR::access_t const v = _mmio.read<Mmio::GT_0_INTERRUPT_IIR>();
bool const ctx_switch = Mmio::GT_0_INTERRUPT_IIR::Cs_ctx_switch_interrupt::get(v); bool const ctx_switch = Mmio::GT_0_INTERRUPT_IIR::Cs_ctx_switch_interrupt::get(v);
(void)ctx_switch; (void)ctx_switch;
@ -1153,10 +1135,10 @@ struct Igd::Device
notify_gpu->user_complete(); notify_gpu->user_complete();
} }
bool const fault_valid = _mmio->fault_regs_valid(); bool const fault_valid = _mmio.fault_regs_valid();
if (fault_valid) { Genode::error("FAULT_REG valid"); } if (fault_valid) { Genode::error("FAULT_REG valid"); }
_mmio->update_context_status_pointer(); _mmio.update_context_status_pointer();
if (user_complete) { if (user_complete) {
_unschedule_current_vgpu(); _unschedule_current_vgpu();
@ -1176,7 +1158,7 @@ struct Igd::Device
return master; return master;
} }
void enable_master_irq() { _mmio->enable_master_irq(); } void enable_master_irq() { _mmio.enable_master_irq(); }
private: private:
@ -1623,9 +1605,10 @@ struct Main
Genode::Sliced_heap _root_heap { _env.ram(), _env.rm() }; Genode::Sliced_heap _root_heap { _env.ram(), _env.rm() };
Gpu::Root _gpu_root { _env, _root_heap }; Gpu::Root _gpu_root { _env, _root_heap };
Genode::Heap _device_md_alloc; Genode::Heap _device_md_alloc { _env.ram(), _env.rm() };
Genode::Constructible<Igd::Device> _device { }; Genode::Constructible<Igd::Device> _device { };
Igd::Resources _gpu_resources { _env, *this, &Main::ack_irq }; Igd::Resources _gpu_resources { _env, _device_md_alloc,
*this, &Main::ack_irq };
Genode::Irq_session_client _irq { _gpu_resources.gpu_client().irq(0) }; Genode::Irq_session_client _irq { _gpu_resources.gpu_client().irq(0) };
Genode::Signal_handler<Main> _irq_dispatcher { Genode::Signal_handler<Main> _irq_dispatcher {
@ -1635,24 +1618,21 @@ struct Main
Main(Genode::Env &env) Main(Genode::Env &env)
: :
_env(env), _device_md_alloc(_env.ram(), _env.rm()) _env(env)
{ {
/* IRQ */ /* IRQ */
_irq.sigh(_irq_dispatcher); _irq.sigh(_irq_dispatcher);
_irq.ack_irq(); _irq.ack_irq();
/* platform service */
_platform_root.construct(_env, _device_md_alloc, _gpu_resources);
/* GPU */ /* GPU */
try { try {
_device.construct(_env, _device_md_alloc, _gpu_resources); _device.construct(_env, _device_md_alloc, _gpu_resources);
} catch (...) { _gpu_root.manage(*_device);
return; _env.parent().announce(_env.ep().manage(_gpu_root));
} } catch (...) { }
_gpu_root.manage(*_device); /* platform service */
_env.parent().announce(_env.ep().manage(_gpu_root)); _platform_root.construct(_env, _device_md_alloc, _gpu_resources);
} }
void handle_irq() void handle_irq()

View File

@ -1,7 +1,6 @@
/* /*
* \brief Platform service implementation * \brief Platform service implementation
* \author Sebastian Sumpf * \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2021-07-16 * \date 2021-07-16
*/ */
@ -196,6 +195,23 @@ class Platform::Session_component : public Rpc_object<Session>
Device_component _device_component; Device_component _device_component;
Connection &_platform; Connection &_platform;
Device_capability _bridge; Device_capability _bridge;
Igd::Resources &_resources;
struct Dma_cap
{
Ram_dataspace_capability cap;
Dma_cap(Ram_dataspace_capability cap)
: cap(cap) { }
virtual ~Dma_cap() { }
};
/*
* track DMA memory allocations so we can free them at session
* destruction
*/
Registry<Registered<Dma_cap>> _dma_registry { };
public: public:
@ -204,7 +220,8 @@ class Platform::Session_component : public Rpc_object<Session>
_env(env), _env(env),
_device_component(env, resources), _device_component(env, resources),
_platform(resources.platform()), _platform(resources.platform()),
_bridge(resources.host_bridge_cap()) _bridge(resources.host_bridge_cap()),
_resources(resources)
{ {
_env.ep().rpc_ep().manage(&_device_component); _env.ep().rpc_ep().manage(&_device_component);
} }
@ -212,13 +229,21 @@ class Platform::Session_component : public Rpc_object<Session>
~Session_component() ~Session_component()
{ {
_env.ep().rpc_ep().dissolve(&_device_component); _env.ep().rpc_ep().dissolve(&_device_component);
/* clear ggtt */
_resources.gtt_platform_reset();
/* free DMA allocations */
_dma_registry.for_each([&](Dma_cap &dma) {
_platform.free_dma_buffer(dma.cap);
destroy(&_resources.heap(), &dma);
});
} }
Device_capability first_device(unsigned device_class, unsigned class_mask) override Device_capability first_device(unsigned device_class, unsigned) override
{ {
enum { ISA_BRIDGE = 0x601u << 8 }; if (device_class == _resources.isa_bridge_class())
if (device_class == ISA_BRIDGE) return _resources.isa_bridge_cap();
return _platform.first_device(device_class, class_mask);
return _bridge; return _bridge;
} }
@ -232,14 +257,9 @@ class Platform::Session_component : public Rpc_object<Session>
return Device_capability(); return Device_capability();
} }
void release_device(Device_capability device) override void release_device(Device_capability) override
{ {
if (device.valid() == false) return; return;
if (_device_component.cap() == device || device == _bridge) {
return;
}
_platform.release_device(device);
} }
Device_capability device(Device_name const & /* string */) override Device_capability device(Device_name const & /* string */) override
@ -250,12 +270,20 @@ class Platform::Session_component : public Rpc_object<Session>
Ram_dataspace_capability alloc_dma_buffer(size_t size, Cache cache) override Ram_dataspace_capability alloc_dma_buffer(size_t size, Cache cache) override
{ {
return _platform.alloc_dma_buffer(size, cache); Ram_dataspace_capability cap = _platform.alloc_dma_buffer(size, cache);
new (&_resources.heap()) Registered<Dma_cap>(_dma_registry, cap);
return cap;
} }
void free_dma_buffer(Ram_dataspace_capability cap) override void free_dma_buffer(Ram_dataspace_capability cap) override
{ {
_platform.free_dma_buffer(cap); if (!cap.valid()) return;
_dma_registry.for_each([&](Dma_cap &dma) {
if ((dma.cap == cap) == false) return;
_platform.free_dma_buffer(cap);
destroy(&_resources.heap(), &dma);
});
} }
addr_t dma_addr(Ram_dataspace_capability cap) override addr_t dma_addr(Ram_dataspace_capability cap) override

View File

@ -31,8 +31,22 @@ class Igd::Resources : Genode::Noncopyable
using Io_mem_connection = Genode::Io_mem_connection; using Io_mem_connection = Genode::Io_mem_connection;
using Io_mem_dataspace_capability = Genode::Io_mem_dataspace_capability; using Io_mem_dataspace_capability = Genode::Io_mem_dataspace_capability;
using Ram_dataspace_capability = Genode::Ram_dataspace_capability;
Genode::Env &_env; Genode::Env &_env;
Genode::Heap &_heap;
/* timer */
Timer::Connection _timer { _env };
struct Timer_delayer : Genode::Mmio::Delayer
{
Timer::Connection &_timer;
Timer_delayer(Timer::Connection &timer) : _timer(timer) { }
void usleep(uint64_t us) override { _timer.usleep(us); }
} _delayer { _timer };
/* irq callback */ /* irq callback */
Main &_obj; Main &_obj;
@ -43,15 +57,26 @@ class Igd::Resources : Genode::Noncopyable
Platform::Device_capability _gpu_cap { }; Platform::Device_capability _gpu_cap { };
Platform::Device_capability _host_bridge_cap { }; Platform::Device_capability _host_bridge_cap { };
Platform::Device_capability _isa_bridge_cap { };
Genode::Constructible<Platform::Device_client> _gpu_client { }; Genode::Constructible<Platform::Device_client> _gpu_client { };
/* mmio + gtt */ /* mmio + ggtt */
Platform::Device::Resource _gttmmadr { }; Platform::Device::Resource _gttmmadr { };
Io_mem_dataspace_capability _gttmmadr_ds { }; Io_mem_dataspace_capability _gttmmadr_ds { };
Genode::Constructible<Io_mem_connection> _gttmmadr_io { }; Genode::Constructible<Io_mem_connection> _gttmmadr_io { };
addr_t _gttmmadr_local { 0 };
Genode::Constructible<Igd::Mmio> _mmio { };
/* scratch page for ggtt */
Ram_dataspace_capability _scratch_page_ds {
_platform.with_upgrade([&] () {
return _platform.alloc_dma_buffer(PAGE_SIZE, Genode::UNCACHED); }) };
addr_t _scratch_page {
Genode::Dataspace_client(_scratch_page_ds).phys_addr() };
/* aperture */ /* aperture */
Platform::Device::Resource _gmadr { };
enum { enum {
/* reserved aperture for platform service */ /* reserved aperture for platform service */
APERTURE_RESERVED = 64u<<20, APERTURE_RESERVED = 64u<<20,
@ -59,14 +84,12 @@ class Igd::Resources : Genode::Noncopyable
GTT_RESERVED = (APERTURE_RESERVED/PAGE_SIZE) * 8, GTT_RESERVED = (APERTURE_RESERVED/PAGE_SIZE) * 8,
}; };
Platform::Device::Resource _gmadr { };
/* managed dataspace for local platform service */ /* managed dataspace for local platform service */
Genode::Rm_connection _rm_connection { _env }; Genode::Rm_connection _rm_connection { _env };
Genode::Constructible<Genode::Region_map_client> _gttmmadr_rm { }; Genode::Constructible<Genode::Region_map_client> _gttmmadr_rm { };
/**********
** Mmio **
**********/
void _create_gttmmadr_rm() void _create_gttmmadr_rm()
{ {
using off_t = Genode::off_t; using off_t = Genode::off_t;
@ -135,6 +158,12 @@ class Igd::Resources : Genode::Noncopyable
continue; continue;
} }
if (device.class_code() == isa_bridge_class()) {
_isa_bridge_cap = cap;
release = false;
continue;
}
release = true; release = true;
} }
} }
@ -185,9 +214,10 @@ class Igd::Resources : Genode::Noncopyable
public: public:
Resources(Genode::Env &env, Main &obj, void (Main::*ack_irq) ()) Resources(Genode::Env &env, Genode::Heap &heap,
Main &obj, void (Main::*ack_irq) ())
: :
_env(env), _obj(obj), _ack_irq(ack_irq) _env(env), _heap(heap), _obj(obj), _ack_irq(ack_irq)
{ {
/* initial donation for device pd */ /* initial donation for device pd */
_platform.upgrade_ram(1024*1024); _platform.upgrade_ram(1024*1024);
@ -207,9 +237,9 @@ class Igd::Resources : Genode::Noncopyable
_enable_pci_bus_master(); _enable_pci_bus_master();
Genode::log("Reserved beginning ", log("Reserved beginning ",
Genode::Number_of_bytes(APERTURE_RESERVED), Genode::Number_of_bytes(APERTURE_RESERVED),
" of aperture for platform service"); " of aperture for platform service");
} }
~Resources() ~Resources()
@ -223,14 +253,16 @@ class Igd::Resources : Genode::Noncopyable
if (!_gttmmadr_ds.valid()) if (!_gttmmadr_ds.valid())
throw Initialization_failed(); throw Initialization_failed();
addr_t addr = (addr_t)(_env.rm().attach(_gttmmadr_ds, _gttmmadr.size())); if (_gttmmadr_local) return _gttmmadr_local;
_gttmmadr_local = (addr_t)(_env.rm().attach(_gttmmadr_ds, _gttmmadr.size()));
log("Map res:", 0, log("Map res:", 0,
" base:", Genode::Hex(_gttmmadr.base()), " base:", Genode::Hex(_gttmmadr.base()),
" size:", Genode::Hex(_gttmmadr.size()), " size:", Genode::Hex(_gttmmadr.size()),
" vaddr:", Genode::Hex(addr)); " vaddr:", Genode::Hex(_gttmmadr_local));
return addr; return _gttmmadr_local;
} }
template <typename T> template <typename T>
@ -254,19 +286,24 @@ class Igd::Resources : Genode::Noncopyable
void ack_irq() { (_obj.*_ack_irq)(); } void ack_irq() { (_obj.*_ack_irq)(); }
Genode::Heap &heap() { return _heap; }
Timer::Connection &timer() { return _timer; };
addr_t scratch_page() const { return _scratch_page; }
Platform::Connection &platform() { return _platform; } Platform::Connection &platform() { return _platform; }
Platform::Device_client &gpu_client() { return *_gpu_client; } Platform::Device_client &gpu_client() { return *_gpu_client; }
Platform::Device_capability host_bridge_cap() { return _host_bridge_cap; } Platform::Device_capability host_bridge_cap() { return _host_bridge_cap; }
Platform::Device_capability isa_bridge_cap() { return _isa_bridge_cap; }
unsigned isa_bridge_class() const { return 0x601u << 8; }
addr_t gmadr_base() const { return _gmadr.base(); } addr_t gmadr_base() const { return _gmadr.base(); }
size_t gmadr_size() const { return _gmadr.size(); } size_t gmadr_size() const { return _gmadr.size(); }
addr_t gttmmadr_base() const { return _gttmmadr.base(); } addr_t gttmmadr_base() const { return _gttmmadr.base(); }
addr_t gttmmadr_size() const { return _gttmmadr.size(); } size_t gttmmadr_size() const { return _gttmmadr.size(); }
size_t gmadr_platform_size() const { return APERTURE_RESERVED; } size_t gmadr_platform_size() const { return APERTURE_RESERVED; }
size_t gttmmadr_platform_size() const { return GTT_RESERVED; } size_t gttmmadr_platform_size() const { return GTT_RESERVED; }
Io_mem_dataspace_capability gttmmadr_platform_ds() Io_mem_dataspace_capability gttmmadr_platform_ds()
{ {
using namespace Genode; using namespace Genode;
@ -276,5 +313,19 @@ class Igd::Resources : Genode::Noncopyable
return static_cap_cast<Io_mem_dataspace>(_gttmmadr_rm->dataspace()); return static_cap_cast<Io_mem_dataspace>(_gttmmadr_rm->dataspace());
} }
void gtt_platform_reset()
{
addr_t const base = map_gttmmadr() + (gttmmadr_size() / 2);
Igd::Ggtt(mmio(), base, gttmmadr_platform_size(), 0, scratch_page(), 0);
}
Igd::Mmio &mmio()
{
if (!_mmio.constructed())
_mmio.construct(_delayer, map_gttmmadr());
return *_mmio;
}
}; };