mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 21:57:55 +00:00
gpu/intel: add platform service for display handling
The platform services is intented to be used by dde_linux's intel_fb_drv in order to initlialize displays. * implement and announce platform session * limit accessible GTT and aperture of client to 64 MB * forward display engine IRQs to platform client * move all PCI resources to 'Igd::Resources' class in order to make them accessible by the platform service and the GPU driver * fix fence register allocation for id zero (return true) issue #4233
This commit is contained in:
parent
11192b18e6
commit
6c003a13d2
@ -40,6 +40,8 @@
|
||||
#include <ggtt.h>
|
||||
#include <context.h>
|
||||
#include <context_descriptor.h>
|
||||
#include <resources.h>
|
||||
#include <platform_session.h>
|
||||
#include <ring_buffer.h>
|
||||
|
||||
|
||||
@ -76,7 +78,6 @@ static Igd::Device_info _supported_devices[] = {
|
||||
|
||||
struct Igd::Device
|
||||
{
|
||||
struct Initialization_failed : Genode::Exception { };
|
||||
struct Unsupported_device : Genode::Exception { };
|
||||
struct Out_of_ram : Genode::Exception { };
|
||||
struct Could_not_map_buffer : Genode::Exception { };
|
||||
@ -105,54 +106,8 @@ struct Igd::Device
|
||||
** PCI **
|
||||
*********/
|
||||
|
||||
/*
|
||||
* Config space utility methods
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FUNC>
|
||||
void _retry_func(FUNC const &func)
|
||||
{
|
||||
Genode::size_t donate = PAGE_SIZE;
|
||||
Genode::retry<Platform::Out_of_ram>(
|
||||
func,
|
||||
[&] () {
|
||||
_pci.upgrade_ram(donate);
|
||||
donate *= 2;
|
||||
}, 2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T _config_read(unsigned int const devfn)
|
||||
{
|
||||
T val = 0;
|
||||
_retry_func([&] () {
|
||||
val = _device.config_read(devfn, _access_size(val));
|
||||
});
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void _config_write(unsigned int const devfn, T val)
|
||||
{
|
||||
_retry_func([&] () {
|
||||
_device.config_write(devfn, val, _access_size(val));
|
||||
});
|
||||
}
|
||||
|
||||
Platform::Connection &_pci;
|
||||
Platform::Device_capability _pci_cap;
|
||||
Platform::Device_client _device { _pci_cap };
|
||||
Resources &_resources;
|
||||
Platform::Device_client &_device { _resources.gpu_client() };
|
||||
|
||||
struct Pci_backend_alloc : Utils::Backend_alloc
|
||||
{
|
||||
@ -176,58 +131,8 @@ struct Igd::Device
|
||||
_pci.free_dma_buffer(cap);
|
||||
}
|
||||
|
||||
} _pci_backend_alloc { _pci };
|
||||
} _pci_backend_alloc { _resources.platform() };
|
||||
|
||||
enum {
|
||||
PCI_NUM_RES = 6,
|
||||
PCI_CMD_REG = 4,
|
||||
PCI_BUS_MASTER = 1<<2,
|
||||
|
||||
GTTMMADR = 0,
|
||||
GMADR = 2,
|
||||
};
|
||||
Genode::Constructible<Genode::Io_mem_connection> _res[PCI_NUM_RES];
|
||||
addr_t _res_base[PCI_NUM_RES];
|
||||
size_t _res_size[PCI_NUM_RES];
|
||||
Genode::Io_mem_dataspace_capability _res_ds[PCI_NUM_RES];
|
||||
|
||||
Genode::Constructible<Genode::Irq_session_client> _irq { };
|
||||
|
||||
void _poke_pci_resource(unsigned const id)
|
||||
{
|
||||
if (id >= PCI_NUM_RES) { throw -1; }
|
||||
if (_res[id].constructed()) { throw -2; }
|
||||
|
||||
Platform::Device::Resource const res = _device.resource(id);
|
||||
_res_base[id] = res.base();
|
||||
_res_size[id] = res.size();
|
||||
}
|
||||
|
||||
addr_t _map_pci_resource(unsigned const id)
|
||||
{
|
||||
_poke_pci_resource(id);
|
||||
|
||||
_res[id].construct(_env, _res_base[id], _res_size[id]);
|
||||
_res_ds[id] = _res[id]->dataspace();
|
||||
if (!_res_ds[id].valid()) { throw Initialization_failed(); }
|
||||
|
||||
addr_t addr = (addr_t)(_env.rm().attach(_res_ds[id], _res_size[id]));
|
||||
|
||||
using namespace Genode;
|
||||
log("Map res:", id,
|
||||
" base:", Hex(_res_base[id]),
|
||||
" size:", Hex(_res_size[id]),
|
||||
" vaddr:", Hex(addr));
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void _enable_pci_bus_master()
|
||||
{
|
||||
uint16_t cmd = _config_read<uint16_t>(PCI_CMD_REG);
|
||||
cmd |= PCI_BUS_MASTER;
|
||||
_config_write(PCI_CMD_REG, cmd);
|
||||
}
|
||||
|
||||
Device_info _info { };
|
||||
|
||||
@ -247,6 +152,7 @@ struct Igd::Device
|
||||
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;
|
||||
@ -342,7 +248,7 @@ struct Igd::Device
|
||||
* so we do not have to rollback when the allocation failes.
|
||||
*/
|
||||
|
||||
addr_t const base = _res_base[GMADR] + _ggtt->addr(offset);
|
||||
addr_t const base = _resources.gmadr_base() + _ggtt->addr(offset);
|
||||
Genode::Registered<Ggtt_mmio_mapping> *mem = new (&alloc)
|
||||
Genode::Registered<Ggtt_mmio_mapping>(_ggtt_mmio_mapping_registry,
|
||||
_env, base, size, offset);
|
||||
@ -913,51 +819,7 @@ struct Igd::Device
|
||||
return true;
|
||||
}
|
||||
|
||||
void _handle_irq()
|
||||
{
|
||||
_mmio->disable_master_irq();
|
||||
|
||||
Mmio::GT_0_INTERRUPT_IIR::access_t const v = _mmio->read<Mmio::GT_0_INTERRUPT_IIR>();
|
||||
|
||||
bool const ctx_switch = Mmio::GT_0_INTERRUPT_IIR::Cs_ctx_switch_interrupt::get(v);
|
||||
(void)ctx_switch;
|
||||
bool const user_complete = Mmio::GT_0_INTERRUPT_IIR::Cs_mi_user_interrupt::get(v);
|
||||
|
||||
if (v) { _clear_rcs_iir(v); }
|
||||
|
||||
Vgpu *notify_gpu = nullptr;
|
||||
if (user_complete) {
|
||||
notify_gpu = _current_vgpu();
|
||||
if (notify_gpu)
|
||||
notify_gpu->user_complete();
|
||||
}
|
||||
|
||||
bool const fault_valid = _mmio->fault_regs_valid();
|
||||
if (fault_valid) { Genode::error("FAULT_REG valid"); }
|
||||
|
||||
_mmio->update_context_status_pointer();
|
||||
|
||||
if (user_complete) {
|
||||
_unschedule_current_vgpu();
|
||||
_active_vgpu = nullptr;
|
||||
|
||||
if (notify_gpu) {
|
||||
if (!_notify_complete(notify_gpu))
|
||||
_vgpu_list.enqueue(*notify_gpu);
|
||||
}
|
||||
|
||||
/* keep the ball rolling... */
|
||||
if (_current_vgpu()) {
|
||||
_schedule_current_vgpu();
|
||||
}
|
||||
}
|
||||
|
||||
_mmio->enable_master_irq();
|
||||
_irq->ack_irq();
|
||||
}
|
||||
|
||||
Genode::Signal_handler<Device> _irq_dispatcher {
|
||||
_env.ep(), *this, &Device::_handle_irq };
|
||||
|
||||
/************
|
||||
** FENCES **
|
||||
@ -1033,19 +895,14 @@ struct Igd::Device
|
||||
*/
|
||||
Device(Genode::Env &env,
|
||||
Genode::Allocator &alloc,
|
||||
Platform::Connection &pci,
|
||||
Platform::Device_capability cap,
|
||||
Genode::Xml_node config)
|
||||
Resources &resources)
|
||||
:
|
||||
_env(env), _md_alloc(alloc), _pci(pci), _pci_cap(cap)
|
||||
_env(env), _md_alloc(alloc), _resources(resources)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!_supported()) { throw Unsupported_device(); }
|
||||
|
||||
/* trigger device_pd assignment */
|
||||
_enable_pci_bus_master();
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1068
|
||||
*/
|
||||
@ -1058,7 +915,7 @@ struct Igd::Device
|
||||
struct Ggc_lock : Bitfield<0, 1> { };
|
||||
};
|
||||
enum { PCI_GMCH_CTL = 0x50, };
|
||||
MGGC_0_2_0_PCI::access_t v = _config_read<uint16_t>(PCI_GMCH_CTL);
|
||||
MGGC_0_2_0_PCI::access_t v = _resources.config_read<uint16_t>(PCI_GMCH_CTL);
|
||||
|
||||
{
|
||||
log("MGGC_0_2_0_PCI");
|
||||
@ -1070,32 +927,26 @@ struct Igd::Device
|
||||
}
|
||||
|
||||
/* map PCI resources */
|
||||
_poke_pci_resource(GMADR);
|
||||
|
||||
addr_t gttmmadr_base = _map_pci_resource(GTTMMADR);
|
||||
addr_t gttmmadr_base = _resources.map_gttmmadr();
|
||||
_mmio.construct(_delayer, gttmmadr_base);
|
||||
|
||||
/* GGTT */
|
||||
Number_of_bytes const fb_size =
|
||||
config.attribute_value("fb_size", 32u<<20);
|
||||
log("Reserve beginning ", fb_size, " in GGTT for framebuffer");
|
||||
|
||||
Ram_dataspace_capability scratch_page_ds = _pci_backend_alloc.alloc(PAGE_SIZE);
|
||||
addr_t const scratch_page = Dataspace_client(scratch_page_ds).phys_addr();
|
||||
|
||||
/* 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 + (_res_size[GTTMMADR] / 2);
|
||||
size_t const gmadr_size = _res_size[GMADR];
|
||||
_ggtt.construct(*_mmio, ggtt_base, ggtt_size, gmadr_size, scratch_page, fb_size);
|
||||
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 - fb_size) / Vgpu::APERTURE_SIZE;
|
||||
_vgpu_avail = (gmadr_size - aperture_reserved) / Vgpu::APERTURE_SIZE;
|
||||
|
||||
_device_reset_and_init();
|
||||
|
||||
_irq.construct(_device.irq(0));
|
||||
_irq->sigh(_irq_dispatcher);
|
||||
_irq->ack_irq();
|
||||
|
||||
_mmio->dump();
|
||||
_mmio->context_status_pointer_dump();
|
||||
@ -1257,9 +1108,8 @@ struct Igd::Device
|
||||
uint32_t const id = _mmio->find_free_fence();
|
||||
if (id == INVALID_FENCE) {
|
||||
Genode::warning("could not find free FENCE");
|
||||
return false;
|
||||
return id;
|
||||
}
|
||||
|
||||
addr_t const lower = start * PAGE_SIZE;
|
||||
addr_t const upper = lower + size;
|
||||
uint32_t const pitch = ((mode & 0xffff0000) >> 16) / 128 - 1;
|
||||
@ -1278,6 +1128,56 @@ struct Igd::Device
|
||||
_clear_fence(id);
|
||||
}
|
||||
|
||||
unsigned handle_irq()
|
||||
{
|
||||
Mmio::MASTER_INT_CTL::access_t master = _mmio->read<Mmio::MASTER_INT_CTL>();
|
||||
|
||||
/* handle render interrupts only */
|
||||
if (Mmio::MASTER_INT_CTL::Render_interrupts_pending::get(master) == 0)
|
||||
return master;
|
||||
|
||||
_mmio->disable_master_irq();
|
||||
|
||||
Mmio::GT_0_INTERRUPT_IIR::access_t const v = _mmio->read<Mmio::GT_0_INTERRUPT_IIR>();
|
||||
|
||||
bool const ctx_switch = Mmio::GT_0_INTERRUPT_IIR::Cs_ctx_switch_interrupt::get(v);
|
||||
(void)ctx_switch;
|
||||
bool const user_complete = Mmio::GT_0_INTERRUPT_IIR::Cs_mi_user_interrupt::get(v);
|
||||
|
||||
if (v) { _clear_rcs_iir(v); }
|
||||
|
||||
Vgpu *notify_gpu = nullptr;
|
||||
if (user_complete) {
|
||||
notify_gpu = _current_vgpu();
|
||||
if (notify_gpu)
|
||||
notify_gpu->user_complete();
|
||||
}
|
||||
|
||||
bool const fault_valid = _mmio->fault_regs_valid();
|
||||
if (fault_valid) { Genode::error("FAULT_REG valid"); }
|
||||
|
||||
_mmio->update_context_status_pointer();
|
||||
|
||||
if (user_complete) {
|
||||
_unschedule_current_vgpu();
|
||||
_active_vgpu = nullptr;
|
||||
|
||||
if (notify_gpu) {
|
||||
if (!_notify_complete(notify_gpu))
|
||||
_vgpu_list.enqueue(*notify_gpu);
|
||||
}
|
||||
|
||||
/* keep the ball rolling... */
|
||||
if (_current_vgpu()) {
|
||||
_schedule_current_vgpu();
|
||||
}
|
||||
}
|
||||
|
||||
return master;
|
||||
}
|
||||
|
||||
void enable_master_irq() { _mmio->enable_master_irq(); }
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
@ -1630,9 +1530,10 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
|
||||
|
||||
Igd::size_t const size = Genode::Dataspace_client(b->cap).size();
|
||||
Genode::uint32_t const fenced = _device.set_tiling(b->map.offset, size, mode);
|
||||
|
||||
b->fenced = fenced;
|
||||
if (fenced != Buffer::INVALID_FENCE) { _vgpu.active_fences++; }
|
||||
return fenced;
|
||||
return fenced != Buffer::INVALID_FENCE;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1715,97 +1616,6 @@ struct Main
|
||||
{
|
||||
Genode::Env &_env;
|
||||
|
||||
/*********
|
||||
** Pci **
|
||||
*********/
|
||||
|
||||
Platform::Connection _pci;
|
||||
Platform::Device_capability _pci_cap { };
|
||||
|
||||
Platform::Device_capability _find_gpu_device()
|
||||
{
|
||||
using namespace Platform;
|
||||
|
||||
auto _scan_pci = [&] (Platform::Connection &pci,
|
||||
Device_capability const &prev) {
|
||||
Device_capability cap = Genode::retry<Platform::Out_of_ram>(
|
||||
[&] () { return pci.next_device(prev, 0, 0); },
|
||||
[&] () { pci.upgrade_ram(4096); }, 8);
|
||||
|
||||
if (prev.valid()) { pci.release_device(prev); }
|
||||
return cap;
|
||||
};
|
||||
|
||||
Device_capability cap;
|
||||
|
||||
while ((cap = _scan_pci(_pci, cap)).valid()) {
|
||||
Device_client device(cap);
|
||||
|
||||
enum { BDW_DEVICE_ID = 0x1600, };
|
||||
if ((device.class_code() >> 8) == 0x0300
|
||||
&& (device.device_id() & 0xff00) == BDW_DEVICE_ID) {
|
||||
return cap;
|
||||
}
|
||||
}
|
||||
|
||||
return Device_capability();
|
||||
}
|
||||
|
||||
Platform::Device_capability _find_bridge()
|
||||
{
|
||||
using namespace Platform;
|
||||
|
||||
auto _scan_pci = [&] (Platform::Connection &pci,
|
||||
Device_capability const &prev) {
|
||||
Device_capability cap;
|
||||
|
||||
cap = Genode::retry<Platform::Out_of_ram>(
|
||||
[&] () { return pci.next_device(prev, 0, 0); },
|
||||
[&] () { pci.upgrade_ram(4096); }, 8);
|
||||
|
||||
if (prev.valid()) { pci.release_device(prev); }
|
||||
return cap;
|
||||
};
|
||||
|
||||
Device_capability cap;
|
||||
|
||||
unsigned char bus = 0xff, dev = 0xff, func = 0xff;
|
||||
while ((cap = _scan_pci(_pci, cap)).valid()) {
|
||||
Device_client device(cap);
|
||||
|
||||
device.bus_address(&bus, &dev, &func);
|
||||
|
||||
if (bus == 0 && dev == 0 && func == 0) {
|
||||
return cap;
|
||||
}
|
||||
}
|
||||
|
||||
return Device_capability();
|
||||
}
|
||||
|
||||
bool _mch_enabled()
|
||||
{
|
||||
using namespace Platform;
|
||||
|
||||
Device_capability cap = _find_bridge();
|
||||
if (!cap.valid()) { return false; }
|
||||
|
||||
Device_client device(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,
|
||||
Device::ACCESS_32BIT);
|
||||
return MCHBAR::Mchbaren::get(v);
|
||||
}
|
||||
|
||||
/*********
|
||||
** Gpu **
|
||||
*********/
|
||||
@ -1813,28 +1623,31 @@ struct Main
|
||||
Genode::Sliced_heap _root_heap { _env.ram(), _env.rm() };
|
||||
Gpu::Root _gpu_root { _env, _root_heap };
|
||||
|
||||
Genode::Attached_rom_dataspace _config_rom { _env, "config" };
|
||||
|
||||
Genode::Heap _device_md_alloc;
|
||||
Genode::Constructible<Igd::Device> _device { };
|
||||
Igd::Resources _gpu_resources { _env, *this, &Main::ack_irq };
|
||||
|
||||
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 { };
|
||||
|
||||
Main(Genode::Env &env)
|
||||
:
|
||||
_env(env), _pci(env), _device_md_alloc(_env.ram(), _env.rm())
|
||||
_env(env), _device_md_alloc(_env.ram(), _env.rm())
|
||||
{
|
||||
/* initial donation for device pd */
|
||||
_pci.upgrade_ram(1024*1024);
|
||||
/* IRQ */
|
||||
_irq.sigh(_irq_dispatcher);
|
||||
_irq.ack_irq();
|
||||
|
||||
_pci_cap = _find_gpu_device();
|
||||
if (!_pci_cap.valid() || !_mch_enabled()) {
|
||||
throw Igd::Device::Initialization_failed();
|
||||
}
|
||||
/* platform service */
|
||||
_platform_root.construct(_env, _device_md_alloc, _gpu_resources);
|
||||
|
||||
/* GPU */
|
||||
try {
|
||||
_device.construct(_env, _device_md_alloc, _pci, _pci_cap,
|
||||
_config_rom.xml());
|
||||
_device.construct(_env, _device_md_alloc, _gpu_resources);
|
||||
} catch (...) {
|
||||
_env.parent().exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1842,7 +1655,37 @@ struct Main
|
||||
_env.parent().announce(_env.ep().manage(_gpu_root));
|
||||
}
|
||||
|
||||
~Main() { _pci.release_device(_pci_cap); }
|
||||
void handle_irq()
|
||||
{
|
||||
unsigned master = 0;
|
||||
if (_device.constructed())
|
||||
master = _device->handle_irq();
|
||||
/* GPU not present forward all IRQs to platform client */
|
||||
else {
|
||||
_platform_root->handle_irq();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPU present check for display engine related IRQs before calling platform
|
||||
* client
|
||||
*/
|
||||
using Master = Igd::Mmio::MASTER_INT_CTL;
|
||||
if (Master::De_interrupts_pending::get(master) &&
|
||||
(_platform_root->handle_irq()))
|
||||
return;
|
||||
|
||||
ack_irq();
|
||||
}
|
||||
|
||||
void ack_irq()
|
||||
{
|
||||
if (_device.constructed()) {
|
||||
_device->enable_master_irq();
|
||||
}
|
||||
|
||||
_irq.ack_irq();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -75,16 +75,20 @@ class Igd::Mmio : public Genode::Mmio
|
||||
struct Audio_codec_interrupts_pending : Bitfield<24, 1> { };
|
||||
struct De_pch_interrupts_pending : Bitfield<23, 1> { };
|
||||
struct De_misc_interrupts_pending : Bitfield<22, 1> { };
|
||||
struct De_pch_misc : Bitfield<22, 2> { };
|
||||
struct De_port_interrupts_pending : Bitfield<20, 1> { };
|
||||
struct De_pipe_c_interrupts_pending : Bitfield<18, 1> { };
|
||||
struct De_pipe_b_interrupts_pending : Bitfield<17, 1> { };
|
||||
struct De_pipe_a_interrupts_pending : Bitfield<16, 1> { };
|
||||
struct De_pipe : Bitfield<16, 3> { };
|
||||
struct Vebox_interrupts_pending : Bitfield< 6, 1> { };
|
||||
struct Gtpm_interrupts_pending : Bitfield< 4, 1> { };
|
||||
struct Vcs2_interrupts_pending : Bitfield< 3, 1> { };
|
||||
struct Vcs1_interrupts_pending : Bitfield< 2, 1> { };
|
||||
struct Blitter_interrupts_pending : Bitfield< 1, 1> { };
|
||||
struct Render_interrupts_pending : Bitfield< 0, 1> { };
|
||||
struct De_interrupts_pending :
|
||||
Genode::Bitset_3<De_pipe, De_port_interrupts_pending, De_pch_misc> { };
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1213,7 +1217,7 @@ class Igd::Mmio : public Genode::Mmio
|
||||
{
|
||||
RCS_RING_CONTEXT_STATUS_PTR::access_t const wp = read<RCS_RING_CONTEXT_STATUS_PTR::Write_pointer>();
|
||||
if (wp > 0x05) {
|
||||
Genode::warning("ring context status write-pointer invalid");
|
||||
Genode::warning("ring context status write-pointer invalid", Genode::Hex(wp));
|
||||
return;
|
||||
}
|
||||
|
||||
|
315
repos/os/src/drivers/gpu/intel/platform_session.h
Normal file
315
repos/os/src/drivers/gpu/intel/platform_session.h
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* \brief Platform service implementation
|
||||
* \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 <platform_session/platform_session.h>
|
||||
|
||||
namespace Platform {
|
||||
class Device_component;
|
||||
class Session_component;
|
||||
class Io_mem_session_component;
|
||||
class Irq_session_component;
|
||||
class Root;
|
||||
}
|
||||
|
||||
|
||||
class Platform::Irq_session_component : public Rpc_object<Irq_session>
|
||||
{
|
||||
private:
|
||||
|
||||
Igd::Resources &_resources;
|
||||
Signal_context_capability _sigh { };
|
||||
|
||||
public:
|
||||
|
||||
Irq_session_component(Igd::Resources &resources)
|
||||
:
|
||||
_resources(resources)
|
||||
{ }
|
||||
|
||||
void ack_irq() override
|
||||
{
|
||||
_resources.ack_irq();
|
||||
}
|
||||
|
||||
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 };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Platform::Io_mem_session_component : public Rpc_object<Io_mem_session>
|
||||
{
|
||||
private:
|
||||
|
||||
Igd::Resources &_resources;
|
||||
|
||||
public:
|
||||
|
||||
Io_mem_session_component(Igd::Resources &resources)
|
||||
:
|
||||
_resources(resources) { }
|
||||
|
||||
Io_mem_dataspace_capability dataspace() override
|
||||
{
|
||||
return _resources.gttmmadr_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 };
|
||||
Constructible<Io_mem_connection> _gmadr_io { };
|
||||
Irq_session_component _irq { _resources };
|
||||
|
||||
public:
|
||||
|
||||
Device_component(Env &env, Igd::Resources &resources)
|
||||
:
|
||||
_env(env), _resources(resources)
|
||||
{
|
||||
_env.ep().rpc_ep().manage(&_gttmmadr_io);
|
||||
_env.ep().rpc_ep().manage(&_irq);
|
||||
}
|
||||
|
||||
~Device_component()
|
||||
{
|
||||
_env.ep().rpc_ep().dissolve(&_gttmmadr_io);
|
||||
_env.ep().rpc_ep().dissolve(&_irq);
|
||||
}
|
||||
|
||||
Irq_session_capability irq(uint8_t) override
|
||||
{
|
||||
return _irq.cap();
|
||||
}
|
||||
|
||||
Io_mem_session_capability io_mem(uint8_t v_id, Cache caching,
|
||||
addr_t /* offset */,
|
||||
size_t /* size */) override
|
||||
{
|
||||
if (v_id == 0)
|
||||
return _gttmmadr_io.cap();
|
||||
|
||||
if (v_id == 1) {
|
||||
if (!_gmadr_io.constructed()) {
|
||||
bool write_combined = (caching == WRITE_COMBINED) ? true : false;
|
||||
_gmadr_io.construct(_env, _resources.gmadr_base(),
|
||||
_resources.gmadr_platform_size(), write_combined);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
Genode::error(__func__, " is not supported");
|
||||
return Io_port_session_capability();
|
||||
}
|
||||
|
||||
bool handle_irq() { return _irq.handle_irq(); }
|
||||
};
|
||||
|
||||
|
||||
class Platform::Session_component : public Rpc_object<Session>
|
||||
{
|
||||
private:
|
||||
|
||||
Env &_env;
|
||||
Device_component _device_component;
|
||||
Connection &_platform;
|
||||
Device_capability _bridge;
|
||||
|
||||
public:
|
||||
|
||||
Session_component(Env &env, Igd::Resources &resources)
|
||||
:
|
||||
_env(env),
|
||||
_device_component(env, resources),
|
||||
_platform(resources.platform()),
|
||||
_bridge(resources.host_bridge_cap())
|
||||
{
|
||||
_env.ep().rpc_ep().manage(&_device_component);
|
||||
}
|
||||
|
||||
~Session_component()
|
||||
{
|
||||
_env.ep().rpc_ep().dissolve(&_device_component);
|
||||
}
|
||||
|
||||
Device_capability first_device(unsigned device_class, unsigned class_mask) override
|
||||
{
|
||||
enum { ISA_BRIDGE = 0x601u << 8 };
|
||||
if (device_class == ISA_BRIDGE)
|
||||
return _platform.first_device(device_class, class_mask);
|
||||
|
||||
return _bridge;
|
||||
}
|
||||
|
||||
Device_capability next_device(Device_capability prev_device,
|
||||
unsigned, unsigned) override
|
||||
{
|
||||
if (prev_device == _bridge)
|
||||
return _device_component.cap();
|
||||
|
||||
return Device_capability();
|
||||
}
|
||||
|
||||
void release_device(Device_capability device) override
|
||||
{
|
||||
if (device.valid() == false) return;
|
||||
|
||||
if (_device_component.cap() == device || device == _bridge) {
|
||||
return;
|
||||
}
|
||||
_platform.release_device(device);
|
||||
}
|
||||
|
||||
Device_capability device(Device_name const & /* string */) override
|
||||
{
|
||||
Genode::error(__func__, " is not supported");
|
||||
return Device_capability();
|
||||
}
|
||||
|
||||
Ram_dataspace_capability alloc_dma_buffer(size_t size, Cache cache) override
|
||||
{
|
||||
return _platform.alloc_dma_buffer(size, cache);
|
||||
}
|
||||
|
||||
void free_dma_buffer(Ram_dataspace_capability cap) override
|
||||
{
|
||||
_platform.free_dma_buffer(cap);
|
||||
}
|
||||
|
||||
addr_t dma_addr(Ram_dataspace_capability cap) override
|
||||
{
|
||||
return _platform.dma_addr(cap);
|
||||
}
|
||||
|
||||
bool handle_irq() { return _device_component.handle_irq(); }
|
||||
};
|
||||
|
||||
|
||||
class Platform::Root : public Root_component<Session_component, Genode::Single_client>
|
||||
{
|
||||
private:
|
||||
|
||||
Env &_env;
|
||||
Constructible<Session_component> _session { };
|
||||
Igd::Resources &_resources;
|
||||
|
||||
public:
|
||||
|
||||
Root(Env &env, Allocator &md_alloc, Igd::Resources &resources)
|
||||
:
|
||||
Root_component<Session_component, Genode::Single_client>(&env.ep().rpc_ep(), &md_alloc),
|
||||
_env(env), _resources(resources)
|
||||
{
|
||||
env.parent().announce(env.ep().manage(*this));
|
||||
}
|
||||
|
||||
Session_component *_create_session(char const * /* args */) override
|
||||
{
|
||||
_session.construct(_env, _resources);
|
||||
|
||||
return &*_session;
|
||||
}
|
||||
|
||||
void _upgrade_session(Session_component *, const char *args) override
|
||||
{
|
||||
if (!_session.constructed()) return;
|
||||
_resources.platform().upgrade({ ram_quota_from_args(args),
|
||||
cap_quota_from_args(args) });
|
||||
}
|
||||
|
||||
void _destroy_session(Session_component *) override
|
||||
{
|
||||
if (_session.constructed())
|
||||
_session.destruct();
|
||||
}
|
||||
|
||||
bool handle_irq()
|
||||
{
|
||||
if (_session.constructed())
|
||||
return _session->handle_irq();
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
280
repos/os/src/drivers/gpu/intel/resources.h
Normal file
280
repos/os/src/drivers/gpu/intel/resources.h
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* \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;
|
||||
|
||||
Genode::Env &_env;
|
||||
|
||||
/* 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 { };
|
||||
Genode::Constructible<Platform::Device_client> _gpu_client { };
|
||||
|
||||
/* mmio + gtt */
|
||||
Platform::Device::Resource _gttmmadr { };
|
||||
Io_mem_dataspace_capability _gttmmadr_ds { };
|
||||
Genode::Constructible<Io_mem_connection> _gttmmadr_io { };
|
||||
|
||||
/* aperture */
|
||||
Platform::Device::Resource _gmadr { };
|
||||
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,
|
||||
};
|
||||
|
||||
/* managed dataspace for local platform service */
|
||||
Genode::Rm_connection _rm_connection { _env };
|
||||
Genode::Constructible<Genode::Region_map_client> _gttmmadr_rm { };
|
||||
|
||||
/**********
|
||||
** Mmio **
|
||||
**********/
|
||||
|
||||
void _create_gttmmadr_rm()
|
||||
{
|
||||
using off_t = Genode::off_t;
|
||||
|
||||
_gttmmadr_rm.construct(_rm_connection.create((gttmmadr_size())));
|
||||
|
||||
/* GTT starts at half of the mmio memory, assumed size is 8 MB */
|
||||
off_t const gtt_offset = gttmmadr_size() / 2;
|
||||
size_t const gtt_size = 8ul << 20;
|
||||
|
||||
/* attach actual iomem + reserved = 8 MB */
|
||||
_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 = gtt_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;
|
||||
}
|
||||
|
||||
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, Main &obj, void (Main::*ack_irq) ())
|
||||
:
|
||||
_env(env), _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);
|
||||
|
||||
_gttmmadr = _gpu_client->resource(0);
|
||||
_gmadr = _gpu_client->resource(2);
|
||||
|
||||
_gttmmadr_io.construct(_env, _gttmmadr.base(), _gttmmadr.size());
|
||||
_gttmmadr_ds = _gttmmadr_io->dataspace();
|
||||
|
||||
_enable_pci_bus_master();
|
||||
|
||||
Genode::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);
|
||||
}
|
||||
|
||||
addr_t map_gttmmadr()
|
||||
{
|
||||
if (!_gttmmadr_ds.valid())
|
||||
throw Initialization_failed();
|
||||
|
||||
addr_t addr = (addr_t)(_env.rm().attach(_gttmmadr_ds, _gttmmadr.size()));
|
||||
|
||||
log("Map res:", 0,
|
||||
" base:", Genode::Hex(_gttmmadr.base()),
|
||||
" size:", Genode::Hex(_gttmmadr.size()),
|
||||
" vaddr:", Genode::Hex(addr));
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
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)(); }
|
||||
|
||||
Platform::Connection &platform() { return _platform; }
|
||||
Platform::Device_client &gpu_client() { return *_gpu_client; }
|
||||
Platform::Device_capability host_bridge_cap() { return _host_bridge_cap; }
|
||||
|
||||
addr_t gmadr_base() const { return _gmadr.base(); }
|
||||
size_t gmadr_size() const { return _gmadr.size(); }
|
||||
addr_t gttmmadr_base() const { return _gttmmadr.base(); }
|
||||
addr_t gttmmadr_size() const { return _gttmmadr.size(); }
|
||||
|
||||
size_t 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();
|
||||
|
||||
return static_cap_cast<Io_mem_dataspace>(_gttmmadr_rm->dataspace());
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user