mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-29 13:44:26 +00:00
parent
9c3867e173
commit
3841ee1d51
@ -246,6 +246,7 @@ struct Pci::Config : Genode::Mmio
|
|||||||
{
|
{
|
||||||
struct Control : Register<0x2, 16>
|
struct Control : Register<0x2, 16>
|
||||||
{
|
{
|
||||||
|
struct Slots : Bitfield<0, 10> {};
|
||||||
struct Size : Bitfield<0, 11> {};
|
struct Size : Bitfield<0, 11> {};
|
||||||
struct Function_mask : Bitfield<14, 1> {};
|
struct Function_mask : Bitfield<14, 1> {};
|
||||||
struct Enable : Bitfield<15, 1> {};
|
struct Enable : Bitfield<15, 1> {};
|
||||||
@ -265,6 +266,8 @@ struct Pci::Config : Genode::Mmio
|
|||||||
|
|
||||||
struct Table_entry : Genode::Mmio
|
struct Table_entry : Genode::Mmio
|
||||||
{
|
{
|
||||||
|
enum { SIZE = 16 };
|
||||||
|
|
||||||
struct Address_64_lower : Register<0x0, 32> { };
|
struct Address_64_lower : Register<0x0, 32> { };
|
||||||
struct Address_64_upper : Register<0x4, 32> { };
|
struct Address_64_upper : Register<0x4, 32> { };
|
||||||
struct Data : Register<0x8, 32> { };
|
struct Data : Register<0x8, 32> { };
|
||||||
@ -277,6 +280,22 @@ struct Pci::Config : Genode::Mmio
|
|||||||
};
|
};
|
||||||
|
|
||||||
using Pci_capability::Pci_capability;
|
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; }
|
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
|
Genode::Io_mem_session_capability
|
||||||
Device_component::io_mem(unsigned idx, Range &range)
|
Device_component::io_mem(unsigned idx, Range &range)
|
||||||
{
|
{
|
||||||
@ -92,7 +101,7 @@ Genode::Irq_session_capability Device_component::irq(unsigned idx)
|
|||||||
pci_cfg_addr);
|
pci_cfg_addr);
|
||||||
Irq_session::Info info = irq.irq->info();
|
Irq_session::Info info = irq.irq->info();
|
||||||
if (info.type == Irq_session::Info::MSI)
|
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())
|
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.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});
|
session.ram_quota_guard().withdraw(Ram_quota{Io_mem_session::RAM_QUOTA});
|
||||||
_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});
|
session.cap_quota_guard().withdraw(Cap_quota{Io_mem_session::CAP_QUOTA});
|
||||||
_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)
|
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});
|
session.cap_quota_guard().withdraw(Cap_quota{Io_mem_session::CAP_QUOTA});
|
||||||
_cap_quota += Io_mem_session::CAP_QUOTA;
|
_cap_quota += Io_mem_session::CAP_QUOTA;
|
||||||
Io_mem & iomem = *(new (session.heap())
|
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.io_mem.construct(_env, iomem.range.start,
|
||||||
iomem.range.size, false);
|
iomem.range.size, false);
|
||||||
session.device_pd().attach_dma_mem(iomem.io_mem->dataspace(),
|
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
|
struct Io_mem : Registry<Io_mem>::Element
|
||||||
{
|
{
|
||||||
|
using Pci_bar = Device::Pci_bar;
|
||||||
|
|
||||||
|
Pci_bar bar;
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
Range range;
|
Range range;
|
||||||
bool prefetchable;
|
bool prefetchable;
|
||||||
Constructible<Io_mem_connection> io_mem {};
|
Constructible<Io_mem_connection> io_mem {};
|
||||||
|
|
||||||
Io_mem(Registry<Io_mem> & registry,
|
Io_mem(Registry<Io_mem> & registry,
|
||||||
|
Pci_bar bar,
|
||||||
unsigned idx,
|
unsigned idx,
|
||||||
Range range,
|
Range range,
|
||||||
bool pf)
|
bool pf)
|
||||||
:
|
:
|
||||||
Registry<Io_mem>::Element(registry, *this),
|
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
|
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;
|
Driver::Device::Name device() const;
|
||||||
Session_component & session();
|
Session_component & session();
|
||||||
|
unsigned io_mem_index(Device::Pci_bar bar);
|
||||||
|
|
||||||
|
|
||||||
/************************************
|
/************************************
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <device.h>
|
#include <device.h>
|
||||||
#include <device_pd.h>
|
#include <device_pd.h>
|
||||||
|
#include <device_component.h>
|
||||||
#include <pci.h>
|
#include <pci.h>
|
||||||
#include <pci_uhci.h>
|
#include <pci_uhci.h>
|
||||||
#include <pci_ehci.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,
|
void Driver::pci_msi_enable(Env & env,
|
||||||
|
Device_component & dc,
|
||||||
addr_t cfg_space,
|
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 };
|
Attached_io_mem_dataspace io_mem { env, cfg_space, 0x1000 };
|
||||||
Config config { (addr_t)io_mem.local_addr<void>() };
|
Config config { (addr_t)io_mem.local_addr<void>() };
|
||||||
config.scan();
|
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);
|
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 <irq_session/irq_session.h>
|
||||||
#include <os/session_policy.h>
|
#include <os/session_policy.h>
|
||||||
|
|
||||||
|
#include <device.h>
|
||||||
|
|
||||||
namespace Driver {
|
namespace Driver {
|
||||||
class Device;
|
class Device_component;
|
||||||
class Device_pd;
|
class Device_pd;
|
||||||
|
|
||||||
void pci_enable(Genode::Env & env, Device_pd & pd, Device const & dev);
|
void pci_enable(Genode::Env & env, Device_pd & pd, Device const & dev);
|
||||||
void pci_disable(Genode::Env & env, Device const & dev);
|
void pci_disable(Genode::Env & env, Device const & dev);
|
||||||
void pci_apply_quirks(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,
|
void pci_msi_enable(Genode::Env & env, Device_component & dc,
|
||||||
Genode::Irq_session::Info const info);
|
addr_t cfg_space, Genode::Irq_session::Info const info,
|
||||||
|
Device::Irq::Type type);
|
||||||
bool pci_device_matches(Genode::Session_policy const & policy,
|
bool pci_device_matches(Genode::Session_policy const & policy,
|
||||||
Device const & dev);
|
Device const & dev);
|
||||||
void pci_device_specific_info(Device const & dev,
|
void pci_device_specific_info(Device const & dev,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user