gpu_drv: use generic platform API

Ref genodelabs/genode#4578
This commit is contained in:
Stefan Kalkowski 2022-09-13 14:27:24 +02:00 committed by Christian Helmuth
parent 03cec5cdd7
commit 250275fbfb
6 changed files with 385 additions and 735 deletions

View File

@ -21,10 +21,7 @@
#include <mmio.h>
namespace Igd {
struct Ggtt;
}
namespace Igd { struct Ggtt; }
/*
* Global Graphics Translation Table
@ -57,6 +54,12 @@ class Igd::Ggtt
private:
/*
* Noncopyable
*/
Ggtt(Ggtt const &);
Ggtt &operator = (Ggtt const &);
/*
* IHD-OS-BDW-Vol 5-11.15 p. 44
*/
@ -113,7 +116,8 @@ class Igd::Ggtt
uint64_t *_entries;
addr_t const _scratch_page;
Platform::Dma_buffer _scratch_page;
size_t const _aperture_size;
size_t const _aperture_entries;
@ -133,6 +137,7 @@ class Igd::Ggtt
/**
* Constructor
*
* \param platform reference to Platform::Connection object
* \param mmio reference to Igd::Mmio object
* \param base virtual base address of GGTT start
* \param size size of GGTT in bytes
@ -140,9 +145,8 @@ class Igd::Ggtt
* \param scratch_page physical address of the scratch page
* \param fb_size size of the framebuffer region in the GTT in bytes
*/
Ggtt(Igd::Mmio &mmio, addr_t base, size_t size,
size_t aperture_size, addr_t scratch_page,
size_t fb_size)
Ggtt(Platform::Connection & platform, Igd::Mmio &mmio,
addr_t base, size_t size, size_t aperture_size, size_t fb_size)
:
_mmio(mmio),
_base(base),
@ -150,7 +154,7 @@ class Igd::Ggtt
/* make the last entry/page unavailable */
_num_entries((_size / 8) - 1),
_entries((uint64_t*)_base),
_scratch_page(scratch_page),
_scratch_page(platform, PAGE_SIZE, Genode::UNCACHED),
_aperture_size(aperture_size),
_aperture_entries(_aperture_size / PAGE_SIZE)
{
@ -160,7 +164,7 @@ class Igd::Ggtt
_space.set(i);
}
for (size_t i = fb_entries; i < _num_entries; i++) {
_insert_pte(_scratch_page, i);
_insert_pte(_scratch_page.dma_addr(), i);
}
}
@ -197,7 +201,7 @@ class Igd::Ggtt
}
_space.clear(offset);
_insert_pte(_scratch_page, offset);
_insert_pte(_scratch_page.dma_addr(), offset);
}
/**
@ -270,13 +274,6 @@ class Igd::Ggtt
*/
size_t entries() const { return _num_entries; }
/**
* Get scratch page address
*
* \return physical address of the scratch page
*/
addr_t scratch_page() const { return _scratch_page; }
/*********************
** Debug interface **
*********************/
@ -290,7 +287,7 @@ class Igd::Ggtt
log("GGTT");
log(" vaddr:", Hex(_base), " size:", Hex(_size), " entries:", _num_entries,
" used:", _space.used(), " aperture_size:", Hex(_aperture_size));
log(" scratch_page:", Hex(_scratch_page), " (PA)");
log(" scratch_page:", Hex(_scratch_page.dma_addr()), " (PA)");
if (!dump_entries) { return; }

View File

@ -24,10 +24,8 @@
#include <dataspace/client.h>
#include <gpu_session/gpu_session.h>
#include <gpu/info_intel.h>
#include <io_mem_session/connection.h>
#include <irq_session/connection.h>
#include <legacy/x86/platform_device/client.h>
#include <legacy/x86/platform_session/connection.h>
#include <platform_session/dma_buffer.h>
#include <platform_session/device.h>
#include <root/component.h>
#include <timer_session/connection.h>
#include <util/fifo.h>
@ -42,12 +40,10 @@
#include <ggtt.h>
#include <context.h>
#include <context_descriptor.h>
#include <resources.h>
#include <platform_session.h>
#include <ring_buffer.h>
#include <workarounds.h>
using namespace Genode;
@ -78,18 +74,21 @@ struct Igd::Device
struct Out_of_ram : Genode::Exception { };
struct Could_not_map_buffer : Genode::Exception { };
Env &_env;
Allocator &_md_alloc;
enum { WATCHDOG_TIMEOUT = 1*1000*1000, };
Env & _env;
Allocator & _md_alloc;
Platform::Connection & _platform;
Rm_connection & _rm;
Igd::Mmio & _mmio;
Platform::Device::Mmio & _gmadr;
uint8_t _gmch_ctl;
Timer::Connection _timer { _env };
/*********
** PCI **
*********/
Resources &_resources;
Platform::Device_client &_device { _resources.gpu_client() };
struct Pci_backend_alloc : Utils::Backend_alloc
{
Platform::Connection &_pci;
@ -98,7 +97,8 @@ struct Igd::Device
Ram_dataspace_capability alloc(size_t size) override
{
return _pci.with_upgrade([&] () {
return _pci.retry_with_upgrade(Genode::Ram_quota{PAGE_SIZE},
Genode::Cap_quota{8}, [&] () {
return _pci.alloc_dma_buffer(size, Genode::UNCACHED); });
}
@ -117,7 +117,7 @@ struct Igd::Device
return _pci.dma_addr(ds_cap);
}
} _pci_backend_alloc { _resources.platform() };
} _pci_backend_alloc { _platform };
Device_info _info { };
@ -127,41 +127,9 @@ struct Igd::Device
Gpu::Info_intel::Eu_total _eus { };
Gpu::Info_intel::Subslices _subslices { };
void _pci_info(String<64> const &descr) const
{
using namespace Genode;
uint16_t const vendor_id = _device.vendor_id();
uint16_t const device_id = _device.device_id();
uint8_t bus = 0, dev = 0, fun = 0;
_device.bus_address(&bus, &dev, &fun);
log("Found: '", descr, "' gen=", _info.generation,
" rev=", _revision.value, " ",
"[", Hex(vendor_id), ":", Hex(device_id), "] (",
Hex(bus, Hex::OMIT_PREFIX), ":",
Hex(dev, Hex::OMIT_PREFIX), ".",
Hex(fun, Hex::OMIT_PREFIX), ")");
enum { PCI_NUM_RES = 6 };
for (int i = 0; i < PCI_NUM_RES; i++) {
using Resource = Platform::Device::Resource;
Resource const resource = _device.resource(i);
if (resource.type() == Resource::INVALID) { continue; }
log(" Resource ", i, " "
"(", resource.type() == Resource::IO ? "I/O" : "MEM", "): "
"base=", Genode::Hex(resource.base()), " "
"size=", Genode::Hex(resource.size()), " ",
(resource.prefetchable() ? "prefetchable" : ""));
}
}
bool _supported(Xml_node &supported)
bool _supported(Xml_node & supported,
uint16_t dev_id,
uint8_t rev_id)
{
bool found = false;
@ -173,7 +141,7 @@ struct Igd::Device
uint16_t const device = node.attribute_value("device", 0U);
uint8_t const generation = node.attribute_value("generation", 0U);
String<16> const platform = node.attribute_value("platform", String<16>("unknown"));
String<64> const desc = node.attribute_value("description", String<64>("unknown"));
//String<64> const desc = node.attribute_value("description", String<64>("unknown"));
if (vendor != 0x8086 /* Intel */ || generation < 8)
return;
@ -188,10 +156,9 @@ struct Igd::Device
if (info.platform == Igd::Device_info::Platform::UNKNOWN)
return;
if (info.id == _device.device_id()) {
if (info.id == dev_id) {
_info = info;
_revision.value = _resources.config_read<uint8_t>(8);
_pci_info(desc.string());
_revision.value = rev_id;
found = true;
return;
@ -218,13 +185,40 @@ struct Igd::Device
** GGTT **
**********/
Genode::Constructible<Igd::Ggtt> _ggtt { };
/**********
** MMIO **
**********/
size_t _ggtt_size()
{
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1068
*/
struct MGGC_0_2_0_PCI : Genode::Register<16>
{
struct Graphics_mode_select : Bitfield<8, 8> { };
struct Gtt_graphics_memory_size : Bitfield<6, 2> { };
struct Versatile_acceleration_mode_enable : Bitfield<3, 1> { };
struct Igd_vga_disable : Bitfield<2, 1> { };
struct Ggc_lock : Bitfield<0, 1> { };
};
enum { PCI_GMCH_CTL = 0x50, };
MGGC_0_2_0_PCI::access_t v = _gmch_ctl;
Igd::Mmio &_mmio { _resources.mmio() };
{
log("MGGC_0_2_0_PCI");
log(" Graphics_mode_select: ", Hex(MGGC_0_2_0_PCI::Graphics_mode_select::get(v)));
log(" Gtt_graphics_memory_size: ", Hex(MGGC_0_2_0_PCI::Gtt_graphics_memory_size::get(v)));
log(" Versatile_acceleration_mode_enable: ", Hex(MGGC_0_2_0_PCI::Versatile_acceleration_mode_enable::get(v)));
log(" Igd_vga_disable: ", Hex(MGGC_0_2_0_PCI::Igd_vga_disable::get(v)));
log(" Ggc_lock: ", Hex(MGGC_0_2_0_PCI::Ggc_lock::get(v)));
}
return (1u << MGGC_0_2_0_PCI::Gtt_graphics_memory_size::get(v)) << 20;
}
addr_t _ggtt_base() const {
return _mmio.base() + (_mmio.size() / 2); }
Igd::Ggtt _ggtt { _platform, _mmio, _ggtt_base(),
_ggtt_size(), _gmadr.size(), APERTURE_RESERVED };
/************
** MEMORY **
@ -250,14 +244,17 @@ struct Igd::Device
struct Ggtt_mmio_mapping : Ggtt::Mapping
{
Region_map_client _rm;
Region_map_client _rmc;
Ggtt_mmio_mapping(Resources &resources, Ggtt::Offset offset, size_t size)
Ggtt_mmio_mapping(Rm_connection & rm,
Dataspace_capability cap,
Ggtt::Offset offset,
size_t size)
:
_rm(resources.rm().create(size))
_rmc(rm.create(size))
{
_rm.attach_at(resources.gmadr_ds(), 0, size, offset * PAGE_SIZE);
Ggtt::Mapping::cap = _rm.dataspace();
_rmc.attach_at(cap, 0, size, offset * PAGE_SIZE);
Ggtt::Mapping::cap = _rmc.dataspace();
Ggtt::Mapping::offset = offset;
}
@ -280,10 +277,10 @@ struct Igd::Device
*/
Genode::Registered<Ggtt_mmio_mapping> *mem = new (&alloc)
Genode::Registered<Ggtt_mmio_mapping>(_ggtt_mmio_mapping_registry,
_resources, offset, size);
_rm, _gmadr.cap(), offset, size);
for (size_t i = 0; i < size; i += PAGE_SIZE) {
addr_t const pa = phys_addr + i;
_ggtt->insert_pte(pa, offset + (i / PAGE_SIZE));
_ggtt.insert_pte(pa, offset + (i / PAGE_SIZE));
}
return *mem;
@ -296,7 +293,7 @@ struct Igd::Device
auto lookup_and_free = [&] (Ggtt_mmio_mapping &m) {
if (!(m.cap == cap)) { return; }
_ggtt->remove_pte_range(m.offset, num);
_ggtt.remove_pte_range(m.offset, num);
Genode::destroy(&alloc, &m);
};
@ -420,7 +417,7 @@ struct Igd::Device
:
device(device),
alloc(alloc),
offset(device._ggtt->find_free(pages, true)),
offset(device._ggtt.find_free(pages, true)),
skip(skip_pages),
ram_ds(device, device._alloc_dataspace(pages * PAGE_SIZE)),
map(device, *this, alloc),
@ -922,7 +919,7 @@ struct Igd::Device
_submit_execlist(rcs);
_active_vgpu = gpu;
_resources.timer().trigger_once(WATCHDOG_TIMEOUT);
_timer.trigger_once(WATCHDOG_TIMEOUT);
}
/**********
@ -1030,56 +1027,28 @@ struct Igd::Device
/**
* Constructor
*/
Device(Genode::Env &env,
Genode::Allocator &alloc,
Resources &resources,
Genode::Xml_node &supported)
Device(Genode::Env & env,
Genode::Allocator & alloc,
Platform::Connection & platform,
Rm_connection & rm,
Igd::Mmio & mmio,
Platform::Device::Mmio & gmadr,
Genode::Xml_node & supported,
uint16_t device_id,
uint8_t revision,
uint8_t gmch_ctl)
:
_env(env), _md_alloc(alloc), _resources(resources)
_env(env), _md_alloc(alloc), _platform(platform), _rm(rm),
_mmio(mmio), _gmadr(gmadr), _gmch_ctl(gmch_ctl)
{
using namespace Genode;
if (!_supported(supported)) { throw Unsupported_device(); }
if (!_supported(supported, device_id, revision))
throw Unsupported_device();
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1068
*/
struct MGGC_0_2_0_PCI : Genode::Register<16>
{
struct Graphics_mode_select : Bitfield<8, 8> { };
struct Gtt_graphics_memory_size : Bitfield<6, 2> { };
struct Versatile_acceleration_mode_enable : Bitfield<3, 1> { };
struct Igd_vga_disable : Bitfield<2, 1> { };
struct Ggc_lock : Bitfield<0, 1> { };
};
enum { PCI_GMCH_CTL = 0x50, };
MGGC_0_2_0_PCI::access_t v = _resources.config_read<uint16_t>(PCI_GMCH_CTL);
_ggtt.dump();
{
log("MGGC_0_2_0_PCI");
log(" Graphics_mode_select: ", Hex(MGGC_0_2_0_PCI::Graphics_mode_select::get(v)));
log(" Gtt_graphics_memory_size: ", Hex(MGGC_0_2_0_PCI::Gtt_graphics_memory_size::get(v)));
log(" Versatile_acceleration_mode_enable: ", Hex(MGGC_0_2_0_PCI::Versatile_acceleration_mode_enable::get(v)));
log(" Igd_vga_disable: ", Hex(MGGC_0_2_0_PCI::Igd_vga_disable::get(v)));
log(" Ggc_lock: ", Hex(MGGC_0_2_0_PCI::Ggc_lock::get(v)));
}
/* map PCI resources */
addr_t gttmmadr_base = _resources.map_gttmmadr();
/* GGTT */
addr_t const scratch_page = _resources.scratch_page();
/* reserverd size for framebuffer */
size_t const aperture_reserved = resources.gmadr_platform_size();
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->dump();
_vgpu_avail = (gmadr_size - aperture_reserved) / Vgpu::APERTURE_SIZE;
_vgpu_avail = (_gmadr.size() - APERTURE_RESERVED) / Vgpu::APERTURE_SIZE;
_device_reset_and_init();
@ -1121,7 +1090,7 @@ struct Igd::Device
/* apply generation specific workarounds */
apply_workarounds(_mmio, _info.generation);
_resources.timer().sigh(_watchdog_timeout_sigh);
_timer.sigh(_watchdog_timeout_sigh);
}
void _clock_gating()
@ -1363,7 +1332,7 @@ struct Igd::Device
size_t const size = Genode::Dataspace_client(cap).size();
size_t const num = size / PAGE_SIZE;
Ggtt::Offset const offset = _ggtt->find_free(num, aperture);
Ggtt::Offset const offset = _ggtt.find_free(num, aperture);
return map_dataspace_ggtt(guard, cap, offset);
}
@ -1464,8 +1433,6 @@ struct Igd::Device
void enable_master_irq() { _mmio.enable_master_irq(); }
Resources &resources() { return _resources; }
private:
/*
@ -2146,31 +2113,31 @@ class Gpu::Root : public Gpu::Root_component
};
struct Main
struct Initialization_failed : Genode::Exception { };
struct Main : Irq_ack_handler, Gpu_reset_handler
{
Genode::Env &_env;
/*********
** Gpu **
*********/
Genode::Sliced_heap _root_heap { _env.ram(), _env.rm() };
Env & _env;
Sliced_heap _root_heap { _env.ram(), _env.rm() };
Gpu::Root _gpu_root { _env, _root_heap };
Genode::Attached_rom_dataspace _config_rom { _env, "config" };
Attached_rom_dataspace _config_rom { _env, "config" };
Heap _md_alloc { _env.ram(), _env.rm() };
Platform::Connection _platform { _env };
Platform::Device _device { _platform };
Platform::Device::Irq _irq { _device };
Igd::Mmio _mmio { _device, _env };
Platform::Device::Mmio _gmadr { _device, { 1 } };
Rm_connection _rm { _env };
Io_signal_handler<Main> _irq_dispatcher { _env.ep(), *this,
&Main::handle_irq };
Signal_handler<Main> _config_sigh { _env.ep(), *this,
&Main::_handle_config_update };
Genode::Heap _device_md_alloc { _env.ram(), _env.rm() };
Genode::Constructible<Igd::Device> _device { };
Igd::Resources _gpu_resources { _env, _device_md_alloc,
*this, &Main::ack_irq };
Platform::Root _platform_root { _env, _md_alloc, _platform, *this, *this,
_mmio, _gmadr, _rm };
Genode::Irq_session_client _irq { _gpu_resources.gpu_client().irq(0) };
Genode::Signal_handler<Main> _irq_dispatcher {
_env.ep(), *this, &Main::handle_irq };
Constructible<Platform::Root> _platform_root { };
Genode::Signal_handler<Main> _config_sigh {
_env.ep(), *this, &Main::_handle_config_update };
Genode::Constructible<Igd::Device> _igd_device { };
Main(Genode::Env &env)
:
@ -2180,29 +2147,33 @@ struct Main
/* IRQ */
_irq.sigh(_irq_dispatcher);
_irq.ack_irq();
/* GPU */
_handle_config_update();
/* platform service */
_platform_root.construct(_env, _device_md_alloc, _gpu_resources);
}
void _handle_config_update()
void _create_device()
{
_config_rom.update();
uint16_t device_id;
uint8_t revision;
uint8_t gmch_ctl;
if (!_config_rom.valid()) { return; }
if (_device.constructed()) {
Genode::log("gpu device already initialized - ignore");
return;
}
_platform.update();
_platform.with_xml([&] (Xml_node node) {
node.with_optional_sub_node("device", [&] (Xml_node node) {
node.with_optional_sub_node("pci-config", [&] (Xml_node node) {
device_id = node.attribute_value("device_id", 0U);
revision = node.attribute_value("revision", 0U);
gmch_ctl = node.attribute_value("intel_gmch_control", 0U);
});
});
});
try {
_device.construct(_env, _device_md_alloc, _gpu_resources, _config_rom.xml());
_gpu_root.manage(*_device);
_igd_device.construct(_env, _md_alloc, _platform, _rm, _mmio,
_gmadr, _config_rom.xml(), device_id,
revision, gmch_ctl);
_gpu_root.manage(*_igd_device);
_env.parent().announce(_env.ep().manage(_gpu_root));
} catch (Igd::Device::Unsupported_device) {
Genode::warning("No supported Intel GPU detected - no GPU service");
@ -2211,14 +2182,28 @@ struct Main
}
}
void _handle_config_update()
{
_config_rom.update();
if (!_config_rom.valid()) { return; }
if (_igd_device.constructed()) {
Genode::log("gpu device already initialized - ignore");
return;
}
_create_device();
}
void handle_irq()
{
unsigned master = 0;
if (_device.constructed())
master = _device->handle_irq();
if (_igd_device.constructed())
master = _igd_device->handle_irq();
/* GPU not present forward all IRQs to platform client */
else {
_platform_root->handle_irq();
_platform_root.handle_irq();
return;
}
@ -2228,19 +2213,25 @@ struct Main
*/
using Master = Igd::Mmio::MASTER_INT_CTL;
if (Master::De_interrupts_pending::get(master) &&
(_platform_root->handle_irq()))
(_platform_root.handle_irq()))
return;
ack_irq();
}
void ack_irq()
void ack_irq() override
{
if (_device.constructed()) {
_device->enable_master_irq();
if (_igd_device.constructed()) {
_igd_device->enable_master_irq();
}
_irq.ack_irq();
_irq.ack();
}
void reset() override
{
addr_t const base = _mmio.base() + (_mmio.size() / 2);
Igd::Ggtt(_platform, _mmio, base, Igd::GTT_RESERVED, 0, 0);
}
};
@ -2250,7 +2241,7 @@ void Component::construct(Genode::Env &env)
static Constructible<Main> main;
try {
main.construct(env);
} catch (Igd::Resources::Initialization_failed) {
} catch (Initialization_failed) {
Genode::warning("Intel GPU resources not found.");
env.parent().exit(0);
}

View File

@ -16,19 +16,17 @@
/* Genode includes */
#include <base/log.h>
#include <util/mmio.h>
#include <platform_session/device.h>
#include <timer_session/connection.h>
/* local includes */
#include <types.h>
namespace Igd {
class Mmio;
}
namespace Igd { class Mmio; }
class Igd::Mmio : public Genode::Mmio
class Igd::Mmio : public Platform::Device::Mmio
{
public:
@ -936,7 +934,13 @@ class Igd::Mmio : public Genode::Mmio
private:
Mmio::Delayer &_delayer;
struct Timer_delayer : Genode::Mmio::Delayer
{
Timer::Connection _timer;
Timer_delayer(Genode::Env & env) : _timer(env) { }
void usleep(uint64_t us) override { _timer.usleep(us); }
} _delayer;
void _fw_reset_gen8()
{
@ -1419,8 +1423,8 @@ class Igd::Mmio : public Genode::Mmio
public:
Mmio(Mmio::Delayer &delayer, addr_t const base)
: Genode::Mmio(base), _delayer(delayer) { }
Mmio(Platform::Device & device, Genode::Env & env)
: Platform::Device::Mmio(device, {0}), _delayer(env) { }
template <typename T>
void write_post(typename T::access_t const value)

View File

@ -11,54 +11,63 @@
* under the terms of the GNU Affero General Public License version 3.
*/
#include <legacy/x86/platform_session/platform_session.h>
#include <region_map/client.h>
#include <rm_session/connection.h>
#include <platform_session/platform_session.h>
#include <types.h>
struct Irq_ack_handler
{
virtual ~Irq_ack_handler() {}
virtual void ack_irq() = 0;
};
struct Gpu_reset_handler
{
virtual ~Gpu_reset_handler() {}
virtual void reset() = 0;
};
namespace Platform {
class Device_component;
class Session_component;
class Io_mem_session_component;
class Io_mem_session_component_gmadr;
class Irq_session_component;
class Root;
using namespace Genode;
class Device_component;
class Session_component;
class Io_mem_session_component;
class Irq_session_component;
class Root;
}
using Range = Platform::Device_interface::Range;
struct Main;
class Platform::Irq_session_component : public Rpc_object<Irq_session>
{
private:
Igd::Resources &_resources;
Irq_ack_handler & _ack_handler;
Signal_context_capability _sigh { };
public:
Irq_session_component(Igd::Resources &resources)
:
_resources(resources)
{ }
Irq_session_component(Irq_ack_handler & ack_handler)
: _ack_handler(ack_handler) { }
void ack_irq() override
{
_resources.ack_irq();
}
void ack_irq() override { _ack_handler.ack_irq(); }
void sigh(Signal_context_capability sigh) override
{
_sigh = sigh;
}
void sigh(Signal_context_capability sigh) override {
_sigh = sigh; }
bool handle_irq()
{
if (!_sigh.valid()) return false;
Signal_transmitter(_sigh).submit();
return true;
}
Info info() override
{
return Info { Info::INVALID, 0, 0 };
}
Info info() override {
return Info { Info::INVALID, 0, 0 }; }
};
@ -66,57 +75,47 @@ class Platform::Io_mem_session_component : public Rpc_object<Io_mem_session>
{
private:
Igd::Resources &_resources;
Io_mem_dataspace_capability _ds_cap;
public:
Io_mem_session_component(Igd::Resources &resources)
:
_resources(resources) { }
Io_mem_session_component(Dataspace_capability cap)
: _ds_cap(static_cap_cast<Io_mem_dataspace>(cap)) { }
Io_mem_dataspace_capability dataspace() override
{
return _resources.gttmmadr_platform_ds();
return _ds_cap;
}
};
class Platform::Io_mem_session_component_gmadr : public Rpc_object<Io_mem_session>
class Platform::Device_component : public Rpc_object<Device_interface,
Device_component>
{
private:
Igd::Resources &_resources;
Env & _env;
Io_mem_session_component _gttmmadr_io;
Range _gttmmadr_range;
Io_mem_session_component _gmadr_io;
Range _gmadr_range;
Irq_session_component _irq;
public:
Io_mem_session_component_gmadr(Igd::Resources &resources)
Device_component(Env & env,
Irq_ack_handler & ack_handler,
Dataspace_capability gttmmadr_ds_cap,
Range gttmmadr_range,
Dataspace_capability gmadr_ds_cap,
Range gmadr_range)
:
_resources(resources) { }
Io_mem_dataspace_capability dataspace() override
{
return _resources.gmadr_platform_ds();
}
};
class Platform::Device_component : public Rpc_object<Device>
{
private:
Env &_env;
Igd::Resources &_resources;
Device_client &_device { _resources.gpu_client() };
Io_mem_session_component _gttmmadr_io { _resources };
Io_mem_session_component_gmadr _gmadr_io { _resources };
Irq_session_component _irq { _resources };
public:
Device_component(Env &env, Igd::Resources &resources)
:
_env(env), _resources(resources)
_env(env),
_gttmmadr_io(gttmmadr_ds_cap),
_gttmmadr_range(gttmmadr_range),
_gmadr_io(gmadr_ds_cap),
_gmadr_range(gmadr_range),
_irq(ack_handler)
{
_env.ep().rpc_ep().manage(&_gttmmadr_io);
_env.ep().rpc_ep().manage(&_gmadr_io);
@ -130,69 +129,31 @@ class Platform::Device_component : public Rpc_object<Device>
_env.ep().rpc_ep().dissolve(&_irq);
}
Irq_session_capability irq(uint8_t) override
Irq_session_capability irq(unsigned)
{
return _irq.cap();
}
Io_mem_session_capability io_mem(uint8_t v_id, Cache /* caching */,
addr_t /* offset */,
size_t /* size */) override
Io_mem_session_capability io_mem(unsigned idx,
Range & range,
Cache /* ignore caching */)
{
if (v_id == 0)
return _gttmmadr_io.cap();
range.start = 0;
if (v_id == 1)
if (idx == 0) {
range.size = _gttmmadr_range.size;
return _gttmmadr_io.cap();
}
if (idx == 1) {
range.size = _gmadr_range.size;
return _gmadr_io.cap();
}
return Io_mem_session_capability();
}
void bus_address(unsigned char *bus, unsigned char *dev,
unsigned char *fn) override
{
_device.bus_address(bus, dev, fn);
}
unsigned short vendor_id() override
{
return _device.vendor_id();
}
unsigned short device_id() override
{
return _device.device_id();
}
unsigned class_code() override
{
return _device.class_code();
}
Resource resource(int resource_id) override
{
/* bar 0 is io mem/gtt */
if (resource_id == 0)
return Resource(_resources.gttmmadr_base(), _resources.gttmmadr_size());
/* bar 2 is GMADR (i.e., aperture) */
if(resource_id == 2)
return Resource(_resources.gmadr_base(), _resources.gmadr_platform_size());
return Resource();
}
unsigned config_read(unsigned char address, Access_size size) override
{
return _device.config_read(address, size);
}
void config_write(unsigned char /* address */, unsigned /* value */,
Access_size/* size */) override
{
}
Io_port_session_capability io_port(uint8_t /* id */) override
Io_port_session_capability io_port_range(unsigned /* id */)
{
Genode::error(__func__, " is not supported");
return Io_port_session_capability();
@ -206,37 +167,47 @@ class Platform::Session_component : public Rpc_object<Session>
{
private:
Env &_env;
Env & _env;
Connection & _platform;
Gpu_reset_handler & _reset_handler;
Heap _heap { _env.ram(), _env.rm() };
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() { }
};
bool _acquired { false };
/*
* track DMA memory allocations so we can free them at session
* destruction
*/
Registry<Registered<Dma_cap>> _dma_registry { };
struct Buffer : Dma_buffer, Registry<Buffer>::Element
{
Buffer(Registry<Buffer> & registry,
Connection & platform,
size_t size,
Cache cache)
:
Dma_buffer(platform, size, cache),
Registry<Buffer>::Element(registry, *this) {}
};
Registry<Buffer> _dma_registry { };
public:
Session_component(Env &env, Igd::Resources &resources)
using Device_capability = Capability<Platform::Device_interface>;
Session_component(Env & env,
Connection & platform,
Irq_ack_handler & ack_handler,
Gpu_reset_handler & reset_handler,
Dataspace_capability gttmmadr_ds_cap,
Range gttmmadr_range,
Dataspace_capability gmadr_ds_cap,
Range gmadr_range)
:
_env(env),
_device_component(env, resources),
_platform(resources.platform()),
_bridge(resources.host_bridge_cap()),
_resources(resources)
_platform(platform),
_reset_handler(reset_handler),
_device_component(env, ack_handler, gttmmadr_ds_cap, gttmmadr_range,
gmadr_ds_cap, gmadr_range)
{
_env.ep().rpc_ep().manage(&_device_component);
}
@ -246,72 +217,63 @@ class Platform::Session_component : public Rpc_object<Session>
_env.ep().rpc_ep().dissolve(&_device_component);
/* clear ggtt */
_resources.gtt_platform_reset();
_reset_handler.reset();
/* free DMA allocations */
_dma_registry.for_each([&](Dma_cap &dma) {
_platform.free_dma_buffer(dma.cap);
destroy(&_resources.heap(), &dma);
_dma_registry.for_each([&](Buffer & dma) {
destroy(_heap, &dma);
});
}
Device_capability first_device(unsigned device_class, unsigned) override
Device_capability acquire_single_device() override
{
if (device_class == _resources.isa_bridge_class())
return _resources.isa_bridge_cap();
return _bridge;
}
Device_capability next_device(Device_capability prev_device,
unsigned, unsigned) override
{
if (!prev_device.valid())
return _bridge;
if (prev_device == _bridge)
return _device_component.cap();
if (prev_device == _device_component.cap())
return _resources.isa_bridge_cap();
if (_acquired)
return Device_capability();
_acquired = true;
return _device_component.cap();
}
void release_device(Device_capability) override
{
return;
_acquired = false;
}
Device_capability device(Device_name const & /* string */) override
Device_capability acquire_device(Device_name const & /* string */) override
{
Genode::error(__func__, " is not supported");
return Device_capability();
return acquire_single_device();
}
Ram_dataspace_capability alloc_dma_buffer(size_t size, Cache cache) override
{
Ram_dataspace_capability cap = _platform.alloc_dma_buffer(size, cache);
new (&_resources.heap()) Registered<Dma_cap>(_dma_registry, cap);
return cap;
Buffer & db = *(new (_heap)
Buffer(_dma_registry, _platform, size, cache));
return static_cap_cast<Ram_dataspace>(db.cap());
}
void free_dma_buffer(Ram_dataspace_capability cap) override
{
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);
_dma_registry.for_each([&](Buffer & db) {
if ((db.cap() == cap) == false) return;
destroy(_heap, &db);
});
}
addr_t dma_addr(Ram_dataspace_capability cap) override
{
return _platform.dma_addr(cap);
addr_t ret = 0UL;
_dma_registry.for_each([&](Buffer & db) {
if ((db.cap() == cap) == false) return;
ret = db.dma_addr();
});
return ret;
}
Rom_session_capability devices_rom() override {
return _platform.devices_rom(); }
bool handle_irq() { return _device_component.handle_irq(); }
};
@ -320,23 +282,83 @@ class Platform::Root : public Root_component<Session_component, Genode::Single_c
{
private:
Env &_env;
Env & _env;
Connection & _platform;
Irq_ack_handler & _ack_handler;
Gpu_reset_handler & _reset_handler;
Region_map_client _gttmmadr_rm;
Range _gttmmadr_range;
Region_map_client _gmadr_rm;
Range _gmadr_range;
Constructible<Session_component> _session { };
Igd::Resources &_resources;
public:
Root(Env &env, Allocator &md_alloc, Igd::Resources &resources)
Root(Env & env,
Allocator & md_alloc,
Connection & platform,
Irq_ack_handler & ack_handler,
Gpu_reset_handler & reset_handler,
Igd::Mmio & mmio,
Device::Mmio & gmadr,
Rm_connection & rm)
:
Root_component<Session_component, Genode::Single_client>(&env.ep().rpc_ep(), &md_alloc),
_env(env), _resources(resources)
Root_component<Session_component,
Genode::Single_client>(&env.ep().rpc_ep(), &md_alloc),
_env(env),
_platform(platform),
_ack_handler(ack_handler),
_reset_handler(reset_handler),
_gttmmadr_rm(rm.create(mmio.size())),
_gttmmadr_range{1<<30, mmio.size()},
_gmadr_rm(rm.create(Igd::APERTURE_RESERVED)),
_gmadr_range{1<<29, gmadr.size()}
{
using namespace Igd;
/********************************
** Prepare managed dataspaces **
********************************/
/* GTT starts at half of the mmio memory */
size_t const gttm_half_size = mmio.size() / 2;
off_t const gtt_offset = gttm_half_size;
if (gttm_half_size < GTT_RESERVED) {
Genode::error("GTTM size too small");
return;
}
/* attach actual iomem + reserved */
_gttmmadr_rm.attach_at(mmio.cap(), 0, gtt_offset);
/* attach beginning of GTT */
_gttmmadr_rm.attach_at(mmio.cap(), gtt_offset,
GTT_RESERVED, gtt_offset);
/* attach the rest of the GTT as dummy RAM */
Genode::Ram_dataspace_capability dummmy_gtt_ds {
_env.ram().alloc(PAGE_SIZE) };
size_t remainder = gttm_half_size - GTT_RESERVED;
for (off_t offset = gtt_offset + GTT_RESERVED;
remainder > 0;
offset += PAGE_SIZE, remainder -= PAGE_SIZE) {
rm.retry_with_upgrade(Genode::Ram_quota{PAGE_SIZE},
Genode::Cap_quota{8}, [&]() {
_gttmmadr_rm.attach_at(dummmy_gtt_ds, offset, PAGE_SIZE); });
}
_gmadr_rm.attach_at(gmadr.cap(), 0, APERTURE_RESERVED);
env.parent().announce(env.ep().manage(*this));
}
Session_component *_create_session(char const * /* args */) override
{
_session.construct(_env, _resources);
_session.construct(_env, _platform, _ack_handler, _reset_handler,
_gttmmadr_rm.dataspace(), _gttmmadr_range,
_gmadr_rm.dataspace(), _gmadr_range);
return &*_session;
}
@ -344,7 +366,7 @@ class Platform::Root : public Root_component<Session_component, Genode::Single_c
void _upgrade_session(Session_component *, const char *args) override
{
if (!_session.constructed()) return;
_resources.platform().upgrade({ ram_quota_from_args(args),
_platform.upgrade({ ram_quota_from_args(args),
cap_quota_from_args(args) });
}

View File

@ -1,370 +0,0 @@
/*
* \brief GPU resource handling
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2021-07-16
*/
/*
* Copyright (C) 2021 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.
*/
#include <region_map/client.h>
#include <rm_session/connection.h>
namespace Igd {
class Resources;
}
struct Main;
class Igd::Resources : Genode::Noncopyable
{
public:
struct Initialization_failed : Genode::Exception { };
private:
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;
using Dataspace_capability = Genode::Dataspace_capability;
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;
void (Main::*_ack_irq) ();
/* platform session */
Platform::Connection _platform { _env };
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 + ggtt */
Platform::Device::Resource _gttmmadr { };
Io_mem_dataspace_capability _gttmmadr_ds { };
Genode::Io_mem_session_capability _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 {
_platform.dma_addr(_scratch_page_ds) };
/* aperture */
enum {
/* reserved aperture for platform service */
APERTURE_RESERVED = 64u<<20,
/* reserved GTT for platform service, GTT entry is 8 byte */
GTT_RESERVED = (APERTURE_RESERVED/PAGE_SIZE) * 8,
};
Genode::Rm_connection _rm_connection { _env };
Platform::Device::Resource _gmadr { };
Io_mem_dataspace_capability _gmadr_ds { };
Genode::Io_mem_session_capability _gmadr_io { };
Genode::Region_map_client _gmadr_rm { _rm_connection.create(APERTURE_RESERVED) };
/* managed dataspace for local platform service */
Genode::Constructible<Genode::Region_map_client> _gttmmadr_rm { };
void _create_gttmmadr_rm()
{
using off_t = Genode::off_t;
size_t const gttm_half_size = gttmmadr_size() / 2;
/* GTT starts at half of the mmio memory */
off_t const gtt_offset = gttm_half_size;
if (gttm_half_size < GTT_RESERVED) {
Genode::error("GTTM size too small");
return;
}
_gttmmadr_rm.construct(_rm_connection.create((gttmmadr_size())));
/* attach actual iomem + reserved */
_gttmmadr_rm->attach_at(_gttmmadr_ds, 0, gtt_offset);
/* attach beginning of GTT */
_gttmmadr_rm->attach_at(_gttmmadr_ds, gtt_offset, GTT_RESERVED, gtt_offset);
/* attach the rest of the GTT as dummy RAM */
Genode::Ram_dataspace_capability dummmy_gtt_ds { _env.ram().alloc(PAGE_SIZE) };
size_t remainder = gttm_half_size - GTT_RESERVED;
for (off_t offset = gtt_offset + GTT_RESERVED;
remainder > 0;
offset += PAGE_SIZE, remainder -= PAGE_SIZE) {
_rm_connection.retry_with_upgrade(Genode::Ram_quota{4096},
Genode::Cap_quota{8}, [&]() {
_gttmmadr_rm->attach_at(dummmy_gtt_ds, offset, PAGE_SIZE);
});
}
}
/*********
** Pci **
*********/
void _find_devices()
{
using namespace Platform;
auto _scan_pci = [&] (Platform::Connection &pci,
Device_capability const &prev,
bool release) {
Device_capability cap = pci.with_upgrade([&]() {
return pci.next_device(prev, 0, 0); });
if (prev.valid() && release) { pci.release_device(prev); }
return cap;
};
Device_capability cap;
bool release = false;
while ((cap = _scan_pci(_platform, cap, release)).valid()) {
Device_client device(cap);
unsigned char bus = 0xff, dev = 0xff, func = 0xff;
device.bus_address(&bus, &dev, &func);
/* host pci bridge */
if (bus == 0 && dev == 0 && func == 0) {
_host_bridge_cap = cap;
release = false;
continue;
}
/* gpu */
if ((device.class_code() >> 8) == 0x0300) {
_gpu_cap = cap;
release = false;
continue;
}
if (device.class_code() == isa_bridge_class()) {
_isa_bridge_cap = cap;
release = false;
continue;
}
release = true;
}
}
bool _mch_enabled()
{
using namespace Platform;
if (!_host_bridge_cap.valid()) { return false; }
Device_client device(_host_bridge_cap);
/*
* 5th Gen Core Processor datasheet vol 2 p. 48
*/
enum { MCHBAR_OFFSET = 0x48, };
struct MCHBAR : Genode::Register<64>
{
struct Mchbaren : Bitfield<0, 1> { };
};
MCHBAR::access_t const v = device.config_read(MCHBAR_OFFSET,
Platform::Device::ACCESS_32BIT);
return MCHBAR::Mchbaren::get(v);
}
template <typename T>
static Platform::Device::Access_size _access_size(T)
{
switch (sizeof(T)) {
case 1: return Platform::Device::ACCESS_8BIT;
case 2: return Platform::Device::ACCESS_16BIT;
default: return Platform::Device::ACCESS_32BIT;
}
}
void _enable_pci_bus_master()
{
enum {
PCI_CMD_REG = 4,
PCI_BUS_MASTER = 1<<2,
};
uint16_t cmd = config_read<uint16_t>(PCI_CMD_REG);
cmd |= PCI_BUS_MASTER;
config_write(PCI_CMD_REG, cmd);
}
public:
Resources(Genode::Env &env, Genode::Heap &heap,
Main &obj, void (Main::*ack_irq) ())
:
_env(env), _heap(heap), _obj(obj), _ack_irq(ack_irq)
{
/* initial donation for device pd */
_platform.upgrade_ram(1024*1024);
_find_devices();
if (!_gpu_cap.valid() || !_mch_enabled()) {
throw Initialization_failed();
}
_gpu_client.construct(_gpu_cap);
/*
* The intel display driver (as client of this gpu driver)
* uses the platform.io_mem() cap interface to obtain the io_mem
* capabilities. The need for directly handling with the physical
* io_mem addresses is not desired and the legacy path. So dummy
* addresses are used here just as placeholder for implementing
* the platform.resource() RPC interface.
*/
_gttmmadr_io = _gpu_client->io_mem(0);
_gttmmadr_ds = Genode::Io_mem_session_client(_gttmmadr_io).dataspace();
_gttmmadr = Platform::Device::Resource(1u << 30 /* dummy */,
Genode::Dataspace_client(_gttmmadr_ds).size());
_gmadr_io = _gpu_client->io_mem(1, Genode::Cache::WRITE_COMBINED);
_gmadr_ds = Genode::Io_mem_session_client(_gmadr_io).dataspace();
_gmadr_rm.attach_at(_gmadr_ds, 0, APERTURE_RESERVED);
_gmadr = Platform::Device::Resource(1u << 29 /* dummy */,
Genode::Dataspace_client(_gmadr_ds).size());
_enable_pci_bus_master();
log("Reserved beginning ",
Genode::Number_of_bytes(APERTURE_RESERVED),
" of aperture for platform service");
}
~Resources()
{
_platform.release_device(_gpu_cap);
_platform.release_device(_host_bridge_cap);
}
Genode::Rm_connection &rm() { return _rm_connection; }
addr_t map_gttmmadr()
{
if (!_gttmmadr_ds.valid())
throw Initialization_failed();
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(_gttmmadr_local));
return _gttmmadr_local;
}
template <typename T>
T config_read(unsigned int const devfn)
{
T val = 0;
_platform.with_upgrade([&] () {
val = _gpu_client->config_read(devfn, _access_size(val));
});
return val;
}
template <typename T>
void config_write(unsigned int const devfn, T val)
{
_platform.with_upgrade([&] () {
_gpu_client->config_write(devfn, val, _access_size(val));
});
}
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(); }
Dataspace_capability gmadr_ds() const { return _gmadr_ds; }
addr_t gttmmadr_base() const { return _gttmmadr.base(); }
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;
if (!_gttmmadr_rm.constructed())
_create_gttmmadr_rm();
if (!_gttmmadr_rm.constructed())
return { };
return static_cap_cast<Io_mem_dataspace>(_gttmmadr_rm->dataspace());
}
Io_mem_dataspace_capability gmadr_platform_ds()
{
using namespace Genode;
return static_cap_cast<Io_mem_dataspace>(_gmadr_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;
}
};

View File

@ -28,7 +28,13 @@ namespace Igd {
using addr_t = Genode::addr_t;
using size_t = Genode::size_t;
enum { PAGE_SIZE = 4096, };
enum {
PAGE_SIZE = 4096,
/* reserved aperture for platform service */
APERTURE_RESERVED = 64u<<20,
/* reserved GTT for platform service, GTT entry is 8 byte */
GTT_RESERVED = (APERTURE_RESERVED/PAGE_SIZE) * 8,
};
inline void wmb() { asm volatile ("sfence": : :"memory"); }
}