Move PCI classes to separate files
This commit is contained in:
@@ -53,29 +53,12 @@ acpi_table_header::validate(uint32_t expected_type) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pci_device::pci_device() :
|
|
||||||
m_base(nullptr),
|
|
||||||
m_bus_addr(0),
|
|
||||||
m_vendor(0),
|
|
||||||
m_device(0),
|
|
||||||
m_class(0),
|
|
||||||
m_subclass(0),
|
|
||||||
m_prog_if(0),
|
|
||||||
m_revision(0),
|
|
||||||
m_irq(isr::isrIgnoreF),
|
|
||||||
m_header_type(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
device_manager::device_manager(const void *root_table) :
|
device_manager::device_manager(const void *root_table) :
|
||||||
m_lapic(nullptr),
|
m_lapic(nullptr)
|
||||||
m_num_ioapics(0)
|
|
||||||
{
|
{
|
||||||
kassert(root_table != 0, "ACPI root table pointer is null.");
|
kassert(root_table != 0, "ACPI root table pointer is null.");
|
||||||
|
|
||||||
kutil::memset(m_ioapics, 0, sizeof(m_ioapics));
|
|
||||||
|
|
||||||
const acpi1_rsdp *acpi1 =
|
const acpi1_rsdp *acpi1 =
|
||||||
reinterpret_cast<const acpi1_rsdp *>(root_table);
|
reinterpret_cast<const acpi1_rsdp *>(root_table);
|
||||||
|
|
||||||
@@ -100,7 +83,7 @@ device_manager::device_manager(const void *root_table) :
|
|||||||
ioapic *
|
ioapic *
|
||||||
device_manager::get_ioapic(int i)
|
device_manager::get_ioapic(int i)
|
||||||
{
|
{
|
||||||
return (i < m_num_ioapics) ? m_ioapics[i] : nullptr;
|
return (i < m_ioapics.count()) ? m_ioapics[i] : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -115,17 +98,17 @@ device_manager::load_xsdt(const acpi_xsdt *xsdt)
|
|||||||
kassert(xsdt && acpi_validate(xsdt), "Invalid ACPI XSDT.");
|
kassert(xsdt && acpi_validate(xsdt), "Invalid ACPI XSDT.");
|
||||||
|
|
||||||
char sig[5] = {0,0,0,0,0};
|
char sig[5] = {0,0,0,0,0};
|
||||||
log::info(logs::devices, "ACPI 2.0+ tables loading");
|
log::info(logs::device, "ACPI 2.0+ tables loading");
|
||||||
|
|
||||||
put_sig(sig, xsdt->header.type);
|
put_sig(sig, xsdt->header.type);
|
||||||
log::debug(logs::devices, " Found table %s", sig);
|
log::debug(logs::device, " Found table %s", sig);
|
||||||
|
|
||||||
size_t num_tables = acpi_table_entries(xsdt, sizeof(void*));
|
size_t num_tables = acpi_table_entries(xsdt, sizeof(void*));
|
||||||
for (size_t i = 0; i < num_tables; ++i) {
|
for (size_t i = 0; i < num_tables; ++i) {
|
||||||
const acpi_table_header *header = xsdt->headers[i];
|
const acpi_table_header *header = xsdt->headers[i];
|
||||||
|
|
||||||
put_sig(sig, header->type);
|
put_sig(sig, header->type);
|
||||||
log::debug(logs::devices, " Found table %s", sig);
|
log::debug(logs::device, " Found table %s", sig);
|
||||||
|
|
||||||
kassert(header->validate(), "Table failed validation.");
|
kassert(header->validate(), "Table failed validation.");
|
||||||
|
|
||||||
@@ -162,7 +145,7 @@ device_manager::load_apic(const acpi_apic *apic)
|
|||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
uint32_t *base = reinterpret_cast<uint32_t *>(kutil::read_from<uint32_t>(p+4));
|
uint32_t *base = reinterpret_cast<uint32_t *>(kutil::read_from<uint32_t>(p+4));
|
||||||
uint32_t base_gsr = kutil::read_from<uint32_t>(p+8);
|
uint32_t base_gsr = kutil::read_from<uint32_t>(p+8);
|
||||||
m_ioapics[m_num_ioapics++] = new ioapic(base, base_gsr);
|
m_ioapics.append(new ioapic(base, base_gsr));
|
||||||
}
|
}
|
||||||
p += length;
|
p += length;
|
||||||
}
|
}
|
||||||
@@ -183,7 +166,7 @@ device_manager::load_apic(const acpi_apic *apic)
|
|||||||
isr gsi = isr::irq00 + kutil::read_from<uint32_t>(p+4);
|
isr gsi = isr::irq00 + kutil::read_from<uint32_t>(p+4);
|
||||||
uint16_t flags = kutil::read_from<uint16_t>(p+8);
|
uint16_t flags = kutil::read_from<uint16_t>(p+8);
|
||||||
|
|
||||||
log::debug(logs::devices, " Intr source override IRQ %d -> %d Pol %d Tri %d",
|
log::debug(logs::device, " Intr source override IRQ %d -> %d Pol %d Tri %d",
|
||||||
source, gsi, (flags & 0x3), ((flags >> 2) & 0x3));
|
source, gsi, (flags & 0x3), ((flags >> 2) & 0x3));
|
||||||
|
|
||||||
// TODO: in a multiple-IOAPIC system this might be elsewhere
|
// TODO: in a multiple-IOAPIC system this might be elsewhere
|
||||||
@@ -196,7 +179,7 @@ device_manager::load_apic(const acpi_apic *apic)
|
|||||||
uint8_t num = kutil::read_from<uint8_t>(p + 5);
|
uint8_t num = kutil::read_from<uint8_t>(p + 5);
|
||||||
uint16_t flags = kutil::read_from<uint16_t>(p + 3);
|
uint16_t flags = kutil::read_from<uint16_t>(p + 3);
|
||||||
|
|
||||||
log::debug(logs::devices, " LAPIC NMI Proc %d LINT%d Pol %d Tri %d",
|
log::debug(logs::device, " LAPIC NMI Proc %d LINT%d Pol %d Tri %d",
|
||||||
kutil::read_from<uint8_t>(p+2),
|
kutil::read_from<uint8_t>(p+2),
|
||||||
kutil::read_from<uint8_t>(p+5),
|
kutil::read_from<uint8_t>(p+5),
|
||||||
kutil::read_from<uint16_t>(p+3) & 0x3,
|
kutil::read_from<uint16_t>(p+3) & 0x3,
|
||||||
@@ -207,7 +190,7 @@ device_manager::load_apic(const acpi_apic *apic)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log::debug(logs::devices, " APIC entry type %d", type);
|
log::debug(logs::device, " APIC entry type %d", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
p += length;
|
p += length;
|
||||||
@@ -249,25 +232,18 @@ device_manager::load_mcfg(const acpi_mcfg *mcfg)
|
|||||||
pm->map_offset_pointer(reinterpret_cast<void **>(&m_pci[i].base),
|
pm->map_offset_pointer(reinterpret_cast<void **>(&m_pci[i].base),
|
||||||
(num_busses << 20));
|
(num_busses << 20));
|
||||||
|
|
||||||
log::debug(logs::devices, " Found MCFG entry: base %lx group %d bus %d-%d",
|
log::debug(logs::device, " Found MCFG entry: base %lx group %d bus %d-%d",
|
||||||
mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end);
|
mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
probe_pci();
|
probe_pci();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
static bool
|
|
||||||
check_function(uint32_t *group, int bus, int dev, int func)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
void
|
||||||
device_manager::probe_pci()
|
device_manager::probe_pci()
|
||||||
{
|
{
|
||||||
for (auto &pci : m_pci) {
|
for (auto &pci : m_pci) {
|
||||||
log::debug(logs::devices, "Probing PCI group at base %016lx", pci.base);
|
log::debug(logs::device, "Probing PCI group at base %016lx", pci.base);
|
||||||
|
|
||||||
for (int bus = pci.bus_start; bus <= pci.bus_end; ++bus) {
|
for (int bus = pci.bus_start; bus <= pci.bus_end; ++bus) {
|
||||||
for (int dev = 0; dev < 32; ++dev) {
|
for (int dev = 0; dev < 32; ++dev) {
|
||||||
@@ -285,31 +261,19 @@ device_manager::probe_pci()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
pci_group::has_device(uint8_t bus, uint8_t device, uint8_t func)
|
device_manager::init_drivers()
|
||||||
{
|
{
|
||||||
return (*base_for(bus, device, func) & 0xffff) != 0xffff;
|
// Eventually this should be e.g. a lookup into a loadable driver list
|
||||||
}
|
// for now, just look for AHCI devices
|
||||||
|
for (auto &device : m_devices) {
|
||||||
|
if (device.devclass() != 1 || device.subclass() != 6)
|
||||||
|
continue;
|
||||||
|
|
||||||
pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func) :
|
if (device.progif() != 1) {
|
||||||
m_base(group.base_for(bus, device, func)),
|
log::warn(logs::device, "Found SATA device %d:%d:%d, but not an AHCI interface.",
|
||||||
m_bus_addr(bus_addr(bus, device, func)),
|
device.bus(), device.device(), device.function());
|
||||||
m_irq(isr::isrIgnoreF)
|
}
|
||||||
{
|
|
||||||
m_vendor = m_base[0] & 0xffff;
|
|
||||||
m_device = (m_base[0] >> 16) & 0xffff;
|
|
||||||
|
|
||||||
m_revision = m_base[2] & 0xff;
|
|
||||||
m_subclass = (m_base[2] >> 16) & 0xff;
|
|
||||||
m_class = (m_base[2] >> 24) & 0xff;
|
|
||||||
|
|
||||||
m_header_type = (m_base[3] >> 16) & 0x7f;
|
|
||||||
m_multi = ((m_base[3] >> 16) & 0x80) == 0x80;
|
|
||||||
|
|
||||||
log::info(logs::devices, "Found PCIe device at %02d:%02d:%d of type %d.%d id %04x:%04x",
|
|
||||||
bus, device, func, m_class, m_subclass, m_vendor, m_device);
|
|
||||||
|
|
||||||
if (m_header_type == 0) {
|
|
||||||
log::debug(logs::devices, " Interrupt: %d", (m_base[15] >> 8) & 0xff);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,94 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
/// \file device_manager.h
|
/// \file device_manager.h
|
||||||
/// The device manager and related device classes.
|
/// The device manager definition
|
||||||
#include <stdint.h>
|
|
||||||
#include "kutil/vector.h"
|
#include "kutil/vector.h"
|
||||||
|
#include "pci.h"
|
||||||
|
|
||||||
struct acpi_xsdt;
|
struct acpi_xsdt;
|
||||||
struct acpi_apic;
|
struct acpi_apic;
|
||||||
struct acpi_mcfg;
|
struct acpi_mcfg;
|
||||||
class lapic;
|
class lapic;
|
||||||
class ioapic;
|
class ioapic;
|
||||||
enum class isr : uint8_t;
|
|
||||||
struct pci_group;
|
|
||||||
|
|
||||||
|
|
||||||
/// Information about a discovered PCIe device
|
|
||||||
class pci_device
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// Default constructor creates an empty object.
|
|
||||||
pci_device();
|
|
||||||
|
|
||||||
/// Constructor
|
|
||||||
/// \arg group The group of this device's bus
|
|
||||||
/// \arg bus The bus number this device is on
|
|
||||||
/// \arg device The device number of this device
|
|
||||||
/// \arg func The function number of this device
|
|
||||||
pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func);
|
|
||||||
|
|
||||||
/// Check if this device is multi-function.
|
|
||||||
/// \returns True if this device is multi-function
|
|
||||||
inline bool multi() const { return m_multi; }
|
|
||||||
|
|
||||||
/// Get a bus address, given the bus/device/function numbers.
|
|
||||||
/// \arg bus Number of the bus
|
|
||||||
/// \arg device Index of the device on the bus
|
|
||||||
/// \arg func The function number within the device
|
|
||||||
/// \returns The computed bus_addr
|
|
||||||
static inline uint16_t bus_addr(uint8_t bus, uint8_t device, uint8_t func)
|
|
||||||
{
|
|
||||||
return bus << 8 | device << 3 | func;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t *m_base;
|
|
||||||
|
|
||||||
/// Bus address: 15:8 bus, 7:3 device, 2:0 device
|
|
||||||
uint16_t m_bus_addr;
|
|
||||||
|
|
||||||
uint16_t m_vendor;
|
|
||||||
uint16_t m_device;
|
|
||||||
|
|
||||||
uint8_t m_class;
|
|
||||||
uint8_t m_subclass;
|
|
||||||
uint8_t m_prog_if;
|
|
||||||
uint8_t m_revision;
|
|
||||||
bool m_multi;
|
|
||||||
|
|
||||||
// Might as well cache these to fill out the struct align
|
|
||||||
isr m_irq;
|
|
||||||
uint8_t m_header_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Represents data about a PCI bus group from the ACPI MCFG
|
|
||||||
struct pci_group
|
|
||||||
{
|
|
||||||
uint16_t group;
|
|
||||||
uint16_t bus_start;
|
|
||||||
uint16_t bus_end;
|
|
||||||
|
|
||||||
uint32_t *base;
|
|
||||||
|
|
||||||
/// Get the base address of the MMIO configuration registers for a device
|
|
||||||
/// \arg bus The bus number of the device (relative to this group)
|
|
||||||
/// \arg device The device number on the given bus
|
|
||||||
/// \arg func The function number on the device
|
|
||||||
/// \returns A pointer to the memory-mapped configuration registers
|
|
||||||
inline uint32_t * base_for(uint8_t bus, uint8_t device, uint8_t func)
|
|
||||||
{
|
|
||||||
return kutil::offset_pointer(base,
|
|
||||||
pci_device::bus_addr(bus, device, func) << 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the given device function is present.
|
|
||||||
/// \arg bus The bus number of the device (relative to this group)
|
|
||||||
/// \arg device The device number on the given bus
|
|
||||||
/// \arg func The function number on the device
|
|
||||||
/// \returns True if the device function is present
|
|
||||||
bool has_device(uint8_t bus, uint8_t device, uint8_t func);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Manager for all system hardware devices
|
/// Manager for all system hardware devices
|
||||||
@@ -109,6 +29,9 @@ public:
|
|||||||
/// otherwise nullptr.
|
/// otherwise nullptr.
|
||||||
ioapic * get_ioapic(int i);
|
ioapic * get_ioapic(int i);
|
||||||
|
|
||||||
|
/// Intialize drivers for the current device list.
|
||||||
|
void init_drivers();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Parse the ACPI XSDT and load relevant sub-tables.
|
/// Parse the ACPI XSDT and load relevant sub-tables.
|
||||||
/// \arg xsdt Pointer to the XSDT from the firmware
|
/// \arg xsdt Pointer to the XSDT from the firmware
|
||||||
@@ -127,10 +50,7 @@ private:
|
|||||||
void probe_pci();
|
void probe_pci();
|
||||||
|
|
||||||
lapic *m_lapic;
|
lapic *m_lapic;
|
||||||
|
kutil::vector<ioapic *> m_ioapics;
|
||||||
static const int max_ioapics = 16;
|
|
||||||
ioapic *m_ioapics[16];
|
|
||||||
int m_num_ioapics;
|
|
||||||
|
|
||||||
kutil::vector<pci_group> m_pci;
|
kutil::vector<pci_group> m_pci;
|
||||||
kutil::vector<pci_device> m_devices;
|
kutil::vector<pci_device> m_devices;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ static const char *areas[] = {
|
|||||||
"mem ",
|
"mem ",
|
||||||
"apic",
|
"apic",
|
||||||
"dev ",
|
"dev ",
|
||||||
|
"driv",
|
||||||
|
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ enum class logs
|
|||||||
boot,
|
boot,
|
||||||
memory,
|
memory,
|
||||||
apic,
|
apic,
|
||||||
devices,
|
device,
|
||||||
|
driver,
|
||||||
|
|
||||||
max
|
max
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ init_console(const popcorn_data *header)
|
|||||||
|
|
||||||
log::init(cons);
|
log::init(cons);
|
||||||
log::enable(logs::apic, log::level::info);
|
log::enable(logs::apic, log::level::info);
|
||||||
log::enable(logs::devices, log::level::debug);
|
log::enable(logs::device, log::level::debug);
|
||||||
|
log::enable(logs::driver, log::level::debug);
|
||||||
log::enable(logs::memory, log::level::debug);
|
log::enable(logs::memory, log::level::debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +87,8 @@ kernel_main(popcorn_data *header)
|
|||||||
log::info(logs::boot, "CPU Family %x Model %x Stepping %x",
|
log::info(logs::boot, "CPU Family %x Model %x Stepping %x",
|
||||||
cpu.family(), cpu.model(), cpu.stepping());
|
cpu.family(), cpu.model(), cpu.stepping());
|
||||||
|
|
||||||
|
devices.init_drivers();
|
||||||
|
|
||||||
// do_error_1();
|
// do_error_1();
|
||||||
// __asm__ __volatile__("int $15");
|
// __asm__ __volatile__("int $15");
|
||||||
|
|
||||||
|
|||||||
74
src/kernel/pci.cpp
Normal file
74
src/kernel/pci.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "kutil/assert.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "interrupts.h"
|
||||||
|
#include "pci.h"
|
||||||
|
|
||||||
|
|
||||||
|
pci_device::pci_device() :
|
||||||
|
m_base(nullptr),
|
||||||
|
m_bus_addr(0),
|
||||||
|
m_vendor(0),
|
||||||
|
m_device(0),
|
||||||
|
m_class(0),
|
||||||
|
m_subclass(0),
|
||||||
|
m_progif(0),
|
||||||
|
m_revision(0),
|
||||||
|
m_irq(isr::isrIgnoreF),
|
||||||
|
m_header_type(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func) :
|
||||||
|
m_base(group.base_for(bus, device, func)),
|
||||||
|
m_bus_addr(bus_addr(bus, device, func)),
|
||||||
|
m_irq(isr::isrIgnoreF)
|
||||||
|
{
|
||||||
|
m_vendor = m_base[0] & 0xffff;
|
||||||
|
m_device = (m_base[0] >> 16) & 0xffff;
|
||||||
|
|
||||||
|
m_revision = m_base[2] & 0xff;
|
||||||
|
m_progif = (m_base[2] >> 8) & 0xff;
|
||||||
|
m_subclass = (m_base[2] >> 16) & 0xff;
|
||||||
|
m_class = (m_base[2] >> 24) & 0xff;
|
||||||
|
|
||||||
|
m_header_type = (m_base[3] >> 16) & 0x7f;
|
||||||
|
m_multi = ((m_base[3] >> 16) & 0x80) == 0x80;
|
||||||
|
|
||||||
|
log::info(logs::device, "Found PCIe device at %02d:%02d:%d of type %d.%d id %04x:%04x",
|
||||||
|
bus, device, func, m_class, m_subclass, m_vendor, m_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
pci_device::get_bar(unsigned i)
|
||||||
|
{
|
||||||
|
if (m_header_type == 0) {
|
||||||
|
kassert(i < 6, "Requested BAR >5 for PCI device");
|
||||||
|
} else if (m_header_type == 1) {
|
||||||
|
kassert(i < 2, "Requested BAR >1 for PCI bridge");
|
||||||
|
} else {
|
||||||
|
kassert(0, "Requested BAR for other PCI device type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_base[4+i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pci_device::set_bar(unsigned i, uint32_t val)
|
||||||
|
{
|
||||||
|
if (m_header_type == 0) {
|
||||||
|
kassert(i < 6, "Requested BAR >5 for PCI device");
|
||||||
|
} else if (m_header_type == 1) {
|
||||||
|
kassert(i < 2, "Requested BAR >1 for PCI bridge");
|
||||||
|
} else {
|
||||||
|
kassert(0, "Requested BAR for other PCI device type");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_base[4+i] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
pci_group::has_device(uint8_t bus, uint8_t device, uint8_t func)
|
||||||
|
{
|
||||||
|
return (*base_for(bus, device, func) & 0xffff) != 0xffff;
|
||||||
|
}
|
||||||
122
src/kernel/pci.h
Normal file
122
src/kernel/pci.h
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file pci.h
|
||||||
|
/// PCI devices and groups
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "kutil/memory.h"
|
||||||
|
|
||||||
|
struct pci_group;
|
||||||
|
enum class isr : uint8_t;
|
||||||
|
|
||||||
|
|
||||||
|
/// Information about a discovered PCIe device
|
||||||
|
class pci_device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Default constructor creates an empty object.
|
||||||
|
pci_device();
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \arg group The group of this device's bus
|
||||||
|
/// \arg bus The bus number this device is on
|
||||||
|
/// \arg device The device number of this device
|
||||||
|
/// \arg func The function number of this device
|
||||||
|
pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func);
|
||||||
|
|
||||||
|
/// Check if this device is multi-function.
|
||||||
|
/// \returns True if this device is multi-function
|
||||||
|
inline bool multi() const { return m_multi; }
|
||||||
|
|
||||||
|
/// Get the bus number this device is on.
|
||||||
|
/// \returns The bus number
|
||||||
|
inline uint8_t bus() const { return (m_bus_addr >> 8); }
|
||||||
|
|
||||||
|
/// Get the device number of this device on its bus
|
||||||
|
/// \returns The device number
|
||||||
|
inline uint8_t device() const { return (m_bus_addr >> 3) & 0x1f; }
|
||||||
|
|
||||||
|
/// Get the function number of this device on its device
|
||||||
|
/// \returns The function number
|
||||||
|
inline uint8_t function() const { return m_bus_addr & 0x7; }
|
||||||
|
|
||||||
|
/// Get the device class
|
||||||
|
/// \returns The PCI device class
|
||||||
|
inline uint8_t devclass() const { return m_class; }
|
||||||
|
|
||||||
|
/// Get the device subclass
|
||||||
|
/// \returns The PCI device subclass
|
||||||
|
inline uint8_t subclass() const { return m_subclass; }
|
||||||
|
|
||||||
|
/// Get the device program interface
|
||||||
|
/// \returns The PCI device program interface
|
||||||
|
inline uint8_t progif() const { return m_progif; }
|
||||||
|
|
||||||
|
/// Read one of the device's Base Address Registers
|
||||||
|
/// \arg i Which BAR to read (up to 5 for non-bridges)
|
||||||
|
/// \returns The contents of the BAR
|
||||||
|
uint32_t get_bar(unsigned i);
|
||||||
|
|
||||||
|
/// Write one of the device's Base Address Registers
|
||||||
|
/// \arg i Which BAR to read (up to 5 for non-bridges)
|
||||||
|
/// \arg val The value to write
|
||||||
|
void set_bar(unsigned i, uint32_t val);
|
||||||
|
|
||||||
|
/// Get a bus address, given the bus/device/function numbers.
|
||||||
|
/// \arg bus Number of the bus
|
||||||
|
/// \arg device Index of the device on the bus
|
||||||
|
/// \arg func The function number within the device
|
||||||
|
/// \returns The computed bus_addr
|
||||||
|
static inline uint16_t bus_addr(uint8_t bus, uint8_t device, uint8_t func)
|
||||||
|
{
|
||||||
|
return bus << 8 | device << 3 | func;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t *m_base;
|
||||||
|
|
||||||
|
/// Bus address: 15:8 bus, 7:3 device, 2:0 device
|
||||||
|
uint16_t m_bus_addr;
|
||||||
|
|
||||||
|
uint16_t m_vendor;
|
||||||
|
uint16_t m_device;
|
||||||
|
|
||||||
|
uint8_t m_class;
|
||||||
|
uint8_t m_subclass;
|
||||||
|
uint8_t m_progif;
|
||||||
|
uint8_t m_revision;
|
||||||
|
bool m_multi;
|
||||||
|
|
||||||
|
// Might as well cache these to fill out the struct align
|
||||||
|
isr m_irq;
|
||||||
|
uint8_t m_header_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Represents data about a PCI bus group from the ACPI MCFG
|
||||||
|
struct pci_group
|
||||||
|
{
|
||||||
|
uint16_t group;
|
||||||
|
uint16_t bus_start;
|
||||||
|
uint16_t bus_end;
|
||||||
|
|
||||||
|
uint32_t *base;
|
||||||
|
|
||||||
|
/// Get the base address of the MMIO configuration registers for a device
|
||||||
|
/// \arg bus The bus number of the device (relative to this group)
|
||||||
|
/// \arg device The device number on the given bus
|
||||||
|
/// \arg func The function number on the device
|
||||||
|
/// \returns A pointer to the memory-mapped configuration registers
|
||||||
|
inline uint32_t * base_for(uint8_t bus, uint8_t device, uint8_t func)
|
||||||
|
{
|
||||||
|
return kutil::offset_pointer(base,
|
||||||
|
pci_device::bus_addr(bus, device, func) << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the given device function is present.
|
||||||
|
/// \arg bus The bus number of the device (relative to this group)
|
||||||
|
/// \arg device The device number on the given bus
|
||||||
|
/// \arg func The function number on the device
|
||||||
|
/// \returns True if the device function is present
|
||||||
|
bool has_device(uint8_t bus, uint8_t device, uint8_t func);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user