dde_linux: remove legacy usb_host_drv for x86

Remove legacy platform_session API usage from legacy lx_kit/lx_emul

Ref genodelabs/genode#4578
This commit is contained in:
Stefan Kalkowski 2022-09-16 15:33:58 +02:00 committed by Christian Helmuth
parent 91e64c3f27
commit b8eab65536
11 changed files with 0 additions and 1304 deletions

View File

@ -1,242 +0,0 @@
/*
* \brief PCI device handling
* \author Sebastian Sumpf
* \date 2016-04-25
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/allocator.h>
#include <base/entrypoint.h>
#include <base/signal.h>
#include <irq_session/client.h>
#include <util/misc_math.h>
#include <lx_emul.h>
#include <platform.h>
#include <legacy/lx_kit/env.h>
#include <legacy/lx_kit/irq.h>
#include <legacy/lx_kit/pci_dev_registry.h>
#include <legacy/lx_kit/malloc.h>
#include <legacy/lx_kit/mapped_io_mem_range.h>
#include <legacy/lx_emul/impl/io.h>
#include <legacy/lx_emul/impl/pci_resource.h>
/**
* Quirks
*/
extern "C" void __pci_fixup_quirk_usb_early_handoff(void *data);
/**
* List of pci devices from platform driver
*/
class Pci_dev_list
{
private:
struct Element : public Lx_kit::List<Element>::Element
{
Platform::Device_capability cap;
Element(Platform::Device_capability cap) : cap(cap) { }
};
Lx_kit::List<Element> _pci_caps;
public:
Pci_dev_list()
{
/*
* Obtain first device, the operation may exceed the session quota.
* So we use the 'with_upgrade' mechanism.
*/
Platform::Device_capability cap =
Lx::pci()->with_upgrade([&] () {
return Lx::pci()->first_device(); });
/*
* Iterate over the devices of the platform session.
*/
while (cap.valid()) {
/*
* Keep PCI devices in natural bus order. Otherwise on a Lenovo
* ThinkCentre M57p, the system locks up when the UHCI
* controller BIOS handoff (disabling bit 4 in the LEGSUP
* register) for the controller with PCI BDF 00:1d:2 is
* attempted before the handoff for the controller with BDF
* 00:1a:0.
*/
_pci_caps.append(new (Lx::Malloc::mem()) Element(cap));
/* try next one. Upgrade session quota on demand.*/
Lx::pci()->with_upgrade([&] () {
cap = Lx::pci()->next_device(cap); });
}
}
template <typename FUNC>
void for_each_pci_device(FUNC const &func)
{
for (Element *e = _pci_caps.first(); e; e = e->next())
func(e->cap);
}
};
Pci_dev_list *pci_dev_list()
{
static Pci_dev_list _list;
return &_list;
}
extern "C" int pci_register_driver(struct pci_driver *driver)
{
driver->driver.name = driver->name;
pci_device_id const *id_table = driver->id_table;
if (!id_table)
return -ENODEV;
using namespace Genode;
bool found = false;
auto lamda = [&] (Platform::Device_capability cap) {
Platform::Device_client client(cap);
/* request device ID from platform driver */
unsigned const class_code = client.class_code();
/* look if we find the device ID in the driver's 'id_table' */
pci_device_id const *matching_id = nullptr;
for (pci_device_id const *id = id_table; id->device; id++) {
lx_log(DEBUG_PCI,"idclass: %x idclassm: %x devclass %x", id->class_,
id->class_mask, class_code);
/* check for drivers that support any device for a given class */
if (id->device != (unsigned)PCI_ANY_ID || !id->class_mask)
continue;
if ((id->class_ & id->class_mask) == (class_code & id->class_mask)) {
matching_id = id;
break;
}
}
/* skip device that is not handled by driver */
if (!matching_id)
return false;
/* create 'pci_dev' struct for matching device */
Lx::Pci_dev *pci_dev = new (Lx::Malloc::mem()) Lx::Pci_dev(cap);
/* enable ioremap to work */
Lx::pci_dev_registry()->insert(pci_dev);
/* register driver at the 'pci_dev' struct */
pci_dev->dev.driver = &driver->driver;
/*
* This quirk handles device handoff from BIOS, since the BIOS may still
* access the USB controller after bootup. For this the ext cap register of
* the PCI config space is checked
*/
if (Lx_kit::env().config_rom().xml().attribute_value("bios_handoff", true))
__pci_fixup_quirk_usb_early_handoff(pci_dev);
/* call probe function of the Linux driver */
if (driver->probe(pci_dev, matching_id)) {
/* if the probing failed, revert the creation of 'pci_dev' */
pci_dev_put(pci_dev);
return false;
}
found = true;
/* multiple device support continue */
return true;
};
pci_dev_list()->for_each_pci_device(lamda);
return found ? 0 : -ENODEV;
}
/***********************
** linux/interrupt.h **
***********************/
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{
for (Lx::Pci_dev *pci_dev = Lx::pci_dev_registry()->first(); pci_dev; pci_dev = pci_dev->next())
if (pci_dev->irq == irq) {
Genode::Irq_session_client is(pci_dev->client().irq(0));
if ((is.info().type != Genode::Irq_session::Info::MSI)
&& !flags) return 1;
Lx::Irq::irq().request_irq(is.rpc_cap(), irq, handler, dev);
return 0;
}
return -ENODEV;
}
/*********************************
** Platform backend alloc init **
*********************************/
void backend_alloc_init(Genode::Env &env, Genode::Ram_allocator &ram,
Genode::Allocator &alloc)
{
Lx::pci_init(env, ram, alloc);
}
extern "C" void module_ehci_hcd_init();
extern "C" void module_ehci_pci_init();
extern "C" void module_ohci_hcd_mod_init();
extern "C" void module_ohci_pci_init();
extern "C" void module_uhci_hcd_init();
extern "C" void module_xhci_hcd_init();
extern "C" void module_xhci_pci_init();
void platform_hcd_init(Genode::Env &, Services *s)
{
if (s->xhci) {
module_xhci_hcd_init();
module_xhci_pci_init();
}
if (s->ehci) {
/* ehci_hcd should always be loaded before uhci_hcd and ohci_hcd, not after */
module_ehci_hcd_init();
module_ehci_pci_init();
}
if (s->ohci) {
module_ohci_hcd_mod_init();
module_ohci_pci_init();
}
if (s->uhci) {
module_uhci_hcd_init();
}
}

View File

@ -1,25 +0,0 @@
include $(REP_DIR)/src/drivers/usb_host/target.inc
TARGET = legacy_pc_usb_host_drv
INC_DIR += $(REP_DIR)/src_drivers/usb_host/spec/x86
INC_DIR += $(REP_DIR)/src/include/spec/x86
SRC_C += usb/core/hcd-pci.c
SRC_C += usb/host/ehci-pci.c
SRC_C += usb/host/ohci-hcd.c
SRC_C += usb/host/ohci-pci.c
SRC_C += usb/host/pci-quirks.c
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 += spec/x86/platform.cc
CC_OPT += -DCONFIG_PCI=1
CC_OPT += -DCONFIG_USB_PCI=1
CC_OPT += -DCONFIG_USB_EHCI_HCD=1
CC_OPT += -DCONFIG_USB_OHCI_HCD=1
CC_OPT += -DCONFIG_USB_UHCI_HCD=1
CC_OPT += -DCONFIG_USB_XHCI_HCD=1

View File

@ -1,4 +0,0 @@
include $(REP_DIR)/src/drivers/usb_host/spec/x86/target.inc
REQUIRES = x86_32
INC_DIR += $(REP_DIR)/src/include/spec/x86_32

View File

@ -1,4 +0,0 @@
include $(REP_DIR)/src/drivers/usb_host/spec/x86/target.inc
REQUIRES = x86_64
INC_DIR += $(REP_DIR)/src/include/spec/x86_64

View File

@ -1,41 +0,0 @@
/*
* \brief Implementation of linux/io.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Linux kit includes */
#include <legacy/lx_kit/pci_dev_registry.h>
#include <legacy/lx_kit/mapped_io_mem_range.h>
void *ioremap(phys_addr_t phys_addr, unsigned long size)
{
return Lx::ioremap(phys_addr, size, Genode::UNCACHED);
}
void *ioremap_wc(resource_size_t phys_addr, unsigned long size)
{
return Lx::ioremap(phys_addr, size, Genode::WRITE_COMBINED);
}
/**********************
** asm-generic/io.h **
**********************/
void outb(u8 value, u32 port) { Lx::pci_dev_registry()->io_write<u8> (port, value); }
void outw(u16 value, u32 port) { Lx::pci_dev_registry()->io_write<u16>(port, value); }
void outl(u32 value, u32 port) { Lx::pci_dev_registry()->io_write<u32>(port, value); }
u8 inb(u32 port) { return Lx::pci_dev_registry()->io_read<u8> (port); }
u16 inw(u32 port) { return Lx::pci_dev_registry()->io_read<u16>(port); }
u32 inl(u32 port) { return Lx::pci_dev_registry()->io_read<u32>(port); }

View File

@ -1,83 +0,0 @@
/*
* \brief Implementation of linux/pci.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Linux kit includes */
#include <legacy/lx_kit/env.h>
#include <legacy/lx_kit/pci_dev_registry.h>
#include <legacy/lx_kit/mapped_io_mem_range.h>
#include <legacy/lx_emul/impl/pci_resource.h>
extern "C" int pci_register_driver(struct pci_driver *driver)
{
driver->driver.name = driver->name;
pci_device_id const *id_table = driver->id_table;
if (!id_table)
return -ENODEV;
using namespace Genode;
Lx::Pci_dev *pci_dev = nullptr;
auto lamda = [&] (Platform::Device_capability cap) {
Platform::Device_client client(cap);
/* request device ID from platform driver */
unsigned const device_id = client.device_id();
unsigned const subdevice_id = client.config_read(0x2e,
Platform::Device::ACCESS_16BIT);
/* look if we find the device ID in the driver's 'id_table' */
pci_device_id const *matching_id = nullptr;
for (pci_device_id const *id = id_table; id->device; id++) {
if ((id->device == device_id) &&
(id->subdevice == (unsigned int)PCI_ANY_ID ||
id->subdevice == subdevice_id)) {
matching_id = id;
break;
}
}
/* skip device that is not handled by driver */
if (!matching_id)
return false;
/* create 'pci_dev' struct for matching device */
pci_dev = new (&Lx_kit::env().heap()) Lx::Pci_dev(cap);
/* enable ioremap to work */
Lx::pci_dev_registry()->insert(pci_dev);
/* register driver at the 'pci_dev' struct */
pci_dev->dev.driver = &driver->driver;
/* call probe function of the Linux driver */
if (driver->probe(pci_dev, matching_id)) {
/* if the probing failed, revert the creation of 'pci_dev' */
pci_dev_put(pci_dev);
pci_dev = nullptr;
return false;
}
/* aquire the device, stop iterating */
return true;
};
Lx::for_each_pci_device(lamda);
return pci_dev ? 0 : -ENODEV;
}

View File

@ -1,136 +0,0 @@
/*
* \brief Implementation of linux/pci.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Linux kit includes */
#include <legacy/lx_kit/pci_dev_registry.h>
#include <legacy/lx_kit/mapped_io_mem_range.h>
extern "C" size_t pci_resource_start(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].start;
}
extern "C" size_t pci_resource_end(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].end;
}
extern "C" size_t pci_resource_len(struct pci_dev *dev, unsigned bar)
{
size_t start = pci_resource_start(dev, bar);
if (!start)
return 0;
return (dev->resource[bar].end - start) + 1;
}
extern "C" void *pci_ioremap_bar(struct pci_dev *dev, int bar)
{
using namespace Genode;
if (bar >= DEVICE_COUNT_RESOURCE || bar < 0)
return 0;
return Lx::ioremap(pci_resource_start(dev, bar),
pci_resource_len(dev, bar),
Genode::UNCACHED);
}
extern "C" unsigned int pci_resource_flags(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].flags;
}
extern "C" int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int, int where, u8 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_read_config_word(struct pci_bus *bus, unsigned int, int where, u16 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int, int where, u32 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int, int where, u8 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" int pci_bus_write_config_word(struct pci_bus *bus, unsigned int, int where, u16 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int, int where, u32 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" const char *pci_name(const struct pci_dev *pdev)
{
/* simply return driver name */
return "dummy";
}
extern "C" int pcie_capability_read_word(struct pci_dev *pdev, int pos, u16 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)pdev->bus;
switch (pos) {
case PCI_EXP_LNKCTL:
dev->config_read(pdev->pcie_cap + PCI_EXP_LNKCTL, val);
return 0;
break;
default:
break;
}
return 1;
}

View File

@ -1,259 +0,0 @@
/*
* \brief Emulate 'pci_dev' structure
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LX_KIT__INTERNAL__PCI_DEV_H_
#define _LX_KIT__INTERNAL__PCI_DEV_H_
/* Genode includes */
#include <base/object_pool.h>
#include <legacy/x86/platform_session/connection.h>
#include <legacy/x86/platform_device/client.h>
#include <io_mem_session/connection.h>
#include <base/attached_dataspace.h>
#include <util/retry.h>
/* Linux emulation environment includes */
#include <legacy/lx_kit/internal/list.h>
#include <legacy/lx_kit/internal/io_port.h>
namespace Lx {
class Pci_dev;
/**
* Return singleton 'Platform::Connection'
*
* Implementation must be provided by the driver.
*/
Platform::Connection *pci();
template <typename FUNC>
static inline void for_each_pci_device(FUNC const &func,
unsigned const device_class = 0,
unsigned const class_mask = 0);
}
class Lx::Pci_dev : public pci_dev, public Lx_kit::List<Pci_dev>::Element
{
private:
bool const verbose = true;
Platform::Device_client _client;
Io_port _io_port;
Genode::Io_mem_session_capability _io_mem[DEVICE_COUNT_RESOURCE];
/* offset used in PCI config space */
enum Pci_config { IRQ = 0x3c, REV = 0x8, CMD = 0x4,
STATUS = 0x4, CAP = 0x34 };
enum Pci_cap { CAP_LIST = 0x10, CAP_EXP = 0x10,
CAP_EXP_FLAGS = 0x2, CAP_EXP_DEVCAP = 0x4 };
template <typename T>
Platform::Device::Access_size _access_size(T t)
{
switch (sizeof(T))
{
case 1:
return Platform::Device::ACCESS_8BIT;
case 2:
return Platform::Device::ACCESS_16BIT;
default:
return Platform::Device::ACCESS_32BIT;
}
}
static unsigned _virq_num()
{
static unsigned instance = 128;
return ++instance;
}
public:
/**
* Constructor
*/
Pci_dev(Platform::Device_capability cap)
:
_client(cap)
{
using namespace Platform;
Genode::memset(static_cast<pci_dev *>(this), 0, sizeof(pci_dev));
this->vendor = _client.vendor_id();
this->device = _client.device_id();
this->class_ = _client.class_code();
this->revision = _client.config_read(REV, Device::ACCESS_8BIT);
/* dummy dma mask used to mark device as DMA capable */
this->dev._dma_mask_buf = ~(u64)0;
this->dev.dma_mask = &this->dev._dma_mask_buf;
this->dev.coherent_dma_mask = ~0;
enum { USB_SUB_CLASS = 0xc0300 };
/*
* For USB we generate virtual IRQ numbers so we can identify the device
* later on
*/
if ((class_ & ~0xffU) == USB_SUB_CLASS)
this->irq = _virq_num();
else
/* read interrupt line */
this->irq = _client.config_read(IRQ, Device::ACCESS_8BIT);
/* hide ourselfs in bus structure */
this->bus = (struct pci_bus *)this;
/* setup resources */
bool io = false;
bool mem = false;
for (int i = 0; i < Device::NUM_RESOURCES; i++) {
Device::Resource res = _client.resource(i);
if (res.type() == Device::Resource::INVALID)
continue;
this->resource[i].start = res.base();
this->resource[i].end = res.base() + res.size() - 1;
unsigned flags = 0;
if (res.type() == Device::Resource::IO) flags |= IORESOURCE_IO;
if (res.type() == Device::Resource::MEMORY) flags |= IORESOURCE_MEM;
this->resource[i].flags = flags;
/* request port I/O session */
if (res.type() == Device::Resource::IO) {
uint8_t const virt_bar = _client.phys_bar_to_virt(i);
_io_port.session(res.base(), res.size(), _client.io_port(virt_bar));
io = true;
}
if (res.type() == Device::Resource::MEMORY)
mem = true;
}
/* enable bus master, memory and io bits */
uint16_t cmd = _client.config_read(CMD, Device::ACCESS_16BIT);
cmd |= io ? 0x1 : 0;
cmd |= mem ? 0x2 : 0;
/* enable bus master */
cmd |= 0x4;
config_write(CMD, cmd);
/* get pci express capability */
this->pcie_cap = 0;
uint16_t status = _client.config_read(STATUS, Device::ACCESS_32BIT) >> 16;
if (status & CAP_LIST) {
uint8_t offset = _client.config_read(CAP, Device::ACCESS_8BIT);
while (offset != 0x00) {
uint8_t value = _client.config_read(offset, Device::ACCESS_8BIT);
if (value == CAP_EXP)
this->pcie_cap = offset;
offset = _client.config_read(offset + 1, Device::ACCESS_8BIT);
}
}
if (this->pcie_cap) {
uint16_t reg_val = _client.config_read(this->pcie_cap, Device::ACCESS_16BIT);
this->pcie_flags_reg = reg_val;
}
}
/**
* Read/write data from/to config space
*/
template <typename T>
void config_read(unsigned int devfn, T *val)
{
*val = _client.config_read(devfn, _access_size(*val));
}
template <typename T>
void config_write(unsigned int devfn, T val)
{
pci()->with_upgrade([&] () {
_client.config_write(devfn, val, _access_size(val)); });
}
Platform::Device &client() { return _client; }
Io_port &io_port() { return _io_port; }
Genode::Io_mem_session_capability io_mem(unsigned bar, Genode::Cache cache)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return Genode::Io_mem_session_capability();
if (!_io_mem[bar].valid())
_io_mem[bar] = _client.io_mem(_client.phys_bar_to_virt(bar),
cache);
return _io_mem[bar];
}
};
/**
* Call functor for each available physical PCI device
*
* The functor is called with the device capability as argument. If
* returns true if we can stop iterating. In this case, the device
* is expected to be acquired by the driver. All other devices are
* released at the platform driver.
*/
template <typename FUNC>
void Lx::for_each_pci_device(FUNC const &func, unsigned const device_class,
unsigned const class_mask)
{
/*
* Obtain first device, the operation may exceed the session quota.
* So we use the 'retry' mechanism.
*/
Platform::Device_capability cap =
Lx::pci()->with_upgrade([&] () {
return Lx::pci()->first_device(device_class, class_mask); });
/*
* Iterate over the devices of the platform session.
*/
while (cap.valid()) {
/*
* Call functor, stop iterating depending on its return value.
*/
if (func(cap))
break;
/*
* Release current device and try next one. Upgrade session
* quota on demand.
*/
Platform::Device_capability next_cap =
Lx::pci()->with_upgrade([&] () {
return pci()->next_device(cap, device_class, class_mask); });
Lx::pci()->release_device(cap);
cap = next_cap;
}
}
#endif /* _LX_KIT__INTERNAL__PCI_DEV_H_ */

View File

@ -1,157 +0,0 @@
/*
* \brief Registry of PCI devices
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LX_KIT__PCI_DEV_REGISTRY_H_
#define _LX_KIT__PCI_DEV_REGISTRY_H_
/* Linux emulation environment includes */
#include <legacy/lx_kit/pci.h>
#include <legacy/lx_kit/internal/pci_dev.h>
#include <io_port_session/connection.h>
namespace Lx {
class Pci_dev_registry;
/**
* Return singleton 'Pci_dev_registry' object
*
* Implementation must be provided by the driver.
*/
Pci_dev_registry *pci_dev_registry(Genode::Env *env = nullptr);
}
class Lx::Pci_dev_registry
{
private:
Lx_kit::List<Pci_dev> _devs;
Genode::Env &_env;
public:
Pci_dev_registry(Genode::Env &env) : _env(env) { }
void insert(Pci_dev *pci_dev)
{
/*
* Keep PCI devices in natural bus order. Otherwise on a Lenovo
* ThinkCentre M57p, the system locks up when the UHCI controller
* BIOS handoff (disabling bit 4 in the LEGSUP register) for the
* controller with PCI BDF 00:1d:2 is attempted before the handoff
* for the controller with BDF 00:1a:0.
*/
_devs.append(pci_dev);
}
void remove(Pci_dev *pci_dev)
{
_devs.remove(pci_dev);
}
Pci_dev* first() { return _devs.first(); }
Genode::Io_mem_dataspace_capability io_mem(Genode::addr_t phys,
Genode::Cache cache,
Genode::size_t size,
Genode::addr_t &offset)
{
enum { PCI_ROM_RESOURCE = 6 };
for (Pci_dev *d = _devs.first(); d; d = d->next()) {
unsigned bar = 0;
for (; bar < PCI_ROM_RESOURCE; bar++) {
if ((pci_resource_flags(d, bar) & IORESOURCE_MEM) &&
(pci_resource_start(d, bar) <= phys) &&
(pci_resource_end(d, bar) >= (phys+size-1)))
break;
}
if (bar >= PCI_ROM_RESOURCE)
continue;
/* offset from the beginning of the PCI resource */
offset = phys - pci_resource_start(d, bar);
Genode::Io_mem_session_capability io_mem_cap =
d->io_mem(bar, cache);
return Genode::Io_mem_session_client(io_mem_cap).dataspace();
}
Genode::error("device using I/O memory of address ",
Genode::Hex(phys), " is unknown");
return Genode::Io_mem_dataspace_capability();
}
template <typename T>
T io_read(unsigned port)
{
/* try I/O access on all PCI devices */
for (Pci_dev *d = _devs.first(); d; d = d->next()) {
T value = 0;
if (d->io_port().in<T>(port, &value))
return value;
}
try {
Genode::Io_port_connection iox(_env, port, sizeof(T));
switch (sizeof(T)) {
case 1:
return iox.inb(port);
case 2:
return iox.inw(port);
case 4:
return iox.inl(port);
}
} catch (...) {
Genode::error("unknown exception io_read");
}
Genode::warning("I/O port(", port, ") read failed");
return (T)~0U;
}
template <typename T>
void io_write(unsigned port, T value)
{
/* try I/O access on all PCI devices, return on first success */
for (Pci_dev *d = _devs.first(); d; d = d->next()) {
if (d->io_port().out<T>(port, value))
return;
}
try {
Genode::Io_port_connection iox(_env, port, sizeof(T));
switch (sizeof(T)) {
case 1:
iox.outb(port, value);
return;
case 2:
iox.outw(port, value);
return;
case 4:
iox.outl(port, value);
return;
}
} catch (...) {
Genode::error("unknown exception io_write");
}
Genode::warning("I/O port(", port, ") write failed");
}
};
#endif /* _LX_KIT__PCI_DEV_REGISTRY_H_ */

View File

@ -1,172 +0,0 @@
/*
* \brief Representation of a locally-mapped MMIO range
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/attached_dataspace.h>
#include <io_mem_session/io_mem_session.h>
#include <rm_session/connection.h>
#include <region_map/client.h>
/* Linux emulation environment */
#include <lx_emul.h>
/* Linux emulation environment includes */
#include <legacy/lx_kit/env.h>
#include <legacy/lx_kit/internal/list.h>
#include <legacy/lx_kit/mapped_io_mem_range.h>
#include <legacy/lx_kit/pci_dev_registry.h>
#include <legacy/lx_kit/types.h>
namespace Lx_kit { class Mapped_io_mem_range; }
/**
* Representation of a locally-mapped MMIO range
*
* This class is supposed to be a private utility to support 'ioremap'.
*/
class Lx_kit::Mapped_io_mem_range : public Lx_kit::List<Mapped_io_mem_range>::Element
{
private:
Genode::size_t const _size;
Genode::addr_t const _phys;
Genode::Region_map_client _region_map;
Genode::Attached_dataspace _ds;
Genode::addr_t const _virt;
public:
Mapped_io_mem_range(Genode::Env &env,
Genode::Rm_connection &rm,
Genode::addr_t phys, Genode::size_t size,
Genode::Io_mem_dataspace_capability ds_cap,
Genode::addr_t offset)
:
_size(size),
_phys(phys),
_region_map(rm.create(size)),
_ds(env.rm(), _region_map.dataspace()),
_virt((Genode::addr_t)_ds.local_addr<void>() | (phys &0xfffUL))
{
_region_map.attach_at(ds_cap, 0, size, offset);
}
Genode::addr_t phys() const { return _phys; }
Genode::addr_t virt() const { return _virt; }
Genode::Dataspace_capability cap() const { return _ds.cap(); }
/**
* Return true if the mapped range contains the specified sub range
*/
bool phys_range(Genode::addr_t phys, Genode::size_t size) const
{
return (phys >= _phys) && (phys + size - 1 <= _phys + _size - 1);
}
/**
* Return true if the mapped range contains the specified sub range
*/
bool virt_range(Genode::addr_t virt, Genode::size_t size) const
{
return (virt >= _virt) && (virt + size - 1 <= _virt + _size - 1);
}
};
static Lx_kit::List<Lx_kit::Mapped_io_mem_range> ranges;
/************************************************
** Lx_kit::Mapped_io_mem_range implementation **
************************************************/
static Genode::Constructible<Genode::Rm_connection> _global_rm;
void *Lx::ioremap(addr_t phys_addr, unsigned long size, Genode::Cache cache)
{
using namespace Genode;
/* search for the requested region within the already mapped ranges */
for (Lx_kit::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
if (r->phys_range(phys_addr, size)) {
void * const virt = (void *)(r->virt() + phys_addr - r->phys());
log("ioremap: return sub range phys ", Hex(phys_addr), " "
"(size ", size, ") to virt ", virt);
return virt;
}
}
addr_t offset = 0;
Io_mem_dataspace_capability ds_cap =
Lx::pci_dev_registry()->io_mem(phys_addr, cache, size, offset);
if (!ds_cap.valid()) {
error("failed to request I/O memory: ",
Hex_range<addr_t>(phys_addr, size));
return nullptr;
}
if (!_global_rm.constructed()) {
_global_rm.construct(Lx_kit::env().env());
}
Lx_kit::Mapped_io_mem_range *io_mem = nullptr;
retry<Genode::Out_of_ram>(
[&] () {
io_mem = new (&Lx_kit::env().heap())
Lx_kit::Mapped_io_mem_range(Lx_kit::env().env(), *_global_rm,
phys_addr, size, ds_cap, offset);
},
[&] () {
_global_rm->upgrade_ram(16384);
},
10
);
ranges.insert(io_mem);
log("ioremap: mapped phys ", Hex(phys_addr), " (size ", size, ") "
"to virt ", Hex(io_mem->virt()));
return (void *)io_mem->virt();
}
void Lx::iounmap(volatile void * virt)
{
using namespace Genode;
/* search for the requested region within the already mapped ranges */
for (Lx_kit::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
if (r->virt() == (addr_t)virt) {
ranges.remove(r);
destroy(&Lx_kit::env().heap(), r);
return;
}
}
}
Genode::Dataspace_capability
Lx::ioremap_lookup(Genode::addr_t virt_addr, Genode::size_t size)
{
/* search for the requested region within the already mapped ranges */
for (Lx_kit::Mapped_io_mem_range *r = ranges.first(); r; r = r->next())
if (r->virt_range(virt_addr, size))
return r->cap();
return Genode::Dataspace_capability();
}

View File

@ -1,181 +0,0 @@
/*
* \brief Backend allocator for DMA-capable memory
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/object_pool.h>
#include <base/env.h>
/* XXX only because of struct pci_dev */
#include <lx_emul.h>
/* Linux emulation environment includes */
#include <legacy/lx_kit/backend_alloc.h>
#include <legacy/lx_kit/pci_dev_registry.h>
namespace Lx_kit {
struct Memory_object_base;
struct Ram_object;
struct Dma_object;
Genode::Object_pool<Memory_object_base> memory_pool;
};
struct Lx_kit::Memory_object_base : Genode::Object_pool<Memory_object_base>::Entry
{
Memory_object_base(Genode::Ram_dataspace_capability cap)
: Genode::Object_pool<Memory_object_base>::Entry(cap) {}
virtual ~Memory_object_base() {};
virtual void free() = 0;
virtual Genode::addr_t dma_addr() const { return 0; }
Genode::Ram_dataspace_capability ram_cap()
{
using namespace Genode;
return reinterpret_cap_cast<Ram_dataspace>(cap());
}
};
struct Lx_kit::Ram_object : Memory_object_base
{
Genode::Ram_allocator &_ram;
Ram_object(Genode::Ram_allocator &ram,
Genode::Ram_dataspace_capability cap)
: Memory_object_base(cap), _ram(ram) {}
void free() { _ram.free(ram_cap()); }
};
struct Lx_kit::Dma_object : Memory_object_base
{
Platform::Connection &_pci;
Genode::addr_t const _dma_addr = _pci.dma_addr(ram_cap());
Dma_object(Platform::Connection &pci,
Genode::Ram_dataspace_capability cap)
: Memory_object_base(cap), _pci(pci) { }
void free() { _pci.free_dma_buffer(ram_cap()); }
Genode::addr_t dma_addr() const override { return _dma_addr; }
};
/********************
** Pci singletons **
********************/
static Genode::Constructible<Platform::Connection> _global_pci;
static Genode::Allocator *_global_md_alloc;
static Genode::Ram_allocator *_global_ram;
void Lx::pci_init(Genode::Env &env, Genode::Ram_allocator &ram,
Genode::Allocator &md_alloc)
{
_global_pci.construct(env);
_global_ram = &ram;
_global_md_alloc = &md_alloc;
Lx::pci_dev_registry(&env);
}
Platform::Connection *Lx::pci()
{
return &*_global_pci;
}
Lx::Pci_dev_registry *Lx::pci_dev_registry(Genode::Env *env)
{
static Lx::Pci_dev_registry _pci_dev_registry(*env);
return &_pci_dev_registry;
}
/*********************************
** Lx::Backend_alloc interface **
*********************************/
Genode::Ram_dataspace_capability
Lx::backend_alloc(Genode::addr_t size, Genode::Cache cache)
{
using namespace Genode;
using namespace Lx_kit;
Memory_object_base *obj;
Genode::Ram_dataspace_capability cap;
if (cache == CACHED) {
cap = _global_ram->alloc(size);
obj = new (_global_md_alloc) Ram_object(*_global_ram, cap);
} else {
Genode::size_t donate = size;
cap = retry<Genode::Out_of_ram>(
[&] () {
return retry<Genode::Out_of_caps>(
[&] () { return _global_pci->alloc_dma_buffer(size, UNCACHED); },
[&] () { _global_pci->upgrade_caps(2); });
},
[&] () {
_global_pci->upgrade_ram(donate);
donate = donate * 2 > size ? 4096 : donate * 2;
});
obj = new (_global_md_alloc) Dma_object(*_global_pci, cap);
}
memory_pool.insert(obj);
return cap;
}
void Lx::backend_free(Genode::Ram_dataspace_capability cap)
{
using namespace Genode;
using namespace Lx_kit;
Memory_object_base *object;
memory_pool.apply(cap, [&] (Memory_object_base *obj) {
object = obj;
if (!object) { return; }
object->free();
memory_pool.remove(object);
});
destroy(_global_md_alloc, object);
}
Genode::addr_t Lx::backend_dma_addr(Genode::Ram_dataspace_capability cap)
{
using namespace Genode;
using namespace Lx_kit;
addr_t result = 0;
memory_pool.apply(cap, [&] (Dma_object *obj_ptr) {
if (obj_ptr)
result = obj_ptr->dma_addr(); });
return result;
}