mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-13 22:23:45 +00:00
gpu/intel: RC6 support
* add RC6 support for GPU GEN9 (Skylake+) and GEN12 (Tiger Lake+), RC6 is entered by software after CHECK_INACTIVEus of inactivity. When a new Vgpu is scheduled we trigger a resume from RC6. * increase VGPU-watchdog timeout to 300ms issue #5504
This commit is contained in:
parent
721e2c634a
commit
e5cbf602e0
34
repos/os/src/driver/gpu/intel/device_info.h
Normal file
34
repos/os/src/driver/gpu/intel/device_info.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* \brief Device_info stores GPU information
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2025-03-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#ifndef _DEVICE_INFO_
|
||||
#define _DEVICE_INFO_
|
||||
|
||||
#include <types.h>
|
||||
|
||||
namespace Igd {
|
||||
struct Device_info;
|
||||
}
|
||||
|
||||
struct Igd::Device_info
|
||||
{
|
||||
enum Platform { UNKNOWN, BROADWELL, SKYLAKE, KABYLAKE, WHISKEYLAKE, TIGERLAKE };
|
||||
enum Stepping { A0, B0, C0, D0, D1, E0, F0, G0 };
|
||||
|
||||
uint16_t id;
|
||||
uint8_t generation;
|
||||
Platform platform;
|
||||
uint64_t features;
|
||||
};
|
||||
|
||||
#endif /* _DEVICE_INFO_ */
|
@ -1,11 +1,13 @@
|
||||
/*
|
||||
* \brief Intel GPU multiplexer for Broadwell generation and newer
|
||||
* \brief Intel GPU multiplexer for GEN8-12
|
||||
* \author Alexander Boettcher
|
||||
* \author Josef Soentgen
|
||||
* \data 2017-03-15
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2017-03-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017-2024 Genode Labs GmbH
|
||||
* Copyright (C) 2017-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.
|
||||
@ -41,6 +43,7 @@
|
||||
#include <context.h>
|
||||
#include <context_descriptor.h>
|
||||
#include <platform_session.h>
|
||||
#include <rc6.h>
|
||||
#include <reset.h>
|
||||
#include <ring_buffer.h>
|
||||
|
||||
@ -55,19 +58,6 @@ namespace Igd {
|
||||
}
|
||||
|
||||
|
||||
struct Igd::Device_info
|
||||
{
|
||||
enum Platform { UNKNOWN, BROADWELL, SKYLAKE, KABYLAKE, WHISKEYLAKE, TIGERLAKE };
|
||||
enum Stepping { A0, B0, C0, D0, D1, E0, F0, G0 };
|
||||
|
||||
uint16_t id;
|
||||
uint8_t generation;
|
||||
Platform platform;
|
||||
uint64_t features;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct Igd::Device
|
||||
{
|
||||
struct Unsupported_device : Genode::Exception { };
|
||||
@ -75,14 +65,15 @@ struct Igd::Device
|
||||
struct Out_of_ram : Genode::Exception { };
|
||||
struct Could_not_map_vram : Genode::Exception { };
|
||||
|
||||
/* 200 ms */
|
||||
enum { WATCHDOG_TIMEOUT = 200*1000 };
|
||||
/* 300 ms */
|
||||
enum { WATCHDOG_TIMEOUT = 300*1000 };
|
||||
|
||||
Env & _env;
|
||||
Allocator & _md_alloc;
|
||||
Platform::Resources & _resources;
|
||||
Rm_connection & _rm;
|
||||
Timer::Connection _timer { _env };
|
||||
Timer::Connection _timer { _env };
|
||||
Constructible<Rc6> _rc6 { };
|
||||
|
||||
/*********
|
||||
** PCI **
|
||||
@ -198,12 +189,14 @@ struct Igd::Device
|
||||
if (info.platform == Igd::Device_info::Platform::UNKNOWN)
|
||||
return;
|
||||
|
||||
/* set generation for device IO as early as possible */
|
||||
mmio.generation(generation);
|
||||
|
||||
if (info.id == dev_id) {
|
||||
_info = info;
|
||||
_revision.value = rev_id;
|
||||
|
||||
/* set generation for device IO as early as possible */
|
||||
mmio.device_info(_info);
|
||||
|
||||
_clock_frequency.value = mmio.clock_frequency();
|
||||
|
||||
found = true;
|
||||
@ -1086,6 +1079,9 @@ struct Igd::Device
|
||||
return;
|
||||
}
|
||||
|
||||
/* signal alive to RC6 watchdog */
|
||||
_rc6->progress();
|
||||
|
||||
Engine<Rcs_context> &rcs = gpu->rcs;
|
||||
|
||||
mmio.flush_gfx_tlb();
|
||||
@ -1228,7 +1224,7 @@ struct Igd::Device
|
||||
|
||||
_resources.with_mmio([&](auto &mmio) {
|
||||
|
||||
mmio.generation(_info.generation);
|
||||
mmio.device_info(_info);
|
||||
reinit(mmio);
|
||||
|
||||
_schedule_stop = false;
|
||||
@ -1267,6 +1263,11 @@ struct Igd::Device
|
||||
mmio.reset();
|
||||
mmio.clear_errors();
|
||||
mmio.init();
|
||||
|
||||
/* try to enable RC6-sleep-state support */
|
||||
_rc6.construct(_env, mmio);
|
||||
_rc6->enable();
|
||||
|
||||
mmio.enable_intr();
|
||||
}
|
||||
|
||||
@ -1473,8 +1474,12 @@ struct Igd::Device
|
||||
vgpu_unschedule(*_active_vgpu);
|
||||
}
|
||||
|
||||
/* disable hw handling of RC6 */
|
||||
_rc6->clear();
|
||||
/* reset */
|
||||
Igd::Reset(mmio).execute();
|
||||
/* re-init RC6 */
|
||||
_rc6->enable();
|
||||
|
||||
/* set address of global hardware status page */
|
||||
if (_hw_status_ctx.constructed()) {
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
#include <device_info.h>
|
||||
|
||||
|
||||
namespace Igd {
|
||||
@ -35,19 +35,28 @@ class Igd::Mmio : public Platform::Device::Mmio<MMIO_SIZE>
|
||||
{
|
||||
public:
|
||||
|
||||
unsigned _generation { 0 };
|
||||
/* Device info related */
|
||||
|
||||
void generation(unsigned gen) { _generation = gen; }
|
||||
Device_info _info { };
|
||||
|
||||
void device_info(Device_info const info) { _info = info; }
|
||||
|
||||
unsigned generation() const
|
||||
{
|
||||
if (!_generation) {
|
||||
Genode::error("Unsupported generation: ", _generation);
|
||||
if (!_info.generation) {
|
||||
Genode::error("Unsupported generation: ", _info.generation);
|
||||
}
|
||||
|
||||
return _generation;
|
||||
return _info.generation;
|
||||
}
|
||||
|
||||
/* expand here as needed */
|
||||
bool skylake() const {
|
||||
return _info.platform == Device_info::Platform::SKYLAKE; }
|
||||
|
||||
|
||||
/* Register definitions */
|
||||
|
||||
enum {
|
||||
/*
|
||||
* XXX IDs are taken from Linux, still looking
|
||||
@ -668,20 +677,6 @@ class Igd::Mmio : public Platform::Device::Mmio<MMIO_SIZE>
|
||||
struct Arbiter_mode_control_1 : Bitfield<1, 1> { };
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1315 ff.
|
||||
*/
|
||||
struct RC_CTRL0 : Register<0x0A090, 32> { };
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1317 ff.
|
||||
*/
|
||||
struct RC_CTRL1 : Register<0x0A094, 32>
|
||||
{
|
||||
struct Rc_state : Bitfield<18, 1> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1095
|
||||
*/
|
||||
@ -1140,6 +1135,109 @@ class Igd::Mmio : public Platform::Device::Mmio<MMIO_SIZE>
|
||||
struct MI_RDRET_STATE : Register<0x20FC, 32> { };
|
||||
struct ECOSKPD : Register<0x21D0, 32> { };
|
||||
|
||||
|
||||
/*********
|
||||
** RC6 **
|
||||
*********/
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1315 ff.
|
||||
*
|
||||
* GEN6_RC_CONTROL in Linux
|
||||
*/
|
||||
struct RC_CTRL0 : Register<0x0A090, 32>
|
||||
{
|
||||
struct Rc6_enable : Bitfield<18, 1> { };
|
||||
struct Ei_hw : Bitfield<27, 1> { };
|
||||
struct Hw_control_enable : Bitfield<31, 1> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1317 ff.
|
||||
*
|
||||
* GEN6_RC_STATE in Linux
|
||||
*/
|
||||
struct RC_CTRL1 : Register<0x0A094, 32>
|
||||
{
|
||||
struct Target : Bitfield<16, 3> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1311 ff.
|
||||
*/
|
||||
struct RC_WAKE_RATE_LIMIT : Register<0xA09C, 32>
|
||||
{
|
||||
struct Rc6_deeper : Bitfield<0, 16> { };
|
||||
struct Rc6 : Bitfield<16, 16> { };
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1296 ff.
|
||||
*/
|
||||
struct RC_EVALUATION_INTERVAL : Register<0xA0A8, 32>
|
||||
{
|
||||
struct Render_standby : Bitfield<0, 24> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1296 ff.
|
||||
*/
|
||||
struct RC_IDLE_HYSTERSIS : Register<0xA0AC, 32>
|
||||
{
|
||||
struct Detection : Bitfield<0, 24> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1557 ff.
|
||||
*
|
||||
* GEN6_RC_SLEEP in Linux
|
||||
*/
|
||||
struct RC_WAKE_HYSTERSIS : Register<0xA0B0, 32>
|
||||
{
|
||||
/* minimum amount of time in RC0 */
|
||||
struct Msg_to_busy_timer : Bitfield<0, 24> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1300 ff.
|
||||
*
|
||||
* GEN6_RC6_THRESHOLD in Linux
|
||||
*/
|
||||
struct RC_PROMO_TIME : Register<0xA0B8, 32>
|
||||
{
|
||||
/* absolute time starting from post-hyst idle */
|
||||
struct Promotion_timer : Bitfield<0, 24> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* Undocumented (PG stands for "power gating")
|
||||
*/
|
||||
struct GEN9_PG_ENABLE : Register<0xA210, 32>
|
||||
{
|
||||
struct Gen9_render_pg_enable : Bitfield<0, 1> { };
|
||||
struct Gen9_media_pg_enable : Bitfield<1, 1> { };
|
||||
struct Gen11_media_sampler_pg_enable : Bitfield<2, 1> { };
|
||||
/* missing HCP/MFX power gates */
|
||||
};
|
||||
|
||||
/*
|
||||
* Undocumented
|
||||
*/
|
||||
struct GEN9_MEDIA_PG_IDLE_HYSTERESIS : Register<0xA0C4, 32> { };
|
||||
struct GEN9_RENDER_PG_IDLE_HYSTERESIS : Register<0xA0C8, 32> { };
|
||||
/*
|
||||
* Undocumented
|
||||
*/
|
||||
struct RING_MAX_IDLE : Register<0x2054, 32> { };
|
||||
|
||||
/*
|
||||
* Bootmsg - Boot Vector in IHD-OS-BDW-Vol 2c-11.15 p. 202
|
||||
*
|
||||
* Does not seem to correlate but is used to check a Wa
|
||||
*/
|
||||
struct GEN8_RC6_CTX_INFO : Register<0x8504, 32> { };
|
||||
|
||||
private:
|
||||
|
||||
struct Timer_delayer : Genode::Mmio<MMIO_SIZE>::Delayer
|
||||
@ -1441,13 +1539,6 @@ class Igd::Mmio : public Platform::Device::Mmio<MMIO_SIZE>
|
||||
*/
|
||||
void _disable_rps()
|
||||
{
|
||||
/*
|
||||
* Set RC0 state -- does not matter at this point b/c
|
||||
* we disable RC states entirely.
|
||||
*/
|
||||
write_post<RC_CTRL1::Rc_state>(0);
|
||||
|
||||
write<RC_CTRL0>(0);
|
||||
write<RP_FREQ_NORMAL::Turbo_disable>(1);
|
||||
write<RP_CTRL>(0);
|
||||
}
|
||||
|
203
repos/os/src/driver/gpu/intel/rc6.h
Normal file
203
repos/os/src/driver/gpu/intel/rc6.h
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* \brief RC6 power stage based on the Linux driver
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2025-03-11
|
||||
*
|
||||
* Enable RC6, there is no support for deep and deep deep. When enabled low
|
||||
* voltage mode is entered when the GPU goes idle for CHECK_INACTIVEus while
|
||||
* power is restored when new workloads are received via 'progress'.
|
||||
*
|
||||
* Note: Bspec = Behavioral Specification
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#ifndef _RC6_H_
|
||||
#define _RC6_H_
|
||||
|
||||
#include <mmio.h>
|
||||
|
||||
namespace Igd {
|
||||
class Rc6;
|
||||
}
|
||||
|
||||
|
||||
class Igd::Rc6
|
||||
{
|
||||
private:
|
||||
|
||||
/* every 2s */
|
||||
enum { CHECK_INACTIVE = 2'000'000 };
|
||||
|
||||
Genode::Env &_env;
|
||||
Mmio &_mmio;
|
||||
|
||||
Timer::Connection _rc6_watchdog { _env };
|
||||
|
||||
Mmio::RC_CTRL0::access_t _ctrl { 0 };
|
||||
|
||||
Genode::Signal_handler<Rc6> _timer_sigh { _env.ep(), *this,
|
||||
&Rc6::_handle_timer };
|
||||
|
||||
bool _progress { false };
|
||||
bool _suspended { false };
|
||||
|
||||
/* NEEDS_RC6_CTX_CORRUPTION_WA(i915)) */
|
||||
bool _pctx_corrupted()
|
||||
{
|
||||
if (_mmio.generation() != 9) return false;
|
||||
if (_mmio.read<Mmio::GEN8_RC6_CTX_INFO>()) return false;
|
||||
|
||||
Genode::warning("RC6 context corruption, disabling RC6");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* handles render engine only */
|
||||
void _gen9_enable()
|
||||
{
|
||||
if (_mmio.skylake()) {
|
||||
/*
|
||||
* WaRsDoubleRc6WrlWithCoarsePowerGating:skl Doubling WRL only
|
||||
* when CPG is enabled
|
||||
*/
|
||||
_mmio.write<Mmio::RC_WAKE_RATE_LIMIT::Rc6>(108);
|
||||
} else
|
||||
_mmio.write<Mmio::RC_WAKE_RATE_LIMIT::Rc6>(54);
|
||||
|
||||
_mmio.write<Mmio::RC_EVALUATION_INTERVAL>(125000); /* 12500 * 1280ns */
|
||||
_mmio.write<Mmio::RC_IDLE_HYSTERSIS>(25); /* 25 * 1280ns */
|
||||
_mmio.write<Mmio::RING_MAX_IDLE>(10);
|
||||
_mmio.write<Mmio::RC_WAKE_HYSTERSIS>(0);
|
||||
_mmio.write<Mmio::RC_PROMO_TIME>(37500); /* 37.5/125ms per EI */
|
||||
|
||||
|
||||
/* 2c: Program Coarse Power Gating Policies */
|
||||
_mmio.write<Mmio::GEN9_RENDER_PG_IDLE_HYSTERESIS>(250);
|
||||
|
||||
/* 3a: Enable RC6 */
|
||||
/*
|
||||
* WaRsDisableCoarsePowerGating:skl,cnl
|
||||
* - Render/Media PG need to be disabled with RC6.
|
||||
*
|
||||
* actually just for gt3 and gt4 not for gt2, but we cannot distinguish
|
||||
* that right now
|
||||
* if (!_mmio.skylake())
|
||||
* _mmio.write<Mmio::GEN9_PG_ENABLE::Gen9_render_pg_enable>(1);
|
||||
*/
|
||||
|
||||
Mmio::RC_CTRL0::Ei_hw::set(_ctrl, 1);
|
||||
Mmio::RC_CTRL0::Rc6_enable::set(_ctrl, 1);
|
||||
Mmio::RC_CTRL0::Hw_control_enable::set(_ctrl, 1);
|
||||
}
|
||||
|
||||
/* handles render engine only */
|
||||
void _gen11_enable()
|
||||
{
|
||||
/* 2b: Program RC6 thresholds.*/
|
||||
_mmio.write<Mmio::RC_WAKE_RATE_LIMIT::Rc6>(54);
|
||||
_mmio.write<Mmio::RC_EVALUATION_INTERVAL>(125000); /* 12500 * 1280ns */
|
||||
_mmio.write<Mmio::RC_IDLE_HYSTERSIS>(25); /* 25 * 1280ns */
|
||||
_mmio.write<Mmio::RING_MAX_IDLE>(10);
|
||||
_mmio.write<Mmio::RC_WAKE_HYSTERSIS>(0);
|
||||
_mmio.write<Mmio::RC_PROMO_TIME>(50000); /* 50/125ms per EI */
|
||||
|
||||
/* 2c: Program Coarse Power Gating Policies */
|
||||
_mmio.write<Mmio::GEN9_RENDER_PG_IDLE_HYSTERESIS>(60);
|
||||
|
||||
/* 3a: Enable RC6 */
|
||||
/*
|
||||
* power-gating, special case for Meteor Lake omitted, power-gating for
|
||||
* VCS omitted
|
||||
*/
|
||||
_mmio.write<Mmio::GEN9_PG_ENABLE::Gen9_render_pg_enable>(1);
|
||||
|
||||
/*
|
||||
* Rc6
|
||||
*/
|
||||
_mmio.write<Mmio::RC_CTRL1::Target>(4); /* target RC6 */
|
||||
Mmio::RC_CTRL0::Ei_hw::set(_ctrl, 1);
|
||||
Mmio::RC_CTRL0::Rc6_enable::set(_ctrl, 1);
|
||||
Mmio::RC_CTRL0::Hw_control_enable::set(_ctrl, 1);
|
||||
}
|
||||
|
||||
void _handle_timer()
|
||||
{
|
||||
if (!_progress) {
|
||||
_enter_rc6();
|
||||
return;
|
||||
}
|
||||
|
||||
_progress = false;
|
||||
_rc6_watchdog.trigger_once(CHECK_INACTIVE);
|
||||
}
|
||||
|
||||
void _enter_rc6()
|
||||
{
|
||||
/* disable HW timers and enter RC6 */
|
||||
_mmio.write<Mmio::RC_CTRL0>(0);
|
||||
_mmio.write<Mmio::RC_CTRL0::Rc6_enable>(1);
|
||||
_mmio.write<Mmio::RC_CTRL1::Target>(4); /* target RC6 */
|
||||
|
||||
_suspended = true;
|
||||
}
|
||||
|
||||
void _resume()
|
||||
{
|
||||
_mmio.write<Mmio::RC_CTRL0>(_ctrl);
|
||||
|
||||
if (_mmio.generation() == 9)
|
||||
_mmio.write<Mmio::RC_CTRL1::Target>(0);
|
||||
|
||||
_rc6_watchdog.trigger_once(CHECK_INACTIVE);
|
||||
|
||||
_suspended = false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Rc6(Genode::Env &env, Mmio &mmio)
|
||||
: _env(env), _mmio(mmio)
|
||||
{
|
||||
_rc6_watchdog.sigh(_timer_sigh);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (_mmio.generation() >= 9)
|
||||
_mmio.write<Mmio::GEN9_PG_ENABLE>(0);
|
||||
|
||||
_mmio.write<Mmio::RC_CTRL0::Rc6_enable>(0);
|
||||
_mmio.write<Mmio::RC_CTRL0>(0);
|
||||
_mmio.write<Mmio::RP_CTRL>(0);
|
||||
_mmio.write_post<Mmio::RC_CTRL1::Target>(0);
|
||||
}
|
||||
|
||||
void enable()
|
||||
{
|
||||
clear();
|
||||
|
||||
if (_mmio.generation() >= 11) {
|
||||
_gen11_enable();
|
||||
}
|
||||
else if (_mmio.generation() >= 9) {
|
||||
_gen9_enable();
|
||||
if (_pctx_corrupted()) return;
|
||||
}
|
||||
else return;
|
||||
|
||||
_resume();
|
||||
}
|
||||
|
||||
void progress()
|
||||
{
|
||||
if (_suspended) _resume();
|
||||
if (!_progress) _progress = true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _RC6_H_ */
|
Loading…
x
Reference in New Issue
Block a user