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;
Allocator &_md_alloc;
/***********
** Timer **
***********/
Timer::Connection _timer { _env };
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 **
*********/
@ -193,7 +178,7 @@ struct Igd::Device
** MMIO **
**********/
Genode::Constructible<Igd::Mmio> _mmio { };
Igd::Mmio &_mmio { _resources.mmio() };
/************
** MEMORY **
@ -732,7 +717,7 @@ struct Igd::Device
{
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);
@ -742,10 +727,10 @@ struct Igd::Device
desc[1] = el.elem0().high();
desc[0] = el.elem0().low();
_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[1]);
_mmio->write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[0]);
_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[1]);
_mmio.write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[0]);
}
Vgpu *_unschedule_current_vgpu()
@ -774,19 +759,19 @@ struct Igd::Device
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
* we actually need to write the register
*/
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);
_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)
{
_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()
{
return _mmio->find_free_fence();
return _mmio.find_free_fence();
}
uint32_t _update_fence(uint32_t const id,
@ -839,12 +824,12 @@ struct Igd::Device
uint32_t const pitch,
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)
{
_mmio->clear_fence(id);
_mmio.clear_fence(id);
}
/**********************
@ -857,10 +842,10 @@ struct Igd::Device
Genode::error("watchdog triggered: engine stuck,"
" vGPU=", _active_vgpu->id());
_mmio->dump();
_mmio->error_dump();
_mmio->fault_dump();
_mmio->execlist_status_dump();
_mmio.dump();
_mmio.error_dump();
_mmio.fault_dump();
_mmio.execlist_status_dump();
_active_vgpu->rcs.context->dump();
_active_vgpu->rcs.context->dump_hw_status_page();
@ -883,11 +868,11 @@ struct Igd::Device
void _device_reset_and_init()
{
_mmio->reset();
_mmio->clear_errors();
_mmio->init();
_mmio->enable_intr();
_mmio->forcewake_enable();
_mmio.reset();
_mmio.clear_errors();
_mmio.init();
_mmio.enable_intr();
_mmio.forcewake_enable();
}
/**
@ -928,11 +913,9 @@ struct Igd::Device
/* map PCI resources */
addr_t gttmmadr_base = _resources.map_gttmmadr();
_mmio.construct(_delayer, gttmmadr_base);
/* GGTT */
Ram_dataspace_capability scratch_page_ds = _pci_backend_alloc.alloc(PAGE_SIZE);
addr_t const scratch_page = Dataspace_client(scratch_page_ds).phys_addr();
addr_t const scratch_page = _resources.scratch_page();
/* reserverd size for framebuffer */
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;
addr_t const ggtt_base = gttmmadr_base + (_resources.gttmmadr_size() / 2);
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();
_vgpu_avail = (gmadr_size - aperture_reserved) / Vgpu::APERTURE_SIZE;
_device_reset_and_init();
_mmio.dump();
_mmio.context_status_pointer_dump();
_mmio->dump();
_mmio->context_status_pointer_dump();
_timer.sigh(_watchdog_timeout_sigh);
_resources.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 const mode)
{
uint32_t const id = _mmio->find_free_fence();
uint32_t const id = _mmio.find_free_fence();
if (id == INVALID_FENCE) {
Genode::warning("could not find free FENCE");
return id;
@ -1130,15 +1112,15 @@ struct Igd::Device
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 */
if (Mmio::MASTER_INT_CTL::Render_interrupts_pending::get(master) == 0)
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);
(void)ctx_switch;
@ -1153,10 +1135,10 @@ struct Igd::Device
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"); }
_mmio->update_context_status_pointer();
_mmio.update_context_status_pointer();
if (user_complete) {
_unschedule_current_vgpu();
@ -1176,7 +1158,7 @@ struct Igd::Device
return master;
}
void enable_master_irq() { _mmio->enable_master_irq(); }
void enable_master_irq() { _mmio.enable_master_irq(); }
private:
@ -1623,9 +1605,10 @@ struct Main
Genode::Sliced_heap _root_heap { _env.ram(), _env.rm() };
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 { };
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::Signal_handler<Main> _irq_dispatcher {
@ -1635,24 +1618,21 @@ struct Main
Main(Genode::Env &env)
:
_env(env), _device_md_alloc(_env.ram(), _env.rm())
_env(env)
{
/* IRQ */
_irq.sigh(_irq_dispatcher);
_irq.ack_irq();
/* platform service */
_platform_root.construct(_env, _device_md_alloc, _gpu_resources);
/* GPU */
try {
_device.construct(_env, _device_md_alloc, _gpu_resources);
} catch (...) {
return;
}
_gpu_root.manage(*_device);
_env.parent().announce(_env.ep().manage(_gpu_root));
} catch (...) { }
_gpu_root.manage(*_device);
_env.parent().announce(_env.ep().manage(_gpu_root));
/* platform service */
_platform_root.construct(_env, _device_md_alloc, _gpu_resources);
}
void handle_irq()

View File

@ -1,7 +1,6 @@
/*
* \brief Platform service implementation
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2021-07-16
*/
@ -196,6 +195,23 @@ class Platform::Session_component : public Rpc_object<Session>
Device_component _device_component;
Connection &_platform;
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:
@ -204,7 +220,8 @@ class Platform::Session_component : public Rpc_object<Session>
_env(env),
_device_component(env, resources),
_platform(resources.platform()),
_bridge(resources.host_bridge_cap())
_bridge(resources.host_bridge_cap()),
_resources(resources)
{
_env.ep().rpc_ep().manage(&_device_component);
}
@ -212,13 +229,21 @@ class Platform::Session_component : public Rpc_object<Session>
~Session_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 == ISA_BRIDGE)
return _platform.first_device(device_class, class_mask);
if (device_class == _resources.isa_bridge_class())
return _resources.isa_bridge_cap();
return _bridge;
}
@ -232,14 +257,9 @@ class Platform::Session_component : public Rpc_object<Session>
return Device_capability();
}
void release_device(Device_capability device) override
void release_device(Device_capability) override
{
if (device.valid() == false) return;
if (_device_component.cap() == device || device == _bridge) {
return;
}
_platform.release_device(device);
return;
}
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
{
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
{
_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

View File

@ -31,8 +31,22 @@ class Igd::Resources : Genode::Noncopyable
using Io_mem_connection = Genode::Io_mem_connection;
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 */
Main &_obj;
@ -43,15 +57,26 @@ class Igd::Resources : Genode::Noncopyable
Platform::Device_capability _gpu_cap { };
Platform::Device_capability _host_bridge_cap { };
Platform::Device_capability _isa_bridge_cap { };
Genode::Constructible<Platform::Device_client> _gpu_client { };
/* mmio + gtt */
/* mmio + ggtt */
Platform::Device::Resource _gttmmadr { };
Io_mem_dataspace_capability _gttmmadr_ds { };
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 */
Platform::Device::Resource _gmadr { };
enum {
/* reserved aperture for platform service */
APERTURE_RESERVED = 64u<<20,
@ -59,14 +84,12 @@ class Igd::Resources : Genode::Noncopyable
GTT_RESERVED = (APERTURE_RESERVED/PAGE_SIZE) * 8,
};
Platform::Device::Resource _gmadr { };
/* managed dataspace for local platform service */
Genode::Rm_connection _rm_connection { _env };
Genode::Constructible<Genode::Region_map_client> _gttmmadr_rm { };
/**********
** Mmio **
**********/
void _create_gttmmadr_rm()
{
using off_t = Genode::off_t;
@ -135,6 +158,12 @@ class Igd::Resources : Genode::Noncopyable
continue;
}
if (device.class_code() == isa_bridge_class()) {
_isa_bridge_cap = cap;
release = false;
continue;
}
release = true;
}
}
@ -185,9 +214,10 @@ class Igd::Resources : Genode::Noncopyable
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 */
_platform.upgrade_ram(1024*1024);
@ -207,9 +237,9 @@ class Igd::Resources : Genode::Noncopyable
_enable_pci_bus_master();
Genode::log("Reserved beginning ",
Genode::Number_of_bytes(APERTURE_RESERVED),
" of aperture for platform service");
log("Reserved beginning ",
Genode::Number_of_bytes(APERTURE_RESERVED),
" of aperture for platform service");
}
~Resources()
@ -223,14 +253,16 @@ class Igd::Resources : Genode::Noncopyable
if (!_gttmmadr_ds.valid())
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,
" base:", Genode::Hex(_gttmmadr.base()),
" size:", Genode::Hex(_gttmmadr.size()),
" vaddr:", Genode::Hex(addr));
" vaddr:", Genode::Hex(_gttmmadr_local));
return addr;
return _gttmmadr_local;
}
template <typename T>
@ -254,19 +286,24 @@ class Igd::Resources : Genode::Noncopyable
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::Device_client &gpu_client() { return *_gpu_client; }
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(); }
size_t gmadr_size() const { return _gmadr.size(); }
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 gttmmadr_platform_size() const { return GTT_RESERVED; }
Io_mem_dataspace_capability gttmmadr_platform_ds()
{
using namespace Genode;
@ -276,5 +313,19 @@ class Igd::Resources : Genode::Noncopyable
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;
}
};