pci: export BAR indices, sub-vendor, -product, rev

The pci_decode has to extract the additional fields from the PCI configuration
space. The platform driver again has to parse and forward the knowledge too.
The PCI BAR indices are exported when info="yes" is set in the policy node for
the corresponding session.

Fix genodelabs/genode#4577
This commit is contained in:
Stefan Kalkowski 2022-07-25 14:04:25 +02:00 committed by Christian Helmuth
parent 5bf3e72d37
commit 2cc6c1adef
9 changed files with 142 additions and 79 deletions

View File

@ -64,6 +64,7 @@ struct Pci::Config : Genode::Mmio
struct Class_code_rev_id : Register<0x8, 32>
{
struct Revision : Bitfield<0, 8> {};
struct Class_code : Bitfield<8, 24> {};
};
@ -522,10 +523,10 @@ struct Pci::Config : Genode::Mmio
if (!reg0.valid())
continue;
if (reg0.memory()) {
memory(reg0.addr(), reg0.size(), i);
if (reg0.bit64()) i++;
memory(reg0.addr(), reg0.size());
} else
io(reg0.addr(), reg0.size());
io(reg0.addr(), reg0.size(), i);
}
};
};
@ -541,6 +542,9 @@ struct Pci::Config_type0 : Pci::Config
Base_address bar3 { base() + BASE_ADDRESS_0 + 0xc };
Base_address bar4 { base() + BASE_ADDRESS_0 + 0x10 };
Base_address bar5 { base() + BASE_ADDRESS_0 + 0x14 };
struct Subsystem_vendor : Register<0x2c, 16> { };
struct Subsystem_device : Register<0x2e, 16> { };
};

View File

@ -15,6 +15,7 @@
#define __INCLUDE__PCI__TYPES_H__
#include <base/stdint.h>
#include <util/register.h>
#include <util/string.h>
namespace Pci {
@ -41,6 +42,7 @@ namespace Pci {
using vendor_t = Genode::uint16_t;
using device_t = Genode::uint16_t;
using class_t = Genode::uint32_t;
using rev_t = Genode::uint8_t;
}

View File

@ -70,18 +70,12 @@ struct Main
void Main::parse_pci_function(Bdf bdf,
Config & cfg,
addr_t cfg_phys_base,
Xml_generator & generator)
Xml_generator & gen)
{
cfg.scan();
Config::Vendor::access_t vendor = cfg.read<Config::Vendor>();
Config::Device::access_t device = cfg.read<Config::Device>();
Config::Header_type::Type::access_t type =
cfg.read<Config::Header_type::Type>();
Config::Class_code_rev_id::Class_code::access_t dclass =
cfg.read<Config::Class_code_rev_id::Class_code>();
if (type) {
/* check for bridges */
if (cfg.read<Config::Header_type::Type>()) {
for_bridge(bdf.bus, [&] (Bridge & parent) {
Config_type1 bcfg(cfg.base());
new (heap) Bridge(parent.sub_bridges, bdf,
@ -94,34 +88,52 @@ void Main::parse_pci_function(Bdf bdf,
bool msi_x = cfg.msi_x_cap.constructed();
irq_pin_t irq_pin = cfg.read<Config::Irq_pin>();
generator.node("device", [&]
gen.node("device", [&]
{
generator.attribute("name", Bdf::string(bdf));
generator.attribute("type", "pci");
auto string = [&] (uint64_t v) { return String<16>(Hex(v)); };
generator.node("pci-config", [&]
gen.attribute("name", Bdf::string(bdf));
gen.attribute("type", "pci");
gen.node("pci-config", [&]
{
generator.attribute("address", String<16>(Hex(cfg_phys_base)));
generator.attribute("bus", String<16>(Hex(bdf.bus)));
generator.attribute("device", String<16>(Hex(bdf.dev)));
generator.attribute("function", String<16>(Hex(bdf.fn)));
generator.attribute("vendor_id", String<16>(Hex(vendor)));
generator.attribute("device_id", String<16>(Hex(device)));
generator.attribute("class", String<16>(Hex(dclass)));
generator.attribute("bridge", cfg.bridge() ? "yes" : "no");
using C = Config;
using C0 = Config_type0;
using Cc = Config::Class_code_rev_id;
gen.attribute("address", string(cfg_phys_base));
gen.attribute("bus", string(bdf.bus));
gen.attribute("device", string(bdf.dev));
gen.attribute("function", string(bdf.fn));
gen.attribute("vendor_id", string(cfg.read<C::Vendor>()));
gen.attribute("device_id", string(cfg.read<C::Device>()));
gen.attribute("class", string(cfg.read<Cc::Class_code>()));
gen.attribute("revision", string(cfg.read<Cc::Revision>()));
gen.attribute("bridge", cfg.bridge() ? "yes" : "no");
if (!cfg.bridge()) {
C0 cfg0(cfg.base());
gen.attribute("sub_vendor_id",
string(cfg0.read<C0::Subsystem_vendor>()));
gen.attribute("sub_device_id",
string(cfg0.read<C0::Subsystem_device>()));
}
});
cfg.for_each_bar([&] (uint64_t addr, size_t size) {
generator.node("io_mem", [&]
cfg.for_each_bar([&] (uint64_t addr, size_t size, unsigned bar) {
gen.node("io_mem", [&]
{
generator.attribute("address", String<16>(Hex(addr)));
generator.attribute("size", String<16>(Hex(size)));
gen.attribute("pci_bar", bar);
gen.attribute("address", string(addr));
gen.attribute("size", string(size));
});
}, [&] (uint64_t addr, size_t size) {
generator.node("io_port_range", [&]
}, [&] (uint64_t addr, size_t size, unsigned bar) {
gen.node("io_port_range", [&]
{
generator.attribute("address", String<16>(Hex(addr)));
generator.attribute("size", String<16>(Hex(size)));
gen.attribute("pci_bar", bar);
gen.attribute("address", string(addr));
/* on x86 I/O ports can be in range 0-64KB only */
gen.attribute("size", string(size & 0xffff));
});
});
@ -130,17 +142,17 @@ void Main::parse_pci_function(Bdf bdf,
if (!irq_pin)
return;
generator.node("irq", [&]
gen.node("irq", [&]
{
if (msi_capable && msi_x) {
generator.attribute("type", "msi-x");
generator.attribute("number", msi_number++);
gen.attribute("type", "msi-x");
gen.attribute("number", msi_number++);
return;
}
if (msi_capable && msi) {
generator.attribute("type", "msi");
generator.attribute("number", msi_number++);
gen.attribute("type", "msi");
gen.attribute("number", msi_number++);
return;
}
@ -152,9 +164,9 @@ void Main::parse_pci_function(Bdf bdf,
});
irq_override_list.for_each([&] (Irq_override & io) {
io.generate(generator, irq); });
io.generate(gen, irq); });
generator.attribute("number", irq);
gen.attribute("number", irq);
});
});
}

View File

@ -1,4 +1,5 @@
TARGET = pci_decode
LIBS = base
SRC_CC = main.cc
INC_DIR = $(PRG_DIR)
TARGET = pci_decode
REQUIRES = x86
LIBS = base
SRC_CC = main.cc
INC_DIR = $(PRG_DIR)

View File

@ -124,6 +124,8 @@ void Driver::Device::generate(Xml_generator & xml, bool info) const
xml.attribute("used", _owner.valid());
_io_mem_list.for_each([&] (Io_mem const & io_mem) {
xml.node("io_mem", [&] () {
if (io_mem.bar.valid())
xml.attribute("pci_bar", io_mem.bar.number);
if (!info)
return;
xml.attribute("phys_addr", String<16>(Hex(io_mem.range.start)));
@ -137,12 +139,14 @@ void Driver::Device::generate(Xml_generator & xml, bool info) const
xml.attribute("number", irq.number);
});
});
_io_port_range_list.for_each([&] (Io_port_range const & io_port_range) {
_io_port_range_list.for_each([&] (Io_port_range const & iop) {
xml.node("io_port_range", [&] () {
if (iop.bar.valid())
xml.attribute("pci_bar", iop.bar.number);
if (!info)
return;
xml.attribute("phys_addr", String<16>(Hex(io_port_range.addr)));
xml.attribute("size", String<16>(Hex(io_port_range.size)));
xml.attribute("phys_addr", String<16>(Hex(iop.range.addr)));
xml.attribute("size", String<16>(Hex(iop.range.size)));
});
});
_property_list.for_each([&] (Property const & p) {
@ -164,6 +168,9 @@ void Driver::Device::generate(Xml_generator & xml, bool info) const
xml.attribute("vendor_id", String<16>(Hex(pci.vendor_id)));
xml.attribute("device_id", String<16>(Hex(pci.device_id)));
xml.attribute("class", String<16>(Hex(pci.class_code)));
xml.attribute("revision", String<16>(Hex(pci.revision)));
xml.attribute("sub_vendor_id", String<16>(Hex(pci.sub_vendor_id)));
xml.attribute("sub_device_id", String<16>(Hex(pci.sub_device_id)));
});
});
});

View File

@ -53,7 +53,15 @@ class Driver::Device : private List_model<Device>::Element
using Name = Genode::String<64>;
using Type = Genode::String<64>;
using Range = Platform::Device_interface::Range;
struct Pci_bar
{
enum { INVALID = 255 };
unsigned char number { INVALID };
bool valid() const { return number < INVALID; }
};
struct Owner
{
@ -71,9 +79,13 @@ class Driver::Device : private List_model<Device>::Element
struct Io_mem : List_model<Io_mem>::Element
{
Range range;
using Range = Platform::Device_interface::Range;
Io_mem(Range range) : range(range) {}
Pci_bar bar;
Range range;
Io_mem(Pci_bar bar, Range range)
: bar(bar), range(range) {}
};
struct Irq : List_model<Irq>::Element
@ -90,11 +102,13 @@ class Driver::Device : private List_model<Device>::Element
struct Io_port_range : List_model<Io_port_range>::Element
{
uint16_t addr;
uint16_t size;
struct Range { uint16_t addr; uint16_t size; };
Io_port_range(uint16_t addr, uint16_t size)
: addr(addr), size(size) {}
Pci_bar bar;
Range range;
Io_port_range(Pci_bar bar, Range range)
: bar(bar), range(range) {}
};
struct Property : List_model<Property>::Element
@ -153,6 +167,9 @@ class Driver::Device : private List_model<Device>::Element
Pci::vendor_t vendor_id;
Pci::device_t device_id;
Pci::class_t class_code;
Pci::rev_t revision;
Pci::vendor_t sub_vendor_id;
Pci::device_t sub_device_id;
bool bridge;
Pci_config(addr_t addr,
@ -162,6 +179,9 @@ class Driver::Device : private List_model<Device>::Element
Pci::vendor_t vendor_id,
Pci::device_t device_id,
Pci::class_t class_code,
Pci::rev_t revision,
Pci::vendor_t sub_vendor_id,
Pci::device_t sub_device_id,
bool bridge)
:
addr(addr),
@ -171,6 +191,9 @@ class Driver::Device : private List_model<Device>::Element
vendor_id(vendor_id),
device_id(device_id),
class_code(class_code),
revision(revision),
sub_vendor_id(sub_vendor_id),
sub_device_id(sub_device_id),
bridge(bridge) {}
};
@ -202,7 +225,7 @@ class Driver::Device : private List_model<Device>::Element
{
unsigned idx = 0;
_io_port_range_list.for_each([&] (Io_port_range const & ipr) {
fn(idx++, ipr.addr, ipr.size); });
fn(idx++, ipr.range); });
}
template <typename FN> void for_pci_config(FN const & fn) const
@ -360,6 +383,9 @@ struct Driver::Irq_update_policy : Genode::List_model<Device::Irq>::Update_polic
struct Driver::Io_mem_update_policy : Genode::List_model<Device::Io_mem>::Update_policy
{
using Range = Device::Io_mem::Range;
using Bar = Device::Pci_bar;
Genode::Allocator & alloc;
Io_mem_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
@ -369,17 +395,18 @@ struct Driver::Io_mem_update_policy : Genode::List_model<Device::Io_mem>::Update
Element & create_element(Genode::Xml_node node)
{
Device::Range range { node.attribute_value<Genode::addr_t>("address", 0),
node.attribute_value<Genode::size_t>("size", 0) };
return *(new (alloc) Element(range));
Bar bar { node.attribute_value<uint8_t>("pci_bar", Bar::INVALID) };
Range range { node.attribute_value<Genode::addr_t>("address", 0),
node.attribute_value<Genode::size_t>("size", 0) };
return *(new (alloc) Element(bar, range));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & iomem, Genode::Xml_node node)
{
Device::Range range { node.attribute_value<Genode::addr_t>("address", 0),
node.attribute_value<Genode::size_t>("size", 0) };
Range range { node.attribute_value<Genode::addr_t>("address", 0),
node.attribute_value<Genode::size_t>("size", 0) };
return (range.start == iomem.range.start) && (range.size == iomem.range.size);
}
@ -393,6 +420,9 @@ struct Driver::Io_mem_update_policy : Genode::List_model<Device::Io_mem>::Update
struct Driver::Io_port_update_policy
: Genode::List_model<Device::Io_port_range>::Update_policy
{
using Range = Device::Io_port_range::Range;
using Bar = Device::Pci_bar;
Genode::Allocator & alloc;
Io_port_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
@ -402,18 +432,19 @@ struct Driver::Io_port_update_policy
Element & create_element(Genode::Xml_node node)
{
uint16_t addr = node.attribute_value<uint16_t>("address", 0);
uint16_t size = node.attribute_value<uint16_t>("size", 0);
return *(new (alloc) Element(addr, size));
Bar bar { node.attribute_value<uint8_t>("pci_bar", Bar::INVALID) };
Range range { node.attribute_value<uint16_t>("address", 0),
node.attribute_value<uint16_t>("size", 0) };
return *(new (alloc) Element(bar, range));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & ipr, Genode::Xml_node node)
{
uint16_t addr = node.attribute_value<uint16_t>("address", 0);
uint16_t size = node.attribute_value<uint16_t>("size", 0);
return addr == ipr.addr && size == ipr.size;
Range range { node.attribute_value<uint16_t>("address", 0),
node.attribute_value<uint16_t>("size", 0) };
return range.addr == ipr.range.addr && range.size == ipr.range.size;
}
static bool node_is_element(Genode::Xml_node node)
@ -573,10 +604,16 @@ struct Driver::Pci_config_update_policy
device_t device_id = node.attribute_value<device_t>("device_id",
0xffff);
class_t class_code = node.attribute_value<class_t>("class", 0xff);
rev_t rev = node.attribute_value<rev_t>("revision", 0xff);
vendor_t sub_v_id = node.attribute_value<vendor_t>("sub_vendor_id",
0xffff);
device_t sub_d_id = node.attribute_value<device_t>("sub_device_id",
0xffff);
bool bridge = node.attribute_value("bridge", false);
return *(new (alloc) Element(addr, bus_num, dev_num, func_num,
vendor_id, device_id, class_code, bridge));
vendor_id, device_id, class_code,
rev, sub_v_id, sub_d_id, bridge));
}
void update_element(Element &, Genode::Xml_node) {}

View File

@ -103,7 +103,8 @@ Genode::Io_port_session_capability Device_component::io_port_range(unsigned idx)
return;
if (!ipr.io_port_range.constructed())
ipr.io_port_range.construct(_session.env(), ipr.addr, ipr.size);
ipr.io_port_range.construct(_session.env(), ipr.range.addr,
ipr.range.size);
cap = ipr.io_port_range->cap();
});
@ -154,15 +155,13 @@ Device_component::Device_component(Registry<Device_component> & registry,
new (session.heap()) Io_mem(_io_mem_registry, idx, range);
});
device.for_each_io_port_range([&] (unsigned idx, uint16_t addr,
uint16_t size)
device.for_each_io_port_range([&] (unsigned idx, Io_port_range::Range range)
{
session.ram_quota_guard().withdraw(Ram_quota{Io_port_session::RAM_QUOTA});
_ram_quota += Io_port_session::RAM_QUOTA;
session.cap_quota_guard().withdraw(Cap_quota{Io_port_session::CAP_QUOTA});
_cap_quota += Io_port_session::CAP_QUOTA;
new (session.heap()) Io_port_range(_io_port_range_registry,
idx, addr, size);
new (session.heap()) Io_port_range(_io_port_range_registry, idx, range);
});
device.for_pci_config([&] (Device::Pci_config const & cfg)

View File

@ -73,18 +73,18 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
struct Io_port_range : Registry<Io_port_range>::Element
{
using Range = Device::Io_port_range::Range;
unsigned idx;
uint16_t addr;
uint16_t size;
Range range;
Constructible<Io_port_connection> io_port_range {};
Io_port_range(Registry<Io_port_range> & registry,
unsigned idx,
uint16_t addr,
uint16_t size)
unsigned idx,
Range range)
:
Registry<Io_port_range>::Element(registry, *this),
idx(idx), addr(addr), size(size) {}
idx(idx), range(range) {}
};
struct Pci_config

View File

@ -47,12 +47,13 @@ struct Config_helper
Config::Command::Bus_master_enable::set(cmd, 1);
/* enable memory space when I/O mem is defined */
_dev.for_each_io_mem([&] (unsigned, Driver::Device::Range) {
_dev.for_each_io_mem([&] (unsigned, Driver::Device::Io_mem::Range) {
Config::Command::Memory_space_enable::set(cmd, 1); });
/* enable i/o space when I/O ports are defined */
_dev.for_each_io_port_range([&] (unsigned, uint16_t, uint16_t) {
Config::Command::Io_space_enable::set(cmd, 1); });
_dev.for_each_io_port_range(
[&] (unsigned, Driver::Device::Io_port_range::Range) {
Config::Command::Io_space_enable::set(cmd, 1); });
_config.write<Config::Command>(cmd);
}