genode/repos/os/src/drivers/gpu/intel/main.cc

1907 lines
48 KiB
C++
Raw Normal View History

/*
* \brief Broadwell multiplexer
* \author Josef Soentgen
* \data 2017-03-15
*/
/*
* Copyright (C) 2017 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.
*/
/* Genode includes */
#include <base/allocator_guard.h>
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/heap.h>
#include <base/log.h>
#include <base/registry.h>
#include <base/rpc_server.h>
#include <base/session_object.h>
#include <dataspace/client.h>
#include <gpu_session/gpu_session.h>
#include <io_mem_session/connection.h>
#include <irq_session/connection.h>
#include <platform_device/client.h>
#include <platform_session/connection.h>
#include <root/component.h>
#include <timer_session/connection.h>
#include <util/fifo.h>
#include <util/mmio.h>
#include <util/retry.h>
#include <util/xml_node.h>
/* local includes */
#include <mmio.h>
#include <ppgtt.h>
#include <ppgtt_allocator.h>
#include <ggtt.h>
#include <context.h>
#include <context_descriptor.h>
#include <ring_buffer.h>
namespace Igd {
struct Device_info;
struct Device;
}
struct Igd::Device_info
{
uint16_t id;
char const *descr;
uint64_t features;
};
/*
* IHD-OS-BDW-Vol 4-11.15 p. 9
*/
static Igd::Device_info _supported_devices[] = {
{ 0x1606, "HD Graphics (BDW GT1 ULT)", 0ull },
{ 0x1616, "HD Graphics 5500 (BDW GT2 ULT)", 0ull },
/* TODO proper eDRAM probing + caching */
{ 0x1622, "Iris Pro Graphics 6200 (BDW GT3e)", 0ull },
};
#define ELEM_NUMBER(x) (sizeof((x)) / sizeof((x)[0]))
struct Igd::Device
{
struct Initialization_failed : Genode::Exception { };
struct Unsupported_device : Genode::Exception { };
struct Out_of_ram : Genode::Exception { };
struct Already_scheduled : Genode::Exception { };
struct Could_not_map_buffer : Genode::Exception { };
Genode::Env &_env;
Genode::Allocator_guard _md_alloc;
/***********
** Timer **
***********/
Timer::Connection _timer { _env };
enum { WATCHDOG_TIMEOUT = 1*1000*1000, };
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 };
/*********
** PCI **
*********/
/*
* Config space utility methods
*/
template <typename T>
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
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 };
struct Pci_backend_alloc : Utils::Backend_alloc
{
Platform::Connection &_pci;
Pci_backend_alloc(Platform::Connection &pci) : _pci(pci) { }
Genode::Ram_dataspace_capability alloc(Genode::Allocator_guard &guard,
Genode::size_t size) override
{
if (!guard.withdraw(size)) { throw Out_of_ram(); }
/*
* XXX we do not account for any metadata the Platform
* driver might allocate on our behalf which will
* make the alloc_dma_buffer call fail.
*/
_pci.upgrade_ram(size);
try {
return _pci.with_upgrade([&] () {
return _pci.alloc_dma_buffer(size); });
}
catch (Platform::Out_of_ram) {
throw Out_of_ram(); }
}
void free(Genode::Allocator_guard &guard, Genode::Ram_dataspace_capability cap) override
{
if (!cap.valid()) {
Genode::error("could not free, capability invalid");
return;
}
size_t const size = Genode::Dataspace_client(cap).size();
/*
* XXX we will leak quota because the Platform session is not
* able to give us back any quota
*/
guard.upgrade(size);
Genode::warning("leaking ", size, " bytes of RAM quota at ",
" platform_drv but upgrade guard anyway");
_pci.free_dma_buffer(cap);
}
} _pci_backend_alloc { _pci };
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];
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
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);
}
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Device_info _info { };
void _pci_info(char const *descr)
{
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, "' ",
"[", Hex(vendor_id), ":", Hex(device_id), "] (",
Hex(bus, Hex::OMIT_PREFIX), ":",
Hex(dev, Hex::OMIT_PREFIX), ".",
Hex(fun, Hex::OMIT_PREFIX), ")");
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()
{
uint16_t const id = _device.device_id();
for (size_t i = 0; i < ELEM_NUMBER(_supported_devices); i++) {
if (_supported_devices[i].id == id) {
_info = _supported_devices[i];
_pci_info(_supported_devices[i].descr);
return true;
}
}
_pci_info("<Unsupported device>");
return false;
}
/**********
** GGTT **
**********/
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Genode::Constructible<Igd::Ggtt> _ggtt { };
/**********
** MMIO **
**********/
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Genode::Constructible<Igd::Mmio> _mmio { };
/************
** MEMORY **
************/
struct Unaligned_size : Genode::Exception { };
Genode::Ram_dataspace_capability _alloc_dataspace(Genode::Allocator_guard &guard,
size_t const size)
{
if (size & 0xfff) { throw Unaligned_size(); }
Genode::Ram_dataspace_capability ds = _pci_backend_alloc.alloc(guard, size);
if (!ds.valid()) { throw Out_of_ram(); }
return ds;
}
void _free_dataspace(Genode::Allocator_guard &guard,
Genode::Ram_dataspace_capability cap)
{
if (!cap.valid()) { return; }
_pci_backend_alloc.free(guard, cap);
}
struct Ggtt_mmio_mapping : Ggtt::Mapping
{
Genode::Io_mem_connection mmio;
Ggtt_mmio_mapping(Genode::Env &env, addr_t base, size_t size,
Ggtt::Offset offset)
:
mmio(env, base, size)
{
Ggtt::Mapping::cap = mmio.dataspace();
Ggtt::Mapping::offset = offset;
}
virtual ~Ggtt_mmio_mapping() { }
};
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Genode::Registry<Genode::Registered<Ggtt_mmio_mapping>> _ggtt_mmio_mapping_registry { };
Ggtt_mmio_mapping const &_map_dataspace_ggtt(Genode::Allocator &alloc,
Genode::Dataspace_capability cap,
Ggtt::Offset offset)
{
Genode::Dataspace_client client(cap);
addr_t const phys_addr = client.phys_addr();
size_t const size = client.size();
/*
* Create the mapping first and insert the entries afterwards
* so we do not have to rollback when the allocation failes.
*/
addr_t const base = _res_base[GMADR] + _ggtt->addr(offset);
Genode::Registered<Ggtt_mmio_mapping> *mem = new (&alloc)
Genode::Registered<Ggtt_mmio_mapping>(_ggtt_mmio_mapping_registry,
_env, base, size, offset);
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));
}
return *mem;
}
void _unmap_dataspace_ggtt(Genode::Allocator &alloc, Genode::Dataspace_capability cap)
{
size_t const num = Genode::Dataspace_client(cap).size() / PAGE_SIZE;
auto lookup_and_free = [&] (Ggtt_mmio_mapping &m) {
if (!(m.cap == cap)) { return; }
_ggtt->remove_pte_range(m.offset, num);
Genode::destroy(&alloc, &m);
};
_ggtt_mmio_mapping_registry.for_each(lookup_and_free);
}
struct Invalid_ppgtt : Genode::Exception { };
static addr_t _ppgtt_phys_addr(Igd::Ppgtt_allocator &alloc,
Igd::Ppgtt const * const ppgtt)
{
void * const p = alloc.phys_addr(const_cast<Igd::Ppgtt*>(ppgtt));
if (p == nullptr) { throw Invalid_ppgtt(); }
return reinterpret_cast<addr_t>(p);
}
/**********
** MISC **
**********/
uint32_t _id_alloc()
{
static uint32_t id = 1;
uint32_t const v = id++;
return v << 8;
}
/************
** ENGINE **
************/
struct Execlist : Genode::Noncopyable
{
Igd::Context_descriptor _elem0;
Igd::Context_descriptor _elem1;
Igd::Ring_buffer _ring;
bool _scheduled;
Execlist(uint32_t const id, addr_t const lrca,
addr_t const ring, size_t const ring_size)
:
_elem0(id, lrca), _elem1(),
_ring(ring, ring_size), _scheduled(false)
{ }
Igd::Context_descriptor elem0() const { return _elem0; }
Igd::Context_descriptor elem1() const { return _elem1; }
void schedule(int port) { _scheduled = port; }
int scheduled() const { return _scheduled; }
/***************************
** Ring buffer interface **
***************************/
void ring_reset() { _ring.reset(); }
Ring_buffer::Index ring_tail() const { return _ring.tail(); }
Ring_buffer::Index ring_head() const { return _ring.head(); }
Ring_buffer::Index ring_append(Igd::Cmd_header cmd) { return _ring.append(cmd); }
bool ring_avail(Ring_buffer::Index num) const { return _ring.avail(num); }
Ring_buffer::Index ring_max() const { return _ring.max(); }
void ring_reset_and_fill_zero() { _ring.reset_and_fill_zero(); }
void ring_update_head(Ring_buffer::Index head) { _ring.update_head(head); }
void ring_flush(Ring_buffer::Index from, Ring_buffer::Index to)
{
_ring.flush(from, to);
}
void ring_dump(size_t limit = 0) const { _ring.dump(limit); }
/*********************
** Debug interface **
*********************/
void dump() { _elem0.dump(); }
};
template <typename CONTEXT>
struct Engine
{
enum {
CONTEXT_PAGES = CONTEXT::CONTEXT_PAGES,
RING_PAGES = CONTEXT::RING_PAGES,
};
Genode::Ram_dataspace_capability ctx_ds;
Ggtt::Mapping const &ctx_map;
addr_t const ctx_vaddr;
addr_t const ctx_gmaddr;
Genode::Ram_dataspace_capability ring_ds;
Ggtt::Mapping const &ring_map;
addr_t const ring_vaddr;
addr_t const ring_gmaddr;
Ppgtt_allocator &ppgtt_allocator;
Ppgtt *ppgtt;
Ppgtt_scratch *ppgtt_scratch;
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Genode::Constructible<CONTEXT> context { };
Genode::Constructible<Execlist> execlist { };
Engine(uint32_t id,
Ram ctx_ds,
Ggtt::Mapping const &ctx_map,
addr_t const ctx_vaddr,
addr_t const ctx_gmaddr,
Ram ring_ds,
Ggtt::Mapping const &ring_map,
addr_t const ring_vaddr,
addr_t const ring_gmaddr,
Ppgtt_allocator &ppgtt_allocator,
Ppgtt *ppgtt,
Ppgtt_scratch *ppgtt_scratch,
addr_t const pml4)
:
ctx_ds(ctx_ds),
ctx_map(ctx_map),
ctx_vaddr(ctx_vaddr),
ctx_gmaddr(ctx_gmaddr),
ring_ds(ring_ds),
ring_map(ring_map),
ring_vaddr(ring_vaddr),
ring_gmaddr(ring_gmaddr),
ppgtt_allocator(ppgtt_allocator),
ppgtt(ppgtt),
ppgtt_scratch(ppgtt_scratch)
{
size_t const ring_size = RING_PAGES * PAGE_SIZE;
/* setup context */
context.construct(ctx_vaddr, ring_gmaddr, ring_size, pml4);
/* setup execlist */
execlist.construct(id, ctx_gmaddr, ring_vaddr, ring_size);
execlist->ring_reset();
}
~Engine()
{
execlist.destruct();
context.destruct();
}
size_t ring_size() const { return RING_PAGES * PAGE_SIZE; }
addr_t hw_status_page() const { return ctx_gmaddr; }
uint64_t seqno() const {
Utils::clflush((uint32_t*)(ctx_vaddr + 0xc0));
return *(uint32_t*)(ctx_vaddr + 0xc0); }
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
private:
/*
* Noncopyable
*/
Engine(Engine const &);
Engine &operator = (Engine const &);
};
void _fill_page(Genode::Ram_dataspace_capability ds, addr_t v)
{
uint64_t * const p = _env.rm().attach(ds);
for (size_t i = 0; i < Ppgtt_scratch::MAX_ENTRIES; i++) {
p[i] = v;
}
_env.rm().detach(p);
}
void _populate_scratch(Ppgtt_scratch *scratch)
{
_fill_page(scratch->pt.ds, scratch->page.addr);
_fill_page(scratch->pd.ds, scratch->pt.addr);
_fill_page(scratch->pdp.ds, scratch->pd.addr);
}
template <typename CONTEXT>
Engine<CONTEXT> *_alloc_engine(Genode::Allocator_guard &md_alloc, uint32_t const id)
{
/* alloc context memory */
size_t const ctx_offset = _ggtt->find_free(CONTEXT::CONTEXT_PAGES, true);
size_t const ctx_size = CONTEXT::CONTEXT_PAGES * PAGE_SIZE;
Ram ctx_ds = _alloc_dataspace(md_alloc, ctx_size);
Ggtt::Mapping const &ctx_map = _map_dataspace_ggtt(md_alloc, ctx_ds, ctx_offset);
addr_t const ctx_vaddr = (addr_t)_env.rm().attach(ctx_map.cap) + PAGE_SIZE /* omit GuC page */;
addr_t const ctx_gmaddr = (ctx_offset + 1 /* omit GuC page */) * PAGE_SIZE;
/* alloc ring memory */
size_t const ring_offset = _ggtt->find_free(Rcs_context::RING_PAGES, true);
size_t const ring_size = CONTEXT::RING_PAGES * PAGE_SIZE;
Ram ring_ds = _alloc_dataspace(md_alloc, ring_size);
Ggtt::Mapping const &ring_map = _map_dataspace_ggtt(md_alloc, ring_ds, ring_offset);
addr_t const ring_vaddr = _env.rm().attach(ring_map.cap);
addr_t const ring_gmaddr = ring_offset * PAGE_SIZE;
/* PPGTT */
Igd::Ppgtt_allocator *ppgtt_allocator =
new (&md_alloc) Igd::Ppgtt_allocator(_env.rm(), md_alloc, _pci_backend_alloc);
Igd::Ppgtt_scratch *scratch =
new (&md_alloc) Igd::Ppgtt_scratch(md_alloc, _pci_backend_alloc);
_populate_scratch(scratch);
Igd::Ppgtt *ppgtt =
new (ppgtt_allocator) Igd::Ppgtt(&scratch->pdp);
/* get PML4 address */
addr_t const ppgtt_phys_addr = _ppgtt_phys_addr(*ppgtt_allocator, ppgtt);
addr_t const pml4 = ppgtt_phys_addr | 1;
return new (&md_alloc) Engine<CONTEXT>(id + CONTEXT::HW_ID,
ctx_ds, ctx_map, ctx_vaddr, ctx_gmaddr,
ring_ds, ring_map, ring_vaddr, ring_gmaddr,
*ppgtt_allocator, ppgtt, scratch, pml4);
}
template <typename CONTEXT>
void _free_engine(Genode::Allocator_guard &md_alloc, Engine<CONTEXT> *engine)
{
/* free PPGTT */
Genode::destroy(&md_alloc, engine->ppgtt_scratch);
Genode::destroy(&engine->ppgtt_allocator, engine->ppgtt);
Genode::destroy(&md_alloc, &engine->ppgtt_allocator);
/* free ring memory */
{
_env.rm().detach(engine->ring_vaddr);
_unmap_dataspace_ggtt(md_alloc, engine->ring_ds);
_free_dataspace(md_alloc, engine->ring_ds);
size_t const offset = (engine->ring_gmaddr / PAGE_SIZE) - 1;
_ggtt->remove_pte_range(offset, Engine<CONTEXT>::RING_PAGES);
}
/* free context memory */
{
_env.rm().detach(engine->ctx_vaddr - PAGE_SIZE);
_unmap_dataspace_ggtt(md_alloc, engine->ctx_ds);
_free_dataspace(md_alloc, engine->ctx_ds);
size_t const offset = (engine->ctx_gmaddr / PAGE_SIZE) - 1;
_ggtt->remove_pte_range(offset, Engine<CONTEXT>::CONTEXT_PAGES);
}
/* free engine */
Genode::destroy(&md_alloc, engine);
}
/**********
** Vgpu **
**********/
uint32_t _vgpu_avail { 0 };
struct Vgpu : Genode::Fifo<Vgpu>::Element
{
enum {
APERTURE_SIZE = 32u << 20,
MAX_FENCES = 4,
};
uint32_t active_fences { 0 };
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Genode::Signal_context_capability _completion_sigh { };
uint64_t _current_seqno { 0 };
uint32_t const _id;
Engine<Rcs_context> &rcs;
Vgpu(uint32_t const id, Engine<Rcs_context> &rcs)
: _id(id), rcs(rcs) { }
uint32_t id() const { return _id; }
void completion_sigh(Genode::Signal_context_capability sigh) {
_completion_sigh = sigh; }
Genode::Signal_context_capability completion_sigh() {
return _completion_sigh; }
uint64_t current_seqno() const { return _current_seqno; }
uint64_t complete_seqno() const { return rcs.seqno(); }
void setup_ring_buffer(Genode::addr_t const buffer_addr,
Genode::addr_t const scratch_addr)
{
_current_seqno++;
Execlist &el = *rcs.execlist;
Ring_buffer::Index advance = 0;
size_t const need = 4 /* batchbuffer cmd */ + 6 /* prolog */ + 16 /* epilog + w/a */;
if (!el.ring_avail(need)) { el.ring_reset_and_fill_zero(); }
/* save old tail */
Ring_buffer::Index const tail = el.ring_tail();
/* prolog */
if (1)
{
enum { CMD_NUM = 6, HWS_DATA = 0xc0, };
Genode::uint32_t cmd[CMD_NUM] = {};
Igd::Pipe_control pc(CMD_NUM);
cmd[0] = pc.value;
Genode::uint32_t tmp = 0;
tmp |= Igd::Pipe_control::CS_STALL;
tmp |= Igd::Pipe_control::TLB_INVALIDATE;
tmp |= Igd::Pipe_control::INSTRUCTION_CACHE_INVALIDATE;
tmp |= Igd::Pipe_control::TEXTURE_CACHE_INVALIDATE;
tmp |= Igd::Pipe_control::VF_CACHE_INVALIDATE;
tmp |= Igd::Pipe_control::CONST_CACHE_INVALIDATE;
tmp |= Igd::Pipe_control::STATE_CACHE_INVALIDATE;
tmp |= Igd::Pipe_control::QW_WRITE;
tmp |= Igd::Pipe_control::GLOBAL_GTT_IVB;
tmp |= Igd::Pipe_control::DC_FLUSH_ENABLE;
tmp |= Igd::Pipe_control::INDIRECT_STATE_DISABLE;
tmp |= Igd::Pipe_control::MEDIA_STATE_CLEAR;
cmd[1] = tmp;
cmd[2] = scratch_addr;
cmd[3] = 0;
cmd[4] = 0;
cmd[5] = 0;
for (size_t i = 0; i < CMD_NUM; i++) {
advance += el.ring_append(cmd[i]);
}
}
/* batch-buffer commands */
if (1)
{
enum { CMD_NUM = 4, };
Genode::uint32_t cmd[CMD_NUM] = {};
Igd::Mi_batch_buffer_start mi;
cmd[0] = mi.value;
cmd[1] = buffer_addr & 0xffffffff;
cmd[2] = (buffer_addr >> 32) & 0xffff;
cmd[3] = 0; /* MI_NOOP */
for (size_t i = 0; i < CMD_NUM; i++) {
advance += el.ring_append(cmd[i]);
}
}
/* epilog */
if (1)
{
enum { CMD_NUM = 6, HWS_DATA = 0xc0, };
Genode::uint32_t cmd[CMD_NUM] = {};
Igd::Pipe_control pc(CMD_NUM);
cmd[0] = pc.value;
Genode::uint32_t tmp = 0;
tmp |= Igd::Pipe_control::CS_STALL;
tmp |= Igd::Pipe_control::RENDER_TARGET_CACHE_FLUSH;
tmp |= Igd::Pipe_control::DEPTH_CACHE_FLUSH;
tmp |= Igd::Pipe_control::DC_FLUSH_ENABLE;
tmp |= Igd::Pipe_control::FLUSH_ENABLE;
cmd[1] = tmp;
cmd[2] = scratch_addr;
cmd[3] = 0;
cmd[4] = 0;
cmd[5] = 0;
for (size_t i = 0; i < CMD_NUM; i++) {
advance += el.ring_append(cmd[i]);
}
}
/*
* IHD-OS-BDW-Vol 2d-11.15 p. 199 ff.
*
* HWS page layout dword 48 - 1023 for driver usage
*/
if (1)
{
enum { CMD_NUM = 8, HWS_DATA = 0xc0, };
Genode::uint32_t cmd[8] = {};
Igd::Pipe_control pc(6);
cmd[0] = pc.value;
Genode::uint32_t tmp = 0;
tmp |= Igd::Pipe_control::GLOBAL_GTT_IVB;
tmp |= Igd::Pipe_control::CS_STALL;
tmp |= Igd::Pipe_control::QW_WRITE;
cmd[1] = tmp;
cmd[2] = (rcs.hw_status_page() + HWS_DATA) & 0xffffffff;
cmd[3] = 0; /* upper addr 0 */
cmd[4] = _current_seqno & 0xffffffff;
cmd[5] = _current_seqno >> 32;
Igd::Mi_user_interrupt ui;
cmd[6] = ui.value;
cmd[7] = 0; /* MI_NOOP */
for (size_t i = 0; i < CMD_NUM; i++) {
advance += el.ring_append(cmd[i]);
}
}
/* w/a */
if (1)
{
for (size_t i = 0; i < 2; i++) {
advance += el.ring_append(0);
}
}
addr_t const offset = (((tail + advance) * sizeof(uint32_t)) >> 3) - 1;
rcs.context->tail_offset(offset % ((4*4096)>>3));
}
void rcs_map_ppgtt(addr_t vo, addr_t pa, size_t size)
{
Genode::Page_flags pf;
pf.writeable = Genode::Writeable::RW;
try {
rcs.ppgtt->insert_translation(vo, pa, size, pf,
&rcs.ppgtt_allocator,
&rcs.ppgtt_scratch->pdp);
} catch (Igd::Ppgtt_allocator::Out_of_memory) {
throw Igd::Device::Out_of_ram();
} catch (...) {
Genode::log(__func__, ": unknown exception");
throw;
}
}
void rcs_unmap_ppgtt(addr_t vo, size_t size)
{
rcs.ppgtt->remove_translation(vo, size,
&rcs.ppgtt_allocator,
&rcs.ppgtt_scratch->pdp);
}
};
Vgpu* _alloc_vgpu(Genode::Allocator_guard &md_alloc)
{
uint32_t const id = _id_alloc();
Engine<Rcs_context> *rcs = _alloc_engine<Rcs_context>(md_alloc, id);
Vgpu *gpu = new (&md_alloc) Vgpu(id, *rcs);
_vgpu_avail--;
return gpu;
}
void _free_vgpu(Genode::Allocator_guard &md_alloc, Vgpu *vgpu)
{
if (!vgpu) { return; }
Engine<Rcs_context> *rcs = &vgpu->rcs;
_free_engine(md_alloc, rcs);
Genode::destroy(&md_alloc, vgpu);
_vgpu_avail++;
}
/****************
** SCHEDULING **
****************/
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Genode::Fifo<Vgpu> _vgpu_list { };
Vgpu *_active_vgpu { nullptr };
bool _vgpu_already_scheduled(Vgpu &vgpu) const
{
bool result = false;
_vgpu_list.for_each([&] (Vgpu const &v) {
result |= (&v == &vgpu); });
return result;
}
void _submit_execlist(Engine<Rcs_context> &engine)
{
Execlist &el = *engine.execlist;
int const port = _mmio->read<Igd::Mmio::EXECLIST_STATUS_RSCUNIT::Execlist_write_pointer>();
el.schedule(port);
uint32_t desc[4];
desc[3] = el.elem1().high();
desc[2] = el.elem1().low();
desc[1] = el.elem0().high();
desc[0] = el.elem0().low();
_mmio->write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[3]);
_mmio->write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[2]);
_mmio->write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[1]);
_mmio->write<Igd::Mmio::EXECLIST_SUBMITPORT_RSCUNIT>(desc[0]);
}
Vgpu *_unschedule_current_vgpu()
{
Vgpu *result = nullptr;
_vgpu_list.dequeue([&] (Vgpu &head) {
result = &head; });
return result;
}
Vgpu *_current_vgpu()
{
Vgpu *result = nullptr;
_vgpu_list.head([&] (Vgpu &head) {
result = &head; });
return result;
}
void _schedule_current_vgpu()
{
Vgpu *gpu = _current_vgpu();
if (!gpu) {
Genode::warning("no valid vGPU for scheduling found.");
return;
}
Engine<Rcs_context> &rcs = gpu->rcs;
_mmio->flush_gfx_tlb();
/*
* XXX check if HWSP is shared across contexts and if not when
* we actually need to write the register
*/
Mmio::HWS_PGA_RCSUNIT::access_t const addr = rcs.hw_status_page();
_mmio->write_post<Igd::Mmio::HWS_PGA_RCSUNIT>(addr);
_submit_execlist(rcs);
_active_vgpu = gpu;
_timer.trigger_once(WATCHDOG_TIMEOUT);
}
/**********
** INTR **
**********/
void _clear_rcs_iir(Mmio::GT_0_INTERRUPT_IIR::access_t const v)
{
_mmio->write_post<Mmio::GT_0_INTERRUPT_IIR>(v);
}
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Vgpu *_last_scheduled = nullptr;
void _notify_complete(Vgpu *gpu)
{
if (!gpu) { return; }
uint64_t const curr_seqno = gpu->current_seqno();
uint64_t const comp_seqno = gpu->complete_seqno();
if (curr_seqno != comp_seqno) {
Genode::error(__func__, "sequence numbers (", curr_seqno, "/", comp_seqno, ") do not match");
_last_scheduled = gpu;
return;
}
Execlist &el = *gpu->rcs.execlist;
el.ring_update_head(gpu->rcs.context->head_offset());
Genode::Signal_transmitter(gpu->completion_sigh()).submit();
}
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);
Vgpu *notify_gpu = nullptr;
if (user_complete) { notify_gpu = _current_vgpu(); }
if (v) { _clear_rcs_iir(v); }
bool const fault_valid = _mmio->fault_regs_valid();
if (fault_valid) { Genode::error("FAULT_REG valid"); }
bool const csb = _mmio->csb_unread();
(void)csb;
_mmio->update_context_status_pointer();
if (user_complete) {
_unschedule_current_vgpu();
_active_vgpu = nullptr;
if (notify_gpu) { _notify_complete(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 **
************/
/* TODO introduce Fences object, Bit_allocator */
enum { INVALID_FENCE = 0xff, };
uint32_t _get_free_fence()
{
return _mmio->find_free_fence();
}
uint32_t _update_fence(uint32_t const id,
addr_t const lower,
addr_t const upper,
uint32_t const pitch,
bool const tile_x)
{
return _mmio->update_fence(id, lower, upper, pitch, tile_x);
}
void _clear_fence(uint32_t const id)
{
_mmio->clear_fence(id);
}
/**********************
** watchdog timeout **
**********************/
void _handle_watchdog_timeout()
{
if (!_active_vgpu) { return; }
Genode::error("watchdog triggered: engine stuck");
_mmio->dump();
_mmio->error_dump();
_mmio->fault_dump();
_mmio->execlist_status_dump();
Vgpu *gpu = _current_vgpu();
gpu = gpu ? gpu : _last_scheduled;
gpu->rcs.context->dump();
gpu->rcs.context->dump_hw_status_page();
Execlist const &el = *gpu->rcs.execlist;
el.ring_dump(52);
_device_reset_and_init();
if (_active_vgpu == gpu) {
_unschedule_current_vgpu();
}
if (_current_vgpu()) {
_schedule_current_vgpu();
}
}
Genode::Signal_handler<Device> _watchdog_timeout_sigh {
_env.ep(), *this, &Device::_handle_watchdog_timeout };
void _device_reset_and_init()
{
_mmio->reset();
_mmio->clear_errors();
_mmio->init();
_mmio->enable_intr();
_mmio->forcewake_enable();
}
/**
* Constructor
*/
Device(Genode::Env &env,
Genode::Allocator &alloc,
Platform::Connection &pci,
Platform::Device_capability cap,
Genode::Xml_node config)
:
_env(env), _md_alloc(&alloc, 8192), _pci(pci), _pci_cap(cap)
{
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
*/
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 = _config_read<uint16_t>(PCI_GMCH_CTL);
{
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 */
_poke_pci_resource(GMADR);
addr_t gttmmadr_base = _map_pci_resource(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(_md_alloc, PAGE_SIZE);
addr_t const scratch_page = Dataspace_client(scratch_page_ds).phys_addr();
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);
_ggtt->dump();
_vgpu_avail = (gmadr_size - fb_size) / Vgpu::APERTURE_SIZE;
_device_reset_and_init();
_irq.construct(_device.irq(0));
_irq->sigh(_irq_dispatcher);
_irq->ack_irq();
_mmio->dump();
_timer.sigh(_watchdog_timeout_sigh);
}
/*********************
** Device handling **
*********************/
/**
* Reset the physical device
*/
void reset() { _device_reset_and_init(); }
/**
* Get chip id of the phyiscal device
*/
uint16_t id() const { return _info.id; }
/**
* Get features of the phyiscal device
*/
uint32_t features() const { return _info.features; }
/*******************
** Vgpu handling **
*******************/
/**
* Allocate new vGPU
*
* \param alloc resource allocator and guard
*
* \return reference to new vGPU
*
* \throw Out_of_ram
* \throw Out_of_caps
*/
Vgpu& alloc_vgpu(Genode::Allocator_guard &alloc)
{
return *_alloc_vgpu(alloc);
}
/**
* Free vGPU
*
* \param alloc reference to resource allocator
* \param vgpu reference to vGPU
*/
void free_vgpu(Genode::Allocator_guard &alloc, Vgpu &vgpu)
{
_free_vgpu(alloc, &vgpu);
}
/**
* Add vGPU to scheduling list
*
* \param vgpu reference to vGPU
*
* \throw Already_scheduled
*/
void vgpu_enqueue(Vgpu &vgpu)
{
if (_vgpu_already_scheduled(vgpu)) { throw Already_scheduled(); }
Vgpu const *pending = _current_vgpu();
_vgpu_list.enqueue(vgpu);
if (pending) { return; }
/* none pending, kick-off execution */
_schedule_current_vgpu();
}
/**
* Check if there is a vGPU slot left
*
* \return true if slot is free, otherwise false is returned
*/
bool vgpu_avail() const { return _vgpu_avail; }
/**
* Check if vGPU is currently scheduled
*
* \return true if vGPU is scheduled, otherwise false is returned
*/
bool vgpu_active(Vgpu const &vgpu) const
{
bool result = false;
_vgpu_list.head([&] (Vgpu const &curr) {
result = (&vgpu == &curr);
});
return result;
}
/*********************
** Buffer handling **
*********************/
/**
* Allocate DMA buffer
*
* \param guard resource allocator and guard
* \param size size of the DMA buffer
*
* \return DMA buffer capability
*
* \throw Out_of_memory
*/
Genode::Dataspace_capability alloc_buffer(Genode::Allocator_guard &guard,
size_t size)
{
return _pci_backend_alloc.alloc(guard, size);
}
/**
* Free DMA buffer
*
* \param guard resource allocator and guard
* \param cap DMA buffer capability
*/
void free_buffer(Genode::Allocator_guard &guard,
Genode::Dataspace_capability cap)
{
if (!cap.valid()) { return; }
_pci_backend_alloc.free(guard,
Genode::static_cap_cast<Genode::Ram_dataspace>(cap));
}
/**
* Map DMA buffer in the GGTT
*
* \param guard resource allocator and guard
* \param cap DMA buffer capability
* \param aperture true if mapping should be accessible by CPU
*
* \return GGTT mapping
*
* \throw Could_not_map_buffer
*/
Ggtt::Mapping const &map_buffer(Genode::Allocator &guard,
Genode::Dataspace_capability cap, bool aperture)
{
size_t const size = Genode::Dataspace_client(cap).size();
try {
size_t const num = size / PAGE_SIZE;
Ggtt::Offset const offset = _ggtt->find_free(num, aperture);
return _map_dataspace_ggtt(guard, cap, offset);
} catch (...) {
throw Could_not_map_buffer();
}
}
/**
* Unmap DMA buffer from GGTT
*
* \param guard resource allocator and guard
* \param mapping GGTT mapping
*/
void unmap_buffer(Genode::Allocator &guard, Ggtt::Mapping mapping)
{
_unmap_dataspace_ggtt(guard, mapping.cap);
}
/**
* Set tiling mode for GGTT region
*
* \param start offset of the GGTT start entry
* \param size size of the region
* \param mode tiling mode for the region
*
* \return id of the used fence register
*/
uint32_t set_tiling(Ggtt::Offset const start, size_t const size,
uint32_t const mode)
{
uint32_t const id = _mmio->find_free_fence();
if (id == INVALID_FENCE) {
Genode::warning("could not find free FENCE");
return false;
}
addr_t const lower = start * PAGE_SIZE;
addr_t const upper = lower + size;
uint32_t const pitch = ((mode & 0xffff0000) >> 16) / 128 - 1;
bool const tilex = (mode & 0x1);
return _update_fence(id, lower, upper, pitch, tilex);
}
/**
* Clear tiling for given fence
*
* \param id id of fence register
*/
void clear_tiling(uint32_t const id)
{
_clear_fence(id);
}
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
private:
/*
* Noncopyable
*/
Device(Device const &);
Device &operator = (Device const &);
};
namespace Gpu {
class Session_component;
class Root;
using Root_component = Genode::Root_component<Session_component, Genode::Multiple_clients>;
}
class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
{
private:
Genode::Region_map &_rm;
Genode::Allocator_guard _guard;
Igd::Device &_device;
Igd::Device::Vgpu &_vgpu;
struct Buffer
{
Genode::Dataspace_capability cap;
Gpu::addr_t ppgtt_va;
enum { INVALID_FENCE = 0xff, };
Genode::uint32_t fenced;
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Igd::Ggtt::Mapping map { };
Buffer(Genode::Dataspace_capability cap)
: cap(cap), ppgtt_va(0), fenced(INVALID_FENCE) { }
virtual ~Buffer() { }
};
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Genode::Registry<Genode::Registered<Buffer>> _buffer_registry { };
Genode::uint64_t seqno { 0 };
void _free_buffers()
{
auto lookup_and_free = [&] (Buffer &buffer) {
if (buffer.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) {
_device.unmap_buffer(_guard, buffer.map);
}
if (buffer.fenced != Buffer::INVALID_FENCE) {
_device.clear_tiling(buffer.fenced);
_vgpu.active_fences--;
}
Genode::Dataspace_client buf(buffer.cap);
Genode::size_t const actual_size = buf.size();
_vgpu.rcs_unmap_ppgtt(buffer.ppgtt_va, actual_size);
_device.free_buffer(_guard, buffer.cap);
Genode::destroy(&_guard, &buffer);
};
_buffer_registry.for_each(lookup_and_free);
}
public:
/**
* Constructor
*
* \param rm region map used for attaching GPU resources
* \param md_alloc meta-data allocator
* \param ram_quota initial ram quota
* \param device reference to the physical device
*/
Session_component(Genode::Entrypoint &ep,
Resources resources,
Label const &label,
Diag diag,
Genode::Region_map &rm,
Genode::Allocator &md_alloc,
Genode::size_t ram_quota,
Igd::Device &device)
:
Session_object(ep, resources, label, diag),
_rm(rm), _guard(&md_alloc, ram_quota),
_device(device), _vgpu(_device.alloc_vgpu(_guard))
{ }
~Session_component()
{
_free_buffers();
_device.free_vgpu(_guard, _vgpu);
}
/*********************************
** Session_component interface **
*********************************/
void upgrade_ram_quota(Genode::size_t quota)
{
_guard.upgrade(quota);
}
bool vgpu_active() const
{
return _device.vgpu_active(_vgpu);
}
/***************************
** Gpu session interface **
***************************/
Info info() const override
{
Genode::size_t const aperture_size = Igd::Device::Vgpu::APERTURE_SIZE;
return Info(_device.id(), _device.features(), aperture_size, _vgpu.id());
}
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
void exec_buffer(Genode::Dataspace_capability cap, Genode::size_t) override
{
Igd::addr_t ppgtt_va = 0;
auto lookup = [&] (Buffer &buffer) {
if (!(buffer.cap == cap)) { return; }
ppgtt_va = buffer.ppgtt_va;
};
_buffer_registry.for_each(lookup);
if (!ppgtt_va) {
Genode::error("Invalid execbuffer");
Genode::Signal_transmitter(_vgpu.completion_sigh()).submit();
return;
}
_vgpu.setup_ring_buffer(ppgtt_va, _device._ggtt->scratch_page());
try {
_device.vgpu_enqueue(_vgpu);
} catch (Igd::Device::Already_scheduled &e) {
Genode::error("vGPU already scheduled");
}
}
void completion_sigh(Genode::Signal_context_capability sigh) override
{
_vgpu.completion_sigh(sigh);
}
Genode::Dataspace_capability alloc_buffer(Genode::size_t size) override
{
/*
* XXX size might not be page aligned, allocator overhead is not
* included, mapping costs are not included and we throw at
* different locations...
*
* => better construct Buffer object as whole
*/
Genode::size_t const need = size + sizeof(Genode::Registered<Buffer>);
Genode::size_t const avail = _guard.quota() - _guard.consumed();
if (need > avail) { throw Gpu::Session_component::Out_of_ram(); }
try {
Genode::Dataspace_capability cap = _device.alloc_buffer(_guard, size);
try {
new (&_guard) Genode::Registered<Buffer>(_buffer_registry, cap);
} catch(...) {
_device.free_buffer(_guard, cap);
throw Gpu::Session_component::Out_of_ram();
}
return cap;
} catch (Igd::Device::Out_of_ram) {
throw Gpu::Session_component::Out_of_ram();
}
return Genode::Dataspace_capability();
}
void free_buffer(Genode::Dataspace_capability cap) override
{
if (!cap.valid()) { return; }
auto lookup_and_free = [&] (Buffer &buffer) {
if (!(buffer.cap == cap)) { return; }
if (buffer.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) {
Genode::error("cannot free mapped buffer");
/* XXX throw */
}
_device.free_buffer(_guard, cap);
Genode::destroy(&_guard, &buffer);
};
_buffer_registry.for_each(lookup_and_free);
}
Genode::Dataspace_capability map_buffer(Genode::Dataspace_capability cap,
bool aperture) override
{
if (!cap.valid()) { return Genode::Dataspace_capability(); }
Genode::Dataspace_capability map_cap;
auto lookup_and_map = [&] (Buffer &buffer) {
if (!(buffer.cap == cap)) { return; }
if (buffer.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) {
Genode::error("buffer already mapped");
return;
}
try {
Igd::Ggtt::Mapping const &map = _device.map_buffer(_guard, cap, aperture);
buffer.map.cap = map.cap;
buffer.map.offset = map.offset;
map_cap = buffer.map.cap;
} catch (Igd::Device::Could_not_map_buffer) {
Genode::error("could not map buffer object");
throw Gpu::Session::Out_of_ram();
}
};
_buffer_registry.for_each(lookup_and_map);
return map_cap;
}
void unmap_buffer(Genode::Dataspace_capability cap) override
{
if (!cap.valid()) { return; }
bool unmapped = false;
auto lookup_and_unmap = [&] (Buffer &buffer) {
if (!(buffer.map.cap == cap)) { return; }
if (buffer.fenced != Buffer::INVALID_FENCE) {
_device.clear_tiling(buffer.fenced);
_vgpu.active_fences--;
}
_device.unmap_buffer(_guard, buffer.map);
buffer.map.offset = Igd::Ggtt::Mapping::INVALID_OFFSET;
unmapped = true;
};
_buffer_registry.for_each(lookup_and_unmap);
if (!unmapped) { Genode::error("buffer not mapped"); }
}
bool map_buffer_ppgtt(Genode::Dataspace_capability cap,
Gpu::addr_t va) override
{
if (!cap.valid()) { return false; }
bool result = false;
auto lookup_and_map = [&] (Buffer &buffer) {
if (!(buffer.cap == cap)) { return; }
if (buffer.ppgtt_va != 0) {
Genode::error("buffer already mapped");
return;
}
try {
Genode::Dataspace_client buf(cap);
/* XXX check that actual_size matches alloc_buffer size */
Genode::size_t const actual_size = buf.size();
Genode::addr_t const phys_addr = buf.phys_addr();
_vgpu.rcs_map_ppgtt(va, phys_addr, actual_size);
buffer.ppgtt_va = va;
result = true;
} catch (Igd::Device::Could_not_map_buffer) {
/* FIXME do not result in Out_of_ram */
Genode::error("could not map buffer object into PPGTT");
return;
}
/* will throw below */
catch (Igd::Device::Out_of_ram) { return; }
};
_buffer_registry.for_each(lookup_and_map);
if (!result) { throw Gpu::Session::Out_of_ram(); }
return result;
}
void unmap_buffer_ppgtt(Genode::Dataspace_capability cap,
Gpu::addr_t va) override
{
if (!cap.valid()) {
Genode::error("invalid buffer capability");
return;
}
auto lookup_and_unmap = [&] (Buffer &buffer) {
if (!(buffer.cap == cap)) { return; }
if (buffer.ppgtt_va == 0) {
Genode::error("buffer not mapped");
return;
}
if (buffer.ppgtt_va != va) {
Genode::error("buffer not mapped at ", Genode::Hex(va));
return;
}
Genode::Dataspace_client buf(cap);
Genode::size_t const actual_size = buf.size();
_vgpu.rcs_unmap_ppgtt(va, actual_size);
buffer.ppgtt_va = 0;
};
_buffer_registry.for_each(lookup_and_unmap);
}
bool set_tiling(Genode::Dataspace_capability cap,
Genode::uint32_t const mode) override
{
if (_vgpu.active_fences > Igd::Device::Vgpu::MAX_FENCES) {
Genode::error("no free fences left, already active: ", _vgpu.active_fences);
return false;
}
Buffer *b = nullptr;
auto lookup = [&] (Buffer &buffer) {
if (!(buffer.map.cap == cap)) { return; }
b = &buffer;
};
_buffer_registry.for_each(lookup);
if (b == nullptr) {
Genode::error("attempt to set tiling for non-mapped buffer");
return false;
}
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;
}
};
class Gpu::Root : public Gpu::Root_component
{
private:
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
/*
* Noncopyable
*/
Root(Root const &);
Root &operator = (Root const &);
Genode::Env &_env;
Igd::Device *_device;
Genode::size_t _ram_quota(char const *args)
{
return Genode::Arg_string::find_arg(args, "ram_quota").ulong_value(0);
}
protected:
Session_component *_create_session(char const *args) override
{
if (!_device || !_device->vgpu_avail()) {
throw Genode::Service_denied();
}
/* at the moment we just need about ~160KiB for initial RCS bring-up */
Genode::size_t const required_quota = Gpu::Session::REQUIRED_QUOTA / 2;
Genode::size_t const ram_quota = _ram_quota(args);
if (ram_quota < required_quota) {
Genode::Session_label const label = Genode::label_from_args(args);
Genode::warning("insufficient dontated ram_quota (", ram_quota,
" bytes), require ", required_quota, " bytes ",
" by '", label, "'");
throw Session::Out_of_ram();
}
try {
using namespace Genode;
return new (md_alloc())
Session_component(_env.ep(),
session_resources_from_args(args),
session_label_from_args(args),
session_diag_from_args(args),
_env.rm(), *md_alloc(), ram_quota,
*_device);
} catch (...) { throw; }
}
void _upgrade_session(Session_component *s, char const *args) override
{
s->upgrade_ram_quota(_ram_quota(args));
/*
s->Ram_quota_guard::upgrade(ram_quota_from_args(args));
s->Cap_quota_guard::upgrade(cap_quota_from_args(args));
*/
}
void _destroy_session(Session_component *s) override
{
if (s->vgpu_active()) {
Genode::warning("vGPU active, reset device and hope for the best");
_device->reset();
}
Genode::destroy(md_alloc(), s);
}
public:
Root(Genode::Env &env, Genode::Allocator &alloc)
: Root_component(env.ep(), alloc), _env(env), _device(nullptr) { }
void manage(Igd::Device &device) { _device = &device; }
};
struct Main
{
Genode::Env &_env;
/*********
** Pci **
*********/
Platform::Connection _pci;
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
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 **
*********/
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;
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Genode::Constructible<Igd::Device> _device { };
Main(Genode::Env &env)
:
_env(env), _pci(env), _device_md_alloc(_env.ram(), _env.rm())
{
/* initial donation for device pd */
_pci.upgrade_ram(1024*1024);
_pci_cap = _find_gpu_device();
if (!_pci_cap.valid() || !_mch_enabled()) {
throw Igd::Device::Initialization_failed();
}
try {
_device.construct(_env, _device_md_alloc, _pci, _pci_cap,
_config_rom.xml());
} catch (...) {
_env.parent().exit(1);
return;
}
_gpu_root.manage(*_device);
_env.parent().announce(_env.ep().manage(_gpu_root));
}
~Main() { _pci.release_device(_pci_cap); }
};
void Component::construct(Genode::Env &env) { static Main main(env); }
Genode::size_t Component::stack_size() { return 32UL*1024*sizeof(long); }