PCI check for MSIs and enable if possible
All checks were successful
Build ISO image / build-and-deploy (push) Successful in 3m55s
Build documentation / build-and-deploy (push) Successful in 3m5s

This commit is contained in:
2026-03-22 11:22:03 +01:00
parent d2ccb96b27
commit 5492b564dd
3 changed files with 96 additions and 22 deletions

View File

@@ -5,6 +5,7 @@
#include <libk/lengthof.h>
#include <libk/std.h>
#include <libk/string.h>
#include <limine/requests.h>
#include <sync/spin_lock.h>
#include <sys/debug.h>
#include <sys/smp.h>
@@ -105,6 +106,61 @@ void pci_write8 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint8_
spin_unlock (&pci_lock, fpci);
}
uint8_t pci_find_cap (uint8_t bus, uint8_t slot, uint8_t func, uint8_t cap_id) {
uint16_t status = pci_read16 (bus, slot, func, PCI_STATUS);
if (!(status & (1 << 4)))
return 0;
uint8_t cap = pci_read8 (bus, slot, func, PCI_CAPABILITY);
while (cap != 0) {
uint8_t id = pci_read8 (bus, slot, func, cap);
if (id == cap_id)
return cap;
cap = pci_read8 (bus, slot, func, cap + 1);
}
return 0;
}
bool pci_msi_init (uint8_t bus, uint8_t slot, uint8_t func, uint8_t vec, uint32_t lapic_id) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
uint8_t cap = pci_find_cap (bus, slot, func, PCI_CAP_MSI);
if (cap == 0) {
DEBUG ("Device does not support MSI\n");
return false;
}
uint16_t msg_ctrl = pci_read16 (bus, slot, func, cap + 2);
uintptr_t lapic_phys = thiscpu->lapic_mmio_base - (uintptr_t)hhdm->offset;
uint32_t msi_addr = (uint32_t)lapic_phys | (lapic_id << 12);
uint32_t msi_data = (uint32_t)vec & 0xFF;
pci_write32 (bus, slot, func, cap + 4, msi_addr);
/* 32 or 64 bit */
if (msg_ctrl & (1 << 7)) {
/* 64 */
pci_write32 (bus, slot, func, cap + 12, msi_data);
} else {
pci_write32 (bus, slot, func, cap + 8, msi_data);
}
pci_write16 (bus, slot, func, cap + 2, msg_ctrl | 0x0001);
DEBUG ("MSI enabled (lapic %u)\n", lapic_id);
return true;
}
static void pci_check_bus (struct proc* proc, struct reschedule_ctx* rctx, uint8_t bus,
pci_cb_func_t cb);
@@ -214,6 +270,12 @@ static void pci_discovery_cb (struct proc* proc, struct reschedule_ctx* rctx,
pci_info.device, pci_info.class, pci_info.subclass, pci_info.bus, pci_info.slot,
pci_info.func, vname, dname, cname);
uint8_t cap = pci_find_cap (pci_info.bus, pci_info.slot, pci_info.func, PCI_CAP_MSI);
if (cap) {
DEBUG ("Device supports MSI!\n");
}
for (size_t driver = 0; driver < lengthof (pci_driver_infos); driver++) {
if (pci_driver_infos[driver].class == pci_info.class &&
pci_driver_infos[driver].subclass == pci_info.subclass) {

View File

@@ -27,14 +27,17 @@
#define PCI_BAR3 0x1C
#define PCI_BAR4 0x20
#define PCI_BAR5 0x24
#define PCI_INTERRUPT 0x3C
#define PCI_SECONDARY_BUS 0x09
#define PCI_CAPABILITY 0x34
#define PCI_INTERRUPT_LINE 0x3C
#define PCI_INTERRUPT_PIN 0x3D
#define PCI_BAR_IO 0x01
#define PCI_BAR_MEM32 0x02
#define PCI_BAR_MEM64 0x04
#define PCI_BAR_PREFETCH 0x08
#define PCI_CAP_MSI 0x05
struct pci_vendor {
uint16_t id;
const char* name;
@@ -75,6 +78,10 @@ uint8_t pci_read8 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
void pci_write8 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint8_t value);
uint8_t pci_find_cap (uint8_t bus, uint8_t slot, uint8_t func, uint8_t cap_id);
bool pci_msi_init (uint8_t bus, uint8_t slot, uint8_t func, uint8_t vec, uint32_t lapic_id);
extern const struct pci_vendor pci_vendors[];
extern const struct pci_device_id pci_device_names[];

View File

@@ -123,8 +123,13 @@ bool pci_ide_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_in
irqs_support = false;
} else {
irqs_support = true;
if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, IDE_DRIVE_PRIM,
thiscpu->lapic_id)) {
ioapic_route_irq (IDE_DRIVE_PRIM, 14, 0, thiscpu->lapic_id);
ioapic_route_irq (IDE_DRIVE_SCND, 15, 0, thiscpu->lapic_id);
DEBUG ("Fallback to IOAPIC interrupt routing\n");
}
}
DEBUG ("pcmd=%x, pctrl=%x\n", pcmd, pctrl);