Kernel: PCI can now get interrupts for devices
This commit is contained in:
parent
f27974dd3c
commit
89c975350d
|
@ -35,6 +35,8 @@ namespace Kernel
|
||||||
static void initialize(bool force_pic);
|
static void initialize(bool force_pic);
|
||||||
static InterruptController& get();
|
static InterruptController& get();
|
||||||
|
|
||||||
|
bool is_using_apic() const { return m_using_apic; }
|
||||||
|
|
||||||
void enter_acpi_mode();
|
void enter_acpi_mode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -75,6 +75,8 @@ namespace Kernel::PCI
|
||||||
|
|
||||||
uint8_t header_type() const { return m_header_type; }
|
uint8_t header_type() const { return m_header_type; }
|
||||||
|
|
||||||
|
BAN::ErrorOr<uint8_t> get_irq();
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<BarRegion>> allocate_bar_region(uint8_t bar_num);
|
BAN::ErrorOr<BAN::UniqPtr<BarRegion>> allocate_bar_region(uint8_t bar_num);
|
||||||
|
|
||||||
void enable_bus_mastering();
|
void enable_bus_mastering();
|
||||||
|
@ -105,6 +107,9 @@ namespace Kernel::PCI
|
||||||
uint8_t m_prog_if;
|
uint8_t m_prog_if;
|
||||||
|
|
||||||
uint8_t m_header_type;
|
uint8_t m_header_type;
|
||||||
|
|
||||||
|
BAN::Optional<uint8_t> m_offset_msi;
|
||||||
|
BAN::Optional<uint8_t> m_offset_msi_x;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PCIManager
|
class PCIManager
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
#define CONFIG_DATA 0xCFC
|
#define CONFIG_DATA 0xCFC
|
||||||
|
|
||||||
#define PCI_REG_COMMAND 0x04
|
#define PCI_REG_COMMAND 0x04
|
||||||
|
#define PCI_REG_STATUS 0x06
|
||||||
|
#define PCI_REG_CAPABILITIES 0x34
|
||||||
|
#define PCI_REG_IRQ_LINE 0x3C
|
||||||
|
#define PCI_REG_IRQ_PIN 0x44
|
||||||
|
|
||||||
#define PCI_CMD_IO_SPACE (1 << 0)
|
#define PCI_CMD_IO_SPACE (1 << 0)
|
||||||
#define PCI_CMD_MEM_SPACE (1 << 1)
|
#define PCI_CMD_MEM_SPACE (1 << 1)
|
||||||
#define PCI_CMD_BUS_MASTER (1 << 2)
|
#define PCI_CMD_BUS_MASTER (1 << 2)
|
||||||
|
@ -187,10 +192,9 @@ namespace Kernel::PCI
|
||||||
{
|
{
|
||||||
ASSERT(device.header_type() == 0x00);
|
ASSERT(device.header_type() == 0x00);
|
||||||
|
|
||||||
uint32_t command_status = device.read_dword(0x04);
|
|
||||||
|
|
||||||
// disable io/mem space while reading bar
|
// disable io/mem space while reading bar
|
||||||
device.write_dword(0x04, command_status & ~3);
|
uint16_t command = device.read_word(PCI_REG_COMMAND);
|
||||||
|
device.write_word(PCI_REG_COMMAND, command & ~(PCI_CMD_IO_SPACE | PCI_CMD_MEM_SPACE));
|
||||||
|
|
||||||
uint8_t offset = 0x10 + bar_num * 4;
|
uint8_t offset = 0x10 + bar_num * 4;
|
||||||
|
|
||||||
|
@ -232,9 +236,9 @@ namespace Kernel::PCI
|
||||||
auto region = BAN::UniqPtr<BarRegion>::adopt(region_ptr);
|
auto region = BAN::UniqPtr<BarRegion>::adopt(region_ptr);
|
||||||
TRY(region->initialize());
|
TRY(region->initialize());
|
||||||
|
|
||||||
// restore old command register and enable correct IO/MEM
|
// restore old command register and enable correct IO/MEM space
|
||||||
command_status |= (type == BarType::IO) ? 1 : 2;
|
command |= (type == BarType::IO) ? PCI_CMD_IO_SPACE : PCI_CMD_MEM_SPACE;
|
||||||
device.write_dword(0x04, command_status);
|
device.write_word(PCI_REG_COMMAND, command);
|
||||||
|
|
||||||
#if DEBUG_PCI
|
#if DEBUG_PCI
|
||||||
dprintln("created BAR region for PCI {}:{}.{}",
|
dprintln("created BAR region for PCI {}:{}.{}",
|
||||||
|
@ -373,19 +377,67 @@ namespace Kernel::PCI
|
||||||
|
|
||||||
void PCI::Device::enumerate_capabilites()
|
void PCI::Device::enumerate_capabilites()
|
||||||
{
|
{
|
||||||
uint16_t status = read_word(0x06);
|
uint16_t status = read_word(PCI_REG_STATUS);
|
||||||
if (!(status & (1 << 4)))
|
if (!(status & (1 << 4)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint8_t capabilities = read_byte(0x34) & 0xFC;
|
uint8_t capability_offset = read_byte(PCI_REG_CAPABILITIES) & 0xFC;
|
||||||
while (capabilities)
|
while (capability_offset)
|
||||||
{
|
{
|
||||||
uint16_t next = read_word(capabilities);
|
uint16_t capability_info = read_word(capability_offset);
|
||||||
dprintln(" cap {2H}", next & 0xFF);
|
|
||||||
capabilities = (next >> 8) & 0xFC;
|
switch (capability_info & 0xFF)
|
||||||
|
{
|
||||||
|
case 0x05:
|
||||||
|
m_offset_msi = capability_offset;
|
||||||
|
dprintln("{}:{}.{} has MSI", m_bus, m_dev, m_func);
|
||||||
|
break;
|
||||||
|
case 0x11:
|
||||||
|
m_offset_msi_x = capability_offset;
|
||||||
|
dprintln("{}:{}.{} has MSI-X", m_bus, m_dev, m_func);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
capability_offset = (capability_info >> 8) & 0xFC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<uint8_t> PCI::Device::get_irq()
|
||||||
|
{
|
||||||
|
// Legacy PIC just uses the interrupt line field
|
||||||
|
if (!InterruptController::get().is_using_apic())
|
||||||
|
return read_byte(PCI_REG_IRQ_LINE);
|
||||||
|
|
||||||
|
// TODO: use MSI and MSI-X if supported
|
||||||
|
|
||||||
|
if (m_offset_msi.has_value())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_offset_msi_x.has_value())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t irq_pin = 1; irq_pin <= 4; irq_pin++)
|
||||||
|
{
|
||||||
|
acpi_resource_t dest;
|
||||||
|
auto err = lai_pci_route_pin(&dest, 0, m_bus, m_dev, m_func, irq_pin);
|
||||||
|
if (err != LAI_ERROR_NONE)
|
||||||
|
{
|
||||||
|
dprintln("{}", lai_api_error_to_string(err));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_byte(PCI_REG_IRQ_PIN, irq_pin);
|
||||||
|
return dest.base;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwarnln("Could not allocate interrupt for PCI {}:{}.{}", m_bus, m_dev, m_func);
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
void PCI::Device::set_command_bits(uint16_t mask)
|
void PCI::Device::set_command_bits(uint16_t mask)
|
||||||
{
|
{
|
||||||
write_dword(PCI_REG_COMMAND, read_dword(PCI_REG_COMMAND) | mask);
|
write_dword(PCI_REG_COMMAND, read_dword(PCI_REG_COMMAND) | mask);
|
||||||
|
|
Loading…
Reference in New Issue