mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-01 08:48:20 +00:00
x86: extend io_mem call of platform_drv
Support allocation of sub I/O memory spaces of one I/O memory bar with write-combined caching attribute.
This commit is contained in:
parent
8f849c9438
commit
bdaf79e3b8
@ -14,6 +14,7 @@
|
||||
#ifndef _INCLUDE__PLATFORM_DEVICE__DEVICE_H_
|
||||
#define _INCLUDE__PLATFORM_DEVICE__DEVICE_H_
|
||||
|
||||
#include <base/cache.h>
|
||||
#include <irq_session/capability.h>
|
||||
#include <io_mem_session/capability.h>
|
||||
|
||||
@ -29,7 +30,9 @@ struct Platform::Abstract_device
|
||||
/**
|
||||
* Get IO mem session capability of specified resource id
|
||||
*/
|
||||
virtual Genode::Io_mem_session_capability io_mem(Genode::uint8_t) = 0;
|
||||
virtual Genode::Io_mem_session_capability io_mem(Genode::uint8_t,
|
||||
Genode::Cache_attribute,
|
||||
Genode::addr_t, Genode::size_t) = 0;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__PLATFORM_DEVICE__DEVICE_H_ */
|
||||
|
@ -54,8 +54,11 @@ struct Platform::Device_client : public Genode::Rpc_client<Device>
|
||||
Genode::Io_port_session_capability io_port(Genode::uint8_t id) override {
|
||||
return call<Rpc_io_port>(id); }
|
||||
|
||||
Genode::Io_mem_session_capability io_mem(Genode::uint8_t id) override {
|
||||
return call<Rpc_io_mem>(id); }
|
||||
Genode::Io_mem_session_capability io_mem(Genode::uint8_t id,
|
||||
Genode::Cache_attribute caching = Genode::Cache_attribute::UNCACHED,
|
||||
Genode::addr_t offset = 0,
|
||||
Genode::size_t size = ~0UL) override {
|
||||
return call<Rpc_io_mem>(id, caching, offset, size); }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__SPEC__X86__PLATFORM_DEVICE__CLIENT_H_ */
|
||||
|
@ -242,7 +242,8 @@ struct Platform::Device : Platform::Abstract_device
|
||||
Genode::uint8_t);
|
||||
GENODE_RPC_THROW(Rpc_io_mem, Genode::Io_mem_session_capability, io_mem,
|
||||
GENODE_TYPE_LIST(Quota_exceeded),
|
||||
Genode::uint8_t);
|
||||
Genode::uint8_t, Genode::Cache_attribute,
|
||||
Genode::addr_t, Genode::size_t);
|
||||
|
||||
typedef Genode::Meta::Type_tuple<Rpc_bus_address,
|
||||
Genode::Meta::Type_tuple<Rpc_vendor_id,
|
||||
|
@ -66,7 +66,10 @@ class Nonpci::Ps2 : public Platform::Device_component
|
||||
return Genode::Io_port_session_capability();
|
||||
}
|
||||
|
||||
Genode::Io_mem_session_capability io_mem(Genode::uint8_t) override
|
||||
Genode::Io_mem_session_capability io_mem(Genode::uint8_t,
|
||||
Genode::Cache_attribute,
|
||||
Genode::addr_t,
|
||||
Genode::size_t) override
|
||||
{
|
||||
return Genode::Io_mem_session_capability();
|
||||
}
|
||||
|
@ -28,18 +28,26 @@ Genode::Io_port_session_capability Platform::Device_component::io_port(Genode::u
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_io_port_conn[v_id] == nullptr)
|
||||
_io_port_conn[v_id] = new (_slab_ioport) Genode::Io_port_connection(res.base(), res.size());
|
||||
|
||||
if (_io_port_conn[v_id] != nullptr)
|
||||
return _io_port_conn[v_id]->cap();
|
||||
|
||||
try {
|
||||
_io_port_conn[v_id] = new (_slab_ioport) Genode::Io_port_connection(res.base(), res.size());
|
||||
return _io_port_conn[v_id]->cap();
|
||||
} catch (...) {
|
||||
return Genode::Io_port_session_capability();
|
||||
}
|
||||
}
|
||||
|
||||
return Genode::Io_port_session_capability();
|
||||
}
|
||||
|
||||
Genode::Io_mem_session_capability Platform::Device_component::io_mem(Genode::uint8_t v_id)
|
||||
Genode::Io_mem_session_capability Platform::Device_component::io_mem(Genode::uint8_t const v_id,
|
||||
Genode::Cache_attribute const caching,
|
||||
Genode::addr_t const offset,
|
||||
Genode::size_t const size)
|
||||
{
|
||||
Genode::uint8_t max = sizeof(_io_mem_conn) / sizeof(_io_mem_conn[0]);
|
||||
Genode::uint8_t max = sizeof(_io_mem) / sizeof(_io_mem[0]);
|
||||
Genode::uint8_t i = 0, r_id = 0;
|
||||
|
||||
for (Resource res = resource(0); i < max; i++, res = resource(i))
|
||||
@ -52,16 +60,30 @@ Genode::Io_mem_session_capability Platform::Device_component::io_mem(Genode::uin
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_io_mem_conn[v_id] == nullptr)
|
||||
_io_mem_conn[v_id] = new (_slab_iomem) Genode::Io_mem_connection(res.base(), res.size());
|
||||
/* limit IO_MEM session size to resource size */
|
||||
Genode::size_t const res_size = Genode::min(size, res.size());
|
||||
|
||||
return _io_mem_conn[v_id]->cap();
|
||||
if (offset >= res.size() || offset > res.size() - res_size)
|
||||
return Genode::Io_mem_session_capability();
|
||||
|
||||
try {
|
||||
bool const wc = caching == Genode::Cache_attribute::WRITE_COMBINED;
|
||||
Io_mem * io_mem = new (_slab_iomem) Io_mem(res.base() + offset,
|
||||
res_size, wc);
|
||||
_io_mem[i].insert(io_mem);
|
||||
return io_mem->cap();
|
||||
} catch (Genode::Allocator::Out_of_memory) {
|
||||
throw Platform::Device::Quota_exceeded();
|
||||
} catch (...) {
|
||||
return Genode::Io_mem_session_capability();
|
||||
}
|
||||
}
|
||||
|
||||
return Genode::Io_mem_session_capability();
|
||||
}
|
||||
|
||||
void Platform::Device_component::config_write(unsigned char address, unsigned value,
|
||||
void Platform::Device_component::config_write(unsigned char address,
|
||||
unsigned value,
|
||||
Access_size size)
|
||||
{
|
||||
/* white list of ports which we permit to write */
|
||||
@ -99,4 +121,3 @@ void Platform::Device_component::config_write(unsigned char address, unsigned va
|
||||
_device_config.write(&_config_access, address, value, size,
|
||||
_device_config.DONT_TRACK_ACCESS);
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,19 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
|
||||
unsigned short _irq_line;
|
||||
Irq_session_component _irq_session;
|
||||
|
||||
class Io_mem : public Genode::Io_mem_connection,
|
||||
public Genode::List<Io_mem>::Element
|
||||
{
|
||||
public:
|
||||
Io_mem (Genode::addr_t base, Genode::size_t size, bool wc)
|
||||
: Genode::Io_mem_connection(base, size, wc) { }
|
||||
};
|
||||
|
||||
enum {
|
||||
IO_BLOCK_SIZE = sizeof(Genode::Io_port_connection) *
|
||||
Device::NUM_RESOURCES + 32 + 8 * sizeof(void *),
|
||||
IO_MEM_SIZE = sizeof(Io_mem) *
|
||||
Device::NUM_RESOURCES + 32 + 8 * sizeof(void *),
|
||||
PCI_CMD_REG = 0x4,
|
||||
PCI_CMD_DMA = 0x4,
|
||||
PCI_IRQ_LINE = 0x3c,
|
||||
@ -58,12 +68,12 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
|
||||
Genode::Slab_block _slab_ioport_block;
|
||||
char _slab_ioport_block_data[IO_BLOCK_SIZE];
|
||||
|
||||
Genode::Tslab<Genode::Io_mem_connection, IO_BLOCK_SIZE> _slab_iomem;
|
||||
Genode::Tslab<Io_mem, IO_MEM_SIZE> _slab_iomem;
|
||||
Genode::Slab_block _slab_iomem_block;
|
||||
char _slab_iomem_block_data[IO_BLOCK_SIZE];
|
||||
char _slab_iomem_block_data[IO_MEM_SIZE];
|
||||
|
||||
Genode::Io_port_connection *_io_port_conn [Device::NUM_RESOURCES];
|
||||
Genode::Io_mem_connection *_io_mem_conn [Device::NUM_RESOURCES];
|
||||
Genode::List<Io_mem> _io_mem [Device::NUM_RESOURCES];
|
||||
|
||||
struct Status : Genode::Register<8> {
|
||||
struct Capabilities : Bitfield<4,1> { };
|
||||
@ -179,6 +189,7 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
|
||||
Device_component(Device_config device_config, Genode::addr_t addr,
|
||||
Genode::Rpc_entrypoint *ep,
|
||||
Platform::Session_component * session,
|
||||
Genode::Allocator * md_alloc,
|
||||
bool use_msi)
|
||||
:
|
||||
_device_config(device_config), _config_space(addr),
|
||||
@ -186,8 +197,8 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
|
||||
_irq_line(_device_config.read(&_config_access, PCI_IRQ_LINE,
|
||||
Platform::Device::ACCESS_8BIT)),
|
||||
_irq_session(_configure_irq(_irq_line), (!use_msi || !_msi_cap()) ? ~0UL : _config_space),
|
||||
_slab_ioport(0, &_slab_ioport_block),
|
||||
_slab_iomem(0, &_slab_iomem_block)
|
||||
_slab_ioport(md_alloc, &_slab_ioport_block),
|
||||
_slab_iomem(md_alloc, &_slab_iomem_block)
|
||||
{
|
||||
if (_config_space != ~0UL) {
|
||||
try {
|
||||
@ -201,7 +212,6 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
|
||||
|
||||
for (unsigned i = 0; i < Device::NUM_RESOURCES; i++) {
|
||||
_io_port_conn[i] = nullptr;
|
||||
_io_mem_conn[i] = nullptr;
|
||||
}
|
||||
|
||||
if (_slab_ioport.num_elem() != Device::NUM_RESOURCES)
|
||||
@ -262,10 +272,8 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
|
||||
{
|
||||
_ep->manage(&_irq_session);
|
||||
|
||||
for (unsigned i = 0; i < Device::NUM_RESOURCES; i++) {
|
||||
for (unsigned i = 0; i < Device::NUM_RESOURCES; i++)
|
||||
_io_port_conn[i] = nullptr;
|
||||
_io_mem_conn[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -278,8 +286,11 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
|
||||
for (unsigned i = 0; i < Device::NUM_RESOURCES; i++) {
|
||||
if (_io_port_conn[i])
|
||||
Genode::destroy(_slab_ioport, _io_port_conn[i]);
|
||||
if (_io_mem_conn[i])
|
||||
Genode::destroy(_slab_iomem, _io_mem_conn[i]);
|
||||
|
||||
while (Io_mem * io_mem = _io_mem[i].first()) {
|
||||
_io_mem[i].remove(io_mem);
|
||||
Genode::destroy(_slab_iomem, io_mem);
|
||||
}
|
||||
}
|
||||
|
||||
if (_io_mem_config_extended.valid())
|
||||
@ -377,5 +388,8 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
|
||||
|
||||
Genode::Io_port_session_capability io_port(Genode::uint8_t) override;
|
||||
|
||||
Genode::Io_mem_session_capability io_mem(Genode::uint8_t) override;
|
||||
Genode::Io_mem_session_capability io_mem(Genode::uint8_t,
|
||||
Genode::Cache_attribute,
|
||||
Genode::addr_t,
|
||||
Genode::size_t) override;
|
||||
};
|
||||
|
@ -535,7 +535,7 @@ namespace Platform {
|
||||
try {
|
||||
Device_component * dev = new (_device_slab)
|
||||
Device_component(config, config_space, _ep, this,
|
||||
msi_usage());
|
||||
&_md_alloc, msi_usage());
|
||||
|
||||
/* if more than one driver uses the device - warn about */
|
||||
if (bdf_in_use.get(Device_config::MAX_BUSES * bus +
|
||||
|
Loading…
x
Reference in New Issue
Block a user