mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-07 11:50:24 +00:00
gpu/intel: release device before suspend
- monitor system ROM changes - stop processing of new Jobs before suspend - destruct platform device before suspend, but keep platform DMA buffers - re-construct platform device and reinit resources (mmio, irq) on resume - re-start GPU job scheduling on resume Fixes #5081
This commit is contained in:
parent
4ce4d4120a
commit
0684101ff0
@ -606,6 +606,7 @@ struct Igd::Device
|
|||||||
Engine<Rcs_context> rcs;
|
Engine<Rcs_context> rcs;
|
||||||
uint32_t active_fences { 0 };
|
uint32_t active_fences { 0 };
|
||||||
uint64_t _current_seqno { 0 };
|
uint64_t _current_seqno { 0 };
|
||||||
|
Gpu::addr_t _delayed_execute { 0 };
|
||||||
|
|
||||||
Genode::Attached_ram_dataspace _info_dataspace;
|
Genode::Attached_ram_dataspace _info_dataspace;
|
||||||
Gpu::Info_intel &_info {
|
Gpu::Info_intel &_info {
|
||||||
@ -673,6 +674,11 @@ struct Igd::Device
|
|||||||
_info.last_completed = Gpu::Sequence_number { .value = current_seqno() };
|
_info.last_completed = Gpu::Sequence_number { .value = current_seqno() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void delay_execute(Gpu::addr_t const vram_addr)
|
||||||
|
{
|
||||||
|
_delayed_execute = vram_addr;
|
||||||
|
}
|
||||||
|
|
||||||
bool setup_ring_vram(Gpu::addr_t const vram_addr)
|
bool setup_ring_vram(Gpu::addr_t const vram_addr)
|
||||||
{
|
{
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
@ -969,16 +975,14 @@ struct Igd::Device
|
|||||||
** SCHEDULING **
|
** SCHEDULING **
|
||||||
****************/
|
****************/
|
||||||
|
|
||||||
Genode::Fifo<Vgpu> _vgpu_list { };
|
Genode::Fifo<Vgpu> _vgpu_list { };
|
||||||
Vgpu *_active_vgpu { nullptr };
|
Genode::Fifo<Vgpu> _vgpu_delay { };
|
||||||
|
Vgpu *_active_vgpu { };
|
||||||
|
bool _schedule_stop { };
|
||||||
|
|
||||||
void _submit_execlist(Igd::Mmio &mmio, Engine<Rcs_context> &engine)
|
|
||||||
|
bool exec_list_empty(Igd::Mmio &mmio) const
|
||||||
{
|
{
|
||||||
Execlist &el = engine.execlist;
|
|
||||||
|
|
||||||
int const port = mmio.read<Igd::Mmio::EXECLIST_STATUS_RSCUNIT::Execlist_write_pointer>();
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exec list might still be executing, check multiple times, in the normal
|
* Exec list might still be executing, check multiple times, in the normal
|
||||||
* case first iteration should succeed. If still running loop should end
|
* case first iteration should succeed. If still running loop should end
|
||||||
@ -994,12 +998,21 @@ struct Igd::Device
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _submit_execlist(Igd::Mmio &mmio, Engine<Rcs_context> &engine)
|
||||||
|
{
|
||||||
|
Execlist &el = engine.execlist;
|
||||||
|
|
||||||
|
int const port = mmio.read<Igd::Mmio::EXECLIST_STATUS_RSCUNIT::Execlist_write_pointer>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case exec list is still running write list anyway, it will preempt
|
* In case exec list is still running write list anyway, it will preempt
|
||||||
* something in the worst case. Nonetheless if you see the warning below,
|
* something in the worst case. Nonetheless if you see the warning below,
|
||||||
* something is not right and should be investigated.
|
* something is not right and should be investigated.
|
||||||
*/
|
*/
|
||||||
if (!empty)
|
if (!exec_list_empty(mmio))
|
||||||
warning("exec list is not empty");
|
warning("exec list is not empty");
|
||||||
|
|
||||||
el.schedule(port);
|
el.schedule(port);
|
||||||
@ -1188,6 +1201,50 @@ struct Igd::Device
|
|||||||
Genode::Signal_handler<Device> _watchdog_timeout_sigh {
|
Genode::Signal_handler<Device> _watchdog_timeout_sigh {
|
||||||
_env.ep(), *this, &Device::_handle_watchdog_timeout };
|
_env.ep(), *this, &Device::_handle_watchdog_timeout };
|
||||||
|
|
||||||
|
void handle_system_update(String<32> const & state)
|
||||||
|
{
|
||||||
|
if (state == "driver_stop") {
|
||||||
|
_schedule_stop = true;
|
||||||
|
device_release_if_stopped_and_idle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == "driver_reinit") {
|
||||||
|
_resources.acquire_device();
|
||||||
|
|
||||||
|
if (!_resources.with_mmio([&](auto &mmio) {
|
||||||
|
|
||||||
|
mmio.generation(_info.generation);
|
||||||
|
reinit(mmio);
|
||||||
|
|
||||||
|
_schedule_stop = false;
|
||||||
|
|
||||||
|
/* resume if there is a current vGPU */
|
||||||
|
if (_current_vgpu())
|
||||||
|
_schedule_current_vgpu(mmio);
|
||||||
|
|
||||||
|
/* re-add delayed execute RPCs() of vGPUs to ready list */
|
||||||
|
_vgpu_delay.dequeue_all([&](auto &vgpu) {
|
||||||
|
if (vgpu.setup_ring_vram(vgpu._delayed_execute)) {
|
||||||
|
vgpu_activate(vgpu, mmio);
|
||||||
|
} else
|
||||||
|
warning("setup_ring_vram failed");
|
||||||
|
});
|
||||||
|
}))
|
||||||
|
error("reinit - failed");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_release_if_stopped_and_idle()
|
||||||
|
{
|
||||||
|
if (!_schedule_stop || _active_vgpu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_resources.release_device();
|
||||||
|
}
|
||||||
|
|
||||||
void _device_reset_and_init(Igd::Mmio &mmio)
|
void _device_reset_and_init(Igd::Mmio &mmio)
|
||||||
{
|
{
|
||||||
mmio.reset();
|
mmio.reset();
|
||||||
@ -1526,6 +1583,9 @@ struct Igd::Device
|
|||||||
|
|
||||||
_vgpu_list.enqueue(vgpu);
|
_vgpu_list.enqueue(vgpu);
|
||||||
|
|
||||||
|
if (_schedule_stop)
|
||||||
|
return;
|
||||||
|
|
||||||
if (pending) { return; }
|
if (pending) { return; }
|
||||||
|
|
||||||
/* none pending, kick-off execution */
|
/* none pending, kick-off execution */
|
||||||
@ -1690,7 +1750,7 @@ struct Igd::Device
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* keep the ball rolling... */
|
/* keep the ball rolling... */
|
||||||
if (_current_vgpu()) {
|
if (!_schedule_stop && _current_vgpu()) {
|
||||||
_schedule_current_vgpu(mmio);
|
_schedule_current_vgpu(mmio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2033,7 +2093,11 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
|
|||||||
|
|
||||||
Gpu::Sequence_number execute(Vram_id id, off_t offset) override
|
Gpu::Sequence_number execute(Vram_id id, off_t offset) override
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
bool ppgtt_va_valid = false;
|
||||||
|
Gpu::addr_t ppgtt_va = 0;
|
||||||
|
|
||||||
|
bool const dev_offline = !_device._resources.with_mmio([](auto &){});
|
||||||
|
|
||||||
_apply_vram_local(id, [&] (Vram_local &vram_local) {
|
_apply_vram_local(id, [&] (Vram_local &vram_local) {
|
||||||
|
|
||||||
@ -2042,9 +2106,7 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_t ppgtt_va { 0 };
|
ppgtt_va_valid = vram_local.mappings.with_element(offset,
|
||||||
|
|
||||||
bool ppgtt_va_valid = vram_local.mappings.with_element(offset,
|
|
||||||
[&] (Vram_local::Mapping const &mapping) {
|
[&] (Vram_local::Mapping const &mapping) {
|
||||||
ppgtt_va = mapping.ppgtt_va; return true; },
|
ppgtt_va = mapping.ppgtt_va; return true; },
|
||||||
[]() { return false; });
|
[]() { return false; });
|
||||||
@ -2055,9 +2117,25 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
|
|||||||
throw Gpu::Session::Invalid_state();
|
throw Gpu::Session::Invalid_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* setup ring vram would require MMIO which is not avail */
|
||||||
|
if (dev_offline)
|
||||||
|
return;
|
||||||
|
|
||||||
found = _vgpu.setup_ring_vram(ppgtt_va);
|
found = _vgpu.setup_ring_vram(ppgtt_va);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (dev_offline && ppgtt_va_valid) {
|
||||||
|
/* add vGPU to the delayed list, resumed after dev is re-acquired */
|
||||||
|
if (!_vgpu.enqueued())
|
||||||
|
_device._vgpu_delay.enqueue(_vgpu);
|
||||||
|
|
||||||
|
/* remember current execute in vGPU */
|
||||||
|
_vgpu.delay_execute(ppgtt_va);
|
||||||
|
|
||||||
|
/* return seqno which will be used after device is re-aquired */
|
||||||
|
return { .value = _vgpu.current_seqno() + 1 };
|
||||||
|
}
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
throw Gpu::Session::Invalid_state();
|
throw Gpu::Session::Invalid_state();
|
||||||
|
|
||||||
@ -2410,10 +2488,14 @@ struct Main : Irq_ack_handler, Gpu_reset_handler
|
|||||||
Signal_handler<Main> _config_sigh { _env.ep(), *this,
|
Signal_handler<Main> _config_sigh { _env.ep(), *this,
|
||||||
&Main::_handle_config_update };
|
&Main::_handle_config_update };
|
||||||
Platform::Resources _dev { _env, _rm, _irq_dispatcher };
|
Platform::Resources _dev { _env, _rm, _irq_dispatcher };
|
||||||
|
Signal_handler<Main> _system_sigh { _env.ep(), *this,
|
||||||
|
&Main::_system_update };
|
||||||
|
|
||||||
Platform::Root _platform_root { _env, _md_alloc, _dev, *this, *this };
|
Platform::Root _platform_root { _env, _md_alloc, _dev, *this, *this };
|
||||||
|
|
||||||
Genode::Constructible<Igd::Device> _igd_device { };
|
Constructible<Igd::Device> _igd_device { };
|
||||||
|
Constructible<Attached_rom_dataspace> _system_rom { };
|
||||||
|
|
||||||
|
|
||||||
Main(Genode::Env &env) : _env(env)
|
Main(Genode::Env &env) : _env(env)
|
||||||
{
|
{
|
||||||
@ -2467,12 +2549,49 @@ struct Main : Irq_ack_handler, Gpu_reset_handler
|
|||||||
|
|
||||||
if (!_config_rom.valid()) { return; }
|
if (!_config_rom.valid()) { return; }
|
||||||
|
|
||||||
|
bool const use_system_rom = _config_rom.xml().attribute_value("system", false);
|
||||||
|
|
||||||
|
if (use_system_rom) {
|
||||||
|
_system_rom.construct(_env, "system");
|
||||||
|
_system_rom->sigh(_system_sigh);
|
||||||
|
_system_update();
|
||||||
|
} else
|
||||||
|
_system_rom.destruct();
|
||||||
|
|
||||||
if (_igd_device.constructed()) {
|
if (_igd_device.constructed()) {
|
||||||
Genode::log("gpu device already initialized - ignore");
|
Genode::log("gpu device already initialized - ignore");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_create_device();
|
_create_device();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void _system_update()
|
||||||
|
{
|
||||||
|
if (!_system_rom.constructed())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_system_rom->update();
|
||||||
|
|
||||||
|
if (!_system_rom->valid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto state = _system_rom->xml().attribute_value("state", String<32>(""));
|
||||||
|
|
||||||
|
if (_igd_device.constructed()) {
|
||||||
|
_igd_device->handle_system_update(state);
|
||||||
|
} else {
|
||||||
|
if (state == "driver_stop") {
|
||||||
|
_dev.release_device();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == "driver_reinit") {
|
||||||
|
_dev.acquire_device();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_irq()
|
void handle_irq()
|
||||||
@ -2511,6 +2630,9 @@ struct Main : Irq_ack_handler, Gpu_reset_handler
|
|||||||
|
|
||||||
if (!_dev.with_irq([&](auto &irq) { irq.ack(); }))
|
if (!_dev.with_irq([&](auto &irq) { irq.ack(); }))
|
||||||
error(__func__, " with_irq failed");
|
error(__func__, " with_irq failed");
|
||||||
|
|
||||||
|
if (_igd_device.constructed())
|
||||||
|
_igd_device->device_release_if_stopped_and_idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() override
|
void reset() override
|
||||||
|
@ -418,6 +418,29 @@ class Platform::Resources : Noncopyable
|
|||||||
}
|
}
|
||||||
|
|
||||||
void with_platform(auto const &fn) { fn(_platform); }
|
void with_platform(auto const &fn) { fn(_platform); }
|
||||||
|
|
||||||
|
void acquire_device()
|
||||||
|
{
|
||||||
|
_device.construct(_platform);
|
||||||
|
|
||||||
|
_irq.construct(*_device);
|
||||||
|
_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();
|
||||||
|
_mmio.destruct();
|
||||||
|
_irq.destruct();
|
||||||
|
_device.destruct();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user