mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-22 16:59:03 +00:00
lx_kit & lx_emul: use generic platform API
* Remove wrapper for legacy x86 platform API * Move PCI configuration space quirks to corresponding driver (pc_usb_host_drv, pc_wifi_drv, pc_intel_fb_drv) * Adapt driver test run-scripts to changed configuration Ref genodelabs/genode#4578
This commit is contained in:
committed by
Christian Helmuth
parent
9f9a5186e0
commit
5528434fb6
@ -14,7 +14,6 @@ SRC_C += usb/host/uhci-hcd.c
|
||||
SRC_C += usb/host/xhci-pci.c
|
||||
|
||||
SRC_CC += lx_kit/mapped_io_mem_range.cc
|
||||
SRC_CC += lx_kit/pci.cc
|
||||
|
||||
SRC_CC += spec/x86/platform.cc
|
||||
|
||||
|
56
repos/dde_linux/src/include/lx_emul/pci.h
Normal file
56
repos/dde_linux/src/include/lx_emul/pci.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* \brief Lx_emul support for accessing PCI devices
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2022-05-23
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#ifndef _LX_EMUL__PCI_H_
|
||||
#define _LX_EMUL__PCI_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*lx_emul_add_resource_callback_t)
|
||||
(void * dev,
|
||||
unsigned number,
|
||||
unsigned long addr,
|
||||
unsigned long size,
|
||||
int io_port);
|
||||
|
||||
|
||||
typedef void (*lx_emul_add_device_callback_t)
|
||||
(void * bus,
|
||||
unsigned number,
|
||||
char const * const name,
|
||||
unsigned short vendor_id,
|
||||
unsigned short device_id,
|
||||
unsigned short sub_vendor,
|
||||
unsigned short sub_device,
|
||||
unsigned int class_code,
|
||||
unsigned char revision,
|
||||
unsigned irq);
|
||||
|
||||
|
||||
void lx_emul_pci_for_each_resource(const char * const name, void * dev,
|
||||
lx_emul_add_resource_callback_t fn);
|
||||
|
||||
void lx_emul_pci_for_each_device(void * bus, lx_emul_add_device_callback_t fn);
|
||||
|
||||
void lx_emul_pci_enable(const char * const name);
|
||||
|
||||
void * lx_emul_pci_root_bus(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LX_EMUL__PCI_H_ */
|
||||
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* \brief Lx_emul support for accessing PCI(e) config space
|
||||
* \author Josef Soentgen
|
||||
* \date 2022-01-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#ifndef _LX_EMUL__PCI_CONFIG_SPACE_H_
|
||||
#define _LX_EMUL__PCI_CONFIG_SPACE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int lx_emul_pci_read_config(unsigned bus, unsigned devfn, unsigned reg, unsigned len, unsigned *val);
|
||||
int lx_emul_pci_write_config(unsigned bus, unsigned devfn, unsigned reg, unsigned len, unsigned val);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LX_EMUL__PCI_CONFIG_SPACE_H_ */
|
@ -19,6 +19,7 @@
|
||||
#include <irq_session/client.h>
|
||||
#include <io_mem_session/client.h>
|
||||
#include <platform_session/device.h>
|
||||
#include <pci/types.h>
|
||||
#include <util/list.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
@ -35,10 +36,7 @@ struct clk {
|
||||
|
||||
class Lx_kit::Device : List<Device>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
friend class Device_list;
|
||||
friend class List<Device>;
|
||||
public:
|
||||
|
||||
using Name = String<64>;
|
||||
using Type = Platform::Device::Type;
|
||||
@ -47,16 +45,17 @@ class Lx_kit::Device : List<Device>::Element
|
||||
{
|
||||
using Index = Platform::Device::Mmio::Index;
|
||||
|
||||
Index idx;
|
||||
addr_t addr;
|
||||
size_t size;
|
||||
Index idx;
|
||||
addr_t addr;
|
||||
size_t size;
|
||||
unsigned pci_bar;
|
||||
|
||||
Constructible<Platform::Device::Mmio> io_mem {};
|
||||
|
||||
bool match(addr_t addr, size_t size);
|
||||
|
||||
Io_mem(unsigned idx, addr_t addr, size_t size)
|
||||
: idx{idx}, addr(addr), size(size) {}
|
||||
Io_mem(unsigned idx, addr_t addr, size_t size, unsigned pci_bar)
|
||||
: idx{idx}, addr(addr), size(size), pci_bar(pci_bar) {}
|
||||
};
|
||||
|
||||
struct Irq : List<Irq>::Element
|
||||
@ -81,13 +80,15 @@ class Lx_kit::Device : List<Device>::Element
|
||||
Index idx;
|
||||
uint16_t addr;
|
||||
uint16_t size;
|
||||
unsigned pci_bar;
|
||||
|
||||
Constructible<Platform::Device::Io_port_range> io_port {};
|
||||
|
||||
bool match(uint16_t addr);
|
||||
|
||||
Io_port(unsigned idx, uint16_t addr, uint16_t size)
|
||||
: idx{idx}, addr(addr), size(size) {}
|
||||
Io_port(unsigned idx, uint16_t addr, uint16_t size,
|
||||
unsigned pci_bar)
|
||||
: idx{idx}, addr(addr), size(size), pci_bar(pci_bar) {}
|
||||
};
|
||||
|
||||
struct Clock : List<Clock>::Element
|
||||
@ -100,6 +101,21 @@ class Lx_kit::Device : List<Device>::Element
|
||||
: idx(idx), name(name), lx_clock{0} {}
|
||||
};
|
||||
|
||||
struct Pci_config
|
||||
{
|
||||
Pci::vendor_t vendor_id;
|
||||
Pci::device_t device_id;
|
||||
Pci::class_t class_code;
|
||||
Pci::rev_t rev;
|
||||
Pci::vendor_t sub_v_id;
|
||||
Pci::device_t sub_d_id;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
friend class Device_list;
|
||||
friend class List<Device>;
|
||||
|
||||
Device(Entrypoint & ep,
|
||||
Platform::Connection & plat,
|
||||
Xml_node & xml,
|
||||
@ -108,23 +124,12 @@ class Lx_kit::Device : List<Device>::Element
|
||||
Platform::Connection & _platform;
|
||||
Name const _name;
|
||||
Type const _type;
|
||||
List<Io_mem> _io_mems {};
|
||||
List<Io_port> _io_ports {};
|
||||
List<Irq> _irqs {};
|
||||
List<Clock> _clocks {};
|
||||
Constructible<Platform::Device> _pdev {};
|
||||
|
||||
template <typename FN>
|
||||
void _for_each_io_mem(FN const & fn) {
|
||||
for (Io_mem * i = _io_mems.first(); i; i = i->next()) fn(*i); }
|
||||
|
||||
template <typename FN>
|
||||
void _for_each_io_port(FN const & fn) {
|
||||
for (Io_port * i = _io_ports.first(); i; i = i->next()) fn(*i); }
|
||||
|
||||
template <typename FN>
|
||||
void _for_each_irq(FN const & fn) {
|
||||
for (Irq * i = _irqs.first(); i; i = i->next()) fn(*i); }
|
||||
List<Io_mem> _io_mems {};
|
||||
List<Io_port> _io_ports {};
|
||||
List<Irq> _irqs {};
|
||||
List<Clock> _clocks {};
|
||||
Constructible<Pci_config> _pci_config {};
|
||||
Constructible<Platform::Device> _pdev {};
|
||||
|
||||
template <typename FN>
|
||||
void _for_each_clock(FN const & fn) {
|
||||
@ -133,7 +138,23 @@ class Lx_kit::Device : List<Device>::Element
|
||||
public:
|
||||
|
||||
const char * compatible();
|
||||
const char * name();
|
||||
Name name();
|
||||
|
||||
template <typename FN>
|
||||
void for_each_io_mem(FN const & fn) {
|
||||
for (Io_mem * i = _io_mems.first(); i; i = i->next()) fn(*i); }
|
||||
|
||||
template <typename FN>
|
||||
void for_each_io_port(FN const & fn) {
|
||||
for (Io_port * i = _io_ports.first(); i; i = i->next()) fn(*i); }
|
||||
|
||||
template <typename FN>
|
||||
void for_each_irq(FN const & fn) {
|
||||
for (Irq * i = _irqs.first(); i; i = i->next()) fn(*i); }
|
||||
|
||||
template <typename FN>
|
||||
void for_pci_config(FN const & fn) {
|
||||
if (_pci_config.constructed()) fn(*_pci_config); }
|
||||
|
||||
void enable();
|
||||
clk * clock(const char * name);
|
||||
@ -163,12 +184,21 @@ class Lx_kit::Device_list : List<Device>
|
||||
|
||||
Platform::Connection & _platform;
|
||||
|
||||
void _handle_signal() {}
|
||||
|
||||
public:
|
||||
|
||||
template <typename FN>
|
||||
void for_each(FN const & fn) {
|
||||
for (Device * d = first(); d; d = d->next()) fn(*d); }
|
||||
|
||||
template <typename FN>
|
||||
void with_xml(FN const & fn)
|
||||
{
|
||||
_platform.update();
|
||||
_platform.with_xml([&] (Xml_node & xml) { fn(xml); });
|
||||
}
|
||||
|
||||
Device_list(Entrypoint & ep,
|
||||
Heap & heap,
|
||||
Platform::Connection & platform);
|
||||
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* \brief Dummy - platform session device interface
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2022-01-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 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.
|
||||
*/
|
||||
|
||||
#ifndef _PLATFORM_SESSION__CONNECTION_H_
|
||||
#define _PLATFORM_SESSION__CONNECTION_H_
|
||||
|
||||
#include <util/mmio.h>
|
||||
#include <util/string.h>
|
||||
#include <base/exception.h>
|
||||
#include <io_mem_session/client.h>
|
||||
#include <irq_session/client.h>
|
||||
|
||||
namespace Platform {
|
||||
struct Connection;
|
||||
class Dma_buffer;
|
||||
|
||||
using namespace Genode;
|
||||
}
|
||||
|
||||
#define Platform Legacy_platform
|
||||
#include <legacy/x86/platform_session/connection.h>
|
||||
#undef Platform
|
||||
|
||||
|
||||
struct Platform::Connection
|
||||
{
|
||||
Env &_env;
|
||||
Region_map &_rm { _env.rm() };
|
||||
char _devices_node_buffer[4096u] { };
|
||||
Constructible<Xml_node> _devices_node { };
|
||||
|
||||
Constructible<Legacy_platform::Connection> _legacy_platform { };
|
||||
struct Device
|
||||
{
|
||||
using Name = String<16>;
|
||||
|
||||
Name name { };
|
||||
Legacy_platform::Device_capability cap { };
|
||||
|
||||
Device(Name const &name, Legacy_platform::Device_capability cap)
|
||||
: name { name }, cap { cap } { }
|
||||
};
|
||||
|
||||
enum : unsigned char { MAX_DEVICES = 4 };
|
||||
Constructible<Device> _devices_list[MAX_DEVICES] { };
|
||||
|
||||
Legacy_platform::Device_capability device_cap(char const *name);
|
||||
|
||||
Connection(Env &);
|
||||
|
||||
/********************************
|
||||
** Platform session interface **
|
||||
********************************/
|
||||
|
||||
void update();
|
||||
|
||||
template <typename FN> void with_xml(FN const & fn)
|
||||
{
|
||||
if (_devices_node.constructed())
|
||||
fn(*_devices_node);
|
||||
}
|
||||
|
||||
Ram_dataspace_capability alloc_dma_buffer(size_t size, Cache cache);
|
||||
|
||||
void free_dma_buffer(Ram_dataspace_capability);
|
||||
|
||||
addr_t dma_addr(Ram_dataspace_capability);
|
||||
|
||||
template <typename FUNC>
|
||||
auto retry_with_upgrade(Ram_quota ram, Cap_quota caps, FUNC func) -> decltype(func())
|
||||
{
|
||||
return _legacy_platform->retry_with_upgrade<FUNC>(ram, caps, func);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* _PLATFORM_SESSION__CONNECTION_H_ */
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* \brief Dummy - platform session device interface
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2022-01-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 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.
|
||||
*/
|
||||
|
||||
#ifndef _PLATFORM_SESSION__DEVICE_H_
|
||||
#define _PLATFORM_SESSION__DEVICE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/attached_dataspace.h>
|
||||
#include <base/exception.h>
|
||||
#include <io_mem_session/client.h>
|
||||
#include <io_port_session/client.h>
|
||||
#include <irq_session/client.h>
|
||||
#include <platform_session/connection.h>
|
||||
#include <util/mmio.h>
|
||||
#include <util/string.h>
|
||||
|
||||
|
||||
namespace Platform {
|
||||
struct Connection;
|
||||
class Device;
|
||||
|
||||
using namespace Genode;
|
||||
}
|
||||
|
||||
|
||||
class Platform::Device : Interface, Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
struct Range { addr_t start; size_t size; };
|
||||
|
||||
struct Mmio;
|
||||
struct Io_port_range;
|
||||
struct Irq;
|
||||
struct Config_space;
|
||||
|
||||
using Name = String<64>;
|
||||
|
||||
private:
|
||||
|
||||
Connection &_platform;
|
||||
Legacy_platform::Device_capability _device_cap { };
|
||||
Name _name { };
|
||||
unsigned _class_code { };
|
||||
|
||||
public:
|
||||
|
||||
int _bar_checked_for_size[6] { };
|
||||
|
||||
struct Index { unsigned value; };
|
||||
|
||||
explicit Device(Connection &platform)
|
||||
: _platform { platform } { }
|
||||
|
||||
struct Type { String<64> name; };
|
||||
|
||||
Device(Connection &platform, Type type);
|
||||
|
||||
Device(Connection &platform, Name name);
|
||||
|
||||
~Device() { }
|
||||
|
||||
Name const &name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Platform::Device::Mmio : Range
|
||||
{
|
||||
public:
|
||||
|
||||
struct Index { unsigned value; };
|
||||
|
||||
private:
|
||||
|
||||
Constructible<Attached_dataspace> _attached_ds { };
|
||||
|
||||
void *_local_addr();
|
||||
|
||||
Device &_device;
|
||||
Index _index;
|
||||
|
||||
public:
|
||||
|
||||
Mmio(Device &device, Index index)
|
||||
: _device { device }, _index { index } { }
|
||||
|
||||
explicit Mmio(Device &device)
|
||||
: _device { device }, _index { ~0u } { }
|
||||
|
||||
size_t size() const;
|
||||
|
||||
template <typename T>
|
||||
T *local_addr() { return reinterpret_cast<T *>(_local_addr()); }
|
||||
};
|
||||
|
||||
|
||||
class Platform::Device::Io_port_range : Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
struct Index { unsigned value; };
|
||||
|
||||
private:
|
||||
|
||||
Device &_device;
|
||||
Index _index;
|
||||
|
||||
Constructible<Io_port_session_client> _io_port { };
|
||||
|
||||
public:
|
||||
|
||||
Io_port_range(Device &device, Index index);
|
||||
|
||||
explicit Io_port_range(Device &device)
|
||||
: _device { device }, _index { ~0u } { }
|
||||
|
||||
uint8_t inb(uint16_t addr);
|
||||
uint16_t inw(uint16_t addr);
|
||||
uint32_t inl(uint16_t addr);
|
||||
|
||||
void outb(uint16_t addr, uint8_t val);
|
||||
void outw(uint16_t addr, uint16_t val);
|
||||
void outl(uint16_t addr, uint32_t val);
|
||||
};
|
||||
|
||||
|
||||
class Platform::Device::Irq : Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
struct Index { unsigned value; };
|
||||
|
||||
private:
|
||||
|
||||
Device &_device;
|
||||
Index _index;
|
||||
|
||||
Constructible<Irq_session_client> _irq { };
|
||||
|
||||
public:
|
||||
|
||||
Irq(Device &device, Index index);
|
||||
|
||||
explicit Irq(Device &device)
|
||||
: _device { device }, _index { ~0u } { }
|
||||
|
||||
void ack();
|
||||
void sigh(Signal_context_capability);
|
||||
void sigh_omit_initial_signal(Signal_context_capability);
|
||||
};
|
||||
|
||||
|
||||
class Platform::Device::Config_space : Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
Device &_device;
|
||||
|
||||
enum class Access_size : unsigned { ACCESS_8BIT, ACCESS_16BIT, ACCESS_32BIT };
|
||||
|
||||
Config_space(Device &device) : _device { device } { }
|
||||
|
||||
unsigned read(unsigned char address, Access_size size);
|
||||
void write(unsigned char address, unsigned value, Access_size size);
|
||||
};
|
||||
|
||||
|
||||
#endif /* _PLATFORM_SESSION__DEVICE_H_ */
|
104
repos/dde_linux/src/lib/lx_emul/pci.cc
Normal file
104
repos/dde_linux/src/lib/lx_emul/pci.cc
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* \brief Lx_emul backend for PCI devices
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2022-05-23
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <base/log.h>
|
||||
#include <pci/types.h>
|
||||
#include <lx_emul/init.h>
|
||||
#include <lx_emul/pci.h>
|
||||
#include <lx_kit/env.h>
|
||||
|
||||
extern "C" void lx_emul_pci_enable(const char * const name)
|
||||
{
|
||||
using namespace Lx_kit;
|
||||
|
||||
env().devices.for_each([&] (Device & d) {
|
||||
if (d.name() == name) d.enable(); });
|
||||
};
|
||||
|
||||
|
||||
extern "C" void
|
||||
lx_emul_pci_for_each_resource(const char * const name, void * dev,
|
||||
lx_emul_add_resource_callback_t fn)
|
||||
{
|
||||
using namespace Lx_kit;
|
||||
using namespace Genode;
|
||||
using namespace Pci;
|
||||
|
||||
env().devices.for_each([&] (Device & d) {
|
||||
if (d.name() != name)
|
||||
return;
|
||||
|
||||
d.for_each_io_mem([&] (Device::Io_mem & io_mem) {
|
||||
fn(dev, io_mem.pci_bar, io_mem.addr, io_mem.size, 0);
|
||||
});
|
||||
|
||||
d.for_each_io_port([&] (Device::Io_port & io_port) {
|
||||
fn(dev, io_port.pci_bar, io_port.addr, io_port.size, 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
extern "C" void
|
||||
lx_emul_pci_for_each_device(void * bus, lx_emul_add_device_callback_t fn)
|
||||
{
|
||||
using namespace Lx_kit;
|
||||
using namespace Genode;
|
||||
using namespace Pci;
|
||||
|
||||
unsigned num = 0;
|
||||
env().devices.for_each([&] (Device & d) {
|
||||
unsigned irq = 0;
|
||||
d.for_each_irq([&] (Device::Irq & i) {
|
||||
if (!irq) irq = i.number; });
|
||||
|
||||
d.for_pci_config([&] (Device::Pci_config & cfg) {
|
||||
fn(bus, num++, d.name().string(), cfg.vendor_id, cfg.device_id,
|
||||
cfg.sub_v_id, cfg.sub_d_id, cfg.class_code, cfg.rev, irq);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static const char * lx_emul_pci_final_fixups[] = {
|
||||
"__pci_fixup_final_quirk_usb_early_handoff",
|
||||
"END_OF_PCI_FIXUPS"
|
||||
};
|
||||
|
||||
|
||||
extern "C" __attribute__((weak)) int inhibit_pci_fixup(char const *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void lx_emul_register_pci_fixup(void (*fn)(struct pci_dev*), const char * name)
|
||||
{
|
||||
if (inhibit_pci_fixup(name))
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < (sizeof(lx_emul_pci_final_fixups) / sizeof(char*));
|
||||
i++) {
|
||||
if (Genode::strcmp(name, lx_emul_pci_final_fixups[i]) == 0) {
|
||||
Lx_kit::env().pci_fixup_calls.add(fn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Genode::error(__func__, " ignore unkown PCI fixup '", name, "'");
|
||||
}
|
||||
|
||||
|
||||
extern "C" void lx_emul_execute_pci_fixup(struct pci_dev *pci_dev)
|
||||
{
|
||||
Lx_kit::env().pci_fixup_calls.execute(pci_dev);
|
||||
}
|
199
repos/dde_linux/src/lib/lx_emul/pci_bus.c
Normal file
199
repos/dde_linux/src/lib/lx_emul/pci_bus.c
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* \brief PCI backend
|
||||
* \author Josef Soentgen
|
||||
* \date 2022-05-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <lx_emul.h>
|
||||
#include <lx_emul/io_mem.h>
|
||||
#include <lx_emul/pci.h>
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
|
||||
extern void lx_backtrace(void);
|
||||
|
||||
|
||||
int arch_probe_nr_irqs(void)
|
||||
{
|
||||
/* needed for 'irq_get_irq_data()' in 'pci_assign_irq()' below */
|
||||
return 256;
|
||||
}
|
||||
|
||||
|
||||
static const struct attribute_group *pci_dev_attr_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
const struct device_type pci_dev_type = {
|
||||
.groups = pci_dev_attr_groups,
|
||||
};
|
||||
|
||||
|
||||
extern const struct device_type pci_dev_type;
|
||||
|
||||
|
||||
static struct pci_bus *_pci_bus;
|
||||
|
||||
|
||||
void * lx_emul_pci_root_bus()
|
||||
{
|
||||
return _pci_bus;
|
||||
}
|
||||
|
||||
|
||||
static struct device * host_bridge_device = NULL;
|
||||
extern struct device * pci_get_host_bridge_device(struct pci_dev * dev);
|
||||
struct device * pci_get_host_bridge_device(struct pci_dev * dev)
|
||||
{
|
||||
return host_bridge_device;
|
||||
}
|
||||
|
||||
|
||||
static struct pci_dev *_pci_alloc_dev(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
|
||||
dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&dev->bus_list);
|
||||
dev->dev.type = &pci_dev_type;
|
||||
dev->bus = bus;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
static void pci_add_resource_to_device_callback(void * data,
|
||||
unsigned number,
|
||||
unsigned long addr,
|
||||
unsigned long size,
|
||||
int io_port)
|
||||
{
|
||||
struct pci_dev * dev = (struct pci_dev*) data;
|
||||
dev->resource[number].start = addr;
|
||||
dev->resource[number].end = dev->resource[number].start + size - 1;
|
||||
if (io_port)
|
||||
dev->resource[number].flags |= IORESOURCE_IO;
|
||||
}
|
||||
|
||||
|
||||
static void pci_add_single_device_callback(void * data,
|
||||
unsigned number,
|
||||
char const * const name,
|
||||
u16 vendor_id,
|
||||
u16 device_id,
|
||||
u16 sub_vendor,
|
||||
u16 sub_device,
|
||||
u32 class_code,
|
||||
u8 revision,
|
||||
unsigned irq)
|
||||
{
|
||||
struct pci_bus * bus = (struct pci_bus*) data;
|
||||
struct pci_dev * dev = _pci_alloc_dev(bus);
|
||||
|
||||
if (!dev) {
|
||||
printk("Error: out of memory, cannot allocate pci device %s\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->devfn = number * 8;
|
||||
dev->vendor = vendor_id;
|
||||
dev->device = device_id;
|
||||
dev->subsystem_vendor = sub_vendor;
|
||||
dev->subsystem_device = sub_device;
|
||||
dev->irq = irq;
|
||||
dev->dma_mask = 0xffffffff;
|
||||
dev->dev.bus = &pci_bus_type;
|
||||
dev->revision = revision;
|
||||
dev->class = class_code;
|
||||
dev->current_state = PCI_UNKNOWN;
|
||||
|
||||
lx_emul_pci_for_each_resource(name, dev,
|
||||
pci_add_resource_to_device_callback);
|
||||
|
||||
list_add_tail(&dev->bus_list, &bus->devices);
|
||||
|
||||
device_initialize(&dev->dev);
|
||||
|
||||
dev_set_name(&dev->dev, name);
|
||||
dev->dev.dma_mask = &dev->dma_mask;
|
||||
|
||||
if (number == 0) { /* host bridge */
|
||||
host_bridge_device = &dev->dev;
|
||||
bus->bridge = &dev->dev;
|
||||
}
|
||||
|
||||
dev->match_driver = false;
|
||||
if (device_add(&dev->dev)) {
|
||||
list_del(&dev->bus_list);
|
||||
kfree(dev);
|
||||
printk("Error: could not add pci device %s\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
lx_emul_execute_pci_fixup(dev);
|
||||
|
||||
dev->match_driver = true;
|
||||
if (device_attach(&dev->dev)) {
|
||||
list_del(&dev->bus_list);
|
||||
kfree(dev);
|
||||
printk("Error: could not attach pci device %s\n", name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int __init pci_subsys_init(void)
|
||||
{
|
||||
struct pci_bus *b;
|
||||
struct pci_sysdata *sd;
|
||||
|
||||
/* pci_alloc_bus(NULL) */
|
||||
b = kzalloc(sizeof (struct pci_bus), GFP_KERNEL);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
sd = kzalloc(sizeof (struct pci_sysdata), GFP_KERNEL);
|
||||
if (!sd) {
|
||||
kfree(b);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* needed by intel_fb */
|
||||
sd->domain = 0;
|
||||
|
||||
b->sysdata = sd;
|
||||
|
||||
INIT_LIST_HEAD(&b->node);
|
||||
INIT_LIST_HEAD(&b->children);
|
||||
INIT_LIST_HEAD(&b->devices);
|
||||
INIT_LIST_HEAD(&b->slots);
|
||||
INIT_LIST_HEAD(&b->resources);
|
||||
b->max_bus_speed = PCI_SPEED_UNKNOWN;
|
||||
b->cur_bus_speed = PCI_SPEED_UNKNOWN;
|
||||
|
||||
_pci_bus = b;
|
||||
|
||||
/* add host bridge device */
|
||||
pci_add_single_device_callback(b, 0, "00:00.0", 0x8086, 0x44, 0x17aa, 0x2193, 0x60000, 2, 0);
|
||||
|
||||
/* attach PCI devices */
|
||||
lx_emul_pci_for_each_device(b, pci_add_single_device_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
subsys_initcall(pci_subsys_init);
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* \brief Lx_emul backend for accessing PCI(e) config space
|
||||
* \author Josef Soentgen
|
||||
* \date 2022-01-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <lx_kit/env.h>
|
||||
#include <lx_emul/pci_config_space.h>
|
||||
|
||||
|
||||
using Device_name = Genode::String<16>;
|
||||
|
||||
template <typename T, typename... TAIL>
|
||||
static Device_name to_string(T const &arg, TAIL &&... args)
|
||||
{
|
||||
return Device_name(arg, args...);
|
||||
}
|
||||
|
||||
|
||||
static Device_name assemble(unsigned bus, unsigned devfn)
|
||||
{
|
||||
using namespace Genode;
|
||||
return to_string("pci-",
|
||||
Hex(bus, Hex::OMIT_PREFIX), ":",
|
||||
Hex((devfn >> 3) & 0x1fu, Hex::OMIT_PREFIX), ".",
|
||||
Hex(devfn & 0x7u, Hex::OMIT_PREFIX));
|
||||
}
|
||||
|
||||
|
||||
int lx_emul_pci_read_config(unsigned bus, unsigned devfn,
|
||||
unsigned reg, unsigned len, unsigned *val)
|
||||
{
|
||||
using namespace Lx_kit;
|
||||
using namespace Genode;
|
||||
|
||||
Device_name name = assemble(bus, devfn);
|
||||
|
||||
bool result = false;
|
||||
bool matched = false;
|
||||
|
||||
env().devices.for_each([&] (Device & d) {
|
||||
matched = name == d.name();
|
||||
if (matched && val)
|
||||
result = d.read_config(reg, len, val);
|
||||
});
|
||||
|
||||
if (!result && matched)
|
||||
error("could not read config space register ", Hex(reg));
|
||||
|
||||
return result ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
int lx_emul_pci_write_config(unsigned bus, unsigned devfn,
|
||||
unsigned reg, unsigned len, unsigned val)
|
||||
{
|
||||
using namespace Lx_kit;
|
||||
using namespace Genode;
|
||||
|
||||
Device_name name = assemble(bus, devfn);
|
||||
|
||||
bool result = false;
|
||||
bool matched = false;
|
||||
env().devices.for_each ([&] (Device & d) {
|
||||
matched = name == d.name();
|
||||
if (matched)
|
||||
result = d.write_config(reg, len, val);
|
||||
});
|
||||
|
||||
if (!result && matched)
|
||||
error("could not write config space register ", Hex(reg),
|
||||
" with ", Hex(val));
|
||||
|
||||
return result ? 0 : -1;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* \brief Lx_emul backend for PCI fixup calls
|
||||
* \author Josef Soentgen
|
||||
* \date 2022-02-04
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <base/log.h>
|
||||
#include <lx_kit/env.h>
|
||||
#include <lx_emul/init.h>
|
||||
|
||||
#include <lx_emul/pci_fixups.h>
|
||||
|
||||
|
||||
extern "C" __attribute__((weak)) int inhibit_pci_fixup(char const *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void lx_emul_register_pci_fixup(void (*fn)(struct pci_dev*), const char * name)
|
||||
{
|
||||
if (inhibit_pci_fixup(name))
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < (sizeof(lx_emul_pci_final_fixups) / sizeof(char*));
|
||||
i++) {
|
||||
if (Genode::strcmp(name, lx_emul_pci_final_fixups[i]) == 0) {
|
||||
Lx_kit::env().pci_fixup_calls.add(fn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Genode::error(__func__, " ignore unkown PCI fixup '", name, "'");
|
||||
}
|
||||
|
||||
|
||||
extern "C" void lx_emul_execute_pci_fixup(struct pci_dev *pci_dev)
|
||||
{
|
||||
Lx_kit::env().pci_fixup_calls.execute(pci_dev);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
#include <linux/pci.h>
|
||||
|
||||
void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
|
||||
struct resource *res)
|
||||
{
|
||||
region->start = res->start;
|
||||
region->end = res->end;
|
||||
}
|
||||
|
||||
|
||||
void pci_put_host_bridge_device(struct device * dev) { }
|
@ -0,0 +1,34 @@
|
||||
#include <linux/pci.h>
|
||||
|
||||
static struct attribute *pci_bus_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
static const struct attribute_group pci_bus_group = {
|
||||
.attrs = pci_bus_attrs,
|
||||
};
|
||||
|
||||
|
||||
const struct attribute_group *pci_bus_groups[] = {
|
||||
&pci_bus_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
static struct attribute *pci_dev_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
static const struct attribute_group pci_dev_group = {
|
||||
.attrs = pci_dev_attrs,
|
||||
};
|
||||
|
||||
|
||||
const struct attribute_group *pci_dev_groups[] = {
|
||||
&pci_dev_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
36
repos/dde_linux/src/lib/lx_emul/shadow/drivers/pci/pci.c
Normal file
36
repos/dde_linux/src/lib/lx_emul/shadow/drivers/pci/pci.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include <linux/pci.h>
|
||||
#include <lx_emul/pci.h>
|
||||
|
||||
int pci_enable_device(struct pci_dev * dev)
|
||||
{
|
||||
lx_emul_pci_enable(dev_name(&dev->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pcim_enable_device(struct pci_dev *pdev)
|
||||
{
|
||||
/* for now ignore devres */
|
||||
return pci_enable_device(pdev);
|
||||
}
|
||||
|
||||
|
||||
void pci_set_master(struct pci_dev * dev) { }
|
||||
|
||||
|
||||
int pci_set_mwi(struct pci_dev * dev)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
bool pci_dev_run_wake(struct pci_dev * dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
u8 pci_find_capability(struct pci_dev * dev,int cap)
|
||||
{
|
||||
return 0;
|
||||
}
|
44
repos/dde_linux/src/lib/lx_emul/shadow/drivers/pci/search.c
Normal file
44
repos/dde_linux/src/lib/lx_emul/shadow/drivers/pci/search.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include <lx_emul/pci.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
struct pci_dev * pci_get_class(unsigned int class, struct pci_dev *from)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *bus = (struct pci_bus *) lx_emul_pci_root_bus();
|
||||
|
||||
/*
|
||||
* Break endless loop (see 'intel_dsm_detect()') by only querying
|
||||
* the bus on the first executuin.
|
||||
*/
|
||||
if (from)
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
if (dev->class == class) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
|
||||
unsigned int devfn)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *pbus = (struct pci_bus *) lx_emul_pci_root_bus();
|
||||
|
||||
list_for_each_entry(dev, &pbus->devices, bus_list) {
|
||||
if (dev->devfn == devfn && dev->class == 0x60000)
|
||||
return dev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct pci_dev * pci_get_device(unsigned int vendor,unsigned int device,struct pci_dev * from)
|
||||
{
|
||||
return NULL;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
extern struct irq_chip dde_irqchip_data_chip;
|
||||
|
||||
|
||||
void pci_assign_irq(struct pci_dev * dev)
|
||||
{
|
||||
struct irq_data *irq_data;
|
||||
|
||||
/*
|
||||
* Be lazy and treat irq as hwirq as this is used by the
|
||||
* dde_irqchip_data_chip for (un-)masking.
|
||||
*/
|
||||
irq_data = irq_get_irq_data(dev->irq);
|
||||
|
||||
irq_data->hwirq = dev->irq;
|
||||
|
||||
irq_set_chip_and_handler(dev->irq, &dde_irqchip_data_chip,
|
||||
handle_level_irq);
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,11 @@
|
||||
#include <linux/pci.h>
|
||||
|
||||
resource_size_t __weak pcibios_align_resource(void *data,
|
||||
const struct resource *res,
|
||||
resource_size_t size,
|
||||
resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
}
|
||||
|
||||
|
@ -1,194 +0,0 @@
|
||||
/*
|
||||
* \brief Linux kernel PCI
|
||||
* \author Josef Soentgen
|
||||
* \date 2022-01-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <lx_emul.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
int arch_probe_nr_irqs(void)
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
|
||||
#include <asm/x86_init.h>
|
||||
|
||||
static int x86_init_pci_init(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void x86_init_pci_init_irq(void) { }
|
||||
|
||||
|
||||
struct x86_init_ops x86_init = {
|
||||
.pci = {
|
||||
.init = x86_init_pci_init,
|
||||
.init_irq = x86_init_pci_init_irq,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
#include <lx_emul/pci_config_space.h>
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/pci_x86.h>
|
||||
|
||||
static int pci_raw_ops_read(unsigned int domain, unsigned int bus, unsigned int devfn,
|
||||
int reg, int len, u32 *val)
|
||||
{
|
||||
return lx_emul_pci_read_config(bus, devfn, (unsigned)reg, (unsigned)len, val);
|
||||
}
|
||||
|
||||
|
||||
static int pci_raw_ops_write(unsigned int domain, unsigned int bus, unsigned int devfn,
|
||||
int reg, int len, u32 val)
|
||||
{
|
||||
return lx_emul_pci_write_config(bus, devfn, (unsigned)reg, (unsigned)len, val);
|
||||
}
|
||||
|
||||
|
||||
const struct pci_raw_ops genode_raw_pci_ops = {
|
||||
.read = pci_raw_ops_read,
|
||||
.write = pci_raw_ops_write,
|
||||
};
|
||||
|
||||
const struct pci_raw_ops *raw_pci_ops = &genode_raw_pci_ops;
|
||||
|
||||
|
||||
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
|
||||
{
|
||||
return pci_raw_ops_read(0, bus->number, devfn, where, size, value);
|
||||
}
|
||||
|
||||
|
||||
static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
|
||||
{
|
||||
return pci_raw_ops_write(0, bus->number, devfn, where, size, value);
|
||||
}
|
||||
|
||||
|
||||
struct pci_ops pci_root_ops = {
|
||||
.read = pci_read,
|
||||
.write = pci_write,
|
||||
};
|
||||
|
||||
|
||||
#include <lx_emul/init.h>
|
||||
|
||||
static struct resource _dummy_parent;
|
||||
|
||||
void pcibios_scan_root(int busnum)
|
||||
{
|
||||
struct pci_bus *bus;
|
||||
struct pci_sysdata *sd;
|
||||
struct pci_dev *dev;
|
||||
|
||||
LIST_HEAD(resources);
|
||||
|
||||
sd = kzalloc(sizeof(*sd), GFP_KERNEL);
|
||||
if (!sd) {
|
||||
return;
|
||||
}
|
||||
sd->node = NUMA_NO_NODE;
|
||||
pci_add_resource(&resources, &ioport_resource);
|
||||
pci_add_resource(&resources, &iomem_resource);
|
||||
|
||||
bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
|
||||
|
||||
if (!bus) {
|
||||
pci_free_resource_list(&resources);
|
||||
kfree(sd);
|
||||
return;
|
||||
}
|
||||
pci_bus_add_devices(bus);
|
||||
|
||||
/* handle early quirks */
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
|
||||
/*
|
||||
* As pci_enable_resources() is only going to check if
|
||||
* the parent of the resource is set register the dummy.
|
||||
*/
|
||||
struct resource *r;
|
||||
int i;
|
||||
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
|
||||
|
||||
r = &dev->resource[i];
|
||||
r->parent = &_dummy_parent;
|
||||
}
|
||||
|
||||
lx_emul_execute_pci_fixup(dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
extern struct irq_chip dde_irqchip_data_chip;
|
||||
|
||||
|
||||
void pci_assign_irq(struct pci_dev * dev)
|
||||
{
|
||||
struct irq_data *irq_data;
|
||||
|
||||
/*
|
||||
* Be lazy and treat irq as hwirq as this is used by the
|
||||
* dde_irqchip_data_chip for (un-)masking.
|
||||
*/
|
||||
irq_data = irq_get_irq_data(dev->irq);
|
||||
irq_data->hwirq = dev->irq;
|
||||
|
||||
irq_set_chip_and_handler(dev->irq, &dde_irqchip_data_chip,
|
||||
handle_level_irq);
|
||||
}
|
||||
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
unsigned long pci_mem_start = 0xaeedbabe;
|
||||
|
||||
const struct attribute_group aspm_ctrl_attr_group[] = { 0 };
|
||||
const struct attribute_group pci_dev_vpd_attr_group = { };
|
||||
|
||||
struct pci_fixup __start_pci_fixups_early[] = { 0 };
|
||||
struct pci_fixup __end_pci_fixups_early[] = { 0 };
|
||||
struct pci_fixup __start_pci_fixups_header[] = { 0 };
|
||||
struct pci_fixup __end_pci_fixups_header[] = { 0 };
|
||||
struct pci_fixup __start_pci_fixups_final[] = { 0 };
|
||||
struct pci_fixup __end_pci_fixups_final[] = { 0 };
|
||||
struct pci_fixup __start_pci_fixups_enable[] = { 0 };
|
||||
struct pci_fixup __end_pci_fixups_enable[] = { 0 };
|
||||
struct pci_fixup __start_pci_fixups_resume[] = { 0 };
|
||||
struct pci_fixup __end_pci_fixups_resume[] = { 0 };
|
||||
struct pci_fixup __start_pci_fixups_resume_early[] = { 0 };
|
||||
struct pci_fixup __end_pci_fixups_resume_early[] = { 0 };
|
||||
struct pci_fixup __start_pci_fixups_suspend[] = { 0 };
|
||||
struct pci_fixup __end_pci_fixups_suspend[] = { 0 };
|
||||
struct pci_fixup __start_pci_fixups_suspend_late[] = { 0 };
|
||||
struct pci_fixup __end_pci_fixups_suspend_late[] = { 0 };
|
||||
|
||||
int pcibios_last_bus = -1;
|
||||
|
||||
|
||||
extern int __init pcibios_init(void);
|
||||
int __init pcibios_init(void)
|
||||
{
|
||||
lx_emul_trace(__func__);
|
||||
return 0;
|
||||
}
|
@ -34,7 +34,7 @@ bool Device::Io_mem::match(addr_t addr, size_t size)
|
||||
bool Device::Io_port::match(uint16_t addr)
|
||||
{
|
||||
return (this->addr <= addr) &&
|
||||
((this->addr + this->size) >= addr);
|
||||
((this->addr + this->size) > addr);
|
||||
}
|
||||
|
||||
|
||||
@ -67,9 +67,9 @@ const char * Device::compatible()
|
||||
}
|
||||
|
||||
|
||||
const char * Device::name()
|
||||
Device::Name Device::name()
|
||||
{
|
||||
return _name.string();
|
||||
return _name;
|
||||
}
|
||||
|
||||
|
||||
@ -102,7 +102,7 @@ clk * Device::clock(unsigned idx)
|
||||
bool Device::io_mem(addr_t phys_addr, size_t size)
|
||||
{
|
||||
bool ret = false;
|
||||
_for_each_io_mem([&] (Io_mem & io) {
|
||||
for_each_io_mem([&] (Io_mem & io) {
|
||||
if (io.match(phys_addr, size))
|
||||
ret = true;
|
||||
});
|
||||
@ -113,7 +113,7 @@ bool Device::io_mem(addr_t phys_addr, size_t size)
|
||||
void * Device::io_mem_local_addr(addr_t phys_addr, size_t size)
|
||||
{
|
||||
void * ret = nullptr;
|
||||
_for_each_io_mem([&] (Io_mem & io) {
|
||||
for_each_io_mem([&] (Io_mem & io) {
|
||||
if (!io.match(phys_addr, size))
|
||||
return;
|
||||
|
||||
@ -132,7 +132,7 @@ bool Device::irq_unmask(unsigned number)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
_for_each_irq([&] (Irq & irq) {
|
||||
for_each_irq([&] (Irq & irq) {
|
||||
if (irq.number != number)
|
||||
return;
|
||||
|
||||
@ -156,7 +156,7 @@ void Device::irq_mask(unsigned number)
|
||||
if (!_pdev.constructed())
|
||||
return;
|
||||
|
||||
_for_each_irq([&] (Irq & irq) {
|
||||
for_each_irq([&] (Irq & irq) {
|
||||
if (irq.number != number)
|
||||
return;
|
||||
irq.session.destruct();
|
||||
@ -170,7 +170,7 @@ void Device::irq_ack(unsigned number)
|
||||
if (!_pdev.constructed())
|
||||
return;
|
||||
|
||||
_for_each_irq([&] (Irq & irq) {
|
||||
for_each_irq([&] (Irq & irq) {
|
||||
if (irq.number != number || !irq.session.constructed())
|
||||
return;
|
||||
irq.session->ack();
|
||||
@ -181,7 +181,7 @@ void Device::irq_ack(unsigned number)
|
||||
bool Device::io_port(uint16_t addr)
|
||||
{
|
||||
bool ret = false;
|
||||
_for_each_io_port([&] (Io_port & io) {
|
||||
for_each_io_port([&] (Io_port & io) {
|
||||
if (io.match(addr))
|
||||
ret = true;
|
||||
});
|
||||
@ -192,7 +192,7 @@ bool Device::io_port(uint16_t addr)
|
||||
uint8_t Device::io_port_inb(uint16_t addr)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
@ -209,7 +209,7 @@ uint8_t Device::io_port_inb(uint16_t addr)
|
||||
uint16_t Device::io_port_inw(uint16_t addr)
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
@ -226,7 +226,7 @@ uint16_t Device::io_port_inw(uint16_t addr)
|
||||
uint32_t Device::io_port_inl(uint16_t addr)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
@ -242,7 +242,7 @@ uint32_t Device::io_port_inl(uint16_t addr)
|
||||
|
||||
void Device::io_port_outb(uint16_t addr, uint8_t val)
|
||||
{
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
@ -256,7 +256,7 @@ void Device::io_port_outb(uint16_t addr, uint8_t val)
|
||||
|
||||
void Device::io_port_outw(uint16_t addr, uint16_t val)
|
||||
{
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
@ -270,7 +270,7 @@ void Device::io_port_outw(uint16_t addr, uint16_t val)
|
||||
|
||||
void Device::io_port_outl(uint16_t addr, uint32_t val)
|
||||
{
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
@ -317,16 +317,18 @@ Device::Device(Entrypoint & ep,
|
||||
{
|
||||
unsigned i = 0;
|
||||
xml.for_each_sub_node("io_mem", [&] (Xml_node node) {
|
||||
addr_t addr = node.attribute_value("phys_addr", 0UL);
|
||||
size_t size = node.attribute_value("size", 0UL);
|
||||
_io_mems.insert(new (heap) Io_mem(i++, addr, size));
|
||||
addr_t addr = node.attribute_value("phys_addr", 0UL);
|
||||
size_t size = node.attribute_value("size", 0UL);
|
||||
unsigned bar = node.attribute_value("pci_bar", 0U);
|
||||
_io_mems.insert(new (heap) Io_mem(i++, addr, size, bar));
|
||||
});
|
||||
|
||||
i = 0;
|
||||
xml.for_each_sub_node("io_port", [&] (Xml_node node) {
|
||||
xml.for_each_sub_node("io_port_range", [&] (Xml_node node) {
|
||||
uint16_t addr = node.attribute_value<uint16_t>("phys_addr", 0U);
|
||||
uint16_t size = node.attribute_value<uint16_t>("size", 0U);
|
||||
_io_ports.insert(new (heap) Io_port(i++, addr, size));
|
||||
unsigned bar = node.attribute_value("pci_bar", 0U);
|
||||
_io_ports.insert(new (heap) Io_port(i++, addr, size, bar));
|
||||
});
|
||||
|
||||
i = 0;
|
||||
@ -339,6 +341,17 @@ Device::Device(Entrypoint & ep,
|
||||
Device::Name name = node.attribute_value("name", Device::Name());
|
||||
_clocks.insert(new (heap) Device::Clock(i++, name));
|
||||
});
|
||||
|
||||
xml.for_each_sub_node("pci-config", [&] (Xml_node node) {
|
||||
using namespace Pci;
|
||||
_pci_config.construct(Pci_config{
|
||||
node.attribute_value<vendor_t>("vendor_id", 0xffff),
|
||||
node.attribute_value<device_t>("device_id", 0xffff),
|
||||
node.attribute_value<class_t>("class", 0xff),
|
||||
node.attribute_value<rev_t>("revision", 0xff),
|
||||
node.attribute_value<vendor_t>("sub_vendor_id", 0xffff),
|
||||
node.attribute_value<device_t>("sub_device_id", 0xffff)});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -352,9 +365,26 @@ Device_list::Device_list(Entrypoint & ep,
|
||||
:
|
||||
_platform(platform)
|
||||
{
|
||||
_platform.with_xml([&] (Xml_node & xml) {
|
||||
xml.for_each_sub_node("device", [&] (Xml_node node) {
|
||||
insert(new (heap) Device(ep, _platform, node, heap));
|
||||
bool initialized = false;
|
||||
Constructible<Io_signal_handler<Device_list>> handler {};
|
||||
|
||||
while (!initialized) {
|
||||
_platform.update();
|
||||
_platform.with_xml([&] (Xml_node & xml) {
|
||||
if (!xml.num_sub_nodes()) {
|
||||
if (!handler.constructed()) {
|
||||
handler.construct(ep, *this, &Device_list::_handle_signal);
|
||||
_platform.sigh(*handler);
|
||||
}
|
||||
ep.wait_and_dispatch_one_io_signal();
|
||||
} else {
|
||||
_platform.sigh(Signal_context_capability());
|
||||
handler.destruct();
|
||||
xml.for_each_sub_node("device", [&] (Xml_node node) {
|
||||
insert(new (heap) Device(ep, _platform, node, heap));
|
||||
});
|
||||
initialized = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,581 +0,0 @@
|
||||
/*
|
||||
* \brief Legacy platform session wrapper
|
||||
* \author Josef Soentgen
|
||||
* \date 2022-01-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/ram_allocator.h>
|
||||
#include <util/xml_generator.h>
|
||||
|
||||
/* DDE includes */
|
||||
#include <lx_kit/env.h>
|
||||
#include <lx_kit/device.h>
|
||||
#include <platform_session/device.h>
|
||||
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
using Str = String<16>;
|
||||
|
||||
template <typename T, typename... TAIL>
|
||||
static Str to_string(T const &arg, TAIL &&... args)
|
||||
{
|
||||
return Str(arg, args...);
|
||||
}
|
||||
|
||||
|
||||
template <typename FN>
|
||||
static void scan_resources(Legacy_platform::Device &device,
|
||||
FN const &fn)
|
||||
{
|
||||
using R = Legacy_platform::Device::Resource;
|
||||
for (unsigned resource_id = 0; resource_id < 6; resource_id++) {
|
||||
|
||||
R const resource = device.resource(resource_id);
|
||||
if (resource.type() != R::INVALID)
|
||||
fn(resource_id, resource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Str create_device_node(Xml_generator &xml,
|
||||
Legacy_platform::Device &device)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* start arbitrarily and count up */
|
||||
static unsigned char irq = 8;
|
||||
|
||||
/* start arbitrarily at the dev 1 for the first device */
|
||||
static unsigned char bdf[3] = { 0, 1, 0 };
|
||||
|
||||
/* start arbitrarily at 1 GiB */
|
||||
static unsigned long mmio_phys_addr = 0x40000000;
|
||||
|
||||
unsigned char pbdf[3];
|
||||
device.bus_address(&pbdf[0], &pbdf[1], &pbdf[2]);
|
||||
|
||||
/*
|
||||
* The host-bridge is only required by the Intel framebuffer
|
||||
* driver and has to be located at 00:00.0. For every other
|
||||
* type of device we simply count upwards.
|
||||
*/
|
||||
unsigned char vbdf[3] = { 0, 0, 0 };
|
||||
unsigned const class_code = device.class_code() >> 8;
|
||||
if (class_code != 0x600 /* host-bridge */) {
|
||||
vbdf[0] = bdf[0]; vbdf[1] = bdf[1]; vbdf[2] = bdf[2];
|
||||
bdf[1]++;
|
||||
}
|
||||
|
||||
log("override physical BDF ",
|
||||
Hex(pbdf[0], Hex::OMIT_PREFIX), ":",
|
||||
Hex(pbdf[1], Hex::OMIT_PREFIX), ".",
|
||||
Hex(pbdf[2], Hex::OMIT_PREFIX), " -> ",
|
||||
Hex(vbdf[0], Hex::OMIT_PREFIX), ":",
|
||||
Hex(vbdf[1], Hex::OMIT_PREFIX), ".",
|
||||
Hex(vbdf[2], Hex::OMIT_PREFIX));
|
||||
|
||||
Str name = to_string("pci-",
|
||||
Hex(vbdf[0], Hex::OMIT_PREFIX), ":",
|
||||
Hex(vbdf[1], Hex::OMIT_PREFIX), ".",
|
||||
Hex(vbdf[2], Hex::OMIT_PREFIX));
|
||||
|
||||
xml.node("device", [&] () {
|
||||
xml.attribute("name", name);
|
||||
xml.attribute("type", "pci");
|
||||
|
||||
xml.node("irq", [&] () {
|
||||
xml.attribute("number", irq++);
|
||||
});
|
||||
|
||||
using R = Legacy_platform::Device::Resource;
|
||||
|
||||
scan_resources(device, [&] (unsigned id, R const &r) {
|
||||
|
||||
bool const memory = r.type() == R::MEMORY;
|
||||
|
||||
if (memory) {
|
||||
xml.node("io_mem", [&] () {
|
||||
xml.attribute("phys_addr", to_string(Hex(mmio_phys_addr)));
|
||||
xml.attribute("size", to_string(Hex(r.size())));
|
||||
xml.attribute("bar", id);
|
||||
});
|
||||
|
||||
mmio_phys_addr += align_addr(r.size(), 12);
|
||||
} else {
|
||||
|
||||
xml.node("io_port", [&] () {
|
||||
xml.attribute("phys_addr", to_string(Hex(r.bar())));
|
||||
xml.attribute("size", to_string(Hex(r.size())));
|
||||
xml.attribute("bar", id);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
Platform::Connection::Connection(Env &env)
|
||||
:
|
||||
_env { env }
|
||||
{
|
||||
try {
|
||||
_legacy_platform.construct(env);
|
||||
} catch (...) {
|
||||
error("could not construct legacy platform connection");
|
||||
throw;
|
||||
}
|
||||
|
||||
/* empirically determined */
|
||||
_legacy_platform->upgrade_ram(32768);
|
||||
_legacy_platform->upgrade_caps(8);
|
||||
|
||||
Xml_generator xml { _devices_node_buffer,
|
||||
sizeof (_devices_node_buffer),
|
||||
"devices", [&] () {
|
||||
_legacy_platform->with_upgrade([&] () {
|
||||
|
||||
/* scan the virtual bus but limit to MAX_DEVICES */
|
||||
Legacy_platform::Device_capability cap { };
|
||||
for (auto &dev : _devices_list) {
|
||||
|
||||
cap = _legacy_platform->next_device(cap, 0x0u, 0x0u);
|
||||
if (!cap.valid()) break;
|
||||
|
||||
Legacy_platform::Device_client device { cap };
|
||||
Str name = create_device_node(xml, device);
|
||||
dev.construct(name, cap);
|
||||
}
|
||||
});
|
||||
} };
|
||||
|
||||
_devices_node.construct(_devices_node_buffer,
|
||||
sizeof (_devices_node_buffer));
|
||||
}
|
||||
|
||||
|
||||
Legacy_platform::Device_capability
|
||||
Platform::Connection::device_cap(char const *name)
|
||||
{
|
||||
for (auto const &dev : _devices_list) {
|
||||
if (!dev.constructed())
|
||||
continue;
|
||||
|
||||
if (dev->name == name)
|
||||
return dev->cap;
|
||||
}
|
||||
|
||||
return Legacy_platform::Device_capability();
|
||||
}
|
||||
|
||||
|
||||
void Platform::Connection::update() { }
|
||||
|
||||
|
||||
Ram_dataspace_capability
|
||||
Platform::Connection::alloc_dma_buffer(size_t size, Cache)
|
||||
{
|
||||
return _legacy_platform->with_upgrade([&] () {
|
||||
return _legacy_platform->alloc_dma_buffer(size, Cache::UNCACHED);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Platform::Connection::free_dma_buffer(Ram_dataspace_capability ds_cap)
|
||||
{
|
||||
_legacy_platform->free_dma_buffer(ds_cap);
|
||||
}
|
||||
|
||||
|
||||
addr_t Platform::Connection::dma_addr(Ram_dataspace_capability ds_cap)
|
||||
{
|
||||
return _legacy_platform->dma_addr(ds_cap);
|
||||
}
|
||||
|
||||
|
||||
static Legacy_platform::Device::Access_size convert(Platform::Device::Config_space::Access_size size)
|
||||
{
|
||||
using PAS = Platform::Device::Config_space::Access_size;
|
||||
using LAS = Legacy_platform::Device::Access_size;
|
||||
switch (size) {
|
||||
case PAS::ACCESS_8BIT:
|
||||
return LAS::ACCESS_8BIT;
|
||||
case PAS::ACCESS_16BIT:
|
||||
return LAS::ACCESS_16BIT;
|
||||
case PAS::ACCESS_32BIT:
|
||||
return LAS::ACCESS_32BIT;
|
||||
}
|
||||
|
||||
return LAS::ACCESS_8BIT;
|
||||
}
|
||||
|
||||
|
||||
template <typename FN>
|
||||
static void apply(Platform::Device const &device,
|
||||
Xml_node const &devices,
|
||||
FN const &fn)
|
||||
{
|
||||
using namespace Genode;
|
||||
using N = Platform::Device::Name;
|
||||
|
||||
auto lookup_device = [&] (Xml_node const &node) {
|
||||
if (node.attribute_value("name", N()) == device.name())
|
||||
fn(node);
|
||||
};
|
||||
|
||||
devices.for_each_sub_node("device", lookup_device);
|
||||
}
|
||||
|
||||
|
||||
static unsigned bar_size(Platform::Device const &dev,
|
||||
Xml_node const &devices, unsigned bar)
|
||||
{
|
||||
if (bar > 6)
|
||||
return 0;
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
unsigned val = 0;
|
||||
apply(dev, devices, [&] (Xml_node device) {
|
||||
device.for_each_sub_node("io_mem", [&] (Xml_node node) {
|
||||
if (node.attribute_value("bar", 6u) != bar)
|
||||
return;
|
||||
|
||||
val = node.attribute_value("size", 0u);
|
||||
});
|
||||
|
||||
device.for_each_sub_node("io_port", [&] (Xml_node node) {
|
||||
if (node.attribute_value("bar", 6u) != bar)
|
||||
return;
|
||||
|
||||
val = node.attribute_value("size", 0u);
|
||||
});
|
||||
});
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static unsigned bar_address(Platform::Device const &dev,
|
||||
Xml_node const &devices, unsigned bar)
|
||||
{
|
||||
if (bar > 6)
|
||||
return 0;
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
unsigned val = 0;
|
||||
apply(dev, devices, [&] (Xml_node device) {
|
||||
device.for_each_sub_node("io_mem", [&] (Xml_node node) {
|
||||
if (node.attribute_value("bar", 6u) != bar)
|
||||
return;
|
||||
|
||||
val = node.attribute_value("phys_addr", 0u);
|
||||
});
|
||||
|
||||
device.for_each_sub_node("io_port", [&] (Xml_node node) {
|
||||
if (node.attribute_value("bar", 6u) != bar)
|
||||
return;
|
||||
|
||||
val = node.attribute_value("phys_addr", 0u);
|
||||
});
|
||||
});
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static unsigned char irq_line(Platform::Device const &dev,
|
||||
Xml_node const &devices)
|
||||
{
|
||||
enum : unsigned char { INVALID_IRQ_LINE = 0xffu };
|
||||
unsigned char irq = INVALID_IRQ_LINE;
|
||||
|
||||
apply(dev, devices, [&] (Xml_node device) {
|
||||
device.for_each_sub_node("irq", [&] (Xml_node node) {
|
||||
irq = node.attribute_value("number", (unsigned char)INVALID_IRQ_LINE);
|
||||
});
|
||||
});
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
|
||||
Platform::Device::Device(Connection &platform, Type)
|
||||
: _platform { platform } { }
|
||||
|
||||
|
||||
Platform::Device::Device(Connection &platform, Name name)
|
||||
:
|
||||
_platform { platform },
|
||||
_device_cap { _platform.device_cap(name.string()) },
|
||||
_name { name }
|
||||
{
|
||||
if (!_device_cap.valid()) {
|
||||
error(__func__, ": could not get device capability");
|
||||
throw -1;
|
||||
}
|
||||
|
||||
Legacy_platform::Device_client device(_device_cap);
|
||||
_class_code = device.class_code() >> 8;
|
||||
}
|
||||
|
||||
|
||||
unsigned Platform::Device::Config_space::read(unsigned char address,
|
||||
Access_size size)
|
||||
{
|
||||
/* 32bit BARs only for now */
|
||||
if (address >= 0x10 && address <= 0x24) {
|
||||
unsigned const bar = (address - 0x10) / 4;
|
||||
if (_device._bar_checked_for_size[bar]) {
|
||||
_device._bar_checked_for_size[bar] = 0;
|
||||
return bar_size(_device, *_device._platform._devices_node, bar);
|
||||
}
|
||||
|
||||
return bar_address(_device, *_device._platform._devices_node, bar);
|
||||
}
|
||||
|
||||
/*
|
||||
* If any PCI device reports 0 as interrupt PIN, drivers may try to force
|
||||
* MSI setup (e.g., xhci). So, we clamp the interrupt PIN to 1 to let
|
||||
* drivers finish initialization and don't bother the platform driver.
|
||||
*/
|
||||
if (address == 0x3d)
|
||||
return 0x01;
|
||||
|
||||
if (address == 0x3c)
|
||||
return irq_line(_device, *_device._platform._devices_node);
|
||||
|
||||
if (address == 0x34)
|
||||
return 0u;
|
||||
|
||||
Legacy_platform::Device::Access_size const as = convert(size);
|
||||
Legacy_platform::Device_client device { _device._device_cap };
|
||||
return device.config_read(address, as);
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device::Config_space::write(unsigned char address,
|
||||
unsigned value,
|
||||
Access_size size)
|
||||
{
|
||||
/* 32bit BARs only for now */
|
||||
if (address >= 0x10 && address <= 0x24) {
|
||||
unsigned const bar = (address - 0x10) / 4;
|
||||
if (value == 0xffffffffu)
|
||||
_device._bar_checked_for_size[bar] = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
enum {
|
||||
CLASS_CODE_USB = 0xc03,
|
||||
};
|
||||
|
||||
switch(_device._class_code) {
|
||||
case CLASS_CODE_USB:
|
||||
/* reject writes to unknown addresses */
|
||||
switch (address) {
|
||||
case 0x04:
|
||||
/*
|
||||
* Doing this multiple times induces multiple "assignment of PCI
|
||||
* device" diasgnostics currently.
|
||||
*/
|
||||
/* command register (value for enable io, memory, bus master) */
|
||||
value = 7;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Write in [0x40,0xff] should be okay if there are is no capability
|
||||
* list (status register bit 4 + capability list pointer). Otherwise,
|
||||
* writes into capability-list entries should be rejected.
|
||||
*/
|
||||
|
||||
case 0xc0: /* UHCI BIOS handoff (UHCI_USBLEGSUP) */ break;
|
||||
case 0xc4: /* UHCI INTEL resume-enable (USBRES_INTEL) */ break;
|
||||
case 0x60 ... 0x6f: /* EHCI BIOS handoff (just empiric, address not fixed) */ break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Legacy_platform::Device::Access_size const as = convert(size);
|
||||
Legacy_platform::Device_client device { _device._device_cap };
|
||||
device.config_write(address, value, as);
|
||||
}
|
||||
|
||||
|
||||
size_t Platform::Device::Mmio::size() const
|
||||
{
|
||||
return _attached_ds.constructed() ? _attached_ds->size() : 0;
|
||||
}
|
||||
|
||||
|
||||
void *Platform::Device::Mmio::_local_addr()
|
||||
{
|
||||
if (!_attached_ds.constructed()) {
|
||||
Legacy_platform::Device_client device { _device._device_cap };
|
||||
|
||||
Cache cache = Cache::UNCACHED;
|
||||
|
||||
{
|
||||
uint8_t phys_bar_id = 0;
|
||||
|
||||
/* convert virtual bar id into phys bar id */
|
||||
for (unsigned virt_id = 0, i = 0; i < 6; i++) {
|
||||
auto const type = device.resource(i).type();
|
||||
if (type == Legacy_platform::Device::Resource::Type::MEMORY) {
|
||||
virt_id ++;
|
||||
phys_bar_id = uint8_t(i);
|
||||
}
|
||||
if (virt_id > _index.value)
|
||||
break;
|
||||
}
|
||||
|
||||
if (device.resource(phys_bar_id).prefetchable())
|
||||
cache = Cache::WRITE_COMBINED;
|
||||
|
||||
auto const r = device.resource(phys_bar_id);
|
||||
Range::start = (r.base() & 0xfffu);
|
||||
}
|
||||
|
||||
Io_mem_session_capability io_mem_cap =
|
||||
device.io_mem(uint8_t(_index.value), cache);
|
||||
|
||||
Io_mem_session_client io_mem_client(io_mem_cap);
|
||||
|
||||
_attached_ds.construct(Lx_kit::env().env.rm(),
|
||||
io_mem_client.dataspace());
|
||||
}
|
||||
|
||||
return (void*)(_attached_ds->local_addr<char>() + Range::start);
|
||||
}
|
||||
|
||||
|
||||
Platform::Device::Io_port_range::Io_port_range(Device &device, Index index)
|
||||
:
|
||||
_device { device },
|
||||
_index { index }
|
||||
{
|
||||
Legacy_platform::Device_client client { _device._device_cap };
|
||||
|
||||
_io_port.construct(client.io_port((uint8_t)index.value));
|
||||
}
|
||||
|
||||
|
||||
unsigned char Platform::Device::Io_port_range::inb(uint16_t addr)
|
||||
{
|
||||
return _io_port->inb(addr);
|
||||
}
|
||||
|
||||
|
||||
unsigned short Platform::Device::Io_port_range::inw(uint16_t addr)
|
||||
{
|
||||
return _io_port->inw(addr);
|
||||
}
|
||||
|
||||
|
||||
unsigned int Platform::Device::Io_port_range::inl(uint16_t addr)
|
||||
{
|
||||
return _io_port->inl(addr);
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device::Io_port_range::outb(uint16_t addr, uint8_t val)
|
||||
{
|
||||
return _io_port->outb(addr, val);
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device::Io_port_range::outw(uint16_t addr, uint16_t val)
|
||||
{
|
||||
return _io_port->outw(addr, val);
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device::Io_port_range::outl(uint16_t addr, uint32_t val)
|
||||
{
|
||||
return _io_port->outl(addr, val);
|
||||
}
|
||||
|
||||
|
||||
Platform::Device::Irq::Irq(Platform::Device &device, Index index)
|
||||
:
|
||||
_device { device },
|
||||
_index { index }
|
||||
{
|
||||
Legacy_platform::Device_client client { _device._device_cap };
|
||||
|
||||
_irq.construct(client.irq((uint8_t)index.value));
|
||||
}
|
||||
|
||||
void Platform::Device::Irq::ack()
|
||||
{
|
||||
_irq->ack_irq();
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device::Irq::sigh(Signal_context_capability sigh)
|
||||
{
|
||||
_irq->sigh(sigh);
|
||||
_irq->ack_irq();
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device::Irq::sigh_omit_initial_signal(Signal_context_capability sigh)
|
||||
{
|
||||
_irq->sigh(sigh);
|
||||
}
|
||||
|
||||
|
||||
static Platform::Device::Config_space::Access_size access_size(unsigned len)
|
||||
{
|
||||
using AS = Platform::Device::Config_space::Access_size;
|
||||
AS as = AS::ACCESS_8BIT;
|
||||
if (len == 4) as = AS::ACCESS_32BIT;
|
||||
else if (len == 2) as = AS::ACCESS_16BIT;
|
||||
else as = AS::ACCESS_8BIT;
|
||||
|
||||
return as;
|
||||
}
|
||||
|
||||
|
||||
bool Lx_kit::Device::read_config(unsigned reg, unsigned len, unsigned *val)
|
||||
{
|
||||
if (!_pdev.constructed())
|
||||
enable();
|
||||
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
using AS = Platform::Device::Config_space::Access_size;
|
||||
AS const as = access_size(len);
|
||||
|
||||
*val = Platform::Device::Config_space(*_pdev).read((unsigned char)reg, as);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Lx_kit::Device::write_config(unsigned reg, unsigned len, unsigned val)
|
||||
{
|
||||
if (!_pdev.constructed())
|
||||
return false;
|
||||
|
||||
using AS = Platform::Device::Config_space::Access_size;
|
||||
AS const as = access_size(len);
|
||||
|
||||
Platform::Device::Config_space(*_pdev).write((unsigned char)reg, val, as);
|
||||
return true;
|
||||
}
|
Reference in New Issue
Block a user