2022-09-21 17:57:02 +02:00
|
|
|
#define MODULE "pci"
|
|
|
|
|
|
|
|
#include "io/PCI.h"
|
|
|
|
#include "io/IO.h"
|
|
|
|
#include "log/Log.h"
|
|
|
|
#include "thread/Spinlock.h"
|
|
|
|
|
|
|
|
#define PCI_ADDRESS 0xCF8
|
|
|
|
#define PCI_VALUE 0xCFC
|
|
|
|
|
|
|
|
Spinlock pci_lock;
|
|
|
|
|
|
|
|
uint32_t PCI::raw_address(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
|
|
|
|
{
|
|
|
|
return 0x80000000 | (bus << 16) | (slot << 11) | (function << 8) | ((offset)&0xFC);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCI::raw_write8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint8_t value)
|
|
|
|
{
|
|
|
|
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
|
|
|
IO::outl(PCI_VALUE, (uint32_t)value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCI::raw_write16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint16_t value)
|
|
|
|
{
|
|
|
|
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
|
|
|
IO::outl(PCI_VALUE, (uint32_t)value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCI::raw_write32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint32_t value)
|
|
|
|
{
|
|
|
|
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
|
|
|
IO::outl(PCI_VALUE, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t PCI::raw_read8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
|
|
|
|
{
|
|
|
|
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
2022-10-06 17:13:34 +02:00
|
|
|
return (uint8_t)(IO::inl(PCI_VALUE + (offset & 3)) & 0xFF);
|
2022-09-21 17:57:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t PCI::raw_read16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
|
|
|
|
{
|
|
|
|
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
2022-10-06 18:02:57 +02:00
|
|
|
return (uint16_t)(IO::inl(PCI_VALUE + (offset & 2)) & 0xFFFF);
|
2022-09-21 17:57:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t PCI::raw_read32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
|
|
|
|
{
|
|
|
|
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
|
|
|
return IO::inl(PCI_VALUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
PCI::DeviceID PCI::get_device_id(uint32_t bus, uint32_t slot, uint32_t function)
|
|
|
|
{
|
|
|
|
uint16_t vendor = PCI::raw_read16(bus, slot, function, PCI_VENDOR_FIELD);
|
|
|
|
uint16_t device = PCI::raw_read16(bus, slot, function, PCI_DEVICE_FIELD);
|
|
|
|
return {vendor, device};
|
|
|
|
}
|
|
|
|
|
|
|
|
PCI::DeviceType PCI::get_device_type(uint32_t bus, uint32_t slot, uint32_t function)
|
|
|
|
{
|
|
|
|
uint8_t dev_subclass = PCI::raw_read8(bus, slot, function, PCI_SUBCLASS_FIELD);
|
|
|
|
uint8_t dev_class = PCI::raw_read8(bus, slot, function, PCI_CLASS_FIELD);
|
|
|
|
uint8_t prog_if = PCI::raw_read8(bus, slot, function, PCI_PROG_IF_FIELD);
|
|
|
|
uint8_t revision = PCI::raw_read8(bus, slot, function, PCI_REVISION_ID_FIELD);
|
|
|
|
return {dev_class, dev_subclass, prog_if, revision};
|
|
|
|
}
|
|
|
|
|
2022-09-23 17:24:45 +02:00
|
|
|
static void pci_scan_bus(uint8_t bus, void (*callback)(PCI::Device&))
|
2022-09-21 17:57:02 +02:00
|
|
|
{
|
|
|
|
for (uint8_t slot = 0; slot < 32; slot++)
|
|
|
|
{
|
|
|
|
uint8_t num_functions = 1;
|
|
|
|
for (uint8_t function = 0; function < num_functions; function++)
|
|
|
|
{
|
|
|
|
PCI::DeviceID device_id = PCI::get_device_id(bus, slot, function);
|
|
|
|
if (device_id.vendor == 0xFFFF || device_id.device == 0xFFFF) continue;
|
|
|
|
PCI::DeviceType device_type = PCI::get_device_type(bus, slot, function);
|
|
|
|
uint8_t header = PCI::raw_read8(bus, slot, function, PCI_HEADER_TYPE_FIELD);
|
|
|
|
if (header & 0x80) // multi function device
|
|
|
|
{
|
|
|
|
num_functions = 8;
|
|
|
|
}
|
|
|
|
if ((header & 0x7F) == 1)
|
|
|
|
{
|
|
|
|
uint8_t sub_bus = PCI::raw_read8(bus, slot, function, PCI_SECONDARY_BUS_NUMBER_FIELD);
|
|
|
|
pci_scan_bus(sub_bus, callback);
|
|
|
|
}
|
2022-09-23 17:24:45 +02:00
|
|
|
PCI::Device device{device_id, device_type, bus, slot, function};
|
2022-09-21 17:57:02 +02:00
|
|
|
pci_lock.release();
|
2022-09-23 17:24:45 +02:00
|
|
|
callback(device);
|
2022-09-21 17:57:02 +02:00
|
|
|
pci_lock.acquire();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-23 17:24:45 +02:00
|
|
|
void PCI::scan(void (*callback)(PCI::Device&))
|
2022-09-21 17:57:02 +02:00
|
|
|
{
|
|
|
|
pci_lock.acquire();
|
2022-09-23 18:01:07 +02:00
|
|
|
uint8_t function;
|
|
|
|
uint8_t bus;
|
|
|
|
|
|
|
|
uint8_t header_type = PCI::raw_read8(0, 0, 0, PCI_HEADER_TYPE_FIELD);
|
|
|
|
if ((header_type & 0x80) == 0)
|
|
|
|
{
|
|
|
|
// Single PCI host controller
|
|
|
|
pci_scan_bus(0, callback);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Multiple PCI host controllers
|
|
|
|
for (function = 0; function < 8; function++)
|
|
|
|
{
|
2022-10-06 18:04:32 +02:00
|
|
|
if (get_device_id(0, 0, function).vendor == 0xFFFF) break;
|
2022-09-23 18:01:07 +02:00
|
|
|
bus = function;
|
|
|
|
pci_scan_bus(bus, callback);
|
|
|
|
}
|
|
|
|
}
|
2022-09-21 17:57:02 +02:00
|
|
|
pci_lock.release();
|
2022-09-23 17:24:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
PCI::Device::Device(const Device& other)
|
|
|
|
: m_id(other.m_id), m_type(other.m_type), m_bus(other.m_bus), m_slot(other.m_slot), m_function(other.m_function)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
PCI::Device::Device(uint8_t bus, uint8_t slot, uint8_t function) : m_bus(bus), m_slot(slot), m_function(function)
|
|
|
|
{
|
|
|
|
m_id = get_device_id(m_bus, m_slot, m_function);
|
|
|
|
m_type = get_device_type(m_bus, m_slot, m_function);
|
|
|
|
}
|
|
|
|
|
|
|
|
PCI::Device::Device(DeviceID id, DeviceType type, uint8_t bus, uint8_t slot, uint8_t function)
|
|
|
|
: m_id(id), m_type(type), m_bus(bus), m_slot(slot), m_function(function)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCI::Device::write8(int32_t offset, uint8_t value)
|
|
|
|
{
|
|
|
|
PCI::raw_write8(m_bus, m_slot, m_function, offset, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCI::Device::write16(int32_t offset, uint16_t value)
|
|
|
|
{
|
|
|
|
PCI::raw_write16(m_bus, m_slot, m_function, offset, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PCI::Device::write32(int32_t offset, uint32_t value)
|
|
|
|
{
|
|
|
|
PCI::raw_write32(m_bus, m_slot, m_function, offset, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t PCI::Device::read8(int32_t offset)
|
|
|
|
{
|
|
|
|
return PCI::raw_read8(m_bus, m_slot, m_function, offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t PCI::Device::read16(int32_t offset)
|
|
|
|
{
|
|
|
|
return PCI::raw_read16(m_bus, m_slot, m_function, offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t PCI::Device::read32(int32_t offset)
|
|
|
|
{
|
|
|
|
return PCI::raw_read32(m_bus, m_slot, m_function, offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t PCI::Device::getBAR0()
|
|
|
|
{
|
|
|
|
return read32(PCI_BAR0_FIELD);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t PCI::Device::getBAR1()
|
|
|
|
{
|
|
|
|
return read32(PCI_BAR1_FIELD);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t PCI::Device::getBAR2()
|
|
|
|
{
|
|
|
|
return read32(PCI_BAR2_FIELD);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t PCI::Device::getBAR3()
|
|
|
|
{
|
|
|
|
return read32(PCI_BAR3_FIELD);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t PCI::Device::getBAR4()
|
|
|
|
{
|
|
|
|
return read32(PCI_BAR4_FIELD);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t PCI::Device::getBAR5()
|
|
|
|
{
|
|
|
|
return read32(PCI_BAR5_FIELD);
|
2022-09-21 17:57:02 +02:00
|
|
|
}
|