mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
gpu/intel: prepare GPU structures for resume
The commit is a preparation commit for suspend/resume. It prepares the GPU structures relying on gmadr.cap() (MMIO) to be re-constructible by applying the with* pattern to context, ring_buffer and ggtt mmio map. It removes the managed dataspace handling of gmadr subsets to make the with_* pattern possible. Issue #5081
This commit is contained in:
parent
d02f4866ea
commit
c2cd4102d8
@ -1,11 +1,11 @@
|
||||
/*
|
||||
* \brief Broadwell logical ring context
|
||||
* \brief Intel GPU logical ring context for Broadwell and newer
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-03-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
* Copyright (C) 2017-2024 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.
|
||||
@ -360,13 +360,12 @@ class Igd::Execlist_context : public Igd::Common_context_regs
|
||||
|
||||
public:
|
||||
|
||||
Execlist_context(addr_t const base,
|
||||
addr_t const ring_buffer_start,
|
||||
size_t const ring_buffer_length,
|
||||
uint32_t const immediate_header,
|
||||
Generation const gen)
|
||||
:
|
||||
Common_context_regs(base)
|
||||
Execlist_context(addr_t const base) : Common_context_regs(base) { }
|
||||
|
||||
void setup(addr_t const ring_buffer_start,
|
||||
size_t const ring_buffer_length,
|
||||
uint32_t const immediate_header,
|
||||
Generation const gen)
|
||||
{
|
||||
write<Load_immediate_header>(immediate_header);
|
||||
write_offset<Context_control_mmio>(RING_BASE);
|
||||
@ -597,9 +596,9 @@ class Igd::Ppgtt_context : public Igd::Common_context_regs
|
||||
|
||||
public:
|
||||
|
||||
Ppgtt_context(addr_t base, uint64_t plm4_addr)
|
||||
:
|
||||
Common_context_regs(base)
|
||||
Ppgtt_context(addr_t const base) : Common_context_regs(base) { }
|
||||
|
||||
void setup(uint64_t const plm4_addr)
|
||||
{
|
||||
write<Load_immediate_header>(0x11001011);
|
||||
write_offset<Cs_ctx_timestamp_mmio>(RING_BASE);
|
||||
@ -843,27 +842,30 @@ class Igd::Rcs_context
|
||||
Pphardware_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;
|
||||
Engine_context _engine_context { };
|
||||
Ext_engine_context _ext_engine_context { };
|
||||
Urb_atomic_context _urb_atomic_context { };
|
||||
|
||||
public:
|
||||
|
||||
Rcs_context(addr_t const map_base,
|
||||
addr_t const ring_buffer_start,
|
||||
size_t const ring_buffer_length,
|
||||
uint64_t const plm4_addr,
|
||||
Generation const gen)
|
||||
Rcs_context(addr_t const map_base)
|
||||
:
|
||||
_hw_status_page(map_base),
|
||||
_execlist_context((addr_t)(map_base + HW_STATUS_PAGE_SIZE),
|
||||
ring_buffer_start, ring_buffer_length,
|
||||
EXECLIST_CTX_IH, gen),
|
||||
_ppgtt_context((addr_t)(map_base + HW_STATUS_PAGE_SIZE), plm4_addr),
|
||||
_engine_context(),
|
||||
_ext_engine_context(),
|
||||
_urb_atomic_context()
|
||||
_hw_status_page (map_base),
|
||||
_execlist_context(map_base + HW_STATUS_PAGE_SIZE),
|
||||
_ppgtt_context (map_base + HW_STATUS_PAGE_SIZE)
|
||||
{ }
|
||||
|
||||
void setup(addr_t const ring_buffer_start,
|
||||
size_t const ring_buffer_length,
|
||||
uint64_t const plm4_addr,
|
||||
Generation const gen)
|
||||
{
|
||||
auto const map_base = _hw_status_page.base();
|
||||
|
||||
_execlist_context.setup(ring_buffer_start, ring_buffer_length,
|
||||
EXECLIST_CTX_IH, gen);
|
||||
_ppgtt_context.setup(plm4_addr);
|
||||
|
||||
if (false)
|
||||
Genode::log(__func__, ":",
|
||||
" map_base:", Genode::Hex(map_base),
|
||||
|
@ -39,16 +39,17 @@ class Igd::Ggtt
|
||||
|
||||
struct Mapping
|
||||
{
|
||||
Genode::Dataspace_capability cap { };
|
||||
Offset offset;
|
||||
Igd::addr_t vaddr = 0;
|
||||
Offset const offset;
|
||||
Igd::addr_t const vsize;
|
||||
|
||||
enum { INVALID_OFFSET = ~0u - 1, };
|
||||
enum { INVALID_OFFSET = ~0u - 1 };
|
||||
|
||||
Mapping() : offset(INVALID_OFFSET) { }
|
||||
Mapping() : offset(INVALID_OFFSET), vsize(0) { }
|
||||
|
||||
Mapping(Genode::Dataspace_capability cap, Offset offset)
|
||||
: cap(cap), offset(offset) { }
|
||||
Mapping(Offset off_set, Igd::addr_t size)
|
||||
: offset(off_set), vsize(size) { }
|
||||
|
||||
bool invalid() const { return offset == INVALID_OFFSET; }
|
||||
|
||||
virtual ~Mapping() { }
|
||||
};
|
||||
|
@ -269,9 +269,9 @@ struct Igd::Device
|
||||
if (!_ggtt.constructed())
|
||||
return false;
|
||||
|
||||
fn(*_ggtt);
|
||||
|
||||
return true;
|
||||
return _resources.with_mmio([&](auto &mmio) {
|
||||
fn(*_ggtt, mmio);
|
||||
});
|
||||
}
|
||||
|
||||
__attribute__((warn_unused_result))
|
||||
@ -307,53 +307,31 @@ struct Igd::Device
|
||||
_pci_backend_alloc.free(cap);
|
||||
}
|
||||
|
||||
struct Ggtt_mmio_mapping : Ggtt::Mapping
|
||||
Genode::Registry<Genode::Registered<Ggtt::Mapping>> _ggtt_mapping_registry { };
|
||||
|
||||
Ggtt::Mapping &map_dataspace_ggtt(Genode::Allocator &alloc,
|
||||
Genode::Ram_dataspace_capability cap,
|
||||
Ggtt::Offset offset)
|
||||
{
|
||||
Region_map_client _rmc;
|
||||
Genode::Registered<Ggtt::Mapping> *mem = nullptr;
|
||||
|
||||
Ggtt_mmio_mapping(Rm_connection & rm,
|
||||
Dataspace_capability cap,
|
||||
Ggtt::Offset offset,
|
||||
size_t size)
|
||||
:
|
||||
_rmc(rm.create(size))
|
||||
{
|
||||
_rmc.attach_at(cap, 0, size, offset * PAGE_SIZE);
|
||||
Ggtt::Mapping::cap = _rmc.dataspace();
|
||||
Ggtt::Mapping::offset = offset;
|
||||
}
|
||||
if (!with_ggtt([&](auto &ggtt, auto &mmio) {
|
||||
Genode::Dataspace_client client(cap);
|
||||
addr_t const phys_addr = _pci_backend_alloc.dma_addr(cap);
|
||||
size_t const size = client.size();
|
||||
|
||||
virtual ~Ggtt_mmio_mapping() { }
|
||||
};
|
||||
/*
|
||||
* Create the mapping first and insert the entries afterwards
|
||||
* so we do not have to rollback when the allocation fails.
|
||||
*/
|
||||
mem = new (&alloc)
|
||||
Genode::Registered<Ggtt::Mapping>(_ggtt_mapping_registry,
|
||||
offset, size);
|
||||
|
||||
Genode::Registry<Genode::Registered<Ggtt_mmio_mapping>> _ggtt_mmio_mapping_registry { };
|
||||
|
||||
Ggtt_mmio_mapping const &map_dataspace_ggtt(Genode::Allocator &alloc,
|
||||
Genode::Ram_dataspace_capability cap,
|
||||
Ggtt::Offset offset)
|
||||
{
|
||||
Genode::Registered<Ggtt_mmio_mapping> *mem = nullptr;
|
||||
|
||||
if (!with_ggtt([&](auto &ggtt) {
|
||||
if (!_resources.with_mmio_gmadr([&](auto &mmio, auto &gmadr) {
|
||||
Genode::Dataspace_client client(cap);
|
||||
addr_t const phys_addr = _pci_backend_alloc.dma_addr(cap);
|
||||
size_t const size = client.size();
|
||||
|
||||
/*
|
||||
* Create the mapping first and insert the entries afterwards
|
||||
* so we do not have to rollback when the allocation fails.
|
||||
*/
|
||||
mem = new (&alloc)
|
||||
Genode::Registered<Ggtt_mmio_mapping>(_ggtt_mmio_mapping_registry,
|
||||
_rm, gmadr.cap(), offset, size);
|
||||
|
||||
for (size_t i = 0; i < size; i += PAGE_SIZE) {
|
||||
addr_t const pa = phys_addr + i;
|
||||
ggtt.insert_pte(mmio, pa, offset + (i / PAGE_SIZE));
|
||||
}
|
||||
}))
|
||||
error(__func__, " failed");
|
||||
for (size_t i = 0; i < size; i += PAGE_SIZE) {
|
||||
addr_t const pa = phys_addr + i;
|
||||
ggtt.insert_pte(mmio, pa, offset + (i / PAGE_SIZE));
|
||||
}
|
||||
}))
|
||||
throw Could_not_map_vram();
|
||||
|
||||
@ -363,22 +341,12 @@ struct Igd::Device
|
||||
return *mem;
|
||||
}
|
||||
|
||||
void unmap_dataspace_ggtt(Genode::Allocator &alloc, Genode::Dataspace_capability cap)
|
||||
void unmap_dataspace_ggtt(Genode::Allocator &alloc, Ggtt::Mapping &m)
|
||||
{
|
||||
size_t const num = Genode::Dataspace_client(cap).size() / PAGE_SIZE;
|
||||
|
||||
if (!with_ggtt([&](auto &ggtt) {
|
||||
if (!_resources.with_mmio([&](auto &mmio) {
|
||||
auto lookup_and_free = [&] (Ggtt_mmio_mapping &m) {
|
||||
if (!(m.cap == cap)) { return; }
|
||||
|
||||
ggtt.remove_pte_range(mmio, m.offset, num);
|
||||
Genode::destroy(&alloc, &m);
|
||||
};
|
||||
|
||||
_ggtt_mmio_mapping_registry.for_each(lookup_and_free);
|
||||
}))
|
||||
error(__func__, " with_mmio failed");
|
||||
if (!with_ggtt([&](auto &ggtt, auto &mmio) {
|
||||
size_t const num = m.vsize / PAGE_SIZE;
|
||||
ggtt.remove_pte_range(mmio, m.offset, num);
|
||||
Genode::destroy(&alloc, &m);
|
||||
}))
|
||||
error(__func__, " failed");
|
||||
}
|
||||
@ -400,17 +368,11 @@ struct Igd::Device
|
||||
struct Execlist : Genode::Noncopyable
|
||||
{
|
||||
Igd::Context_descriptor _elem0;
|
||||
Igd::Context_descriptor _elem1;
|
||||
Igd::Context_descriptor _elem1 { };
|
||||
|
||||
Igd::Ring_buffer _ring;
|
||||
bool _scheduled;
|
||||
bool _scheduled { };
|
||||
|
||||
Execlist(uint32_t const id, addr_t const lrca,
|
||||
addr_t const ring, size_t const ring_size)
|
||||
:
|
||||
_elem0(id, lrca), _elem1(),
|
||||
_ring(ring, ring_size), _scheduled(false)
|
||||
{ }
|
||||
Execlist(uint32_t const id, addr_t const lrca) : _elem0(id, lrca) { }
|
||||
|
||||
Igd::Context_descriptor elem0() const { return _elem0; }
|
||||
Igd::Context_descriptor elem1() const { return _elem1; }
|
||||
@ -418,28 +380,6 @@ struct Igd::Device
|
||||
void schedule(int port) { _scheduled = port; }
|
||||
int scheduled() const { return _scheduled; }
|
||||
|
||||
/*************************
|
||||
** Ring vram interface **
|
||||
*************************/
|
||||
|
||||
void ring_reset() { _ring.reset(); }
|
||||
Ring_buffer::Index ring_tail() const { return _ring.tail(); }
|
||||
Ring_buffer::Index ring_head() const { return _ring.head(); }
|
||||
Ring_buffer::Index ring_append(Igd::Cmd_header cmd) { return _ring.append(cmd); }
|
||||
|
||||
bool ring_avail(Ring_buffer::Index num) const { return _ring.avail(num); }
|
||||
Ring_buffer::Index ring_max() const { return _ring.max(); }
|
||||
void ring_reset_and_fill_zero() { _ring.reset_and_fill_zero(); }
|
||||
void ring_update_head(Ring_buffer::Index head) { _ring.update_head(head); }
|
||||
void ring_reset_to_head(Ring_buffer::Index head) { _ring.reset_to_head(head); }
|
||||
|
||||
void ring_flush(Ring_buffer::Index from, Ring_buffer::Index to)
|
||||
{
|
||||
_ring.flush(from, to);
|
||||
}
|
||||
|
||||
void ring_dump(size_t limit, unsigned hw_tail, unsigned hw_head) const { _ring.dump(limit, hw_tail, hw_head); }
|
||||
|
||||
/*********************
|
||||
** Debug interface **
|
||||
*********************/
|
||||
@ -465,18 +405,20 @@ struct Igd::Device
|
||||
};
|
||||
|
||||
struct Mapping_guard {
|
||||
Device &device;
|
||||
Allocator &alloc;
|
||||
Ggtt::Mapping const ↦
|
||||
Device &device;
|
||||
Allocator &alloc;
|
||||
Ggtt::Mapping ↦
|
||||
|
||||
Mapping_guard(Device &device, Ggtt_map_memory &gmm, Allocator &alloc)
|
||||
Mapping_guard(Device & device,
|
||||
Ggtt_map_memory & gmm,
|
||||
Allocator & alloc)
|
||||
:
|
||||
device(device),
|
||||
alloc(alloc),
|
||||
map(device.map_dataspace_ggtt(alloc, gmm.ram_ds.ds, gmm.offset))
|
||||
{ }
|
||||
|
||||
~Mapping_guard() { device.unmap_dataspace_ggtt(alloc, map.cap); }
|
||||
~Mapping_guard() { device.unmap_dataspace_ggtt(alloc, map); }
|
||||
};
|
||||
|
||||
Device const &device;
|
||||
@ -485,13 +427,6 @@ struct Igd::Device
|
||||
Ggtt::Offset const skip;
|
||||
Dataspace_guard const ram_ds;
|
||||
Mapping_guard const map;
|
||||
Attached_dataspace const ram;
|
||||
|
||||
addr_t vaddr() const
|
||||
{
|
||||
return reinterpret_cast<addr_t>(ram.local_addr<addr_t>())
|
||||
+ (skip * PAGE_SIZE);
|
||||
}
|
||||
|
||||
Ggtt::Offset _offset(Ggtt::Offset const &pages)
|
||||
{
|
||||
@ -505,10 +440,20 @@ struct Igd::Device
|
||||
return offset;
|
||||
}
|
||||
|
||||
void with_vaddr(auto const &fn) const
|
||||
{
|
||||
addr_t const offset = (map.map.offset + skip) * PAGE_SIZE;
|
||||
|
||||
if (!device._resources.with_gmadr(offset, [&](auto const addr) {
|
||||
fn(addr);
|
||||
}))
|
||||
error("Gmadr object unavailable");
|
||||
}
|
||||
|
||||
addr_t gmaddr() const { /* graphics memory address */
|
||||
return (offset + skip) * PAGE_SIZE; }
|
||||
|
||||
Ggtt_map_memory(Region_map &rm, Allocator &alloc, Device &device,
|
||||
Ggtt_map_memory(Allocator &alloc, Device &device,
|
||||
Ggtt::Offset const pages, Ggtt::Offset const skip_pages)
|
||||
:
|
||||
device(device),
|
||||
@ -516,8 +461,7 @@ struct Igd::Device
|
||||
offset(_offset(pages)),
|
||||
skip(skip_pages),
|
||||
ram_ds(device, device._alloc_dataspace(pages * PAGE_SIZE)),
|
||||
map(device, *this, alloc),
|
||||
ram(rm, map.map.cap)
|
||||
map(device, *this, alloc)
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -534,17 +478,42 @@ struct Igd::Device
|
||||
Ppgtt_scratch ppgtt_scratch;
|
||||
Ppgtt *ppgtt { nullptr };
|
||||
|
||||
Genode::Constructible<CONTEXT> context { };
|
||||
Genode::Constructible<Execlist> execlist { };
|
||||
Execlist execlist;
|
||||
|
||||
Igd::Ring_buffer<Ggtt_map_memory> _ring { ring, ring_size() };
|
||||
|
||||
void with_context(auto const &fn)
|
||||
{
|
||||
ctx.with_vaddr([&](auto const vaddr) {
|
||||
auto context = CONTEXT(vaddr);
|
||||
|
||||
fn(context);
|
||||
});
|
||||
}
|
||||
|
||||
void with_context_ring(auto const &fn)
|
||||
{
|
||||
ctx.with_vaddr([&](auto const vaddr) {
|
||||
auto context = CONTEXT(vaddr);
|
||||
|
||||
fn(context, _ring);
|
||||
});
|
||||
}
|
||||
|
||||
void with_ring(auto const &fn)
|
||||
{
|
||||
fn(_ring);
|
||||
}
|
||||
|
||||
Engine(Igd::Device &device,
|
||||
uint32_t id,
|
||||
Allocator &alloc)
|
||||
:
|
||||
ctx (device._env.rm(), alloc, device, CONTEXT::CONTEXT_PAGES, 1 /* omit GuC page */),
|
||||
ring(device._env.rm(), alloc, device, CONTEXT::RING_PAGES, 0),
|
||||
ctx (alloc, device, CONTEXT::CONTEXT_PAGES, 1 /* omit GuC page */),
|
||||
ring(alloc, device, CONTEXT::RING_PAGES, 0),
|
||||
ppgtt_allocator(alloc, device._env.rm(), device._pci_backend_alloc),
|
||||
ppgtt_scratch(device._pci_backend_alloc)
|
||||
ppgtt_scratch(device._pci_backend_alloc),
|
||||
execlist(id, ctx.gmaddr())
|
||||
{
|
||||
/* PPGTT */
|
||||
device._populate_scratch(ppgtt_scratch);
|
||||
@ -552,7 +521,6 @@ struct Igd::Device
|
||||
ppgtt = new (ppgtt_allocator) Igd::Ppgtt(&ppgtt_scratch.pdp);
|
||||
|
||||
try {
|
||||
size_t const ring_size = RING_PAGES * PAGE_SIZE;
|
||||
|
||||
/* get PML4 address */
|
||||
addr_t const ppgtt_phys_addr = _ppgtt_phys_addr(ppgtt_allocator,
|
||||
@ -560,11 +528,13 @@ struct Igd::Device
|
||||
addr_t const pml4 = ppgtt_phys_addr | 1;
|
||||
|
||||
/* setup context */
|
||||
context.construct(ctx.vaddr(), ring.gmaddr(), ring_size, pml4, device.generation());
|
||||
with_context([&](auto &context) {
|
||||
context.setup(ring.gmaddr(), ring_size(), pml4,
|
||||
device.generation());
|
||||
});
|
||||
|
||||
/* setup execlist */
|
||||
execlist.construct(id, ctx.gmaddr(), ring.vaddr(), ring_size);
|
||||
execlist->ring_reset();
|
||||
/* initialize ring */
|
||||
_ring.reset();
|
||||
} catch (...) {
|
||||
_destruct();
|
||||
throw;
|
||||
@ -577,9 +547,6 @@ struct Igd::Device
|
||||
{
|
||||
if (ppgtt)
|
||||
Genode::destroy(ppgtt_allocator, ppgtt);
|
||||
|
||||
execlist.destruct();
|
||||
context.destruct();
|
||||
}
|
||||
|
||||
size_t ring_size() const { return RING_PAGES * PAGE_SIZE; }
|
||||
@ -707,14 +674,23 @@ struct Igd::Device
|
||||
}
|
||||
|
||||
bool setup_ring_vram(Gpu::addr_t const vram_addr)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
rcs.with_ring([&](auto &ring) {
|
||||
ok = _setup_ring_vram(vram_addr, ring);
|
||||
});
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool _setup_ring_vram(Gpu::addr_t const vram_addr, auto &ring)
|
||||
{
|
||||
_current_seqno++;
|
||||
|
||||
unsigned generation = _device.generation().value;
|
||||
|
||||
Execlist &el = *rcs.execlist;
|
||||
|
||||
Ring_buffer::Index advance = 0;
|
||||
auto advance = 0;
|
||||
|
||||
bool dc_flush_wa = _device.match(Device_info::Platform::KABYLAKE,
|
||||
Device_info::Stepping::A0,
|
||||
@ -725,11 +701,11 @@ struct Igd::Device
|
||||
+ ((generation == 8) ? 20 : 22) /* epilog + w/a */
|
||||
+ (dc_flush_wa ? 12 : 0);
|
||||
|
||||
if (!el.ring_avail(need))
|
||||
el.ring_reset_and_fill_zero();
|
||||
if (!ring.avail(need))
|
||||
ring.reset_and_fill_zero();
|
||||
|
||||
/* save old tail */
|
||||
Ring_buffer::Index const tail = el.ring_tail();
|
||||
auto const tail = ring.tail();
|
||||
|
||||
/*
|
||||
* IHD-OS-BDW-Vol 7-11.15 p. 18 ff.
|
||||
@ -748,7 +724,7 @@ struct Igd::Device
|
||||
cmd[0] = pc.value;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -760,7 +736,7 @@ struct Igd::Device
|
||||
cmd[1] = Igd::Pipe_control::DC_FLUSH_ENABLE;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -790,7 +766,7 @@ struct Igd::Device
|
||||
cmd[2] = 0x34 * 4;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -802,7 +778,7 @@ struct Igd::Device
|
||||
cmd[1] = Igd::Pipe_control::CS_STALL;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -823,7 +799,7 @@ struct Igd::Device
|
||||
cmd[3] = (vram_addr >> 32) & 0xffff;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -846,7 +822,7 @@ struct Igd::Device
|
||||
cmd[5] = Mi_noop().value;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -864,7 +840,7 @@ struct Igd::Device
|
||||
cmd[1] = tmp;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -890,7 +866,7 @@ struct Igd::Device
|
||||
cmd[5] = _current_seqno >> 32;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -917,7 +893,7 @@ struct Igd::Device
|
||||
cmd[5] = generation < 12 ? Mi_noop().value : 0;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -930,7 +906,7 @@ struct Igd::Device
|
||||
cmd[1] = ui.value;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -950,7 +926,7 @@ struct Igd::Device
|
||||
cmd[1] = Mi_noop().value;
|
||||
|
||||
for (size_t i = 0; i < CMD_NUM; i++) {
|
||||
advance += el.ring_append(cmd[i]);
|
||||
advance += ring.append(cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -961,10 +937,12 @@ struct Igd::Device
|
||||
return false;
|
||||
}
|
||||
|
||||
el.ring_flush(tail, tail + advance);
|
||||
ring.flush(tail, tail + advance);
|
||||
|
||||
/* tail_offset must be specified in qword */
|
||||
rcs.context->tail_offset((offset % (rcs.ring_size())) / 8);
|
||||
rcs.with_context([&](auto &context) {
|
||||
context.tail_offset((offset % (rcs.ring_size())) / 8);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -996,7 +974,7 @@ struct Igd::Device
|
||||
|
||||
void _submit_execlist(Igd::Mmio &mmio, Engine<Rcs_context> &engine)
|
||||
{
|
||||
Execlist &el = *engine.execlist;
|
||||
Execlist &el = engine.execlist;
|
||||
|
||||
int const port = mmio.read<Igd::Mmio::EXECLIST_STATUS_RSCUNIT::Execlist_write_pointer>();
|
||||
|
||||
@ -1043,7 +1021,7 @@ struct Igd::Device
|
||||
if (mmio.read<Igd::Mmio::GEN12_EXECLIST_STATUS_RSCUNIT::Execution_queue_invalid>() == 0)
|
||||
return;
|
||||
|
||||
Execlist &el = *engine.execlist;
|
||||
Execlist &el = engine.execlist;
|
||||
|
||||
mmio.write<Igd::Mmio::GEN12_EXECLIST_SQ_CONTENTS_RSCUNIT>(el.elem0().low(), 0);
|
||||
mmio.write<Igd::Mmio::GEN12_EXECLIST_SQ_CONTENTS_RSCUNIT>(el.elem0().high(), 1);
|
||||
@ -1104,20 +1082,19 @@ struct Igd::Device
|
||||
/**
|
||||
* \return true, if Vgpu is done and has not further work
|
||||
*/
|
||||
bool _notify_complete(Vgpu *gpu)
|
||||
bool _notify_complete(Vgpu &gpu)
|
||||
{
|
||||
if (!gpu) { return true; }
|
||||
uint64_t const curr_seqno = gpu.current_seqno();
|
||||
uint64_t const comp_seqno = gpu.completed_seqno();
|
||||
|
||||
uint64_t const curr_seqno = gpu->current_seqno();
|
||||
uint64_t const comp_seqno = gpu->completed_seqno();
|
||||
|
||||
Execlist &el = *gpu->rcs.execlist;
|
||||
el.ring_update_head(gpu->rcs.context->head_offset());
|
||||
gpu.rcs.with_context_ring([&](auto &context, auto &ring) {
|
||||
ring.update_head(context.head_offset());
|
||||
});
|
||||
|
||||
if (curr_seqno != comp_seqno)
|
||||
return false;
|
||||
|
||||
Genode::Signal_transmitter(gpu->completion_sigh()).submit();
|
||||
Genode::Signal_transmitter(gpu.completion_sigh()).submit();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1158,15 +1135,16 @@ struct Igd::Device
|
||||
{
|
||||
/* signal completion of last job to vgpu */
|
||||
vgpu.mark_completed();
|
||||
_notify_complete(&vgpu);
|
||||
_notify_complete(vgpu);
|
||||
|
||||
/* offset of head in ring context */
|
||||
size_t head_offset = vgpu.rcs.context->head_offset();
|
||||
/* set head = tail in ring and ring context */
|
||||
Execlist &el = *vgpu.rcs.execlist;
|
||||
el.ring_reset_to_head(head_offset);
|
||||
/* set tail in context in qwords */
|
||||
vgpu.rcs.context->tail_offset((head_offset % (vgpu.rcs.ring_size())) / 8);
|
||||
vgpu.rcs.with_context_ring([&](auto &context, auto &ring) {
|
||||
/* offset of head in ring context */
|
||||
size_t head_offset = context.head_offset();
|
||||
/* set head = tail in ring and ring context */
|
||||
ring.reset_to_head(head_offset);
|
||||
/* set tail in context in qwords */
|
||||
context.tail_offset((head_offset % (vgpu.rcs.ring_size())) / 8);
|
||||
});
|
||||
}
|
||||
|
||||
void _handle_watchdog_timeout()
|
||||
@ -1183,12 +1161,14 @@ struct Igd::Device
|
||||
mmio.fault_dump();
|
||||
mmio.execlist_status_dump();
|
||||
|
||||
_active_vgpu->rcs.context->dump();
|
||||
_hw_status_page->dump();
|
||||
Execlist &el = *_active_vgpu->rcs.execlist;
|
||||
el.ring_update_head(_active_vgpu->rcs.context->head_offset());
|
||||
el.ring_dump(4096, _active_vgpu->rcs.context->tail_offset() * 2,
|
||||
_active_vgpu->rcs.context->head_offset());
|
||||
_active_vgpu->rcs.with_context_ring([&](auto &context, auto &ring) {
|
||||
context.dump();
|
||||
_hw_status_page->dump();
|
||||
|
||||
ring.update_head(context.head_offset());
|
||||
ring.dump(4096, context.tail_offset() * 2,
|
||||
context.head_offset());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -1265,9 +1245,13 @@ struct Igd::Device
|
||||
|
||||
/* setup global hardware status page */
|
||||
if (!_hw_status_ctx.constructed())
|
||||
_hw_status_ctx.construct(_env.rm(), _md_alloc, *this, 1, 0);
|
||||
if (!_hw_status_page.constructed())
|
||||
_hw_status_page.construct(_hw_status_ctx->vaddr());
|
||||
_hw_status_ctx.construct(_md_alloc, *this, 1, 0);
|
||||
if (!_hw_status_page.constructed()) {
|
||||
/* global hw_status_ctx becomes never invalid up to now, so using vaddr is ok */
|
||||
_hw_status_ctx->with_vaddr([&](auto const vaddr) {
|
||||
_hw_status_page.construct(vaddr);
|
||||
});
|
||||
}
|
||||
|
||||
Mmio::HWS_PGA_RCSUNIT::access_t const addr = _hw_status_ctx->gmaddr();
|
||||
mmio.write_post<Igd::Mmio::HWS_PGA_RCSUNIT>(addr);
|
||||
@ -1629,48 +1613,6 @@ struct Igd::Device
|
||||
_pci_backend_alloc.free(Genode::static_cap_cast<Genode::Ram_dataspace>(cap));
|
||||
}
|
||||
|
||||
/**
|
||||
* Map DMA vram in the GGTT
|
||||
*
|
||||
* \param guard resource allocator and guard
|
||||
* \param cap DMA vram capability
|
||||
* \param aperture true if mapping should be accessible by CPU
|
||||
*
|
||||
* \return GGTT mapping
|
||||
*
|
||||
* \throw Could_not_map_vram
|
||||
*/
|
||||
Ggtt::Mapping const &map_vram(Genode::Allocator &guard,
|
||||
Genode::Ram_dataspace_capability cap,
|
||||
bool aperture)
|
||||
{
|
||||
if (aperture == false) {
|
||||
error("GGTT mapping outside aperture");
|
||||
throw Could_not_map_vram();
|
||||
}
|
||||
|
||||
if (!_ggtt.constructed()) {
|
||||
error("GGTT mapping failed");
|
||||
throw Could_not_map_vram();
|
||||
}
|
||||
|
||||
size_t const size = Genode::Dataspace_client(cap).size();
|
||||
size_t const num = size / PAGE_SIZE;
|
||||
Ggtt::Offset const offset = _ggtt->find_free(num, aperture);
|
||||
return map_dataspace_ggtt(guard, cap, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap DMA vram from GGTT
|
||||
*
|
||||
* \param guard resource allocator and guard
|
||||
* \param mapping GGTT mapping
|
||||
*/
|
||||
void unmap_vram(Genode::Allocator &guard, Ggtt::Mapping mapping)
|
||||
{
|
||||
unmap_dataspace_ggtt(guard, mapping.cap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set tiling mode for GGTT region
|
||||
*
|
||||
@ -1742,7 +1684,7 @@ struct Igd::Device
|
||||
_unschedule_current_vgpu();
|
||||
|
||||
if (notify_gpu) {
|
||||
if (!_notify_complete(notify_gpu)) {
|
||||
if (!_notify_complete(*notify_gpu)) {
|
||||
_vgpu_list.enqueue(*notify_gpu);
|
||||
}
|
||||
}
|
||||
@ -2027,8 +1969,8 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
|
||||
*/
|
||||
if (vram.owner(_owner.cap) == false) return false;
|
||||
|
||||
if (vram.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) {
|
||||
_device.unmap_vram(_heap, vram.map);
|
||||
if (!vram.map.invalid()) {
|
||||
_device.unmap_dataspace_ggtt(_heap, vram.map);
|
||||
}
|
||||
|
||||
if (vram.fenced != Vram::INVALID_FENCE) {
|
||||
@ -2187,7 +2129,7 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
|
||||
|
||||
if (vram.owner(cap()) == false) return false;
|
||||
|
||||
if (vram.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) {
|
||||
if (!vram.map.invalid()) {
|
||||
Genode::error("cannot free mapped vram");
|
||||
/* XXX throw */
|
||||
return false;
|
||||
@ -2342,7 +2284,7 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
|
||||
|
||||
Vram *v = nullptr;
|
||||
auto lookup = [&] (Vram &vram) {
|
||||
if (!vram.map.cap.valid() || !vram.owner(cap())) { return false; }
|
||||
if (vram.map.invalid() || !vram.owner(cap())) { return false; }
|
||||
v = &vram;
|
||||
return false;
|
||||
};
|
||||
@ -2435,7 +2377,6 @@ class Gpu::Root : public Gpu::Root_component
|
||||
_device->reset(mmio);
|
||||
}))
|
||||
Genode::warning("vGPU active, reset of device failed");
|
||||
|
||||
} else {
|
||||
/* remove from scheduled list */
|
||||
s->vgpu_unschedule();
|
||||
|
@ -286,11 +286,13 @@ class Platform::Resources : Noncopyable
|
||||
|
||||
Env & _env;
|
||||
Signal_context_capability const _irq_cap;
|
||||
Platform::Connection _platform { _env };
|
||||
Reconstructible<Platform::Device> _device { _platform };
|
||||
Reconstructible<Platform::Device::Irq> _irq { *_device };
|
||||
Reconstructible<Igd::Mmio> _mmio { *_device, _env };
|
||||
Reconstructible<Platform::Device::Mmio> _gmadr { *_device, Platform::Device::Mmio::Index(1) };
|
||||
Platform::Connection _platform { _env };
|
||||
|
||||
Reconstructible<Platform::Device> _device { _platform };
|
||||
Reconstructible<Platform::Device::Irq> _irq { *_device };
|
||||
Reconstructible<Igd::Mmio> _mmio { *_device, _env };
|
||||
Reconstructible<Platform::Device::Mmio> _gmadr { *_device, Platform::Device::Mmio::Index(1) };
|
||||
Reconstructible<Attached_dataspace> _gmadr_mem { _env.rm(), _gmadr->cap() };
|
||||
|
||||
Region_map_client _rm_gttmm;
|
||||
Region_map_client _rm_gmadr;
|
||||
@ -379,6 +381,19 @@ class Platform::Resources : Noncopyable
|
||||
return true;
|
||||
}
|
||||
|
||||
__attribute__((warn_unused_result))
|
||||
bool with_gmadr(auto const offset, auto const &fn)
|
||||
{
|
||||
if (!_gmadr_mem.constructed())
|
||||
return false;
|
||||
|
||||
auto const addr = reinterpret_cast<addr_t>(_gmadr_mem->local_addr<addr_t>())
|
||||
+ offset;
|
||||
fn(addr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
__attribute__((warn_unused_result))
|
||||
bool with_irq(auto const &fn)
|
||||
{
|
||||
|
@ -1,11 +1,11 @@
|
||||
/*
|
||||
* \brief Broadwell ring buffer
|
||||
* \brief Ring buffer for Broadwell and newer
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-03-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
* Copyright (C) 2017-2024 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.
|
||||
@ -24,12 +24,13 @@
|
||||
|
||||
namespace Igd {
|
||||
|
||||
class Ring_buffer;
|
||||
template <typename> class Ring_buffer;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
template <typename MEMORY>
|
||||
class Igd::Ring_buffer
|
||||
{
|
||||
public:
|
||||
@ -38,30 +39,31 @@ class Igd::Ring_buffer
|
||||
|
||||
private:
|
||||
|
||||
uint32_t *_dwords;
|
||||
Index _max;
|
||||
Index _tail;
|
||||
Index _head;
|
||||
MEMORY & _memory;
|
||||
Index const _max;
|
||||
Index _tail { };
|
||||
Index _head { };
|
||||
|
||||
void with_dwords(auto const &fn) const {
|
||||
_memory.with_vaddr([&](auto vaddr) { fn((uint32_t *)vaddr); }); }
|
||||
|
||||
void with_dwords(auto const &fn) {
|
||||
_memory.with_vaddr([&](auto vaddr) { fn((uint32_t *)vaddr); }); }
|
||||
|
||||
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);
|
||||
}
|
||||
Ring_buffer(MEMORY & memory, size_t const size)
|
||||
: _memory(memory), _max(size / sizeof (uint32_t)) { }
|
||||
|
||||
/**
|
||||
* Clear ring buffer and reset tail
|
||||
*/
|
||||
void reset()
|
||||
{
|
||||
Genode::memset(_dwords, 0, _max * sizeof(uint32_t));
|
||||
_tail = 0;
|
||||
with_dwords([&](auto dwords) {
|
||||
Genode::memset(dwords, 0, _max * sizeof(uint32_t));
|
||||
_tail = 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,9 +71,11 @@ class Igd::Ring_buffer
|
||||
*/
|
||||
void reset_and_fill_zero()
|
||||
{
|
||||
Genode::size_t const bytes = (_max - _tail) * sizeof(uint32_t);
|
||||
Genode::memset(_dwords + _tail, 0, bytes);
|
||||
_tail = 0;
|
||||
with_dwords([&](auto dwords) {
|
||||
auto const bytes = (_max - _tail) * sizeof(uint32_t);
|
||||
Genode::memset(dwords + _tail, 0, bytes);
|
||||
_tail = 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,19 +122,21 @@ class Igd::Ring_buffer
|
||||
if (index < _tail) { throw -1; }
|
||||
if (index > _max) { throw -2; }
|
||||
|
||||
_dwords[index] = cmd.value;
|
||||
_tail++;
|
||||
with_dwords([&](auto dwords) {
|
||||
dwords[index] = cmd.value;
|
||||
_tail++;
|
||||
|
||||
if (_tail >= _max) {
|
||||
Genode::warning("ring buffer wrapped ",
|
||||
"_tail: ", _tail, " ", "_max: ", _max);
|
||||
_tail = 0;
|
||||
}
|
||||
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");
|
||||
}
|
||||
if (_tail == _head) {
|
||||
Genode::error("tail: ", Genode::Hex(_tail), " == head: ",
|
||||
Genode::Hex(_head), " in ring buffer");
|
||||
}
|
||||
});
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -184,11 +190,13 @@ class Igd::Ring_buffer
|
||||
*/
|
||||
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);
|
||||
}
|
||||
with_dwords([&](auto dwords) {
|
||||
uint32_t *start = dwords + from;
|
||||
for (Index i = 0; i < (to - from); i++) {
|
||||
uint32_t *addr = start++;
|
||||
Utils::clflush(addr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*********************
|
||||
@ -199,21 +207,24 @@ class Igd::Ring_buffer
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
size_t const max = dw_limit ? dw_limit : _max;
|
||||
with_dwords([&](auto dwords) {
|
||||
size_t const max = dw_limit ? dw_limit : _max;
|
||||
|
||||
log("Ring_buffer: ", Hex(*_dwords), " max: ", _max, " (limit: ", max, ")",
|
||||
" hardware read: tail=", Genode::Hex(hw_tail),
|
||||
" head=", Genode::Hex(hw_head));
|
||||
log("Ring_buffer: ", Hex(*dwords),
|
||||
" max: ", _max, " (limit: ", max, ")",
|
||||
" hardware read: tail=", Genode::Hex(hw_tail),
|
||||
" head=", Genode::Hex(hw_head));
|
||||
|
||||
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 " : " ",
|
||||
i == hw_tail ? " T_HW " : " ",
|
||||
i == hw_head ? " H_HW " : " "
|
||||
);
|
||||
}
|
||||
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 " : " ",
|
||||
i == hw_tail ? " T_HW " : " ",
|
||||
i == hw_head ? " H_HW " : " "
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user