Kernel: Add config read/write api to PCI
This commit is contained in:
parent
bc1087f5a7
commit
0d67e46041
|
@ -58,6 +58,8 @@ namespace Kernel::PCI
|
||||||
uint8_t read_byte(uint8_t) const;
|
uint8_t read_byte(uint8_t) const;
|
||||||
|
|
||||||
void write_dword(uint8_t, uint32_t);
|
void write_dword(uint8_t, uint32_t);
|
||||||
|
void write_word(uint8_t, uint16_t);
|
||||||
|
void write_byte(uint8_t, uint8_t);
|
||||||
|
|
||||||
uint8_t bus() const { return m_bus; }
|
uint8_t bus() const { return m_bus; }
|
||||||
uint8_t dev() const { return m_dev; }
|
uint8_t dev() const { return m_dev; }
|
||||||
|
@ -109,6 +111,14 @@ namespace Kernel::PCI
|
||||||
|
|
||||||
const BAN::Vector<PCI::Device>& devices() const { return m_devices; }
|
const BAN::Vector<PCI::Device>& devices() const { return m_devices; }
|
||||||
|
|
||||||
|
static uint32_t read_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset);
|
||||||
|
static uint16_t read_config_word(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset);
|
||||||
|
static uint8_t read_config_byte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset);
|
||||||
|
|
||||||
|
static void write_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint32_t value);
|
||||||
|
static void write_config_word(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint16_t value);
|
||||||
|
static void write_config_byte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint8_t value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PCIManager() = default;
|
PCIManager() = default;
|
||||||
void check_function(uint8_t bus, uint8_t dev, uint8_t func);
|
void check_function(uint8_t bus, uint8_t dev, uint8_t func);
|
||||||
|
|
|
@ -18,29 +18,63 @@ namespace Kernel::PCI
|
||||||
|
|
||||||
static PCIManager* s_instance = nullptr;
|
static PCIManager* s_instance = nullptr;
|
||||||
|
|
||||||
static uint32_t read_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset)
|
uint32_t PCIManager::read_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset)
|
||||||
{
|
{
|
||||||
|
ASSERT(offset % 4 == 0);
|
||||||
uint32_t config_addr = 0x80000000 | ((uint32_t)bus << 16) | ((uint32_t)dev << 11) | ((uint32_t)func << 8) | offset;
|
uint32_t config_addr = 0x80000000 | ((uint32_t)bus << 16) | ((uint32_t)dev << 11) | ((uint32_t)func << 8) | offset;
|
||||||
IO::outl(CONFIG_ADDRESS, config_addr);
|
IO::outl(CONFIG_ADDRESS, config_addr);
|
||||||
return IO::inl(CONFIG_DATA);
|
return IO::inl(CONFIG_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint32_t value)
|
uint16_t PCIManager::read_config_word(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset)
|
||||||
{
|
{
|
||||||
|
ASSERT(offset % 2 == 0);
|
||||||
|
uint32_t dword = read_config_dword(bus, dev, func, offset & ~3);
|
||||||
|
return (dword >> ((offset & 3) * 8)) & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t PCIManager::read_config_byte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset)
|
||||||
|
{
|
||||||
|
uint32_t dword = read_config_dword(bus, dev, func, offset & ~3);
|
||||||
|
return (dword >> ((offset & 3) * 8)) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCIManager::write_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint32_t value)
|
||||||
|
{
|
||||||
|
ASSERT(offset % 4 == 0);
|
||||||
uint32_t config_addr = 0x80000000 | ((uint32_t)bus << 16) | ((uint32_t)dev << 11) | ((uint32_t)func << 8) | offset;
|
uint32_t config_addr = 0x80000000 | ((uint32_t)bus << 16) | ((uint32_t)dev << 11) | ((uint32_t)func << 8) | offset;
|
||||||
IO::outl(CONFIG_ADDRESS, config_addr);
|
IO::outl(CONFIG_ADDRESS, config_addr);
|
||||||
IO::outl(CONFIG_DATA, value);
|
IO::outl(CONFIG_DATA, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PCIManager::write_config_word(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint16_t value)
|
||||||
|
{
|
||||||
|
ASSERT(offset % 2 == 0);
|
||||||
|
uint32_t byte = (offset & 3) * 8;
|
||||||
|
uint32_t temp = read_config_dword(bus, dev, func, offset & ~3);
|
||||||
|
temp &= ~(0xFFFF << byte);
|
||||||
|
temp |= (uint32_t)value << byte;
|
||||||
|
write_config_dword(bus, dev, func, offset & ~3, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCIManager::write_config_byte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint8_t value)
|
||||||
|
{
|
||||||
|
uint32_t byte = (offset & 3) * 8;
|
||||||
|
uint32_t temp = read_config_dword(bus, dev, func, offset & ~3);
|
||||||
|
temp &= ~(0xFF << byte);
|
||||||
|
temp |= (uint32_t)value << byte;
|
||||||
|
write_config_dword(bus, dev, func, offset, temp);
|
||||||
|
}
|
||||||
|
|
||||||
static uint16_t get_vendor_id(uint8_t bus, uint8_t dev, uint8_t func)
|
static uint16_t get_vendor_id(uint8_t bus, uint8_t dev, uint8_t func)
|
||||||
{
|
{
|
||||||
uint32_t dword = read_config_dword(bus, dev, func, 0x00);
|
uint32_t dword = PCIManager::read_config_dword(bus, dev, func, 0x00);
|
||||||
return dword & 0xFFFF;
|
return dword & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t get_header_type(uint8_t bus, uint8_t dev, uint8_t func)
|
static uint8_t get_header_type(uint8_t bus, uint8_t dev, uint8_t func)
|
||||||
{
|
{
|
||||||
uint32_t dword = read_config_dword(bus, dev, func, 0x0C);
|
uint32_t dword = PCIManager::read_config_dword(bus, dev, func, 0x0C);
|
||||||
return (dword >> 16) & 0xFF;
|
return (dword >> 16) & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,27 +323,36 @@ namespace Kernel::PCI
|
||||||
|
|
||||||
uint32_t PCI::Device::read_dword(uint8_t offset) const
|
uint32_t PCI::Device::read_dword(uint8_t offset) const
|
||||||
{
|
{
|
||||||
ASSERT((offset & 0x03) == 0);
|
ASSERT(offset % 4 == 0);
|
||||||
return read_config_dword(m_bus, m_dev, m_func, offset);
|
return PCIManager::read_config_dword(m_bus, m_dev, m_func, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t PCI::Device::read_word(uint8_t offset) const
|
uint16_t PCI::Device::read_word(uint8_t offset) const
|
||||||
{
|
{
|
||||||
ASSERT((offset & 0x01) == 0);
|
ASSERT(offset % 2 == 0);
|
||||||
uint32_t dword = read_config_dword(m_bus, m_dev, m_func, offset & 0xFC);
|
return PCIManager::read_config_word(m_bus, m_dev, m_func, offset);
|
||||||
return (uint16_t)(dword >> (8 * (offset & 0x03)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t PCI::Device::read_byte(uint8_t offset) const
|
uint8_t PCI::Device::read_byte(uint8_t offset) const
|
||||||
{
|
{
|
||||||
uint32_t dword = read_config_dword(m_bus, m_dev, m_func, offset & 0xFC);
|
return PCIManager::read_config_byte(m_bus, m_dev, m_func, offset);
|
||||||
return (uint8_t)(dword >> (8 * (offset & 0x03)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCI::Device::write_dword(uint8_t offset, uint32_t value)
|
void PCI::Device::write_dword(uint8_t offset, uint32_t value)
|
||||||
{
|
{
|
||||||
ASSERT((offset & 0x03) == 0);
|
ASSERT(offset % 4 == 0);
|
||||||
write_config_dword(m_bus, m_dev, m_func, offset, value);
|
PCIManager::write_config_dword(m_bus, m_dev, m_func, offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCI::Device::write_word(uint8_t offset, uint16_t value)
|
||||||
|
{
|
||||||
|
ASSERT(offset % 2 == 0);
|
||||||
|
PCIManager::write_config_word(m_bus, m_dev, m_func, offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCI::Device::write_byte(uint8_t offset, uint8_t value)
|
||||||
|
{
|
||||||
|
PCIManager::write_config_byte(m_bus, m_dev, m_func, offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<BarRegion>> PCI::Device::allocate_bar_region(uint8_t bar_num)
|
BAN::ErrorOr<BAN::UniqPtr<BarRegion>> PCI::Device::allocate_bar_region(uint8_t bar_num)
|
||||||
|
|
Loading…
Reference in New Issue