mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +00:00
os: add Gpu driver for Intel Gen8 HD graphics
This commit introduces a experimental 3D driver for Intel Gen8 HD graphics devices as well as the corresponding Gpu session. Fixes #2507.
This commit is contained in:
parent
1ac7b034ba
commit
198019edca
22
repos/os/include/gpu_session/capability.h
Normal file
22
repos/os/include/gpu_session/capability.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* \brief GPU session capability type
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _INCLUDE__GPU_SESSION__CAPABILITY_H_
|
||||
#define _INCLUDE__GPU_SESSION__CAPABILITY_H_
|
||||
|
||||
#include <base/capability.h>
|
||||
#include <gpu_session/gpu_session.h>
|
||||
|
||||
namespace Gpu { typedef Genode::Capability<Session> Session_capability; }
|
||||
|
||||
#endif /* _INCLUDE__GPU_SESSION__CAPABILITY_H_ */
|
73
repos/os/include/gpu_session/client.h
Normal file
73
repos/os/include/gpu_session/client.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* \brief Client-side Gpu session interface
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _INCLUDE__GPU_SESSION__CLIENT_H_
|
||||
#define _INCLUDE__GPU_SESSION__CLIENT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/rpc_client.h>
|
||||
#include <gpu_session/capability.h>
|
||||
|
||||
namespace Gpu { class Session_client; }
|
||||
|
||||
|
||||
class Gpu::Session_client : public Genode::Rpc_client<Session>
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param session session capability
|
||||
*/
|
||||
Session_client(Session_capability session)
|
||||
: Genode::Rpc_client<Session>(session) { }
|
||||
|
||||
/***********************
|
||||
** Session interface **
|
||||
***********************/
|
||||
|
||||
Info info() const override {
|
||||
return call<Rpc_info>(); }
|
||||
|
||||
void exec_buffer(Genode::Dataspace_capability cap, Genode::size_t size) override {
|
||||
call<Rpc_exec_buffer>(cap, size); }
|
||||
|
||||
void completion_sigh(Genode::Signal_context_capability sigh) override {
|
||||
call<Rpc_completion_sigh>(sigh); }
|
||||
|
||||
Genode::Dataspace_capability alloc_buffer(Genode::size_t size) override {
|
||||
return call<Rpc_alloc_buffer>(size); }
|
||||
|
||||
void free_buffer(Genode::Dataspace_capability ds) override {
|
||||
call<Rpc_free_buffer>(ds); }
|
||||
|
||||
Genode::Dataspace_capability map_buffer(Genode::Dataspace_capability ds,
|
||||
bool aperture) override {
|
||||
return call<Rpc_map_buffer>(ds, aperture); }
|
||||
|
||||
void unmap_buffer(Genode::Dataspace_capability ds) override {
|
||||
call<Rpc_unmap_buffer>(ds); }
|
||||
|
||||
bool map_buffer_ppgtt(Genode::Dataspace_capability ds,
|
||||
Gpu::addr_t va) override {
|
||||
return call<Rpc_map_buffer_ppgtt>(ds, va); }
|
||||
|
||||
void unmap_buffer_ppgtt(Genode::Dataspace_capability ds, Gpu::addr_t va) override {
|
||||
call<Rpc_unmap_buffer_ppgtt>(ds, va); }
|
||||
|
||||
bool set_tiling(Genode::Dataspace_capability ds, unsigned mode) override {
|
||||
return call<Rpc_set_tiling>(ds, mode); }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__GPU_SESSION__CLIENT_H_ */
|
51
repos/os/include/gpu_session/connection.h
Normal file
51
repos/os/include/gpu_session/connection.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* \brief Connection to Gpu service
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _INCLUDE__GPU_SESSION__CONNECTION_H_
|
||||
#define _INCLUDE__GPU_SESSION__CONNECTION_H_
|
||||
|
||||
#include <gpu_session/client.h>
|
||||
#include <base/connection.h>
|
||||
#include <base/allocator.h>
|
||||
|
||||
namespace Gpu { struct Connection; }
|
||||
|
||||
struct Gpu::Connection : Genode::Connection<Session>, Session_client
|
||||
{
|
||||
/**
|
||||
* Issue session request
|
||||
*
|
||||
* \noapi
|
||||
*/
|
||||
Capability<Gpu::Session> _session(Genode::Parent &parent,
|
||||
char const *label, Genode::size_t quota)
|
||||
{
|
||||
return session(parent, "ram_quota=%ld, label=\"%s\"", quota, label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param quota initial amount of quota used for allocating Gpu
|
||||
* memory
|
||||
*/
|
||||
Connection(Genode::Env &env,
|
||||
Genode::size_t quota = Session::REQUIRED_QUOTA,
|
||||
const char *label = "")
|
||||
:
|
||||
Genode::Connection<Session>(env, _session(env.parent(), label, quota)),
|
||||
Session_client(cap())
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__GPU_SESSION__CONNECTION_H_ */
|
184
repos/os/include/gpu_session/gpu_session.h
Normal file
184
repos/os/include/gpu_session/gpu_session.h
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* \brief Gpu session interface.
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _INCLUDE__GPU_SESSION__GPU_SESSION_H_
|
||||
#define _INCLUDE__GPU_SESSION__GPU_SESSION_H_
|
||||
|
||||
#include <session/session.h>
|
||||
|
||||
namespace Gpu {
|
||||
|
||||
using addr_t = Genode::uint64_t;
|
||||
|
||||
struct Info;
|
||||
struct Session;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Gpu information
|
||||
*
|
||||
* Used to query information in the DRM backend
|
||||
*/
|
||||
struct Gpu::Info
|
||||
{
|
||||
using Chip_id = Genode::uint16_t;
|
||||
using Features = Genode::uint32_t;
|
||||
using size_t = Genode::size_t;
|
||||
using Context_id = Genode::uint32_t;
|
||||
|
||||
Chip_id chip_id;
|
||||
Features features;
|
||||
size_t aperture_size;
|
||||
Context_id ctx_id;
|
||||
|
||||
Info(Chip_id chip_id, Features features,
|
||||
size_t aperture_size, Context_id ctx_id)
|
||||
:
|
||||
chip_id(chip_id), features(features),
|
||||
aperture_size(aperture_size), ctx_id(ctx_id)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Gpu session interface
|
||||
*/
|
||||
struct Gpu::Session : public Genode::Session
|
||||
{
|
||||
struct Out_of_ram : Genode::Exception { };
|
||||
struct Out_of_caps : Genode::Exception { };
|
||||
|
||||
enum { REQUIRED_QUOTA = 1024 * 1024, CAP_QUOTA = 8, };
|
||||
|
||||
static const char *service_name() { return "Gpu"; }
|
||||
|
||||
virtual ~Session() { }
|
||||
|
||||
/***********************
|
||||
** Session interface **
|
||||
***********************/
|
||||
|
||||
/**
|
||||
* Query GPU information
|
||||
*/
|
||||
virtual Info info() const = 0;
|
||||
|
||||
/**
|
||||
* Execute commands from given buffer
|
||||
*
|
||||
* \param cap capability to buffer object containing the exec buffer
|
||||
* \param size size of the batch buffer in bytes
|
||||
*/
|
||||
virtual void exec_buffer(Genode::Dataspace_capability cap, Genode::size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Register completion signal handler
|
||||
*
|
||||
* \param sigh signal handler that is called when the execution
|
||||
* has completed
|
||||
*/
|
||||
virtual void completion_sigh(Genode::Signal_context_capability sigh) = 0;
|
||||
|
||||
/**
|
||||
* Allocate buffer dataspace
|
||||
*
|
||||
* \param size size of buffer in bytes
|
||||
*
|
||||
* \throw Out_of_ram
|
||||
* \throw Out_of_caps
|
||||
*/
|
||||
virtual Genode::Dataspace_capability alloc_buffer(Genode::size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Free buffer dataspace
|
||||
*
|
||||
* \param ds dataspace capability for buffer
|
||||
*/
|
||||
virtual void free_buffer(Genode::Dataspace_capability ds) = 0;
|
||||
|
||||
/**
|
||||
* Map buffer
|
||||
*
|
||||
* \param ds dataspace capability for buffer
|
||||
* \param aperture if true create CPU accessible mapping through
|
||||
* GGTT window, otherwise create PPGTT mapping
|
||||
*/
|
||||
virtual Genode::Dataspace_capability map_buffer(Genode::Dataspace_capability ds,
|
||||
bool aperture) = 0;
|
||||
|
||||
/**
|
||||
* Unmap buffer
|
||||
*
|
||||
* \param ds dataspace capability for buffer
|
||||
*/
|
||||
virtual void unmap_buffer(Genode::Dataspace_capability ds) = 0;
|
||||
|
||||
/**
|
||||
* Map buffer in PPGTT
|
||||
*
|
||||
* \param ds dataspace capability for buffer
|
||||
* \param va virtual address
|
||||
*/
|
||||
virtual bool map_buffer_ppgtt(Genode::Dataspace_capability ds,
|
||||
Gpu::addr_t va) = 0;
|
||||
|
||||
/**
|
||||
* Unmap buffer
|
||||
*
|
||||
* \param ds dataspace capability for buffer
|
||||
*/
|
||||
virtual void unmap_buffer_ppgtt(Genode::Dataspace_capability ds, Gpu::addr_t) = 0;
|
||||
|
||||
/**
|
||||
* Set tiling for buffer
|
||||
*
|
||||
* \param ds dataspace capability for buffer
|
||||
* \param mode tiling mode
|
||||
*/
|
||||
virtual bool set_tiling(Genode::Dataspace_capability ds, unsigned mode) = 0;
|
||||
|
||||
/*******************
|
||||
** RPC interface **
|
||||
*******************/
|
||||
|
||||
GENODE_RPC(Rpc_info, Info, info);
|
||||
GENODE_RPC(Rpc_exec_buffer, void, exec_buffer, Genode::Dataspace_capability,
|
||||
Genode::size_t);
|
||||
GENODE_RPC(Rpc_completion_sigh, void, completion_sigh,
|
||||
Genode::Signal_context_capability);
|
||||
GENODE_RPC_THROW(Rpc_alloc_buffer, Genode::Dataspace_capability, alloc_buffer,
|
||||
GENODE_TYPE_LIST(Out_of_ram),
|
||||
Genode::size_t);
|
||||
GENODE_RPC(Rpc_free_buffer, void, free_buffer, Genode::Dataspace_capability);
|
||||
GENODE_RPC_THROW(Rpc_map_buffer, Genode::Dataspace_capability, map_buffer,
|
||||
GENODE_TYPE_LIST(Out_of_ram),
|
||||
Genode::Dataspace_capability, bool);
|
||||
GENODE_RPC(Rpc_unmap_buffer, void, unmap_buffer,
|
||||
Genode::Dataspace_capability);
|
||||
GENODE_RPC_THROW(Rpc_map_buffer_ppgtt, bool, map_buffer_ppgtt,
|
||||
GENODE_TYPE_LIST(Out_of_ram),
|
||||
Genode::Dataspace_capability, Gpu::addr_t);
|
||||
GENODE_RPC(Rpc_unmap_buffer_ppgtt, void, unmap_buffer_ppgtt,
|
||||
Genode::Dataspace_capability, Gpu::addr_t);
|
||||
GENODE_RPC(Rpc_set_tiling, bool, set_tiling,
|
||||
Genode::Dataspace_capability, unsigned);
|
||||
|
||||
GENODE_RPC_INTERFACE(Rpc_info, Rpc_exec_buffer,
|
||||
Rpc_completion_sigh, Rpc_alloc_buffer,
|
||||
Rpc_free_buffer, Rpc_map_buffer, Rpc_unmap_buffer,
|
||||
Rpc_map_buffer_ppgtt, Rpc_unmap_buffer_ppgtt,
|
||||
Rpc_set_tiling);
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__GPU_SESSION__GPU_SESSION_H_ */
|
202
repos/os/src/drivers/gpu/intel/commands.h
Normal file
202
repos/os/src/drivers/gpu/intel/commands.h
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* \brief Broadwell MI commands
|
||||
* \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 _COMMANDS_H_
|
||||
#define _COMMANDS_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/mmio.h>
|
||||
#include <util/string.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
|
||||
|
||||
namespace Igd {
|
||||
|
||||
struct Cmd_header;
|
||||
struct Mi_noop;
|
||||
struct Mi_user_interrupt;
|
||||
struct Mi_batch_buffer_start;
|
||||
struct Pipe_control;
|
||||
|
||||
void cmd_dump(uint32_t cmd, uint32_t index = 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 6-11.15 p. 2
|
||||
*/
|
||||
struct Igd::Cmd_header : Genode::Register<32>
|
||||
{
|
||||
struct Cmd_type : Bitfield<29, 3>
|
||||
{
|
||||
enum {
|
||||
MI_COMMAND = 0b000,
|
||||
MI_BCS = 0b010,
|
||||
MI_RCS = 0b011,
|
||||
};
|
||||
};
|
||||
|
||||
struct Cmd_subtype : Bitfield<27, 2> { };
|
||||
struct Cmd_opcode : Bitfield<24, 3> { };
|
||||
|
||||
/*
|
||||
* Actually bit 23:x seems to be the sub-opcode but opcodes
|
||||
* include bit 23 (see p. 5).
|
||||
*/
|
||||
struct Mi_cmd_opcode : Bitfield<23, 6>
|
||||
{
|
||||
enum {
|
||||
MI_NOOP = 0x00,
|
||||
MI_USER_INTERRUPT = 0x02,
|
||||
MI_WAIT_FOR_EVENT = 0x03,
|
||||
MI_FLUSH = 0x04,
|
||||
MI_REPORT_HEAD = 0x07,
|
||||
MI_ARB_ON_OFF = 0x08,
|
||||
MI_BATCH_BUFFER_END = 0x0A,
|
||||
MI_SUSPEND_FLUSH = 0x0B,
|
||||
MI_SET_APPID = 0x0E,
|
||||
MI_OVERLAY_FLIP = 0x11,
|
||||
MI_LOAD_SCAN_LINES_INCL = 0x12,
|
||||
MI_DISPLAY_FLIP = 0x14,
|
||||
MI_DISPLAY_FLIP_I915 = 0x14,
|
||||
MI_SEMAPHORE_MBOX = 0x16,
|
||||
MI_SET_CONTEXT = 0x18,
|
||||
MI_SEMAPHORE_SIGNAL = 0x1b,
|
||||
MI_SEMAPHORE_WAIT = 0x1c,
|
||||
MI_STORE_DWORD_IMM = 0x20,
|
||||
MI_STORE_DWORD_INDEX = 0x21,
|
||||
MI_LOAD_REGISTER_IMM = 0x22,
|
||||
MI_STORE_REGISTER_MEM = 0x24,
|
||||
MI_FLUSH_DW = 0x26,
|
||||
MI_LOAD_REGISTER_MEM = 0x29,
|
||||
MI_BATCH_BUFFER = 0x30,
|
||||
MI_BATCH_BUFFER_START = 0x31,
|
||||
};
|
||||
};
|
||||
|
||||
typename Cmd_header::access_t value;
|
||||
|
||||
Cmd_header() : value(0) { }
|
||||
|
||||
Cmd_header(Igd::uint32_t value) : value(value) { }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2a-11.15 p. 870
|
||||
*/
|
||||
struct Igd::Mi_noop : Cmd_header
|
||||
{
|
||||
Mi_noop()
|
||||
{
|
||||
Cmd_header::Cmd_type::set(Cmd_header::value,
|
||||
Cmd_header::Cmd_type::MI_COMMAND);
|
||||
Cmd_header::Mi_cmd_opcode::set(Cmd_header::value,
|
||||
Cmd_header::Mi_cmd_opcode::MI_NOOP);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2a-11.15 p. 948 ff.
|
||||
*/
|
||||
struct Igd::Mi_user_interrupt : Cmd_header
|
||||
{
|
||||
|
||||
Mi_user_interrupt()
|
||||
{
|
||||
Cmd_header::Cmd_type::set(Cmd_header::value,
|
||||
Cmd_header::Cmd_type::MI_COMMAND);
|
||||
Cmd_header::Mi_cmd_opcode::set(Cmd_header::value,
|
||||
Cmd_header::Mi_cmd_opcode::MI_USER_INTERRUPT);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2a-11.15 p. 793 ff.
|
||||
*/
|
||||
struct Igd::Mi_batch_buffer_start : Cmd_header
|
||||
{
|
||||
struct Address_space_indicator : Bitfield<8, 1>
|
||||
{
|
||||
enum { GTT = 0b0, PPGTT = 0b1, };
|
||||
};
|
||||
|
||||
struct Dword_length : Bitfield<0, 8> { };
|
||||
|
||||
Mi_batch_buffer_start()
|
||||
{
|
||||
Cmd_header::Cmd_type::set(Cmd_header::value,
|
||||
Cmd_header::Cmd_type::MI_COMMAND);
|
||||
Cmd_header::Mi_cmd_opcode::set(Cmd_header::value,
|
||||
Cmd_header::Mi_cmd_opcode::MI_BATCH_BUFFER_START);
|
||||
Address_space_indicator::set(Cmd_header::value, Address_space_indicator::PPGTT);
|
||||
|
||||
Dword_length::set(Cmd_header::value, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2a-11.15 p. 983 ff.
|
||||
*/
|
||||
struct Igd::Pipe_control : Cmd_header
|
||||
{
|
||||
struct Dword_length : Bitfield<0, 8> { };
|
||||
|
||||
enum {
|
||||
GFX_PIPE_LINE = 0b11,
|
||||
PIPE_CONTROL = 0b10,
|
||||
};
|
||||
|
||||
enum {
|
||||
FLUSH_L3 = (1 << 27),
|
||||
GLOBAL_GTT_IVB = (1 << 24),
|
||||
MMIO_WRITE = (1 << 23),
|
||||
STORE_DATA_INDEX = (1 << 21),
|
||||
CS_STALL = (1 << 20),
|
||||
TLB_INVALIDATE = (1 << 18),
|
||||
MEDIA_STATE_CLEAR = (1 << 16),
|
||||
QW_WRITE = (1 << 14),
|
||||
POST_SYNC_OP_MASK = (3 << 14),
|
||||
DEPTH_STALL = (1 << 13),
|
||||
WRITE_FLUSH = (1 << 12),
|
||||
RENDER_TARGET_CACHE_FLUSH = (1 << 12),
|
||||
INSTRUCTION_CACHE_INVALIDATE = (1 << 11),
|
||||
TEXTURE_CACHE_INVALIDATE = (1 << 10),
|
||||
INDIRECT_STATE_DISABLE = (1 << 9),
|
||||
NOTIFY = (1 << 8),
|
||||
FLUSH_ENABLE = (1 << 7),
|
||||
DC_FLUSH_ENABLE = (1 << 5),
|
||||
VF_CACHE_INVALIDATE = (1 << 4),
|
||||
CONST_CACHE_INVALIDATE = (1 << 3),
|
||||
STATE_CACHE_INVALIDATE = (1 << 2),
|
||||
STALL_AT_SCOREBOARD = (1 << 1),
|
||||
DEPTH_CACHE_FLUSH = (1 << 0),
|
||||
};
|
||||
|
||||
Pipe_control(Genode::uint8_t length)
|
||||
{
|
||||
Cmd_header::Cmd_type::set(Cmd_header::value,
|
||||
Cmd_header::Cmd_type::MI_RCS);
|
||||
Cmd_header::Cmd_subtype::set(Cmd_header::value, GFX_PIPE_LINE);
|
||||
Cmd_header::Cmd_opcode::set(Cmd_header::value, PIPE_CONTROL);
|
||||
|
||||
Dword_length::set(Cmd_header::value, (length-2));
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _COMMANDS_H_ */
|
885
repos/os/src/drivers/gpu/intel/context.h
Normal file
885
repos/os/src/drivers/gpu/intel/context.h
Normal file
@ -0,0 +1,885 @@
|
||||
/*
|
||||
* \brief Broadwell logical ring context
|
||||
* \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 _LOGICAL_RING_CONTEXT_H_
|
||||
#define _LOGICAL_RING_CONTEXT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/mmio.h>
|
||||
#include <util/string.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
#include <commands.h>
|
||||
|
||||
|
||||
namespace Igd {
|
||||
|
||||
struct Context_status_qword;
|
||||
|
||||
struct Common_context_regs;
|
||||
|
||||
struct Hardware_status_page;
|
||||
template <addr_t RING_BASE> class Execlist_context;
|
||||
template <addr_t RING_BASE> class Ppgtt_context;
|
||||
class Engine_context;
|
||||
class Ext_engine_context;
|
||||
class Urb_atomic_context;
|
||||
|
||||
class Rcs_context;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 6-11.15 p. 8
|
||||
* IHD-OS-BDW-Vol 2d-11.15 p. 111
|
||||
*/
|
||||
struct Igd::Context_status_qword : Genode::Register<64>
|
||||
{
|
||||
struct Context_id : Bitfield<32, 32> { };
|
||||
/* only valid if Preempted set bit */
|
||||
struct Lite_restore : Bitfield<15, 1> { };
|
||||
struct Display_plane : Bitfield<12, 3>
|
||||
{
|
||||
enum {
|
||||
DISPLAY_PLANE_A = 0b000,
|
||||
DISPLAY_PLANE_B = 0b001,
|
||||
DISPLAY_PLANE_C = 0b010,
|
||||
DISPLAY_PLANE_SPRITE_A = 0b011,
|
||||
DISPLAY_PLANE_SPRITE_B = 0b100,
|
||||
DISPLAY_PLANE_SPRITE_C = 0b101,
|
||||
};
|
||||
};
|
||||
/* only valid if Wait_on_semaphore bit set */
|
||||
struct Semaphore_wait_mode : Bitfield<11, 1>
|
||||
{
|
||||
enum {
|
||||
SIGNAL_MODE = 0b00,
|
||||
POLL_MODE = 0b01,
|
||||
};
|
||||
};
|
||||
struct Wait_on_scanline : Bitfield< 8, 1> { };
|
||||
struct Wait_on_semaphore : Bitfield< 7, 1> { };
|
||||
struct Wait_on_v_blank : Bitfield< 6, 1> { };
|
||||
struct Wait_on_sync_flip : Bitfield< 5, 1> { };
|
||||
struct Context_complete : Bitfield< 4, 1> { };
|
||||
struct Active_to_idle : Bitfield< 3, 1> { };
|
||||
struct Element_switch : Bitfield< 2, 1> { };
|
||||
struct Preempted : Bitfield< 1, 1> { };
|
||||
struct Idle_to_active : Bitfield< 0, 1> { };
|
||||
};
|
||||
|
||||
|
||||
struct Igd::Common_context_regs : public Genode::Mmio
|
||||
{
|
||||
template <long int OFFSET>
|
||||
struct Common_register : Register<OFFSET * sizeof(uint32_t), 32> { };
|
||||
|
||||
template <long int OFFSET, size_t NUM>
|
||||
struct Common_register_array : Register_array<OFFSET * sizeof(uint32_t), 32, NUM, 32> { };
|
||||
|
||||
addr_t _base;
|
||||
|
||||
Common_context_regs(addr_t base) : Genode::Mmio(base), _base(base) { }
|
||||
|
||||
addr_t base() const { return _base; }
|
||||
|
||||
template <typename T>
|
||||
void write_offset(typename T::access_t const value)
|
||||
{
|
||||
write<T>(value + T::OFFSET);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 3-11.15 p. 18 (for VCS)
|
||||
* IHD-OS-BDW-Vol 3-11.15 p. 20 (for BCS)
|
||||
* IHD-OS-BDW-Vol 3-11.15 p. 22 (for VECS)
|
||||
* IHD-OS-BDW-Vol 7-11.15 p. 27 (for RCS)
|
||||
*
|
||||
* All engines use the same layout until offset 0x118.
|
||||
*/
|
||||
template <Genode::addr_t RING_BASE>
|
||||
class Igd::Execlist_context : public Igd::Common_context_regs
|
||||
{
|
||||
public:
|
||||
|
||||
/* MI_NOOP */
|
||||
struct Noop_1 : Common_register<0x0000> { };
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2a-11.15 p. 841 ff.
|
||||
*/
|
||||
struct Load_immediate_header : Common_register<0x0001> { };
|
||||
|
||||
/*
|
||||
* XXX see i915 intel_lrc.h
|
||||
*/
|
||||
struct Context_control_mmio : Common_register<0x0002>
|
||||
{
|
||||
enum { OFFSET = 0x244, };
|
||||
};
|
||||
struct Context_control_value : Common_register<0x0003>
|
||||
{
|
||||
using R = Common_register<0x0003>;
|
||||
|
||||
struct Mask_bits : R::template Bitfield<16, 16> { };
|
||||
|
||||
struct Inhibit_syn_context_switch_mask : R::template Bitfield<18, 1> { };
|
||||
struct Inhibit_syn_context_switch : R::template Bitfield< 3, 1> { };
|
||||
|
||||
struct Rs_context_enable_mask : R::template Bitfield<17, 1> { };
|
||||
struct Rs_context_enable : R::template Bitfield< 1, 1> { };
|
||||
|
||||
struct Engine_context_restore_inhibit_mask : R::template Bitfield<16, 1> { };
|
||||
struct Engine_context_restore_inhibit : R::template Bitfield< 0, 1> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1350 ff
|
||||
*/
|
||||
struct Ring_buffer_head_mmio : Common_register<0x0004>
|
||||
{
|
||||
enum { OFFSET = 0x34, };
|
||||
};
|
||||
struct Ring_buffer_head_value : Common_register<0x0005>
|
||||
{
|
||||
using R = Common_register<0x0005>;
|
||||
|
||||
struct Wrap_count : R::template Bitfield<21,11> { };
|
||||
struct Head_offset : R::template Bitfield< 2,19> { };
|
||||
struct Reserved_mbz : R::template Bitfield< 0, 2> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1353 ff
|
||||
*/
|
||||
struct Ring_buffer_tail_mmio : Common_register<0x0006>
|
||||
{
|
||||
enum { OFFSET = 0x30, };
|
||||
};
|
||||
struct Ring_buffer_tail_value : Common_register<0x0007>
|
||||
{
|
||||
using R = Common_register<0x0007>;
|
||||
|
||||
struct Reserved_mbz_1 : R::template Bitfield<21, 11> { };
|
||||
struct Tail_offset : R::template Bitfield< 3, 18> { };
|
||||
struct Reserved_mbz_2 : R::template Bitfield< 0, 3> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1352 ff
|
||||
*/
|
||||
struct Ring_buffer_start_mmio : Common_register<0x0008>
|
||||
{
|
||||
enum { OFFSET = 0x38, };
|
||||
};
|
||||
struct Ring_buffer_start_value : Common_register<0x0009>
|
||||
{
|
||||
using R = Common_register<0x0009>;
|
||||
|
||||
struct Starting_address : R::template Bitfield<12, 20> { };
|
||||
struct Reserved_mbz : R::template Bitfield< 0, 12> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1345 ff
|
||||
*/
|
||||
struct Ring_buffer_control_mmio : Common_register<0x000A>
|
||||
{
|
||||
enum { OFFSET = 0x3c, };
|
||||
};
|
||||
struct Ring_buffer_control_value : Common_register<0x000B>
|
||||
{
|
||||
using R = Common_register<0x000B>;
|
||||
|
||||
struct Reserved_mbz_1 : R::template Bitfield<21, 11> { };
|
||||
struct Buffer_length : R::template Bitfield<12, 9> { };
|
||||
struct RBwait : R::template Bitfield<11, 1>
|
||||
{
|
||||
enum { CLEAR = 0b01, };
|
||||
};
|
||||
|
||||
struct Semaphore_wait : R::template Bitfield<10, 1>
|
||||
{
|
||||
enum { CLEAR = 0b01, };
|
||||
};
|
||||
|
||||
struct Reserved_mbz_2 : R::template Bitfield< 3, 7> { };
|
||||
struct Arhp : R::template Bitfield< 1, 2>
|
||||
{
|
||||
enum {
|
||||
MI_AUTOREPORT_OFF = 0,
|
||||
MI_AUTOREPORT_64KB = 1,
|
||||
MI_AUTOREPORT_4KB = 2,
|
||||
MI_AUTOREPORT_128KB = 3
|
||||
};
|
||||
};
|
||||
|
||||
struct Ring_buffer_enable : R::template Bitfield< 0, 1> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 142
|
||||
*/
|
||||
struct Bb_addr_udw_mmio : Common_register<0x000C>
|
||||
{
|
||||
enum { OFFSET = 0x168, };
|
||||
};
|
||||
struct Bb_addr_udw_value : Common_register<0x000D> { };
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 129
|
||||
*/
|
||||
struct Bb_addr_mmio : Common_register<0x000E>
|
||||
{
|
||||
enum { OFFSET = 0x140, };
|
||||
};
|
||||
struct Bb_addr_value : Common_register<0x000F> { };
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 138
|
||||
*/
|
||||
struct Bb_state_mmio : Common_register<0x0010>
|
||||
{
|
||||
enum { OFFSET = 0x110, };
|
||||
};
|
||||
struct Bb_state_value : Common_register<0x0011>
|
||||
{
|
||||
struct Address_space_indicator : Bitfield<5, 1> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1402
|
||||
*/
|
||||
struct Sbb_addr_udw_mmio : Common_register<0x0012>
|
||||
{
|
||||
enum { OFFSET = 0x11C, };
|
||||
};
|
||||
struct Sbb_addr_udw_value : Common_register<0x0013> { };
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1397
|
||||
*/
|
||||
struct Sbb_addr_mmio : Common_register<0x0014>
|
||||
{
|
||||
enum { OFFSET = 0x114, };
|
||||
};
|
||||
struct Sbb_addr_value : Common_register<0x0015> { };
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1399
|
||||
*/
|
||||
struct Sbb_state_mmio : Common_register<0x0016>
|
||||
{
|
||||
enum { OFFSET = 0x118, };
|
||||
};
|
||||
struct Sbb_state_value : Common_register<0x0017> { };
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 131 ff
|
||||
*
|
||||
* RCS only
|
||||
*/
|
||||
struct Bb_per_ctx_ptr_mmio : Common_register<0x0018>
|
||||
{
|
||||
enum { OFFSET = 0x1C0, };
|
||||
};
|
||||
struct Bb_per_ctx_ptr_value : Common_register<0x0019>
|
||||
{
|
||||
using R = Common_register<0x0019>;
|
||||
|
||||
struct Address : R::template Bitfield<12, 20> { };
|
||||
struct Reserved_mbz : R::template Bitfield< 2, 10> { };
|
||||
struct Enable : R::template Bitfield< 1, 1> { };
|
||||
struct Valid : R::template Bitfield< 0, 1> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 821 ff
|
||||
*
|
||||
* RCS only
|
||||
*/
|
||||
struct Rcs_indirect_ctx_mmio : Common_register<0x001A>
|
||||
{
|
||||
enum { OFFSET = 0x1C4, };
|
||||
};
|
||||
struct Rcs_indirect_ctx_value : Common_register<0x001B>
|
||||
{
|
||||
using R = Common_register<0x001B>;
|
||||
|
||||
struct Address : R::template Bitfield< 6, 26> { };
|
||||
struct Size : R::template Bitfield< 0, 6> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* XXX
|
||||
*
|
||||
* RCS only
|
||||
*/
|
||||
struct Rcs_indirect_ctx_offset_mmio : Common_register<0x001C>
|
||||
{
|
||||
enum { OFFSET = 0x1C8, };
|
||||
};
|
||||
struct Rcs_indirect_ctx_offset_value : Common_register<0x001D>
|
||||
{
|
||||
using R = Common_register<0x001D>;
|
||||
|
||||
struct Reserved_mbz_1 : R::template Bitfield<16, 16> { };
|
||||
struct Offset : R::template Bitfield< 6, 10> { };
|
||||
struct Reserved_mbz_2 : R::template Bitfield< 0, 6> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* XXX
|
||||
*
|
||||
* RCS only
|
||||
*/
|
||||
struct Rcs_noop_1 : Common_register_array<0x001E, 2> { };
|
||||
|
||||
public:
|
||||
|
||||
Execlist_context(addr_t base,
|
||||
addr_t ring_buffer_start,
|
||||
size_t ring_buffer_length,
|
||||
uint32_t immediate_header)
|
||||
:
|
||||
Common_context_regs(base)
|
||||
{
|
||||
write<Load_immediate_header>(immediate_header);
|
||||
write_offset<Context_control_mmio>(RING_BASE);
|
||||
{
|
||||
typename Context_control_value::access_t v = read<Context_control_value>();
|
||||
Context_control_value::Engine_context_restore_inhibit_mask::set(v, 1);
|
||||
Context_control_value::Engine_context_restore_inhibit::set(v, 1);
|
||||
Context_control_value::Inhibit_syn_context_switch_mask::set(v, 1);
|
||||
Context_control_value::Inhibit_syn_context_switch::set(v, 1);
|
||||
write<Context_control_value>(v);
|
||||
}
|
||||
write_offset<Ring_buffer_head_mmio>(RING_BASE);
|
||||
write_offset<Ring_buffer_tail_mmio>(RING_BASE);
|
||||
write_offset<Ring_buffer_start_mmio>(RING_BASE);
|
||||
{
|
||||
typename Ring_buffer_start_value::access_t v = read<Ring_buffer_start_value>();
|
||||
/* shift ring_buffer_start value accordingly */
|
||||
typename Ring_buffer_start_value::access_t const addr = Ring_buffer_start_value::Starting_address::get(ring_buffer_start);
|
||||
Ring_buffer_start_value::Starting_address::set(v, addr);
|
||||
write<Ring_buffer_start_value>(v);
|
||||
}
|
||||
write_offset<Ring_buffer_control_mmio>(RING_BASE);
|
||||
{
|
||||
typename Ring_buffer_control_value::access_t v = read<Ring_buffer_control_value>();
|
||||
/* length is given in number of pages */
|
||||
Ring_buffer_control_value::Buffer_length::set(v, ring_buffer_length / PAGE_SIZE);
|
||||
/* according to the PRM it should be disable b/c of the amount of reports generated */
|
||||
Ring_buffer_control_value::Arhp::set(v, Ring_buffer_control_value::Arhp::MI_AUTOREPORT_OFF);
|
||||
Ring_buffer_control_value::Ring_buffer_enable::set(v, 1);
|
||||
write<Ring_buffer_control_value>(v);
|
||||
}
|
||||
write_offset<Bb_addr_udw_mmio>(RING_BASE);
|
||||
write_offset<Bb_addr_mmio>(RING_BASE);
|
||||
write_offset<Bb_state_mmio>(RING_BASE);
|
||||
{
|
||||
/* should actually not be written by software */
|
||||
typename Bb_state_value::access_t v = 0;
|
||||
Bb_state_value::Address_space_indicator::set(v, 1);
|
||||
write<Bb_state_value>(v);
|
||||
}
|
||||
write_offset<Sbb_addr_udw_mmio>(RING_BASE);
|
||||
write_offset<Sbb_addr_mmio>(RING_BASE);
|
||||
write_offset<Sbb_state_mmio>(RING_BASE);
|
||||
}
|
||||
|
||||
size_t tail_offset()
|
||||
{
|
||||
return read<typename Ring_buffer_tail_value::Tail_offset>();
|
||||
}
|
||||
|
||||
void tail_offset(size_t offset)
|
||||
{
|
||||
write<typename Ring_buffer_tail_value::Tail_offset>(offset);
|
||||
}
|
||||
|
||||
size_t head_offset()
|
||||
{
|
||||
return read<typename Ring_buffer_head_value::Head_offset>();
|
||||
}
|
||||
|
||||
/*********************
|
||||
** Debug interface **
|
||||
*********************/
|
||||
|
||||
void dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log("Execlist_context");
|
||||
log(" Load_immediate_header: ", Hex(read<Load_immediate_header>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Context_control: ", Hex(read<Context_control_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Ring_buffer_head: ", Hex(read<Ring_buffer_head_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Wrap_count: ", Hex(read<typename Ring_buffer_head_value::Wrap_count>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Ring_buffer_tail: ", Hex(read<Ring_buffer_tail_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Ring_buffer_start: ", Hex(read<Ring_buffer_start_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Ring_buffer_control: ", Hex(read<Ring_buffer_control_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Bb_addr_udw: ", Hex(read<Bb_addr_udw_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Bb_addr: ", Hex(read<Bb_addr_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Bb_state: ", Hex(read<Bb_state_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Sbb_addr_udw: ", Hex(read<Sbb_addr_udw_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Sbb_addr: ", Hex(read<Sbb_addr_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Sbb_state: ", Hex(read<Sbb_state_value>(), Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <Genode::addr_t RING_BASE>
|
||||
class Igd::Ppgtt_context : public Igd::Common_context_regs
|
||||
{
|
||||
public:
|
||||
|
||||
/* MI_NOOP */
|
||||
struct Noop_1 : Common_register<0x0020> { };
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2a-11.15 p. 841 ff.
|
||||
*/
|
||||
struct Load_immediate_header : Common_register<0x0021> { };
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 283
|
||||
*
|
||||
* RCS only
|
||||
*/
|
||||
struct Cs_ctx_timestamp_mmio : Common_register<0x0022>
|
||||
{
|
||||
enum { OFFSET = 0x3A8, };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1143
|
||||
*/
|
||||
struct Pdp_3_udw_mmio : Common_register<0x0024>
|
||||
{
|
||||
enum { OFFSET = 0x28C, };
|
||||
};
|
||||
struct Pdp_3_udw_value : Common_register<0x0025>
|
||||
{
|
||||
struct Value : Bitfield<0,32> { };
|
||||
};
|
||||
|
||||
struct Pdp_3_ldw_mmio : Common_register<0x0026>
|
||||
{
|
||||
enum { OFFSET = 0x288, };
|
||||
};
|
||||
struct Pdp_3_ldw_value : Common_register<0x0027>
|
||||
{
|
||||
struct Value : Bitfield<0,32> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1142
|
||||
*/
|
||||
struct Pdp_2_udw_mmio : Common_register<0x0028>
|
||||
{
|
||||
enum { OFFSET = 0x284, };
|
||||
};
|
||||
struct Pdp_2_udw_value : Common_register<0x0029>
|
||||
{
|
||||
struct Value : Bitfield<0,32> { };
|
||||
};
|
||||
|
||||
struct Pdp_2_ldw_mmio : Common_register<0x002A>
|
||||
{
|
||||
enum { OFFSET = 0x280, };
|
||||
};
|
||||
struct Pdp_2_ldw_value : Common_register<0x002B>
|
||||
{
|
||||
struct Value : Bitfield<0,32> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1141
|
||||
*/
|
||||
struct Pdp_1_udw_mmio : Common_register<0x002C>
|
||||
{
|
||||
enum { OFFSET = 0x27C, };
|
||||
};
|
||||
struct Pdp_1_udw_value : Common_register<0x002D>
|
||||
{
|
||||
struct Value : Bitfield<0,32> { };
|
||||
};
|
||||
|
||||
struct Pdp_1_ldw_mmio : Common_register<0x002E>
|
||||
{
|
||||
enum { OFFSET = 0x278, };
|
||||
};
|
||||
struct Pdp_1_ldw_value : Common_register<0x002F>
|
||||
{
|
||||
struct Value : Bitfield<0,32> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1140
|
||||
*/
|
||||
struct Pdp_0_udw_mmio : Common_register<0x0030>
|
||||
{
|
||||
enum { OFFSET = 0x274, };
|
||||
};
|
||||
struct Pdp_0_udw_value : Common_register<0x0031>
|
||||
{
|
||||
struct Value : Bitfield<0,32> { };
|
||||
};
|
||||
|
||||
struct Pdp_0_ldw_mmio : Common_register<0x0032>
|
||||
{
|
||||
enum { OFFSET = 0x270, };
|
||||
};
|
||||
struct Pdp_0_ldw_value : Common_register<0x0033>
|
||||
{
|
||||
struct Value : Bitfield<0,32> { };
|
||||
};
|
||||
|
||||
struct Noop_2 : Common_register_array<0x0034, 12> { };
|
||||
struct Noop_3 : Common_register_array<0x0040, 1> { };
|
||||
|
||||
struct Load_immediate_header_2 : Common_register<0x0041> { };
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2c-11.15 p. 1325
|
||||
*/
|
||||
struct R_pwr_clk_state_mmio : Common_register<0x0042>
|
||||
{
|
||||
enum { OFFSET = 0x0C8, };
|
||||
};
|
||||
struct R_pwr_clk_state_value : Common_register<0x0043>
|
||||
{
|
||||
using R = Common_register<0x0043>;
|
||||
|
||||
struct Power_clock_state_enable : R::template Bitfield<31, 1> { };
|
||||
struct Power_clock_state : R::template Bitfield< 0, 31> { };
|
||||
};
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 7-11.15 p. 659
|
||||
*/
|
||||
struct Gpgpu_csr_base_Address : Common_register_array<0x00044, 3> { };
|
||||
|
||||
struct Noop_4 : Common_register_array<0x0047, 9> { };
|
||||
|
||||
public:
|
||||
|
||||
Ppgtt_context(addr_t base, uint64_t plm4_addr)
|
||||
:
|
||||
Common_context_regs(base)
|
||||
{
|
||||
write<Load_immediate_header>(0x11001011);
|
||||
write_offset<Cs_ctx_timestamp_mmio>(RING_BASE);
|
||||
{
|
||||
write<Cs_ctx_timestamp_mmio>(0);
|
||||
}
|
||||
write_offset<Pdp_3_udw_mmio>(RING_BASE);
|
||||
write_offset<Pdp_3_ldw_mmio>(RING_BASE);
|
||||
write_offset<Pdp_2_udw_mmio>(RING_BASE);
|
||||
write_offset<Pdp_2_ldw_mmio>(RING_BASE);
|
||||
write_offset<Pdp_1_udw_mmio>(RING_BASE);
|
||||
write_offset<Pdp_1_ldw_mmio>(RING_BASE);
|
||||
write_offset<Pdp_0_udw_mmio>(RING_BASE);
|
||||
{
|
||||
Genode::uint32_t const udw = (Genode::uint32_t)((plm4_addr >> 16) >> 16);
|
||||
write<Pdp_0_udw_value>(udw);
|
||||
}
|
||||
write_offset<Pdp_0_ldw_mmio>(RING_BASE);
|
||||
{
|
||||
Genode::uint32_t const ldw = (Genode::uint32_t)plm4_addr;
|
||||
write<Pdp_0_ldw_value>(ldw);
|
||||
}
|
||||
|
||||
write_offset<R_pwr_clk_state_mmio>(RING_BASE);
|
||||
}
|
||||
|
||||
/*********************
|
||||
** Debug interface **
|
||||
*********************/
|
||||
|
||||
void dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
using C = Ppgtt_context<RING_BASE>;
|
||||
|
||||
log("Ppgtt_context");
|
||||
log(" Pdp_0_udw: ", Hex(read<C::Pdp_0_udw_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Pdp_0_ldw: ", Hex(read<C::Pdp_0_ldw_value>(), Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* TODO
|
||||
*/
|
||||
class Igd::Engine_context
|
||||
{
|
||||
public:
|
||||
|
||||
Engine_context() { }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* TODO
|
||||
*/
|
||||
class Igd::Ext_engine_context
|
||||
{
|
||||
public:
|
||||
|
||||
Ext_engine_context() { }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* TODO
|
||||
*/
|
||||
class Igd::Urb_atomic_context
|
||||
{
|
||||
public:
|
||||
|
||||
Urb_atomic_context() { }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2d-11.15 p. 199
|
||||
*/
|
||||
class Igd::Hardware_status_page : public Igd::Common_context_regs
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
* See ISR register definition
|
||||
*/
|
||||
struct Interrupt_status_register_storage : Common_register<0> { };
|
||||
|
||||
/*
|
||||
* See RING_BUFFER_HEAD_RCSUNIT definition
|
||||
*/
|
||||
struct Ring_head_ptr_storage : Common_register<4> { };
|
||||
|
||||
/*
|
||||
* See CTXT_ST_BUF
|
||||
*/
|
||||
enum { CONTEXT_STATUS_DWORDS_NUM = 12, };
|
||||
struct Context_status_dwords : Common_register_array<16, CONTEXT_STATUS_DWORDS_NUM> { };
|
||||
struct Last_written_status_offset : Common_register<31> { };
|
||||
|
||||
Hardware_status_page(addr_t base)
|
||||
: Common_context_regs(base) { }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
class Igd::Rcs_context
|
||||
{
|
||||
public:
|
||||
|
||||
enum {
|
||||
HW_ID = 0,
|
||||
CONTEXT_PAGES = 20 /* ctx */ + 1 /* GuC */,
|
||||
RING_PAGES = 4,
|
||||
|
||||
RCS_RING_BASE = 0x2000,
|
||||
|
||||
HW_STATUS_PAGE_SIZE = PAGE_SIZE,
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 7-11.15 p. 27 ff
|
||||
*/
|
||||
EXECLIST_CTX_START = 0x0000,
|
||||
EXECLIST_CTX_END = 0x0020,
|
||||
EXECLIST_CTX_SIZE = (EXECLIST_CTX_END - EXECLIST_CTX_START) * sizeof(uint32_t),
|
||||
EXECLIST_CTX_IH = 0x1100101B,
|
||||
|
||||
PPGTT_CTX_START = EXECLIST_CTX_END,
|
||||
PPGTT_CTX_END = 0x0050,
|
||||
PPGTT_CTX_SIZE = (PPGTT_CTX_END - PPGTT_CTX_START) * sizeof(uint32_t),
|
||||
PPGTT_CTX_IH = 0x11000001,
|
||||
|
||||
ENGINE_CTX_START = PPGTT_CTX_END,
|
||||
ENGINE_CTX_END = 0x0EC0,
|
||||
ENGINE_CTX_SIZE = (ENGINE_CTX_END - ENGINE_CTX_START) * sizeof(uint32_t),
|
||||
|
||||
EXT_ENGINE_CTX_START = ENGINE_CTX_END,
|
||||
EXT_ENGINE_CTX_END = 0x26B0,
|
||||
|
||||
URB_ATOMIC_STORE_START = EXT_ENGINE_CTX_END,
|
||||
URB_ATOMIC_STORE_END = 0x46B0,
|
||||
URB_ATOMIC_STORE_SIZE = (URB_ATOMIC_STORE_END - URB_ATOMIC_STORE_START) * sizeof(uint32_t),
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
|
||||
Hardware_status_page _hw_status_page;
|
||||
Execlist_context<RCS_RING_BASE> _execlist_context;
|
||||
Ppgtt_context<RCS_RING_BASE> _ppgtt_context;
|
||||
Engine_context _engine_context;
|
||||
Ext_engine_context _ext_engine_context;
|
||||
Urb_atomic_context _urb_atomic_context;
|
||||
|
||||
public:
|
||||
|
||||
Rcs_context(addr_t map_base,
|
||||
addr_t ring_buffer_start,
|
||||
size_t ring_buffer_length,
|
||||
uint64_t plm4_addr)
|
||||
:
|
||||
_hw_status_page(map_base),
|
||||
_execlist_context((addr_t)(map_base + HW_STATUS_PAGE_SIZE),
|
||||
ring_buffer_start, ring_buffer_length,
|
||||
EXECLIST_CTX_IH),
|
||||
_ppgtt_context((addr_t)(map_base + HW_STATUS_PAGE_SIZE), plm4_addr),
|
||||
_engine_context(),
|
||||
_ext_engine_context(),
|
||||
_urb_atomic_context()
|
||||
{
|
||||
Genode::log(__func__, ":",
|
||||
" map_base:", Genode::Hex(map_base),
|
||||
" ring_buffer_start:", Genode::Hex(ring_buffer_start),
|
||||
" ring_buffer_length:", Genode::Hex(ring_buffer_length),
|
||||
" plm4_addr:", Genode::Hex(plm4_addr, Genode::Hex::PREFIX, Genode::Hex::PAD));
|
||||
|
||||
using C = Execlist_context<RCS_RING_BASE>;
|
||||
|
||||
_execlist_context.write_offset<C::Bb_per_ctx_ptr_mmio>(RCS_RING_BASE);
|
||||
{
|
||||
using R = C::Bb_per_ctx_ptr_value;
|
||||
typename R::access_t v = _execlist_context.read<R>();
|
||||
R::Address::set(v, 0);
|
||||
R::Valid::set(v, 0);
|
||||
_execlist_context.write<R>(v);
|
||||
}
|
||||
|
||||
_execlist_context.write_offset<C::Rcs_indirect_ctx_mmio>(RCS_RING_BASE);
|
||||
{
|
||||
using R = C::Rcs_indirect_ctx_value;
|
||||
typename R::access_t v = _execlist_context.read<R>();
|
||||
R::Address::set(v, 0);
|
||||
R::Size::set(v, 0);
|
||||
_execlist_context.write<R>(v);
|
||||
}
|
||||
|
||||
_execlist_context.write_offset<C::Rcs_indirect_ctx_offset_mmio>(RCS_RING_BASE);
|
||||
{
|
||||
using R = C::Rcs_indirect_ctx_offset_value;
|
||||
typename R::access_t v = _execlist_context.read<R>();
|
||||
R::Offset::set(v, 0);
|
||||
_execlist_context.write<R>(v);
|
||||
}
|
||||
|
||||
using P = Ppgtt_context<RCS_RING_BASE>;
|
||||
|
||||
_ppgtt_context.write<P::Load_immediate_header_2>(PPGTT_CTX_IH);
|
||||
}
|
||||
|
||||
size_t head_offset()
|
||||
{
|
||||
return _execlist_context.head_offset();
|
||||
}
|
||||
|
||||
void tail_offset(addr_t offset)
|
||||
{
|
||||
_execlist_context.tail_offset(offset);
|
||||
}
|
||||
|
||||
/*********************
|
||||
** Debug interface **
|
||||
*********************/
|
||||
|
||||
void dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log("Rcs_context");
|
||||
log(" HW status page: ", Hex(_hw_status_page.base(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Execlist_context: ", Hex(_execlist_context.base(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Ppgtt_context: ", Hex(_ppgtt_context.base(), Hex::PREFIX, Hex::PAD));
|
||||
|
||||
_execlist_context.dump();
|
||||
|
||||
using C = Execlist_context<RCS_RING_BASE>;
|
||||
|
||||
log(" Bb_per_ctx_ptr: ", Hex(_execlist_context.read<C::Bb_per_ctx_ptr_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Rcs_indirect_ctx: ", Hex(_execlist_context.read<C::Rcs_indirect_ctx_value>(), Hex::PREFIX, Hex::PAD));
|
||||
log(" Rcs_indirect_ctx_offset: ", Hex(_execlist_context.read<C::Rcs_indirect_ctx_offset_value>(), Hex::PREFIX, Hex::PAD));
|
||||
|
||||
_ppgtt_context.dump();
|
||||
}
|
||||
|
||||
void dump_hw_status_page(bool raw = false)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (raw) {
|
||||
uint32_t const *p = (uint32_t const *)_hw_status_page.base();
|
||||
for (uint32_t i = 0; i < HW_STATUS_PAGE_SIZE / sizeof(uint32_t); i += 8) {
|
||||
log(Hex(i, Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i ], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+1], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+2], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+3], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+4], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+5], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+6], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+7], Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
} else {
|
||||
using H = Hardware_status_page;
|
||||
log("Hardware_status_page");
|
||||
log(" Interrupt_status_register_storage: ",
|
||||
Hex(_hw_status_page.read<H::Interrupt_status_register_storage>(),
|
||||
Hex::PREFIX, Hex::PAD));
|
||||
log(" Ring_head_ptr_storage: ",
|
||||
Hex(_hw_status_page.read<H::Ring_head_ptr_storage>(),
|
||||
Hex::PREFIX, Hex::PAD));
|
||||
for (int i = 0; i < H::CONTEXT_STATUS_DWORDS_NUM; i++) {
|
||||
log(" Context_status_dwords: ",
|
||||
Hex(_hw_status_page.read<H::Context_status_dwords>(i),
|
||||
Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
log(" Last_written_status_offset: ",
|
||||
Hex(_hw_status_page.read<H::Last_written_status_offset>(),
|
||||
Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
}
|
||||
|
||||
void dump_execlist_context()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log("Execlist_context");
|
||||
uint32_t const *p = (uint32_t const *)_execlist_context.base();
|
||||
for (uint32_t i = 0; i < EXECLIST_CTX_SIZE / sizeof(uint32_t); i += 8) {
|
||||
log(" ", Hex(i, Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i ], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+1], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+2], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+3], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+4], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+5], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+6], Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(p[i+7], Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _LOGICAL_RING_CONTEXT_H_ */
|
117
repos/os/src/drivers/gpu/intel/context_descriptor.h
Normal file
117
repos/os/src/drivers/gpu/intel/context_descriptor.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* \brief Broadwell context descriptor
|
||||
* \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 _CONTEXT_DESCRIPTOR_H_
|
||||
#define _CONTEXT_DESCRIPTOR_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/register.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
|
||||
|
||||
namespace Igd {
|
||||
|
||||
class Context_descriptor;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 2d-11.15 p. 107
|
||||
*/
|
||||
class Igd::Context_descriptor : Genode::Register<64>
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
* Context ID covers 63:32 where we currently only
|
||||
* care about the lowest 20 bits.
|
||||
*
|
||||
* 63:55 group ID
|
||||
* 54 MBZ
|
||||
* 53 MBZ
|
||||
* 20:0 globally unique SW controlled ID
|
||||
*/
|
||||
struct Context_id : Bitfield<32, 20> { };
|
||||
struct Logical_ring_context_address : Bitfield<12, 20> { };
|
||||
struct Privilege_access : Bitfield< 8, 1> { };
|
||||
struct Fault_handling : Bitfield< 6, 2>
|
||||
{
|
||||
enum { FAULT_AND_HANG = 0b00, };
|
||||
};
|
||||
struct Addressing_mode : Bitfield< 3, 2>
|
||||
{
|
||||
enum {
|
||||
ADVANCED_WO_AD = 0b00,
|
||||
LEGACY_WO_64 = 0b01,
|
||||
ADVANCED_WITH_AD = 0b10,
|
||||
LEGACY_WITH_64 = 0b11,
|
||||
};
|
||||
};
|
||||
struct Force_restore : Bitfield< 2, 1> { };
|
||||
struct Force_pd_restore : Bitfield< 1, 1> { };
|
||||
struct Valid : Bitfield< 0, 1> { };
|
||||
|
||||
private:
|
||||
|
||||
uint64_t _value;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param id context id
|
||||
* \param lrca graphics memory address of the context
|
||||
*/
|
||||
Context_descriptor(uint32_t id,
|
||||
addr_t lrca)
|
||||
{
|
||||
/* shift lrca value accordingly */
|
||||
typename Context_descriptor::access_t const addr = Context_descriptor::Logical_ring_context_address::get(lrca);
|
||||
Logical_ring_context_address::set(_value, addr);
|
||||
|
||||
Privilege_access::set(_value, 1);
|
||||
/* must be set to FAULT_AND_HANG according to PRM when legacy mode is used */
|
||||
Fault_handling::set(_value, Fault_handling::FAULT_AND_HANG);
|
||||
Addressing_mode::set(_value, Addressing_mode::LEGACY_WITH_64);
|
||||
Context_id::set(_value, id);
|
||||
Force_restore::set(_value, 1);
|
||||
Force_pd_restore::set(_value, 1);
|
||||
Valid::set(_value, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Context_descriptor() : _value(0) { }
|
||||
|
||||
uint32_t low() const { return (uint32_t)(_value & 0xffffffff); }
|
||||
uint32_t high() const { return (uint32_t)(_value >> 32); }
|
||||
bool valid() const { return Valid::get(_value) == 1; }
|
||||
uint64_t value() const { return _value; }
|
||||
|
||||
/*********************
|
||||
** Debug interface **
|
||||
*********************/
|
||||
|
||||
void dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log("Context_descriptor: ", Hex(_value, Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CONTEXT_DESCRIPTOR_H_ */
|
312
repos/os/src/drivers/gpu/intel/ggtt.h
Normal file
312
repos/os/src/drivers/gpu/intel/ggtt.h
Normal file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* \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;
|
||||
|
||||
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;
|
||||
|
||||
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_ */
|
1873
repos/os/src/drivers/gpu/intel/main.cc
Normal file
1873
repos/os/src/drivers/gpu/intel/main.cc
Normal file
File diff suppressed because it is too large
Load Diff
1310
repos/os/src/drivers/gpu/intel/mmio.h
Normal file
1310
repos/os/src/drivers/gpu/intel/mmio.h
Normal file
File diff suppressed because it is too large
Load Diff
327
repos/os/src/drivers/gpu/intel/mmio_dump.cc
Normal file
327
repos/os/src/drivers/gpu/intel/mmio_dump.cc
Normal file
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* \brief Dump Broadwell MMIO registers
|
||||
* \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.
|
||||
*/
|
||||
|
||||
/* local includes */
|
||||
#include <mmio.h>
|
||||
#include <context.h>
|
||||
|
||||
|
||||
void Igd::Mmio::dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log("MMIO vaddr:", Hex(base()), " size:", Hex(Igd::Mmio::SIZE));
|
||||
log("GFX_MODE: ", Hex(read<GFX_MODE>()));
|
||||
log(" Privilege_check_disable: ", Hex(read<GFX_MODE::Privilege_check_disable>()));
|
||||
log(" Execlist_enable: ", Hex(read<GFX_MODE::Execlist_enable>()));
|
||||
log(" Virtual_addressing_enable: ", Hex(read<GFX_MODE::Virtual_addressing_enable>()));
|
||||
log(" Ppgtt_enable: ", Hex(read<GFX_MODE::Ppgtt_enable>()));
|
||||
log("HWS_PGA: ", Hex(read<HWS_PGA_RCSUNIT>()));
|
||||
log("HWSTAM: ", Hex(read<HWSTAM>()));
|
||||
}
|
||||
|
||||
|
||||
void Igd::Mmio::power_dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log("PWR_WELL_CTL2");
|
||||
log(" Misc_io_power_state: ", Hex(read<PWR_WELL_CTL2::Misc_io_power_state>()));
|
||||
log(" Misc_io_power_request: ", Hex(read<PWR_WELL_CTL2::Misc_io_power_request>()));
|
||||
log(" Ddi_a_and_ddi_e_io_power_state: ", Hex(read<PWR_WELL_CTL2::Ddi_a_and_ddi_e_io_power_state>()));
|
||||
log(" Ddi_a_and_ddi_e_io_power_request: ", Hex(read<PWR_WELL_CTL2::Ddi_a_and_ddi_e_io_power_request>()));
|
||||
log(" Ddi_b_io_power_state: ", Hex(read<PWR_WELL_CTL2::Ddi_b_io_power_state>()));
|
||||
log(" Ddi_b_io_power_request: ", Hex(read<PWR_WELL_CTL2::Ddi_b_io_power_request>()));
|
||||
log(" Ddi_c_io_power_state: ", Hex(read<PWR_WELL_CTL2::Ddi_c_io_power_state>()));
|
||||
log(" Ddi_c_io_power_request: ", Hex(read<PWR_WELL_CTL2::Ddi_c_io_power_request>()));
|
||||
log(" Ddi_d_io_power_state: ", Hex(read<PWR_WELL_CTL2::Ddi_d_io_power_state>()));
|
||||
log(" Ddi_d_io_power_request: ", Hex(read<PWR_WELL_CTL2::Ddi_d_io_power_request>()));
|
||||
log(" Power_well_1_state: ", Hex(read<PWR_WELL_CTL2::Power_well_1_state>()));
|
||||
log(" Power_well_1_request: ", Hex(read<PWR_WELL_CTL2::Power_well_1_request>()));
|
||||
log(" Power_well_2_state: ", Hex(read<PWR_WELL_CTL2::Power_well_2_state>()));
|
||||
log(" Power_well_2_request: ", Hex(read<PWR_WELL_CTL2::Power_well_2_request>()));
|
||||
}
|
||||
|
||||
|
||||
void Igd::Mmio::error_dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log("ERROR: ", Hex(read<ERROR>()));
|
||||
if (read<ERROR>()) {
|
||||
log(" Ctx_fault_ctxt_not_prsnt_err: ", Hex(read<ERROR::Ctx_fault_ctxt_not_prsnt_err>()));
|
||||
log(" Ctx_fault_root_not_prsnt_err: ", Hex(read<ERROR::Ctx_fault_root_not_prsnt_err>()));
|
||||
log(" Ctx_fault_pasid_not_prsnt_err: ", Hex(read<ERROR::Ctx_fault_pasid_not_prsnt_err>()));
|
||||
log(" Ctx_fault_pasid_ovflw_err: ", Hex(read<ERROR::Ctx_fault_pasid_ovflw_err>()));
|
||||
log(" Ctx_fault_pasid_dis_err: ", Hex(read<ERROR::Ctx_fault_pasid_dis_err>()));
|
||||
log(" Rstrm_fault_nowb_atomic_err: ", Hex(read<ERROR::Rstrm_fault_nowb_atomic_err>()));
|
||||
log(" Unloaded_pd_error: ", Hex(read<ERROR::Unloaded_pd_error>()));
|
||||
log(" Hws_page_fault_error: ", Hex(read<ERROR::Hws_page_fault_error>()));
|
||||
log(" Invalid_page_directory_entry_error: ", Hex(read<ERROR::Invalid_page_directory_entry_error>()));
|
||||
log(" Ctx_page_fault_error: ", Hex(read<ERROR::Ctx_page_fault_error>()));
|
||||
log(" Tlb_fault_error: ", Hex(read<ERROR::Tlb_fault_error>()));
|
||||
}
|
||||
|
||||
log("ERROR_2: ", Hex(read<ERROR_2>()));
|
||||
if (read<ERROR_2>()) {
|
||||
log(" Tlbpend_reg_faultcnt: ", Hex(read<ERROR_2::Tlbpend_reg_faultcnt>()));
|
||||
}
|
||||
|
||||
log("RCS_EIR: ", Hex(read<RCS_EIR>()));
|
||||
log("RCS_ESR: ", Hex(read<RCS_ESR>()));
|
||||
log("RCS_EMR: ", Hex(read<RCS_EMR>()));
|
||||
log("RCS_INSTDONE: ", Hex(read<RCS_INSTDONE>()));
|
||||
if (read<RCS_INSTDONE>() != RCS_INSTDONE::DEFAULT_VALUE ||
|
||||
read<RCS_INSTDONE>() != 0xffffffff) {
|
||||
log(" Row_0_eu_0_done : ", Hex(read<RCS_INSTDONE::Row_0_eu_0_done >()));
|
||||
log(" Row_0_eu_1_done : ", Hex(read<RCS_INSTDONE::Row_0_eu_1_done >()));
|
||||
log(" Row_0_eu_2_done : ", Hex(read<RCS_INSTDONE::Row_0_eu_2_done >()));
|
||||
log(" Row_0_eu_3_done : ", Hex(read<RCS_INSTDONE::Row_0_eu_3_done >()));
|
||||
log(" Row_1_eu_0_done : ", Hex(read<RCS_INSTDONE::Row_1_eu_0_done >()));
|
||||
log(" Row_1_eu_1_done : ", Hex(read<RCS_INSTDONE::Row_1_eu_1_done >()));
|
||||
log(" Row_1_eu_2_done : ", Hex(read<RCS_INSTDONE::Row_1_eu_2_done >()));
|
||||
log(" Row_1_eu_3_done : ", Hex(read<RCS_INSTDONE::Row_1_eu_3_done >()));
|
||||
log(" Sf_done : ", Hex(read<RCS_INSTDONE::Sf_done >()));
|
||||
log(" Se_done : ", Hex(read<RCS_INSTDONE::Se_done >()));
|
||||
log(" Windower_done : ", Hex(read<RCS_INSTDONE::Windower_done >()));
|
||||
log(" Reserved1 : ", Hex(read<RCS_INSTDONE::Reserved1 >()));
|
||||
log(" Reserved2 : ", Hex(read<RCS_INSTDONE::Reserved2 >()));
|
||||
log(" Dip_done : ", Hex(read<RCS_INSTDONE::Dip_done >()));
|
||||
log(" Pl_done : ", Hex(read<RCS_INSTDONE::Pl_done >()));
|
||||
log(" Dg_done : ", Hex(read<RCS_INSTDONE::Dg_done >()));
|
||||
log(" Qc_done : ", Hex(read<RCS_INSTDONE::Qc_done >()));
|
||||
log(" Ft_done : ", Hex(read<RCS_INSTDONE::Ft_done >()));
|
||||
log(" Dm_done : ", Hex(read<RCS_INSTDONE::Dm_done >()));
|
||||
log(" Sc_done : ", Hex(read<RCS_INSTDONE::Sc_done >()));
|
||||
log(" Fl_done : ", Hex(read<RCS_INSTDONE::Fl_done >()));
|
||||
log(" By_done : ", Hex(read<RCS_INSTDONE::By_done >()));
|
||||
log(" Ps_done : ", Hex(read<RCS_INSTDONE::Ps_done >()));
|
||||
log(" Cc_done : ", Hex(read<RCS_INSTDONE::Cc_done >()));
|
||||
log(" Map_fl_done : ", Hex(read<RCS_INSTDONE::Map_fl_done >()));
|
||||
log(" Map_l2_idle : ", Hex(read<RCS_INSTDONE::Map_l2_idle >()));
|
||||
log(" Msg_arb_0_done : ", Hex(read<RCS_INSTDONE::Msg_arb_0_done >()));
|
||||
log(" Msg_arb_1_done : ", Hex(read<RCS_INSTDONE::Msg_arb_1_done >()));
|
||||
log(" Ic_row_0_done : ", Hex(read<RCS_INSTDONE::Ic_row_0_done >()));
|
||||
log(" Ic_row_1_done : ", Hex(read<RCS_INSTDONE::Ic_row_1_done >()));
|
||||
log(" Cp_done : ", Hex(read<RCS_INSTDONE::Cp_done >()));
|
||||
log(" Ring_0_enable : ", Hex(read<RCS_INSTDONE::Ring_0_enable >()));
|
||||
}
|
||||
log("RCS_INSTDONE_1: ", Hex(read<RCS_INSTDONE_1>()));
|
||||
log("RCS_ACTHD: ", Hex(read<RCS_ACTHD>()));
|
||||
log("IPEHR: ", Hex(read<IPEHR>()));
|
||||
log("IPEIR: ", Hex(read<IPEIR>()));
|
||||
log("PGTBL_ER: ", Hex(read<PGTBL_ER>()));
|
||||
}
|
||||
|
||||
|
||||
void Igd::Mmio::intr_dump()
|
||||
{
|
||||
#define DUMP_GT_1
|
||||
#define DUMP_GT_2
|
||||
#define DUMP_GT_3
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
log("MASTER_INT_CTL");
|
||||
log(" Master_interrupt_enable: ", Hex(read<MASTER_INT_CTL::Master_interrupt_enable>()));
|
||||
log(" Pcu_interrupts_pending: ", Hex(read<MASTER_INT_CTL::Pcu_interrupts_pending>()));
|
||||
log(" Audio_codec_interrupts_pending: ", Hex(read<MASTER_INT_CTL::Audio_codec_interrupts_pending>()));
|
||||
log(" De_pch_interrupts_pending: ", Hex(read<MASTER_INT_CTL::De_pch_interrupts_pending>()));
|
||||
log(" De_misc_interrupts_pending: ", Hex(read<MASTER_INT_CTL::De_misc_interrupts_pending>()));
|
||||
log(" De_port_interrupts_pending: ", Hex(read<MASTER_INT_CTL::De_port_interrupts_pending>()));
|
||||
log(" De_pipe_c_interrupts_pending: ", Hex(read<MASTER_INT_CTL::De_pipe_c_interrupts_pending>()));
|
||||
log(" De_pipe_b_interrupts_pending: ", Hex(read<MASTER_INT_CTL::De_pipe_b_interrupts_pending>()));
|
||||
log(" De_pipe_a_interrupts_pending: ", Hex(read<MASTER_INT_CTL::De_pipe_a_interrupts_pending>()));
|
||||
log(" Vebox_interrupts_pending: ", Hex(read<MASTER_INT_CTL::Vebox_interrupts_pending>()));
|
||||
log(" Gtpm_interrupts_pending: ", Hex(read<MASTER_INT_CTL::Gtpm_interrupts_pending>()));
|
||||
log(" Vcs2_interrupts_pending: ", Hex(read<MASTER_INT_CTL::Vcs2_interrupts_pending>()));
|
||||
log(" Vcs1_interrupts_pending: ", Hex(read<MASTER_INT_CTL::Vcs1_interrupts_pending>()));
|
||||
log(" Blitter_interrupts_pending: ", Hex(read<MASTER_INT_CTL::Blitter_interrupts_pending>()));
|
||||
log(" Render_interrupts_pending: ", Hex(read<MASTER_INT_CTL::Render_interrupts_pending>()));
|
||||
|
||||
#ifndef DUMP_GT_0
|
||||
#define DUMP_GT_0(reg) \
|
||||
log(#reg); \
|
||||
log(" Bcs_wait_on_semaphore: ", Hex(read<reg::Bcs_wait_on_semaphore>())); \
|
||||
log(" Bcs_ctx_switch_interrupt: ", Hex(read<reg::Bcs_ctx_switch_interrupt>())); \
|
||||
log(" Bcs_mi_flush_dw_notify: ", Hex(read<reg::Bcs_mi_flush_dw_notify>())); \
|
||||
log(" Bcs_error_interrupt: ", Hex(read<reg::Bcs_error_interrupt>())); \
|
||||
log(" Bcs_mi_user_interrupt: ", Hex(read<reg::Bcs_mi_user_interrupt>())); \
|
||||
log(" Cs_wait_on_semaphore: ", Hex(read<reg::Cs_wait_on_semaphore>())); \
|
||||
log(" Cs_l3_counter_slave: ", Hex(read<reg::Cs_l3_counter_slave>())); \
|
||||
log(" Cs_ctx_switch_interrupt: ", Hex(read<reg::Cs_ctx_switch_interrupt>())); \
|
||||
log(" Page_fault_error: ", Hex(read<reg::Page_fault_error>())); \
|
||||
log(" Cs_watchdog_counter_expired: ", Hex(read<reg::Cs_watchdog_counter_expired>())); \
|
||||
log(" L3_parity_error: ", Hex(read<reg::L3_parity_error>())); \
|
||||
log(" Cs_pipe_control_notify: ", Hex(read<reg::Cs_pipe_control_notify>())); \
|
||||
log(" Cs_error_interrupt: ", Hex(read<reg::Cs_error_interrupt>())); \
|
||||
log(" Cs_mi_user_interrupt: ", Hex(read<reg::Cs_mi_user_interrupt>()));
|
||||
|
||||
DUMP_GT_0(GT_0_INTERRUPT_ISR);
|
||||
DUMP_GT_0(GT_0_INTERRUPT_IIR);
|
||||
DUMP_GT_0(GT_0_INTERRUPT_IER);
|
||||
DUMP_GT_0(GT_0_INTERRUPT_IMR);
|
||||
#undef DUMP_GT_0
|
||||
#endif
|
||||
|
||||
#ifndef DUMP_GT_1
|
||||
#define DUMP_GT_1(reg) \
|
||||
log(#reg); \
|
||||
log(" Vcs2_wait_on_semaphore: ", Hex(read<reg::Vcs2_wait_on_semaphore>())); \
|
||||
log(" Vcs2_ctx_switch_interrupt: ", Hex(read<reg::Vcs2_ctx_switch_interrupt>())); \
|
||||
log(" Vcs2_watchdog_counter_expired: ", Hex(read<reg::Vcs2_watchdog_counter_expired>())); \
|
||||
log(" Vcs2_mi_flush_dw_notify: ", Hex(read<reg::Vcs2_mi_flush_dw_notify>())); \
|
||||
log(" Vcs2_error_interrupt: ", Hex(read<reg::Vcs2_error_interrupt>())); \
|
||||
log(" Vcs2_mi_user_interrupt: ", Hex(read<reg::Vcs2_mi_user_interrupt>())); \
|
||||
log(" Vcs1_wait_on_semaphore: ", Hex(read<reg::Vcs1_wait_on_semaphore>())); \
|
||||
log(" Vcs1_ctx_switch_interrupt: ", Hex(read<reg::Vcs1_ctx_switch_interrupt>())); \
|
||||
log(" Vcs1_watchdog_counter_expired: ", Hex(read<reg::Vcs1_watchdog_counter_expired>())); \
|
||||
log(" Vcs1_pipe_control_notify: ", Hex(read<reg::Vcs1_pipe_control_notify>())); \
|
||||
log(" Vcs1_error_interrupt: ", Hex(read<reg::Vcs1_error_interrupt>())); \
|
||||
log(" Vcs1_mi_user_interrupt: ", Hex(read<reg::Vcs1_mi_user_interrupt>())); \
|
||||
|
||||
DUMP_GT_1(GT_1_INTERRUPT_ISR);
|
||||
DUMP_GT_1(GT_1_INTERRUPT_IIR);
|
||||
DUMP_GT_1(GT_1_INTERRUPT_IER);
|
||||
DUMP_GT_1(GT_1_INTERRUPT_IMR);
|
||||
#undef DUMP_GT_1
|
||||
#endif
|
||||
|
||||
#ifndef DUMP_GT_2
|
||||
#define DUMP_GT_2(reg) \
|
||||
log(#reg); \
|
||||
log(" Unslice_frequency_control_up_interrupt: ", Hex(read<reg::Unslice_frequency_control_up_interrupt>())); \
|
||||
log(" Unslice_frequency_control_down_interrupt: ", Hex(read<reg::Unslice_frequency_control_down_interrupt>())); \
|
||||
log(" Nfafdl_frequency_up_interrupt: ", Hex(read<reg::Nfafdl_frequency_up_interrupt>())); \
|
||||
log(" Nfafdl_frequency_down_interrupt: ", Hex(read<reg::Nfafdl_frequency_down_interrupt>())); \
|
||||
log(" Gtpm_engines_idle_interrupt: ", Hex(read<reg::Gtpm_engines_idle_interrupt>())); \
|
||||
log(" Gtpm_uncore_to_core_trap_interrupt: ", Hex(read<reg::Gtpm_uncore_to_core_trap_interrupt>())); \
|
||||
log(" Gtpm_render_frequency_downwards_timeout_during_rc6_interrupt: ", Hex(read<reg::Gtpm_render_frequency_downwards_timeout_during_rc6_interrupt>())); \
|
||||
log(" Gtpm_render_p_state_up_threshold_interrupt: ", Hex(read<reg::Gtpm_render_p_state_up_threshold_interrupt>())); \
|
||||
log(" Gtpm_render_p_state_down_threshold_interrupt: ", Hex(read<reg::Gtpm_render_p_state_down_threshold_interrupt>())); \
|
||||
log(" Gtpm_render_geyserville_up_evaluation_interval_interrupt: ", Hex(read<reg::Gtpm_render_geyserville_up_evaluation_interval_interrupt>())); \
|
||||
log(" Gtpm_render_geyserville_down_evaluation_interval_interrupt: ", Hex(read<reg::Gtpm_render_geyserville_down_evaluation_interval_interrupt>()));
|
||||
|
||||
DUMP_GT_2(GT_2_INTERRUPT_ISR);
|
||||
DUMP_GT_2(GT_2_INTERRUPT_IIR);
|
||||
DUMP_GT_2(GT_2_INTERRUPT_IER);
|
||||
DUMP_GT_2(GT_2_INTERRUPT_IMR);
|
||||
#undef DUMP_GT_2
|
||||
#endif
|
||||
|
||||
#ifndef DUMP_GT_3
|
||||
#define DUMP_GT_3(reg) \
|
||||
log(#reg); \
|
||||
log(" Performance_monitoring_buffer_half_full_interrupt: ", Hex(read<reg::Performance_monitoring_buffer_half_full_interrupt>())); \
|
||||
log(" Vecs_wait_on_semaphore: ", Hex(read<reg::Vecs_wait_on_semaphore>())); \
|
||||
log(" Vecs_ctx_switch_interrupt: ", Hex(read<reg::Vecs_ctx_switch_interrupt>())); \
|
||||
log(" Vecs_mi_flush_dw_notify: ", Hex(read<reg::Vecs_mi_flush_dw_notify>())); \
|
||||
log(" Vecs_error_interrupt: ", Hex(read<reg::Vecs_error_interrupt>())); \
|
||||
log(" Vecs_mi_user_interrupt: ", Hex(read<reg::Vecs_mi_user_interrupt>())); \
|
||||
|
||||
DUMP_GT_3(GT_3_INTERRUPT_ISR);
|
||||
DUMP_GT_3(GT_3_INTERRUPT_IIR);
|
||||
DUMP_GT_3(GT_3_INTERRUPT_IER);
|
||||
DUMP_GT_3(GT_3_INTERRUPT_IMR);
|
||||
#undef DUMP_GT_3
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Igd::Mmio::fault_dump()
|
||||
{
|
||||
Genode::log("FAULT_TLB_RB_DATA0: ", Genode::Hex(read<FAULT_TLB_RB_DATA0>()));
|
||||
Genode::log("FAULT_TLB_RB_DATA1: ", Genode::Hex(read<FAULT_TLB_RB_DATA1>()));
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
uint64_t const addr = ((uint64_t)(read<FAULT_TLB_RB_DATA1::Fault_cycle_va>() & 0xf) << 44) |
|
||||
((uint64_t) read<FAULT_TLB_RB_DATA0>() << 12);
|
||||
Genode::log(" ggtt: ", read<FAULT_TLB_RB_DATA1::Cycle_gtt_sel>(), " "
|
||||
"addr: ", Genode::Hex(addr));
|
||||
}
|
||||
|
||||
|
||||
void Igd::Mmio::execlist_status_dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
#define DUMP_EXECLIST_STATUS(reg) \
|
||||
log(#reg); \
|
||||
log(" Current_context_id: ", Hex(read<reg::Current_context_id>())); \
|
||||
log(" Arbitration_enable: ", Hex(read<reg::Arbitration_enable>())); \
|
||||
log(" Current_active_element_status: ", Hex(read<reg::Current_active_element_status>())); \
|
||||
log(" Last_context_switch_reason: ", Hex(read<reg::Last_context_switch_reason>())); \
|
||||
if (read<reg::Last_context_switch_reason>()) { \
|
||||
Igd::Context_status_qword::access_t v = read<reg::Last_context_switch_reason>(); \
|
||||
log(" Wait_on_scanline: ", Igd::Context_status_qword::Wait_on_scanline::get(v)); \
|
||||
log(" Wait_on_semaphore: ", Igd::Context_status_qword::Wait_on_semaphore::get(v)); \
|
||||
log(" Wait_on_v_blank: ", Igd::Context_status_qword::Wait_on_v_blank::get(v)); \
|
||||
log(" Wait_on_sync_flip: ", Igd::Context_status_qword::Wait_on_sync_flip::get(v)); \
|
||||
log(" Context_complete: ", Igd::Context_status_qword::Context_complete::get(v)); \
|
||||
log(" Active_to_idle: ", Igd::Context_status_qword::Active_to_idle::get(v)); \
|
||||
log(" Element_switch: ", Igd::Context_status_qword::Element_switch::get(v)); \
|
||||
log(" Preempted: ", Igd::Context_status_qword::Preempted::get(v)); \
|
||||
log(" Idle_to_active: ", Igd::Context_status_qword::Idle_to_active::get(v)); \
|
||||
} \
|
||||
log(" Execlist_0_valid: ", Hex(read<reg::Execlist_0_valid>())); \
|
||||
log(" Execlist_1_valid: ", Hex(read<reg::Execlist_1_valid>())); \
|
||||
log(" Execlist_queue_full: ", Hex(read<reg::Execlist_queue_full>())); \
|
||||
log(" Execlist_write_pointer: ", Hex(read<reg::Execlist_write_pointer>())); \
|
||||
log(" Current_execlist_pointer: ", Hex(read<reg::Current_execlist_pointer>()));
|
||||
|
||||
DUMP_EXECLIST_STATUS(EXECLIST_STATUS_RSCUNIT);
|
||||
|
||||
#undef DUMP_EXECLIST_STATUS
|
||||
}
|
||||
|
||||
|
||||
void Igd::Mmio::context_status_pointer_dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
uint32_t const v = read<RCS_RING_CONTEXT_STATUS_PTR>();
|
||||
uint32_t const wp = read<RCS_RING_CONTEXT_STATUS_PTR::Write_pointer>();
|
||||
uint32_t const rp = read<RCS_RING_CONTEXT_STATUS_PTR::Read_pointer>();
|
||||
|
||||
log("RCS_RING_CONTEXT_STATUS_PTR: ", Hex(v, Hex::PREFIX, Hex::PAD));
|
||||
log(" Read pointer: ", Hex(rp));
|
||||
log(" Write pointer: ", Hex(wp));
|
||||
|
||||
if (wp == 0x7) {
|
||||
warning("RCS seems to be idle");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t r = rp;
|
||||
uint32_t w = wp;
|
||||
if (r > w) { w += CTXT_ST_BUF_NUM; }
|
||||
while (r < w) {
|
||||
uint32_t const i = ++r % CTXT_ST_BUF_NUM;
|
||||
|
||||
uint64_t const cs = read<CTXT_ST_BUF_RCSUNIT>(i);
|
||||
uint32_t const csu = read<CTXT_ST_BUF_RCSUNIT::Context_status_udw>(i);
|
||||
uint32_t const csl = read<CTXT_ST_BUF_RCSUNIT::Context_status_ldw>(i);
|
||||
log(i, " Context_status: ", Hex(cs));
|
||||
|
||||
Igd::Context_status_qword::access_t const v = csl;
|
||||
log(i, " Context_complete: ", Igd::Context_status_qword::Context_complete::get(v));
|
||||
log(i, " Active_to_idle: ", Igd::Context_status_qword::Active_to_idle::get(v));
|
||||
log(i, " Element_switch: ", Igd::Context_status_qword::Element_switch::get(v));
|
||||
log(i, " Preempted: ", Igd::Context_status_qword::Preempted::get(v));
|
||||
log(i, " Idle_to_active: ", Igd::Context_status_qword::Idle_to_active::get(v));
|
||||
|
||||
log(i, " Context_status_udw: ", Hex(csu));
|
||||
log(i, " Context_status_ldw: ", Hex(csl));
|
||||
}
|
||||
}
|
849
repos/os/src/drivers/gpu/intel/ppgtt.h
Normal file
849
repos/os/src/drivers/gpu/intel/ppgtt.h
Normal file
@ -0,0 +1,849 @@
|
||||
/*
|
||||
* \brief Broadwell graphics translation table definitions
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-03-15
|
||||
*
|
||||
* Adapted copy of base-hw's IA-32e translation table by
|
||||
* Adrian-Ken Rueegsegger et. al.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _PPGTT_H_
|
||||
#define _PPGTT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator.h>
|
||||
#include <base/cache.h>
|
||||
#include <base/output.h>
|
||||
#include <util/misc_math.h>
|
||||
#include <util/register.h>
|
||||
|
||||
/* local includes */
|
||||
#include <utils.h>
|
||||
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
/**
|
||||
* Return an address rounded down to a specific alignment
|
||||
*
|
||||
* \param addr original address
|
||||
* \param alignm_log2 log2 of the required alignment
|
||||
*/
|
||||
inline addr_t trunc(addr_t const addr, addr_t const alignm_log2) {
|
||||
return (addr >> alignm_log2) << alignm_log2; }
|
||||
|
||||
/**
|
||||
* Return wether a pointer fullfills an alignment
|
||||
*
|
||||
* \param p pointer
|
||||
* \param alignm_log2 log2 of the required alignment
|
||||
*/
|
||||
inline bool aligned(void * const p, addr_t const alignm_log2) {
|
||||
return (addr_t)p == trunc((addr_t)p, alignm_log2); }
|
||||
|
||||
/**
|
||||
* Translation table allocator interface
|
||||
*/
|
||||
class Translation_table_allocator : public Genode::Allocator
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Return physical address of given virtual page address
|
||||
*
|
||||
* \param addr virtual page address
|
||||
*/
|
||||
virtual void * phys_addr(void * addr) = 0;
|
||||
|
||||
/**
|
||||
* Return virtual address of given physical page address
|
||||
*
|
||||
* \param addr physical page address
|
||||
*/
|
||||
virtual void * virt_addr(void * addr) = 0;
|
||||
};
|
||||
|
||||
enum Writeable { RO, RW };
|
||||
enum Executeable { NO_EXEC, EXEC };
|
||||
enum Privileged { USER, KERN };
|
||||
enum Global { NO_GLOBAL, GLOBAL };
|
||||
enum Type { RAM, DEVICE };
|
||||
|
||||
struct Page_flags
|
||||
{
|
||||
Writeable writeable;
|
||||
};
|
||||
|
||||
/**
|
||||
* IA-32e paging translates 48-bit linear addresses to 52-bit physical
|
||||
* addresses. Translation structures are hierarchical and four levels
|
||||
* deep.
|
||||
*
|
||||
* For detailed information refer to Intel SDM Vol. 3A, section 4.5.
|
||||
*/
|
||||
|
||||
enum {
|
||||
SIZE_LOG2_4KB = 12,
|
||||
SIZE_LOG2_2MB = 21,
|
||||
SIZE_LOG2_1GB = 30,
|
||||
SIZE_LOG2_512GB = 39,
|
||||
SIZE_LOG2_256TB = 48,
|
||||
};
|
||||
|
||||
class Level_4_translation_table;
|
||||
class Pml4_table;
|
||||
|
||||
/**
|
||||
* IA-32e page directory template.
|
||||
*
|
||||
* Page directories can refer to paging structures of the next higher level
|
||||
* or directly map page frames by using large page mappings.
|
||||
*
|
||||
* \param PAGE_SIZE_LOG2 virtual address range size in log2
|
||||
* of a single table entry
|
||||
* \param SIZE_LOG2 virtual address range size in log2 of whole table
|
||||
*/
|
||||
template <typename ENTRY, unsigned PAGE_SIZE_LOG2, unsigned SIZE_LOG2>
|
||||
class Page_directory;
|
||||
|
||||
using Level_3_translation_table =
|
||||
Page_directory<Level_4_translation_table,
|
||||
SIZE_LOG2_2MB, SIZE_LOG2_1GB>;
|
||||
using Level_2_translation_table =
|
||||
Page_directory<Level_3_translation_table,
|
||||
SIZE_LOG2_1GB, SIZE_LOG2_512GB>;
|
||||
|
||||
/**
|
||||
* IA-32e common descriptor.
|
||||
*
|
||||
* Table entry contains descriptor fields common to all four levels.
|
||||
*
|
||||
* IHD-OS-BDW-Vol 5-11.15 p. 23 ff.
|
||||
*/
|
||||
struct Common_descriptor : Register<64>
|
||||
{
|
||||
struct P : Bitfield< 0, 1> { }; /* present */ /* must always be 1, see scratch pages */
|
||||
struct Rw : Bitfield< 1, 1> { }; /* read/write */ /* not supported on Gen8 */
|
||||
struct Us : Bitfield< 2, 1> { }; /* user/supervisor */ /* not supported on Gen8 */
|
||||
struct Pwt : Bitfield< 3, 1> { }; /* write-through */ /* Pwt and Pcd are used as index into PAT */
|
||||
struct Pcd : Bitfield< 4, 1> { }; /* cache disable */ /* see Mmio::PAT_INDEX */
|
||||
struct A : Bitfield< 5, 1> { }; /* accessed */
|
||||
struct D : Bitfield< 6, 1> { }; /* dirty */
|
||||
struct Xd : Bitfield<63, 1> { }; /* execute-disable */ /* not supported on Gen8 */
|
||||
|
||||
static bool present(access_t const v) { return P::get(v); }
|
||||
|
||||
static access_t create(Page_flags const &flags)
|
||||
{
|
||||
return P::bits(1) | Rw::bits(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge access rights of descriptor with given flags.
|
||||
*/
|
||||
static void merge_access_rights(access_t &desc,
|
||||
Page_flags const &flags)
|
||||
{
|
||||
Rw::set(desc, Rw::get(desc) | flags.writeable);
|
||||
}
|
||||
};
|
||||
|
||||
struct Scratch
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Allocator_guard &_guard;
|
||||
Utils::Backend_alloc &_backend;
|
||||
|
||||
public:
|
||||
|
||||
enum {
|
||||
PAGE_SIZE = 4096,
|
||||
MAX_ENTRIES = 512,
|
||||
};
|
||||
|
||||
using Ram = Utils::Ram;
|
||||
|
||||
struct Page
|
||||
{
|
||||
Genode::Ram_dataspace_capability ds;
|
||||
addr_t addr;
|
||||
Page *next;
|
||||
};
|
||||
|
||||
Page page;
|
||||
Page pt;
|
||||
Page pd;
|
||||
Page pdp;
|
||||
|
||||
Scratch(Genode::Allocator_guard &guard,
|
||||
Utils::Backend_alloc &backend)
|
||||
:
|
||||
_guard(guard), _backend(backend)
|
||||
{
|
||||
/* XXX addr PAT helper instead of hardcoding */
|
||||
page.ds = _backend.alloc(_guard, PAGE_SIZE);
|
||||
page.addr = Genode::Dataspace_client(page.ds).phys_addr();
|
||||
page.addr |= 1;
|
||||
page.addr |= 1 << 1;
|
||||
page.next = nullptr;
|
||||
|
||||
pt.ds = _backend.alloc(_guard, PAGE_SIZE);
|
||||
pt.addr = Genode::Dataspace_client(pt.ds).phys_addr();
|
||||
pt.addr |= 1;
|
||||
pt.addr |= 1 << 1;
|
||||
pt.addr |= 1 << 7;
|
||||
pt.next = &page;
|
||||
|
||||
pd.ds = _backend.alloc(_guard, PAGE_SIZE);
|
||||
pd.addr = Genode::Dataspace_client(pd.ds).phys_addr();
|
||||
pd.addr |= 1;
|
||||
pd.addr |= 1 << 1;
|
||||
pd.next = &pt;
|
||||
|
||||
pdp.ds = _backend.alloc(_guard, PAGE_SIZE);
|
||||
pdp.addr = Genode::Dataspace_client(pdp.ds).phys_addr();
|
||||
pdp.addr |= 1;
|
||||
pdp.addr |= 1 << 1;
|
||||
pdp.next = &pd;
|
||||
}
|
||||
|
||||
virtual ~Scratch()
|
||||
{
|
||||
_backend.free(_guard, pdp.ds);
|
||||
_backend.free(_guard, pd.ds);
|
||||
_backend.free(_guard, pt.ds);
|
||||
_backend.free(_guard, page.ds);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class Genode::Level_4_translation_table
|
||||
{
|
||||
private:
|
||||
|
||||
static constexpr size_t PAGE_SIZE_LOG2 = SIZE_LOG2_4KB;
|
||||
static constexpr size_t SIZE_LOG2 = SIZE_LOG2_2MB;
|
||||
static constexpr size_t MAX_ENTRIES = 1UL << (SIZE_LOG2-PAGE_SIZE_LOG2);
|
||||
static constexpr size_t PAGE_SIZE = 1UL << PAGE_SIZE_LOG2;
|
||||
static constexpr size_t PAGE_MASK = ~((1UL << PAGE_SIZE_LOG2) - 1);
|
||||
|
||||
class Misaligned {};
|
||||
class Invalid_range {};
|
||||
class Double_insertion {};
|
||||
|
||||
struct Descriptor : Common_descriptor
|
||||
{
|
||||
using Common = Common_descriptor;
|
||||
|
||||
struct Pat : Bitfield<7, 1> { }; /* page attribute table */
|
||||
struct G : Bitfield<8, 1> { }; /* global */
|
||||
struct Pa : Bitfield<12, 36> { }; /* physical address */
|
||||
struct Mt : Bitset_3<Pwt, Pcd, Pat> { }; /* memory type */
|
||||
|
||||
static access_t create(Page_flags const &flags, addr_t const pa)
|
||||
{
|
||||
/* XXX: Set memory type depending on active PAT */
|
||||
return Common::create(flags) | Pat::bits(1) | Pa::masked(pa);
|
||||
}
|
||||
|
||||
static bool scratch(typename Descriptor::access_t desc,
|
||||
addr_t scratch_addr)
|
||||
{
|
||||
return desc == scratch_addr;
|
||||
}
|
||||
};
|
||||
|
||||
typename Descriptor::access_t _entries[MAX_ENTRIES];
|
||||
|
||||
struct Insert_func
|
||||
{
|
||||
Page_flags const &flags;
|
||||
Translation_table_allocator *alloc;
|
||||
Scratch::Page *scratch;
|
||||
|
||||
Insert_func(Page_flags const &flags,
|
||||
Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
: flags(flags), alloc(alloc), scratch(scratch) { }
|
||||
|
||||
void operator () (addr_t const vo, addr_t const pa,
|
||||
size_t const size,
|
||||
Descriptor::access_t &desc)
|
||||
{
|
||||
if ((vo & ~PAGE_MASK) || (pa & ~PAGE_MASK) ||
|
||||
size < PAGE_SIZE)
|
||||
{
|
||||
throw Invalid_range();
|
||||
}
|
||||
Descriptor::access_t table_entry =
|
||||
Descriptor::create(flags, pa);
|
||||
|
||||
if ( Descriptor::present(desc)
|
||||
&& !Descriptor::scratch(desc, scratch->addr)) {
|
||||
throw Double_insertion();
|
||||
}
|
||||
desc = table_entry;
|
||||
}
|
||||
};
|
||||
|
||||
struct Remove_func
|
||||
{
|
||||
Translation_table_allocator *alloc;
|
||||
Scratch::Page *scratch;
|
||||
|
||||
Remove_func(Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
: alloc(alloc), scratch(scratch) { }
|
||||
|
||||
void operator () (addr_t const vo, addr_t const pa,
|
||||
size_t const size,
|
||||
Descriptor::access_t &desc)
|
||||
{
|
||||
desc = scratch->addr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FUNC>
|
||||
void _range_op(addr_t vo, addr_t pa, size_t size, FUNC &&func)
|
||||
{
|
||||
for (size_t i = vo >> PAGE_SIZE_LOG2; size > 0;
|
||||
i = vo >> PAGE_SIZE_LOG2) {
|
||||
addr_t end = (vo + PAGE_SIZE) & PAGE_MASK;
|
||||
size_t sz = min(size, end-vo);
|
||||
|
||||
func(vo, pa, sz, _entries[i]);
|
||||
|
||||
/* check whether we wrap */
|
||||
if (end < vo) return;
|
||||
|
||||
size = size - sz;
|
||||
vo += sz;
|
||||
pa += sz;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static constexpr size_t MIN_PAGE_SIZE_LOG2 = SIZE_LOG2_4KB;
|
||||
static constexpr size_t ALIGNM_LOG2 = SIZE_LOG2_4KB;
|
||||
|
||||
/**
|
||||
* IA-32e page table (Level 4)
|
||||
*
|
||||
* A page table consists of 512 entries that each maps a 4KB page
|
||||
* frame. For further details refer to Intel SDM Vol. 3A, table 4-19.
|
||||
*/
|
||||
Level_4_translation_table(Scratch::Page *scratch)
|
||||
{
|
||||
if (!aligned(this, ALIGNM_LOG2)) { throw Misaligned(); }
|
||||
|
||||
for (size_t i = 0; i < MAX_ENTRIES; i++) {
|
||||
_entries[i] = scratch->addr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns True if table does not contain any page mappings.
|
||||
*/
|
||||
bool empty(addr_t scratch_addr)
|
||||
{
|
||||
for (unsigned i = 0; i < MAX_ENTRIES; i++) {
|
||||
if (!Descriptor::scratch(_entries[i], scratch_addr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert translations into this table
|
||||
*
|
||||
* \param vo offset of the virtual region represented
|
||||
* by the translation within the virtual
|
||||
* region represented by this table
|
||||
* \param pa base of the physical backing store
|
||||
* \param size size of the translated region
|
||||
* \param flags mapping flags
|
||||
* \param alloc second level translation table allocator
|
||||
*/
|
||||
void insert_translation(addr_t vo, addr_t pa, size_t size,
|
||||
Page_flags const & flags,
|
||||
Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
{
|
||||
_range_op(vo, pa, size, Insert_func(flags, alloc, scratch));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove translations that overlap with a given virtual region
|
||||
*
|
||||
* \param vo region offset within the tables virtual region
|
||||
* \param size region size
|
||||
* \param alloc second level translation table allocator
|
||||
*/
|
||||
void remove_translation(addr_t vo, size_t size,
|
||||
Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
{
|
||||
_range_op(vo, 0, size, Remove_func(alloc, scratch));
|
||||
}
|
||||
} __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||
|
||||
|
||||
template <typename ENTRY, unsigned PAGE_SIZE_LOG2, unsigned SIZE_LOG2>
|
||||
class Genode::Page_directory
|
||||
{
|
||||
private:
|
||||
|
||||
static constexpr size_t MAX_ENTRIES = 1UL << (SIZE_LOG2-PAGE_SIZE_LOG2);
|
||||
static constexpr size_t PAGE_SIZE = 1UL << PAGE_SIZE_LOG2;
|
||||
static constexpr size_t PAGE_MASK = ~((1UL << PAGE_SIZE_LOG2) - 1);
|
||||
|
||||
class Misaligned {};
|
||||
class Invalid_range {};
|
||||
class Double_insertion {};
|
||||
|
||||
struct Base_descriptor : Common_descriptor
|
||||
{
|
||||
using Common = Common_descriptor;
|
||||
|
||||
struct Ps : Common::template Bitfield<7, 1> { }; /* page size */
|
||||
|
||||
static bool maps_page(access_t const v) { return Ps::get(v); }
|
||||
};
|
||||
|
||||
struct Page_descriptor : Base_descriptor
|
||||
{
|
||||
using Base = Base_descriptor;
|
||||
|
||||
/**
|
||||
* Global attribute
|
||||
*/
|
||||
struct G : Base::template Bitfield<8, 1> { };
|
||||
|
||||
/**
|
||||
* Page attribute table
|
||||
*/
|
||||
struct Pat : Base::template Bitfield<12, 1> { };
|
||||
|
||||
/**
|
||||
* Physical address
|
||||
*/
|
||||
struct Pa : Base::template Bitfield<PAGE_SIZE_LOG2,
|
||||
48 - PAGE_SIZE_LOG2> { };
|
||||
|
||||
/**
|
||||
* Memory type
|
||||
*/
|
||||
struct Mt : Base::template Bitset_3<Base::Pwt,
|
||||
Base::Pcd, Pat> { };
|
||||
|
||||
static typename Base::access_t create(Page_flags const &flags,
|
||||
addr_t const pa)
|
||||
{
|
||||
/* XXX: Set memory type depending on active PAT */
|
||||
return Base::create(flags) | Pa::masked(pa);
|
||||
}
|
||||
|
||||
static bool scratch(typename Page_descriptor::access_t desc,
|
||||
addr_t scratch_addr)
|
||||
{
|
||||
return desc == scratch_addr;
|
||||
}
|
||||
};
|
||||
|
||||
struct Table_descriptor : Base_descriptor
|
||||
{
|
||||
using Base = Base_descriptor;
|
||||
|
||||
/**
|
||||
* Physical address
|
||||
*/
|
||||
struct Pa : Base::template Bitfield<12, 36> { };
|
||||
|
||||
/**
|
||||
* Memory types
|
||||
*/
|
||||
struct Mt : Base::template Bitset_2<Base::Pwt,
|
||||
Base::Pcd> { };
|
||||
|
||||
static typename Base::access_t create(Page_flags const &flags,
|
||||
addr_t const pa)
|
||||
{
|
||||
/* XXX: Set memory type depending on active PAT */
|
||||
return Base::create(flags) | Pa::masked(pa);
|
||||
}
|
||||
};
|
||||
|
||||
typename Base_descriptor::access_t _entries[MAX_ENTRIES];
|
||||
|
||||
struct Insert_func
|
||||
{
|
||||
Page_flags const &flags;
|
||||
Translation_table_allocator *alloc;
|
||||
Scratch::Page *scratch;
|
||||
|
||||
Insert_func(Page_flags const &flags,
|
||||
Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
: flags(flags), alloc(alloc), scratch(scratch) { }
|
||||
|
||||
void operator () (addr_t const vo, addr_t const pa,
|
||||
size_t const size,
|
||||
typename Base_descriptor::access_t &desc)
|
||||
{
|
||||
/* we need to use a next level table */
|
||||
ENTRY *table;
|
||||
if (Page_descriptor::scratch(desc, scratch->addr)) {
|
||||
if (!alloc) { throw Allocator::Out_of_memory(); }
|
||||
|
||||
/* create and link next level table */
|
||||
try { table = new (alloc) ENTRY(scratch->next); }
|
||||
catch (...) { throw Allocator::Out_of_memory(); }
|
||||
ENTRY * phys_addr = (ENTRY*) alloc->phys_addr(table);
|
||||
|
||||
addr_t const pa = (addr_t)(phys_addr ? phys_addr : table);
|
||||
desc = (typename Base_descriptor::access_t) Table_descriptor::create(flags, pa);
|
||||
|
||||
} else if (Base_descriptor::maps_page(desc)) {
|
||||
throw Double_insertion();
|
||||
} else {
|
||||
Base_descriptor::merge_access_rights(desc, flags);
|
||||
ENTRY * phys_addr = (ENTRY*) Table_descriptor::Pa::masked(desc);
|
||||
table = (ENTRY*) alloc->virt_addr(phys_addr);
|
||||
if (!table) { table = (ENTRY*) phys_addr; }
|
||||
}
|
||||
|
||||
/* insert translation */
|
||||
addr_t const table_vo = vo - (vo & PAGE_MASK);
|
||||
table->insert_translation(table_vo, pa, size, flags, alloc, scratch->next);
|
||||
}
|
||||
};
|
||||
|
||||
struct Remove_func
|
||||
{
|
||||
Translation_table_allocator *alloc;
|
||||
Scratch::Page *scratch;
|
||||
|
||||
Remove_func(Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
: alloc(alloc), scratch(scratch) { }
|
||||
|
||||
void operator () (addr_t const vo, addr_t const pa,
|
||||
size_t const size,
|
||||
typename Base_descriptor::access_t &desc)
|
||||
{
|
||||
if (Base_descriptor::present(desc) &&
|
||||
!Page_descriptor::scratch(desc, scratch->addr)) {
|
||||
|
||||
if (Base_descriptor::maps_page(desc)) {
|
||||
desc = scratch->addr;
|
||||
} else {
|
||||
/* use allocator to retrieve virt address of table */
|
||||
ENTRY *phys_addr = (ENTRY*)
|
||||
Table_descriptor::Pa::masked(desc);
|
||||
ENTRY *table = (ENTRY*) alloc->virt_addr(phys_addr);
|
||||
if (!table) { table = (ENTRY*) phys_addr; }
|
||||
|
||||
addr_t const table_vo = vo - (vo & PAGE_MASK);
|
||||
table->remove_translation(table_vo, size, alloc, scratch->next);
|
||||
if (table->empty(scratch->next->addr)) {
|
||||
destroy(alloc, table);
|
||||
desc = scratch->addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FUNC>
|
||||
void _range_op(addr_t vo, addr_t pa, size_t size, FUNC &&func)
|
||||
{
|
||||
for (size_t i = vo >> PAGE_SIZE_LOG2; size > 0;
|
||||
i = vo >> PAGE_SIZE_LOG2)
|
||||
{
|
||||
addr_t end = (vo + PAGE_SIZE) & PAGE_MASK;
|
||||
size_t sz = min(size, end-vo);
|
||||
|
||||
func(vo, pa, sz, _entries[i]);
|
||||
|
||||
/* check whether we wrap */
|
||||
if (end < vo) { return; }
|
||||
|
||||
size = size - sz;
|
||||
vo += sz;
|
||||
pa += sz;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static constexpr size_t MIN_PAGE_SIZE_LOG2 = SIZE_LOG2_4KB;
|
||||
static constexpr size_t ALIGNM_LOG2 = SIZE_LOG2_4KB;
|
||||
|
||||
Page_directory(Scratch::Page *scratch)
|
||||
{
|
||||
if (!aligned(this, ALIGNM_LOG2)) { throw Misaligned(); }
|
||||
|
||||
for (size_t i = 0; i < MAX_ENTRIES; i++) {
|
||||
_entries[i] = scratch->addr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns True if table does not contain any page mappings.
|
||||
*
|
||||
* \return false if an entry is present, True otherwise
|
||||
*/
|
||||
bool empty(addr_t scratch_addr)
|
||||
{
|
||||
for (unsigned i = 0; i < MAX_ENTRIES; i++) {
|
||||
if (!Page_descriptor::scratch(_entries[i], scratch_addr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert translations into this table
|
||||
*
|
||||
* \param vo offset of the virtual region represented
|
||||
* by the translation within the virtual
|
||||
* region represented by this table
|
||||
* \param pa base of the physical backing store
|
||||
* \param size size of the translated region
|
||||
* \param flags mapping flags
|
||||
* \param alloc second level translation table allocator
|
||||
*/
|
||||
void insert_translation(addr_t vo, addr_t pa, size_t size,
|
||||
Page_flags const & flags,
|
||||
Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
{
|
||||
_range_op(vo, pa, size, Insert_func(flags, alloc, scratch));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove translations that overlap with a given virtual region
|
||||
*
|
||||
* \param vo region offset within the tables virtual region
|
||||
* \param size region size
|
||||
* \param alloc second level translation table allocator
|
||||
*/
|
||||
void remove_translation(addr_t vo, size_t size,
|
||||
Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
{
|
||||
_range_op(vo, 0, size, Remove_func(alloc, scratch));
|
||||
}
|
||||
} __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||
|
||||
|
||||
class Genode::Pml4_table
|
||||
{
|
||||
private:
|
||||
|
||||
static constexpr size_t PAGE_SIZE_LOG2 = SIZE_LOG2_512GB;
|
||||
static constexpr size_t SIZE_LOG2 = SIZE_LOG2_256TB;
|
||||
static constexpr size_t MAX_ENTRIES = 512;
|
||||
static constexpr uint64_t PAGE_SIZE = 1ULL << PAGE_SIZE_LOG2;
|
||||
static constexpr uint64_t PAGE_MASK = ~((1ULL << PAGE_SIZE_LOG2) - 1);
|
||||
|
||||
class Misaligned {};
|
||||
class Invalid_range {};
|
||||
|
||||
struct Descriptor : Common_descriptor
|
||||
{
|
||||
struct Pa : Bitfield<12, 36> { }; /* physical address */
|
||||
struct Mt : Bitset_2<Pwt, Pcd> { }; /* memory type */
|
||||
|
||||
static access_t create(Page_flags const &flags, addr_t const pa)
|
||||
{
|
||||
/* XXX: Set memory type depending on active PAT */
|
||||
return Common_descriptor::create(flags) | Pa::masked(pa);
|
||||
}
|
||||
|
||||
static bool scratch(Descriptor::access_t desc, addr_t const pa)
|
||||
{
|
||||
return desc == pa;
|
||||
}
|
||||
};
|
||||
|
||||
typename Descriptor::access_t _entries[MAX_ENTRIES];
|
||||
|
||||
using ENTRY = Level_2_translation_table;
|
||||
|
||||
struct Insert_func
|
||||
{
|
||||
Page_flags const &flags;
|
||||
Translation_table_allocator *alloc;
|
||||
Scratch::Page *scratch;
|
||||
|
||||
Insert_func(Page_flags const &flags,
|
||||
Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
: flags(flags), alloc(alloc), scratch(scratch) { }
|
||||
|
||||
void operator () (addr_t const vo, addr_t const pa,
|
||||
size_t const size,
|
||||
Descriptor::access_t &desc)
|
||||
{
|
||||
/* we need to use a next level table */
|
||||
ENTRY *table;
|
||||
if (Descriptor::scratch(desc, scratch->addr)) {
|
||||
if (!alloc) { throw Allocator::Out_of_memory(); }
|
||||
|
||||
/* create and link next level table */
|
||||
try { table = new (alloc) ENTRY(scratch->next); }
|
||||
catch (...) { throw Allocator::Out_of_memory(); }
|
||||
|
||||
ENTRY * phys_addr = (ENTRY*) alloc->phys_addr(table);
|
||||
addr_t const pa = (addr_t)(phys_addr ? phys_addr : table);
|
||||
desc = Descriptor::create(flags, pa);
|
||||
} else {
|
||||
Descriptor::merge_access_rights(desc, flags);
|
||||
ENTRY * phys_addr = (ENTRY*) Descriptor::Pa::masked(desc);
|
||||
table = (ENTRY*) alloc->virt_addr(phys_addr);
|
||||
if (!table) { table = (ENTRY*) phys_addr; }
|
||||
}
|
||||
|
||||
/* insert translation */
|
||||
addr_t const table_vo = vo - (vo & PAGE_MASK);
|
||||
table->insert_translation(table_vo, pa, size, flags, alloc, scratch->next);
|
||||
}
|
||||
};
|
||||
|
||||
struct Remove_func
|
||||
{
|
||||
Translation_table_allocator *alloc;
|
||||
Scratch::Page *scratch;
|
||||
|
||||
Remove_func(Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
: alloc(alloc), scratch(scratch) { }
|
||||
|
||||
void operator () (addr_t const vo, addr_t const pa,
|
||||
size_t const size,
|
||||
Descriptor::access_t &desc)
|
||||
{
|
||||
if (!Descriptor::scratch(desc, scratch->addr)) {
|
||||
|
||||
ENTRY* phys_addr = (ENTRY*) Descriptor::Pa::masked(desc);
|
||||
ENTRY *table = (ENTRY*) alloc->virt_addr(phys_addr);
|
||||
if (!table) { table = (ENTRY*) phys_addr; }
|
||||
|
||||
addr_t const table_vo = vo - (vo & PAGE_MASK);
|
||||
table->remove_translation(table_vo, size, alloc, scratch->next);
|
||||
if (table->empty(scratch->next->addr)) {
|
||||
destroy(alloc, table);
|
||||
desc = scratch->addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FUNC>
|
||||
void _range_op(addr_t vo, addr_t pa, size_t size, FUNC &&func)
|
||||
{
|
||||
for (size_t i = vo >> PAGE_SIZE_LOG2; size > 0;
|
||||
i = vo >> PAGE_SIZE_LOG2) {
|
||||
addr_t const end = (vo + PAGE_SIZE) & PAGE_MASK;
|
||||
size_t const sz = min(size, end-vo);
|
||||
|
||||
func(vo, pa, sz, _entries[i]);
|
||||
|
||||
/* check whether we wrap */
|
||||
if (end < vo) { return; }
|
||||
|
||||
size = size - sz;
|
||||
vo += sz;
|
||||
pa += sz;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static constexpr size_t MIN_PAGE_SIZE_LOG2 = SIZE_LOG2_4KB;
|
||||
static constexpr size_t ALIGNM_LOG2 = SIZE_LOG2_4KB;
|
||||
|
||||
Pml4_table(Scratch::Page *scratch)
|
||||
{
|
||||
if (!aligned(this, ALIGNM_LOG2)) { throw Misaligned(); }
|
||||
|
||||
for (size_t i = 0; i < MAX_ENTRIES; i++) {
|
||||
_entries[i] = scratch->addr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert translations into this table
|
||||
*
|
||||
* \param vo offset of the virtual region represented
|
||||
* by the translation within the virtual
|
||||
* region represented by this table
|
||||
* \param pa base of the physical backing store
|
||||
* \param size size of the translated region
|
||||
* \param flags mapping flags
|
||||
* \param alloc second level translation table allocator
|
||||
*/
|
||||
void insert_translation(addr_t vo, addr_t pa, size_t size,
|
||||
Page_flags const & flags,
|
||||
Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
{
|
||||
_range_op(vo, pa, size, Insert_func(flags, alloc, scratch));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove translations that overlap with a given virtual region
|
||||
*
|
||||
* \param vo region offset within the tables virtual region
|
||||
* \param size region size
|
||||
* \param alloc second level translation table allocator
|
||||
*/
|
||||
void remove_translation(addr_t vo, size_t size,
|
||||
Translation_table_allocator *alloc,
|
||||
Scratch::Page *scratch)
|
||||
{
|
||||
_range_op(vo, 0, size, Remove_func(alloc, scratch));
|
||||
}
|
||||
} __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||
|
||||
|
||||
namespace Igd {
|
||||
|
||||
struct Ppgtt;
|
||||
struct Ppgtt_scratch;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Per-process graphics translation table
|
||||
*/
|
||||
struct Igd::Ppgtt : public Genode::Pml4_table
|
||||
{
|
||||
Ppgtt(Genode::Scratch::Page *scratch) : Pml4_table(scratch) { }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Per-process graphics translation table scratch pages
|
||||
*/
|
||||
struct Igd::Ppgtt_scratch : public Genode::Scratch
|
||||
{
|
||||
Ppgtt_scratch(Genode::Allocator_guard &guard,
|
||||
Utils::Backend_alloc &backend)
|
||||
: Scratch(guard, backend) { }
|
||||
};
|
||||
|
||||
#endif /* _PPGTT_H_ */
|
98
repos/os/src/drivers/gpu/intel/ppgtt_allocator.h
Normal file
98
repos/os/src/drivers/gpu/intel/ppgtt_allocator.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* \brief PPGTT translation table allocator
|
||||
* \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.
|
||||
*/
|
||||
|
||||
#ifndef _PPGTT_ALLOCATOR_H_
|
||||
#define _PPGTT_ALLOCATOR_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator_guard.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
#include <utils.h>
|
||||
|
||||
|
||||
namespace Igd {
|
||||
|
||||
class Ppgtt_allocator;
|
||||
}
|
||||
|
||||
|
||||
class Igd::Ppgtt_allocator : public Genode::Translation_table_allocator
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Region_map &_rm;
|
||||
Genode::Allocator_guard &_guard;
|
||||
Utils::Backend_alloc &_backend;
|
||||
|
||||
enum { ELEMENTS = 256, };
|
||||
Utils::Address_map<ELEMENTS> _map;
|
||||
|
||||
public:
|
||||
|
||||
Ppgtt_allocator(Genode::Region_map &rm,
|
||||
Genode::Allocator_guard &guard,
|
||||
Utils::Backend_alloc &backend)
|
||||
: _rm(rm), _guard(guard), _backend(backend) { }
|
||||
|
||||
/*************************
|
||||
** Allocator interface **
|
||||
*************************/
|
||||
|
||||
bool alloc(size_t size, void **out_addr)
|
||||
{
|
||||
Genode::Ram_dataspace_capability ds = _backend.alloc(_guard, size);
|
||||
if (!ds.valid()) { return false; }
|
||||
|
||||
*out_addr = _rm.attach(ds);
|
||||
return _map.add(ds, *out_addr);
|
||||
}
|
||||
|
||||
void free(void *addr, size_t size)
|
||||
{
|
||||
if (addr == nullptr) { return; }
|
||||
|
||||
Genode::Ram_dataspace_capability cap = _map.remove(addr);
|
||||
if (!cap.valid()) {
|
||||
Genode::error("could not lookup capability for addr: ", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
_rm.detach(addr);
|
||||
_backend.free(_guard, cap);
|
||||
}
|
||||
|
||||
bool need_size_for_free() const override { return false; }
|
||||
size_t overhead(size_t size) const override { return 0; }
|
||||
|
||||
/*******************************************
|
||||
** Translation_table_allocator interface **
|
||||
*******************************************/
|
||||
|
||||
void *phys_addr(void *va)
|
||||
{
|
||||
if (va == nullptr) { return nullptr; }
|
||||
typename Utils::Address_map<ELEMENTS>::Element *e = _map.phys_addr(va);
|
||||
return e ? (void*)e->pa : nullptr;
|
||||
}
|
||||
|
||||
void *virt_addr(void *pa)
|
||||
{
|
||||
if (pa == nullptr) { return nullptr; }
|
||||
typename Utils::Address_map<ELEMENTS>::Element *e = _map.virt_addr(pa);
|
||||
return e ? (void*)e->va : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _PPGTT_ALLOCATOR_H_ */
|
207
repos/os/src/drivers/gpu/intel/ring_buffer.h
Normal file
207
repos/os/src/drivers/gpu/intel/ring_buffer.h
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* \brief Broadwell ring buffer
|
||||
* \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 _RING_BUFFER_H_
|
||||
#define _RING_BUFFER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
#include <commands.h>
|
||||
|
||||
|
||||
namespace Igd {
|
||||
|
||||
class Ring_buffer;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
class Igd::Ring_buffer
|
||||
{
|
||||
public:
|
||||
|
||||
using Index = size_t;
|
||||
|
||||
private:
|
||||
|
||||
uint32_t *_dwords;
|
||||
Index _max;
|
||||
Index _tail;
|
||||
Index _head;
|
||||
|
||||
public:
|
||||
|
||||
Ring_buffer(addr_t base,
|
||||
size_t length)
|
||||
:
|
||||
_dwords((uint32_t*)base), _max(length / sizeof (uint32_t)),
|
||||
_tail(0), _head(0)
|
||||
{
|
||||
/* initial clear */
|
||||
Genode::memset(_dwords, 0, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear ring buffer and reset tail
|
||||
*/
|
||||
void reset()
|
||||
{
|
||||
Genode::memset(_dwords, 0, _max * sizeof(uint32_t));
|
||||
_tail = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear remaining ring buffer and reset tail
|
||||
*/
|
||||
void reset_and_fill_zero()
|
||||
{
|
||||
Genode::size_t const bytes = (_max - _tail) * sizeof(uint32_t);
|
||||
Genode::memset(_dwords + _tail, 0, bytes);
|
||||
_tail = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current tail
|
||||
*
|
||||
* \return current tail index
|
||||
*/
|
||||
Index tail() const { return _tail; }
|
||||
|
||||
/**
|
||||
* Get current head
|
||||
*
|
||||
* \return current head index
|
||||
*/
|
||||
Index head() const { return _head; }
|
||||
|
||||
/**
|
||||
* Update head
|
||||
*
|
||||
* \param head new head index
|
||||
*/
|
||||
void update_head(Index head)
|
||||
{
|
||||
_head = head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert new command at given index
|
||||
*
|
||||
* \param cmmd new command
|
||||
* \param index index for new command
|
||||
*/
|
||||
Index insert(Igd::Cmd_header cmd, Index index)
|
||||
{
|
||||
if (index < _tail) { throw -1; }
|
||||
if (index > _max) { throw -2; }
|
||||
|
||||
_dwords[index] = cmd.value;
|
||||
_tail++;
|
||||
|
||||
if (_tail > _max) {
|
||||
Genode::warning("ring buffer wrapped ",
|
||||
"_tail: ", _tail, " ", "_max: ", _max);
|
||||
_tail = 0;
|
||||
}
|
||||
|
||||
if (_tail == _head) {
|
||||
Genode::error("tail: ", Genode::Hex(_tail), " == head: ",
|
||||
Genode::Hex(_head), " in ring buffer");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append command to ring buffer
|
||||
*
|
||||
* \param cmd command
|
||||
*
|
||||
* \return number of command words written
|
||||
*/
|
||||
Index append(Igd::Cmd_header cmd)
|
||||
{
|
||||
return insert(cmd, _tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append command to ring buffer
|
||||
*
|
||||
* \param v dword value
|
||||
*
|
||||
* \return number of command words written
|
||||
*/
|
||||
Index append(uint32_t v)
|
||||
{
|
||||
return insert(Igd::Cmd_header(v), _tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if remaing space is enough for number of commands
|
||||
*
|
||||
* \return true if space is sufficient, otherwise false is returned
|
||||
*/
|
||||
bool avail(Index num) const
|
||||
{
|
||||
return (_tail + num) < _max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total number of commands that fit into the ring buffer
|
||||
*
|
||||
* \return number of total commands fitting the ring buffer
|
||||
*/
|
||||
Index max() const { return _max; }
|
||||
|
||||
/**
|
||||
* Flush range of commands in ring buffer
|
||||
*
|
||||
* \param from index to start from
|
||||
* \param to index to end on
|
||||
*/
|
||||
void flush(Index from, Index to) const
|
||||
{
|
||||
uint32_t *start = _dwords + from;
|
||||
for (Index i = 0; i < (to - from); i++) {
|
||||
uint32_t *addr = start++;
|
||||
Utils::clflush(addr);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************
|
||||
** Debug interface **
|
||||
*********************/
|
||||
|
||||
void dump(size_t dw_limit = 0) const
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
size_t const max = dw_limit ? dw_limit : _max;
|
||||
|
||||
log("Ring_buffer: ", Hex(*_dwords), " max: ", _max, " (limit: ", max, ")");
|
||||
|
||||
for (size_t i = 0; i < max; i++) {
|
||||
log(Hex(i*4, Hex::PREFIX, Hex::PAD), " ",
|
||||
Hex(_dwords[i], Hex::PREFIX, Hex::PAD),
|
||||
i == _tail ? " T " : " ",
|
||||
i == _head ? " H " : " "
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _RING_BUFFER_H_ */
|
7
repos/os/src/drivers/gpu/intel/target.mk
Normal file
7
repos/os/src/drivers/gpu/intel/target.mk
Normal file
@ -0,0 +1,7 @@
|
||||
TARGET = intel_gpu_drv
|
||||
SRC_CC = main.cc mmio_dump.cc
|
||||
LIBS = base
|
||||
|
||||
REQUIRES = x86
|
||||
|
||||
INC_DIR += $(PRG_DIR)
|
37
repos/os/src/drivers/gpu/intel/types.h
Normal file
37
repos/os/src/drivers/gpu/intel/types.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* \brief Broadwell type definitions
|
||||
* \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.
|
||||
*/
|
||||
|
||||
#ifndef _TYPES_H_
|
||||
#define _TYPES_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <ram_session/ram_session.h>
|
||||
|
||||
namespace Igd {
|
||||
|
||||
using Ram_dataspace_capability = Genode::Ram_dataspace_capability;
|
||||
using Ram = Genode::Ram_dataspace_capability;
|
||||
|
||||
using uint8_t = Genode::uint8_t;
|
||||
using uint16_t = Genode::uint16_t;
|
||||
using uint32_t = Genode::uint32_t;
|
||||
using uint64_t = Genode::uint64_t;
|
||||
using addr_t = Genode::addr_t;
|
||||
using size_t = Genode::size_t;
|
||||
|
||||
enum { PAGE_SIZE = 4096, };
|
||||
|
||||
inline void wmb() { asm volatile ("sfence": : :"memory"); }
|
||||
}
|
||||
|
||||
#endif /* _TYPES_H_ */
|
133
repos/os/src/drivers/gpu/intel/utils.h
Normal file
133
repos/os/src/drivers/gpu/intel/utils.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* \brief Helper utilities for Broadwell GPU mutliplexer
|
||||
* \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.
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <ram_session/ram_session.h>
|
||||
|
||||
namespace Utils {
|
||||
|
||||
using size_t = Genode::size_t;
|
||||
using uint32_t = Genode::uint32_t;
|
||||
using Ram = Genode::Ram_dataspace_capability;
|
||||
|
||||
/*
|
||||
* Backend allocator interface
|
||||
*/
|
||||
struct Backend_alloc
|
||||
{
|
||||
virtual Ram alloc(Genode::Allocator_guard &, Genode::size_t) = 0;
|
||||
virtual void free(Genode::Allocator_guard &, Ram) = 0;
|
||||
};
|
||||
|
||||
template <unsigned int ELEMENTS> class Address_map;
|
||||
|
||||
void clflush(volatile void *addr)
|
||||
{
|
||||
asm volatile("clflush %0" : "+m" (*(volatile char *)addr));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <unsigned int ELEMENTS>
|
||||
class Utils::Address_map
|
||||
{
|
||||
public:
|
||||
|
||||
struct Element
|
||||
{
|
||||
Ram ds_cap;
|
||||
void *va;
|
||||
void *pa;
|
||||
uint32_t index;
|
||||
|
||||
Element() : ds_cap(Ram()), va(nullptr), pa(nullptr), index(0) { }
|
||||
|
||||
Element(uint32_t index, Ram ds_cap, void *va)
|
||||
:
|
||||
ds_cap(ds_cap),
|
||||
va(va),
|
||||
pa((void *)Genode::Dataspace_client(ds_cap).phys_addr()),
|
||||
index(index)
|
||||
{ }
|
||||
|
||||
bool valid() { return va && pa; }
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Element _map[ELEMENTS];
|
||||
|
||||
public:
|
||||
|
||||
Address_map()
|
||||
{
|
||||
Genode::memset(&_map, 0, sizeof(_map));
|
||||
}
|
||||
|
||||
~Address_map()
|
||||
{
|
||||
for (uint32_t i = 0; i < ELEMENTS; i++) {
|
||||
if (!_map[i].valid()) { continue; }
|
||||
|
||||
Genode::error("Address_map entry ", Genode::Hex(i), " ",
|
||||
"still valid (", _map[i].va, "/", _map[i].pa, ")");
|
||||
}
|
||||
}
|
||||
|
||||
bool add(Ram ds_cap, void *va)
|
||||
{
|
||||
for (uint32_t i = 0; i < ELEMENTS; i++) {
|
||||
if (_map[i].valid()) { continue; }
|
||||
|
||||
_map[i] = Element(i, ds_cap, va);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Ram remove(void *va)
|
||||
{
|
||||
Ram cap;
|
||||
|
||||
for (uint32_t i = 0; i < ELEMENTS; i++) {
|
||||
if (_map[i].va != va) { continue; }
|
||||
|
||||
cap = _map[i].ds_cap;
|
||||
_map[i] = Element();
|
||||
break;
|
||||
}
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
Element *phys_addr(void *va)
|
||||
{
|
||||
for (uint32_t i = 0; i < ELEMENTS; i++) {
|
||||
if (_map[i].va == va) { return &_map[i]; }
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element *virt_addr(void *pa)
|
||||
{
|
||||
for (uint32_t i = 0; i < ELEMENTS; i++) {
|
||||
if (_map[i].pa == pa) { return &_map[i]; }
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _UTILS_H_ */
|
Loading…
x
Reference in New Issue
Block a user