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:
Alexander Boettcher 2015-09-09 11:06:36 +02:00 committed by Christian Helmuth
parent 8f849c9438
commit bdaf79e3b8
7 changed files with 74 additions and 29 deletions

View File

@ -14,6 +14,7 @@
#ifndef _INCLUDE__PLATFORM_DEVICE__DEVICE_H_ #ifndef _INCLUDE__PLATFORM_DEVICE__DEVICE_H_
#define _INCLUDE__PLATFORM_DEVICE__DEVICE_H_ #define _INCLUDE__PLATFORM_DEVICE__DEVICE_H_
#include <base/cache.h>
#include <irq_session/capability.h> #include <irq_session/capability.h>
#include <io_mem_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 * 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_ */ #endif /* _INCLUDE__PLATFORM_DEVICE__DEVICE_H_ */

View File

@ -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 { Genode::Io_port_session_capability io_port(Genode::uint8_t id) override {
return call<Rpc_io_port>(id); } return call<Rpc_io_port>(id); }
Genode::Io_mem_session_capability io_mem(Genode::uint8_t id) override { Genode::Io_mem_session_capability io_mem(Genode::uint8_t id,
return call<Rpc_io_mem>(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_ */ #endif /* _INCLUDE__SPEC__X86__PLATFORM_DEVICE__CLIENT_H_ */

View File

@ -242,7 +242,8 @@ struct Platform::Device : Platform::Abstract_device
Genode::uint8_t); Genode::uint8_t);
GENODE_RPC_THROW(Rpc_io_mem, Genode::Io_mem_session_capability, io_mem, GENODE_RPC_THROW(Rpc_io_mem, Genode::Io_mem_session_capability, io_mem,
GENODE_TYPE_LIST(Quota_exceeded), 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, typedef Genode::Meta::Type_tuple<Rpc_bus_address,
Genode::Meta::Type_tuple<Rpc_vendor_id, Genode::Meta::Type_tuple<Rpc_vendor_id,

View File

@ -66,7 +66,10 @@ class Nonpci::Ps2 : public Platform::Device_component
return Genode::Io_port_session_capability(); 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(); return Genode::Io_mem_session_capability();
} }

View File

@ -28,18 +28,26 @@ Genode::Io_port_session_capability Platform::Device_component::io_port(Genode::u
continue; continue;
} }
if (_io_port_conn[v_id] == nullptr) if (_io_port_conn[v_id] != nullptr)
_io_port_conn[v_id] = new (_slab_ioport) Genode::Io_port_connection(res.base(), res.size());
return _io_port_conn[v_id]->cap(); 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(); 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; Genode::uint8_t i = 0, r_id = 0;
for (Resource res = resource(0); i < max; i++, res = resource(i)) 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; continue;
} }
if (_io_mem_conn[v_id] == nullptr) /* limit IO_MEM session size to resource size */
_io_mem_conn[v_id] = new (_slab_iomem) Genode::Io_mem_connection(res.base(), res.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(); 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) Access_size size)
{ {
/* white list of ports which we permit to write */ /* 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.write(&_config_access, address, value, size,
_device_config.DONT_TRACK_ACCESS); _device_config.DONT_TRACK_ACCESS);
} }

View File

@ -42,9 +42,19 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
unsigned short _irq_line; unsigned short _irq_line;
Irq_session_component _irq_session; 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 { enum {
IO_BLOCK_SIZE = sizeof(Genode::Io_port_connection) * IO_BLOCK_SIZE = sizeof(Genode::Io_port_connection) *
Device::NUM_RESOURCES + 32 + 8 * sizeof(void *), 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_REG = 0x4,
PCI_CMD_DMA = 0x4, PCI_CMD_DMA = 0x4,
PCI_IRQ_LINE = 0x3c, PCI_IRQ_LINE = 0x3c,
@ -58,12 +68,12 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
Genode::Slab_block _slab_ioport_block; Genode::Slab_block _slab_ioport_block;
char _slab_ioport_block_data[IO_BLOCK_SIZE]; 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; 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_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 Status : Genode::Register<8> {
struct Capabilities : Bitfield<4,1> { }; 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, Device_component(Device_config device_config, Genode::addr_t addr,
Genode::Rpc_entrypoint *ep, Genode::Rpc_entrypoint *ep,
Platform::Session_component * session, Platform::Session_component * session,
Genode::Allocator * md_alloc,
bool use_msi) bool use_msi)
: :
_device_config(device_config), _config_space(addr), _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, _irq_line(_device_config.read(&_config_access, PCI_IRQ_LINE,
Platform::Device::ACCESS_8BIT)), Platform::Device::ACCESS_8BIT)),
_irq_session(_configure_irq(_irq_line), (!use_msi || !_msi_cap()) ? ~0UL : _config_space), _irq_session(_configure_irq(_irq_line), (!use_msi || !_msi_cap()) ? ~0UL : _config_space),
_slab_ioport(0, &_slab_ioport_block), _slab_ioport(md_alloc, &_slab_ioport_block),
_slab_iomem(0, &_slab_iomem_block) _slab_iomem(md_alloc, &_slab_iomem_block)
{ {
if (_config_space != ~0UL) { if (_config_space != ~0UL) {
try { try {
@ -201,7 +212,6 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
for (unsigned i = 0; i < Device::NUM_RESOURCES; i++) { for (unsigned i = 0; i < Device::NUM_RESOURCES; i++) {
_io_port_conn[i] = nullptr; _io_port_conn[i] = nullptr;
_io_mem_conn[i] = nullptr;
} }
if (_slab_ioport.num_elem() != Device::NUM_RESOURCES) 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); _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_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++) { for (unsigned i = 0; i < Device::NUM_RESOURCES; i++) {
if (_io_port_conn[i]) if (_io_port_conn[i])
Genode::destroy(_slab_ioport, _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()) 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_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;
}; };

View File

@ -535,7 +535,7 @@ namespace Platform {
try { try {
Device_component * dev = new (_device_slab) Device_component * dev = new (_device_slab)
Device_component(config, config_space, _ep, this, Device_component(config, config_space, _ep, this,
msi_usage()); &_md_alloc, msi_usage());
/* if more than one driver uses the device - warn about */ /* if more than one driver uses the device - warn about */
if (bdf_in_use.get(Device_config::MAX_BUSES * bus + if (bdf_in_use.get(Device_config::MAX_BUSES * bus +