pci: assign device during pci config cmd write

Issue #1216
This commit is contained in:
Alexander Boettcher 2015-05-05 18:43:58 +02:00 committed by Christian Helmuth
parent 3eed3ad329
commit 2ceecd44f9
8 changed files with 62 additions and 76 deletions

View File

@ -121,15 +121,6 @@ class Pci_driver : public Bsd::Bus_driver
Genode::Ram_dataspace_capability _alloc_dma_memory(Genode::size_t size)
{
try {
/* trigger that the device gets assigned to this driver (needed by IOMMUs) */
for (unsigned i = 0; i < 2; i++)
try {
_pci.config_extended(_cap);
break;
} catch (Pci::Device::Quota_exceeded) {
Genode::env()->parent()->upgrade(_pci.cap(), "ram_quota=4096");
}
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%zu", size);
Genode::env()->parent()->upgrade(_pci.cap(), buf);

View File

@ -200,16 +200,6 @@ struct Pci_driver
try {
using namespace Genode;
/* trigger that the device gets assigned to this driver */
for (unsigned i = 0; i < 2; i++) {
try {
_pci.config_extended(_cap);
break;
} catch (Pci::Device::Quota_exceeded) {
Genode::env()->parent()->upgrade(_pci.cap(), "ram_quota=4096");
}
}
/* transfer quota to pci driver, otherwise it will give us a exception */
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%zd", size);

View File

@ -313,9 +313,6 @@ int pci_register_driver(struct pci_driver *drv)
Pci_driver *pci_drv = 0;
try {
/* trigger that the device get be assigned to the usb driver */
pci.config_extended(cap);
/* probe device */
pci_drv = new (env()->heap()) Pci_driver(drv, cap, id);
pci.on_destruction(Pci::Connection::KEEP_OPEN);

View File

@ -295,9 +295,6 @@ extern "C" int pci_register_driver(struct pci_driver *drv)
try {
pci_device_cap = cap;
/* trigger that the device get be assigned to the wifi driver */
pci()->config_extended(cap);
/* probe device */
pci_drv = new (env()->heap()) Pci_driver(drv, cap, id);
pci()->on_destruction(Pci::Connection::KEEP_OPEN);

View File

@ -36,6 +36,7 @@ class Ahci_device : public Ahci_device_base
CLASS_MASK = 0xffff00U,
AHCI_BASE_ID = 0x5, /* resource id of AHCI base addr <BAR 5> */
AHCI_INTR_OFF = 0x3c, /* offset of interrupt information in config space */
PCI_CFG_CMD_REG = 0x4,
};
::Pci::Connection &_pci;
@ -137,6 +138,10 @@ class Ahci_device : public Ahci_device_base
" %08x)\n", pci_device->vendor_id(),
pci_device->device_id(), pci_device->class_code());
/* enable Bus Master, Memory Space, I/O Space access by dev */
pci_device->config_write(PCI_CFG_CMD_REG, 0x7,
::Pci::Device::ACCESS_16BIT);
/* read and map base address of AHCI controller */
Pci::Device::Resource resource = pci_device->resource(AHCI_BASE_ID);
@ -173,14 +178,6 @@ class Ahci_device : public Ahci_device_base
device->_irq->ack_irq();
device->_pci_device = pci_device;
/* trigger assignment of pci device to the ahci driver */
try {
pci.config_extended(device_cap);
} catch (Pci::Device::Quota_exceeded) {
Genode::env()->parent()->upgrade(pci.cap(), "ram_quota=4096");
pci.config_extended(device_cap);
}
/* get device ready */
device->_init(pci_device);

View File

@ -60,3 +60,39 @@ Genode::Io_mem_session_capability Pci::Device_component::io_mem(Genode::uint8_t
return Genode::Io_mem_session_capability();
}
void Pci::Device_component::config_write(unsigned char address, unsigned value,
Access_size size)
{
/* white list of ports which we permit to write */
switch (address) {
case 0x40 ... 0xff: /* allow access to device-specific registers */
break;
case PCI_CMD_REG: /* COMMAND register - first byte */
if (size == Access_size::ACCESS_16BIT)
break;
case PCI_CMD_REG + 1: /* COMMAND register - second byte */
case 0xd: /* Latency timer */
if (size == Access_size::ACCESS_8BIT)
break;
case PCI_IRQ_LINE:
/* permitted up to now solely for acpi driver */
if (address == PCI_IRQ_LINE && _rewrite_irq_line &&
size == Access_size::ACCESS_8BIT)
break;
default:
PWRN("%x:%x:%x write access to address=%x value=0x%x "
" size=0x%x got dropped", _device_config.bus_number(),
_device_config.device_number(),
_device_config.function_number(),
address, value, size);
return;
}
/* assign device to device_pd */
if (address == PCI_CMD_REG && value & PCI_CMD_DMA && _session)
_session->assign_device(this);
_device_config.write(&_config_access, address, value, size);
}

View File

@ -543,16 +543,32 @@ namespace Pci {
_device_list.remove(device);
_ep->dissolve(device);
Genode::Io_mem_connection * io_mem = device->get_config_space();
if (io_mem)
destroy(_md_alloc, io_mem);
if (device->config().valid())
destroy(_device_slab, device);
else
destroy(_md_alloc, device);
}
Genode::Io_mem_dataspace_capability assign_device(Device_component * device)
{
using namespace Genode;
if (!device || !device->get_config_space().valid())
return Io_mem_dataspace_capability();
Io_mem_dataspace_capability io_mem = device->get_config_space();
if (_child)
_child->assign_pci(io_mem);
/*
* By now forbid usage of extended pci config space dataspace,
* - until required.
*/
// return io_mem;
return Io_mem_dataspace_capability();
}
Genode::Io_mem_dataspace_capability config_extended(Device_capability device_cap)
{
using namespace Genode;
@ -560,33 +576,7 @@ namespace Pci {
Object_pool<Device_component>::Guard
device(_ep->lookup_and_lock(device_cap));
if (!device || device->config_space() == ~0UL)
return Io_mem_dataspace_capability();
Io_mem_connection * io_mem = device->get_config_space();
if (io_mem)
return io_mem->dataspace();
try {
io_mem = new (_md_alloc) Io_mem_connection(device->config_space(),
0x1000);
} catch (Genode::Allocator::Out_of_memory) {
throw Device::Quota_exceeded();
} catch (Parent::Service_denied) {
return Io_mem_dataspace_capability();
}
device->set_config_space(io_mem);
if (_child)
_child->assign_pci(io_mem->dataspace());
/*
* By now forbid usage of extended pci config space dataspace,
* - until required.
*/
// return io_mem->dataspace();
return Io_mem_dataspace_capability();
return assign_device(device);
}
/**

View File

@ -126,18 +126,6 @@ namespace Dde_kit {
Ram_dataspace_capability alloc_dma_buffer(Pci::Connection &pci_drv,
size_t size)
{
/* trigger that the device gets assigned to this driver */
for (unsigned i = 0; i < 2; i++) {
try {
pci_drv.config_extended(_device);
break;
} catch (Pci::Device::Quota_exceeded) {
if (i == 1)
return Ram_dataspace_capability();
Genode::env()->parent()->upgrade(pci_drv.cap(), "ram_quota=4096");
}
}
for (unsigned i = 0; i < 2; i++) {
try {
return pci_drv.alloc_dma_buffer(size);