mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 15:32:25 +00:00
parent
03cec5cdd7
commit
250275fbfb
@ -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; }
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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) });
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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"); }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user