genode/repos/os/src/drivers/gpu/intel/ggtt.h
Norman Feske eba9c15746 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
2018-01-17 12:14:35 +01:00

314 lines
7.1 KiB
C++

/*
* \brief Broadwell global graphics translation table
* \author Josef Soentgen
* \date 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.
*/
#ifndef _GLOBAL_GTT_H_
#define _GLOBAL_GTT_H_
/* Genode includes */
#include <util/bit_array.h>
/* local includes */
#include <mmio.h>
namespace Igd {
struct Ggtt;
}
/*
* Global Graphics Translation Table
*/
class Igd::Ggtt
{
public:
struct Could_not_find_free : Genode::Exception { };
struct Offset_out_of_range : Genode::Exception { };
struct Wrong_graphics_address : Genode::Exception { };
using Offset = Igd::uint32_t;
struct Mapping
{
Genode::Dataspace_capability cap { };
Offset offset;
Igd::addr_t vaddr = 0;
enum { INVALID_OFFSET = ~0u - 1, };
Mapping() : offset(INVALID_OFFSET) { }
Mapping(Genode::Dataspace_capability cap, Offset offset)
: cap(cap), offset(offset) { }
virtual ~Mapping() { }
};
private:
/*
* IHD-OS-BDW-Vol 5-11.15 p. 44
*/
struct Page_table_entry : Genode::Register<64>
{
struct Physical_adress : Bitfield<12, 36> { };
struct Present : Bitfield< 0, 1> { };
};
struct Space_allocator
{
Genode::Bit_array<1024*1024> _array { };
size_t _used { 0 };
bool allocated(addr_t const index) const
{
return _array.get(index, 1);
}
void set(addr_t const index)
{
_used++;
_array.set(index, 1);
}
void clear(addr_t const index)
{
_used--;
_array.clear(index, 1);
}
bool word_free(size_t const word) const
{
try {
size_t const bits = sizeof(size_t) * 8;
size_t const index = word * sizeof(size_t);
return !_array.get(index, bits);
} catch (...) { }
return false;
}
size_t used() const { return _used; }
} _space { };
Igd::Mmio &_mmio;
addr_t const _base;
size_t const _size;
size_t const _num_entries;
uint64_t *_entries;
addr_t const _scratch_page;
size_t const _aperture_size;
size_t const _aperture_entries;
void _insert_pte(addr_t pa, Offset offset)
{
Page_table_entry::access_t pte = 0;
Page_table_entry::Physical_adress::set(pte, pa >> 12);
Page_table_entry::Present::set(pte, 1);
_entries[offset] = pte;
_mmio.flush_gfx_tlb();
Igd::wmb();
}
public:
/**
* Constructor
*
* \param mmio reference to Igd::Mmio object
* \param base virtual base address of GGTT start
* \param size size of GGTT in bytes
* \param aperture_size size of the aperture in bytes
* \param scratch_page physical address of the scratch page
* \param fb_size size of the framebuffer region in the GTT in bytes
*/
Ggtt(Igd::Mmio &mmio, addr_t base, size_t size,
size_t aperture_size, addr_t scratch_page,
size_t fb_size)
:
_mmio(mmio),
_base(base),
_size(size),
/* make the last entry/page unavailable */
_num_entries((_size / 8) - 1),
_entries((uint64_t*)_base),
_scratch_page(scratch_page),
_aperture_size(aperture_size),
_aperture_entries(_aperture_size / PAGE_SIZE)
{
/* reserve GGTT region occupied by the framebuffer */
size_t const fb_entries = fb_size / PAGE_SIZE;
for (size_t i = 0; i < fb_entries; i++) {
_space.set(i);
}
for (size_t i = fb_entries; i < _num_entries; i++) {
_insert_pte(_scratch_page, i);
}
}
/**
* Insert page into GGTT
*
* \param pa physical address
* \param offset offset of GTT entry
*
* \throw Offset_out_of_range
*/
void insert_pte(addr_t pa, Offset offset)
{
if (offset > _num_entries) { throw Offset_out_of_range(); }
if (_space.allocated(offset)) {
Genode::warning(__func__, " offset:", offset, " already used");
}
_space.set(offset);
_insert_pte(pa, offset);
}
/**
* Remove page from GTT
*
* \param offset offset of GTT entry
*/
void remove_pte(Offset offset)
{
if (!_space.allocated(offset)) {
Genode::warning(__func__, " offset:", offset, " was not used");
return;
}
_space.clear(offset);
_insert_pte(_scratch_page, offset);
}
/**
* Remove range of pages from GTT
*
* \param start offset of the first page in the GGTT
* \param num number of pages
*/
void remove_pte_range(Offset const start, Offset const num)
{
Offset const end = start + num;
for (Offset offset = start; offset < end; offset++) {
remove_pte(offset);
}
}
/**
* Find free GGTT entries
*
* \param num number of continuous entries
* \param aperture request entries mappable by CPU
*
* \return start offset of free entry range
*
* \throw Could_not_find_free
*/
Offset find_free(size_t /* num */, bool aperture = false) const
{
size_t const start_index = aperture ? 0 : _aperture_entries;
size_t const end_index = aperture ? _aperture_entries : _num_entries;
for (size_t i = start_index; i < end_index; i++) {
bool const f = _space.word_free(i);
if (f) { return i * (sizeof(size_t)); }
}
throw Could_not_find_free();
}
/**
* Get GGTT entry offset from GMADDR
*
* \param gmaddr graphics memory address
*
* \return GGTT offset of GMADDR
*
* \throw Wrong_graphics_address
*/
Offset offset(addr_t const gmaddr) const
{
if (gmaddr & 0xfffu) { throw Wrong_graphics_address(); }
if (gmaddr > 0xffffffffu) { throw Wrong_graphics_address(); }
return gmaddr / PAGE_SIZE;
}
/**
* Get GMADDR for GGTT entry offset
*
* \param offset offset of GGTT entry
*
* \return graphics memory address
*
* \throw Offset_out_of_range
*/
addr_t addr(Offset offset) const
{
if (offset > _num_entries) { throw Offset_out_of_range(); }
return offset * PAGE_SIZE;
}
/**
* Get total number of entries in GGTT
*
* \return number of entries
*/
size_t entries() const { return _num_entries; }
/**
* Get scratch page address
*
* \return physical address of the scratch page
*/
addr_t scratch_page() const { return _scratch_page; }
/*********************
** Debug interface **
*********************/
void dump(bool const dump_entries = false,
size_t const limit = 0u,
size_t const start = 0u) const
{
using namespace Genode;
log("GGTT");
log(" vaddr:", Hex(_base), " size:", Hex(_size), " entries:", _num_entries,
" used:", _space.used(), " aperture_size:", Hex(_aperture_size));
log(" scratch_page:", Hex(_scratch_page), " (PA)");
if (!dump_entries) { return; }
log(" entries:");
uint64_t *ggtt = (uint64_t*)_base;
size_t const max = !limit ? _num_entries : limit > _num_entries ? _num_entries : limit;
for (size_t i = start; i < start + max; i += 8) {
log(" ", Hex(i, Hex::PREFIX, Hex::PAD), " ",
Hex(ggtt[i]), " ", Hex(ggtt[i + 1]), " ",
Hex(ggtt[i + 2]), " ", Hex(ggtt[i + 3]), " ",
Hex(ggtt[i + 4]), " ", Hex(ggtt[i + 5]), " ",
Hex(ggtt[i + 6]), " ", Hex(ggtt[i + 7]));
}
}
};
#endif /* _GLOBAL_GTT_H_ */