mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-29 15:44:02 +00:00
parent
9c3867e173
commit
3841ee1d51
@ -246,6 +246,7 @@ struct Pci::Config : Genode::Mmio
|
||||
{
|
||||
struct Control : Register<0x2, 16>
|
||||
{
|
||||
struct Slots : Bitfield<0, 10> {};
|
||||
struct Size : Bitfield<0, 11> {};
|
||||
struct Function_mask : Bitfield<14, 1> {};
|
||||
struct Enable : Bitfield<15, 1> {};
|
||||
@ -265,6 +266,8 @@ struct Pci::Config : Genode::Mmio
|
||||
|
||||
struct Table_entry : Genode::Mmio
|
||||
{
|
||||
enum { SIZE = 16 };
|
||||
|
||||
struct Address_64_lower : Register<0x0, 32> { };
|
||||
struct Address_64_upper : Register<0x4, 32> { };
|
||||
struct Data : Register<0x8, 32> { };
|
||||
@ -277,6 +280,22 @@ struct Pci::Config : Genode::Mmio
|
||||
};
|
||||
|
||||
using Pci_capability::Pci_capability;
|
||||
|
||||
Genode::uint8_t bar() {
|
||||
return (Genode::uint8_t) read<Table::Bar_index>(); }
|
||||
|
||||
Genode::size_t table_offset() {
|
||||
return read<Table::Offset>() << 3; }
|
||||
|
||||
unsigned slots() { return read<Control::Slots>(); }
|
||||
|
||||
void enable()
|
||||
{
|
||||
Control::access_t ctrl = read<Control>();
|
||||
Control::Function_mask::set(ctrl, 0);
|
||||
Control::Enable::set(ctrl, 1);
|
||||
write<Control>(ctrl);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -47,6 +47,15 @@ Driver::Device::Name Device_component::device() const { return _device; }
|
||||
Driver::Session_component & Device_component::session() { return _session; }
|
||||
|
||||
|
||||
unsigned Device_component::io_mem_index(Device::Pci_bar bar)
|
||||
{
|
||||
unsigned ret = ~0U;
|
||||
_io_mem_registry.for_each([&] (Io_mem & iomem) {
|
||||
if (iomem.bar.number == bar.number) ret = iomem.idx; });
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Genode::Io_mem_session_capability
|
||||
Device_component::io_mem(unsigned idx, Range &range)
|
||||
{
|
||||
@ -92,7 +101,7 @@ Genode::Irq_session_capability Device_component::irq(unsigned idx)
|
||||
pci_cfg_addr);
|
||||
Irq_session::Info info = irq.irq->info();
|
||||
if (info.type == Irq_session::Info::MSI)
|
||||
pci_msi_enable(_env, pci_cfg_addr, info);
|
||||
pci_msi_enable(_env, *this, pci_cfg_addr, info, irq.type);
|
||||
}
|
||||
|
||||
if (irq.shared && !irq.sirq.constructed())
|
||||
@ -172,13 +181,13 @@ Device_component::Device_component(Registry<Device_component> & registry,
|
||||
});
|
||||
|
||||
device.for_each_io_mem([&] (unsigned idx, Range range,
|
||||
Device::Pci_bar, bool pf)
|
||||
Device::Pci_bar bar, bool pf)
|
||||
{
|
||||
session.ram_quota_guard().withdraw(Ram_quota{Io_mem_session::RAM_QUOTA});
|
||||
_ram_quota += Io_mem_session::RAM_QUOTA;
|
||||
session.cap_quota_guard().withdraw(Cap_quota{Io_mem_session::CAP_QUOTA});
|
||||
_cap_quota += Io_mem_session::CAP_QUOTA;
|
||||
new (session.heap()) Io_mem(_io_mem_registry, idx, range, pf);
|
||||
new (session.heap()) Io_mem(_io_mem_registry, bar, idx, range, pf);
|
||||
});
|
||||
|
||||
device.for_each_io_port_range([&] (unsigned idx, Io_port_range::Range range)
|
||||
@ -206,7 +215,7 @@ Device_component::Device_component(Registry<Device_component> & registry,
|
||||
session.cap_quota_guard().withdraw(Cap_quota{Io_mem_session::CAP_QUOTA});
|
||||
_cap_quota += Io_mem_session::CAP_QUOTA;
|
||||
Io_mem & iomem = *(new (session.heap())
|
||||
Io_mem(_reserved_mem_registry, idx, range, false));
|
||||
Io_mem(_reserved_mem_registry, {0}, idx, range, false));
|
||||
iomem.io_mem.construct(_env, iomem.range.start,
|
||||
iomem.range.size, false);
|
||||
session.device_pd().attach_dma_mem(iomem.io_mem->dataspace(),
|
||||
|
@ -62,18 +62,22 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
|
||||
|
||||
struct Io_mem : Registry<Io_mem>::Element
|
||||
{
|
||||
using Pci_bar = Device::Pci_bar;
|
||||
|
||||
Pci_bar bar;
|
||||
unsigned idx;
|
||||
Range range;
|
||||
bool prefetchable;
|
||||
Constructible<Io_mem_connection> io_mem {};
|
||||
|
||||
Io_mem(Registry<Io_mem> & registry,
|
||||
Pci_bar bar,
|
||||
unsigned idx,
|
||||
Range range,
|
||||
bool pf)
|
||||
:
|
||||
Registry<Io_mem>::Element(registry, *this),
|
||||
idx(idx), range(range), prefetchable(pf) {}
|
||||
bar(bar), idx(idx), range(range), prefetchable(pf) {}
|
||||
};
|
||||
|
||||
struct Io_port_range : Registry<Io_port_range>::Element
|
||||
@ -108,6 +112,7 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
|
||||
|
||||
Driver::Device::Name device() const;
|
||||
Session_component & session();
|
||||
unsigned io_mem_index(Device::Pci_bar bar);
|
||||
|
||||
|
||||
/************************************
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <device.h>
|
||||
#include <device_pd.h>
|
||||
#include <device_component.h>
|
||||
#include <pci.h>
|
||||
#include <pci_uhci.h>
|
||||
#include <pci_ehci.h>
|
||||
@ -127,15 +128,53 @@ void Driver::pci_apply_quirks(Env & env, Device const & dev)
|
||||
|
||||
|
||||
void Driver::pci_msi_enable(Env & env,
|
||||
Device_component & dc,
|
||||
addr_t cfg_space,
|
||||
Irq_session::Info const info)
|
||||
Irq_session::Info const info,
|
||||
Device::Irq::Type type)
|
||||
{
|
||||
Attached_io_mem_dataspace io_mem { env, cfg_space, 0x1000 };
|
||||
Config config { (addr_t)io_mem.local_addr<void>() };
|
||||
config.scan();
|
||||
if (config.msi_cap.constructed())
|
||||
|
||||
if (type == Device::Irq::Type::MSIX && config.msi_x_cap.constructed()) {
|
||||
try {
|
||||
/* find the MSI-x table from the device's memory bars */
|
||||
Platform::Device_interface::Range range;
|
||||
unsigned idx = dc.io_mem_index({config.msi_x_cap->bar()});
|
||||
Io_mem_session_client dsc(dc.io_mem(idx, range));
|
||||
Attached_dataspace msix_table_ds(env.rm(), dsc.dataspace());
|
||||
addr_t msix_table_start = (addr_t)msix_table_ds.local_addr<void>()
|
||||
+ config.msi_x_cap->table_offset();
|
||||
|
||||
/* disable all msi-x table entries beside the first one */
|
||||
unsigned slots = config.msi_x_cap->slots();
|
||||
for (unsigned i = 0; i < slots; i++) {
|
||||
using Entry = Config::Msi_x_capability::Table_entry;
|
||||
Entry e (msix_table_start + Entry::SIZE * i);
|
||||
if (!i) {
|
||||
uint32_t lower = info.address & 0xfffffffc;
|
||||
uint32_t upper = sizeof(info.address) > 4 ?
|
||||
(uint32_t)(info.address >> 32) : 0;
|
||||
e.write<Entry::Address_64_lower>(lower);
|
||||
e.write<Entry::Address_64_upper>(upper);
|
||||
e.write<Entry::Data>((uint32_t)info.value);
|
||||
e.write<Entry::Vector_control::Mask>(0);
|
||||
} else
|
||||
e.write<Entry::Vector_control::Mask>(1);
|
||||
}
|
||||
|
||||
config.msi_x_cap->enable();
|
||||
} catch(...) { error("Failed to setup MSI-x!"); }
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == Device::Irq::Type::MSI && config.msi_cap.constructed()) {
|
||||
config.msi_cap->enable(info.address, (uint16_t)info.value);
|
||||
else error("Device does not support MSI(-x)!");
|
||||
return;
|
||||
}
|
||||
|
||||
error("Device does not support MSI(-x)!");
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,15 +18,18 @@
|
||||
#include <irq_session/irq_session.h>
|
||||
#include <os/session_policy.h>
|
||||
|
||||
#include <device.h>
|
||||
|
||||
namespace Driver {
|
||||
class Device;
|
||||
class Device_component;
|
||||
class Device_pd;
|
||||
|
||||
void pci_enable(Genode::Env & env, Device_pd & pd, Device const & dev);
|
||||
void pci_disable(Genode::Env & env, Device const & dev);
|
||||
void pci_apply_quirks(Genode::Env & env, Device const & dev);
|
||||
void pci_msi_enable(Genode::Env & env, addr_t cfg_space,
|
||||
Genode::Irq_session::Info const info);
|
||||
void pci_msi_enable(Genode::Env & env, Device_component & dc,
|
||||
addr_t cfg_space, Genode::Irq_session::Info const info,
|
||||
Device::Irq::Type type);
|
||||
bool pci_device_matches(Genode::Session_policy const & policy,
|
||||
Device const & dev);
|
||||
void pci_device_specific_info(Device const & dev,
|
||||
|
Loading…
x
Reference in New Issue
Block a user