diff --git a/kernel/device/pci.c b/kernel/device/pci.c index e246370..52acef8 100644 --- a/kernel/device/pci.c +++ b/kernel/device/pci.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -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) { diff --git a/kernel/device/pci.h b/kernel/device/pci.h index b8ae220..cdb0318 100644 --- a/kernel/device/pci.h +++ b/kernel/device/pci.h @@ -9,32 +9,35 @@ #define PCI_CONFIG_ADDR 0xCF8 #define PCI_CONFIG_DATA 0xCFC -#define PCI_VENDOR_ID 0x00 -#define PCI_DEVICE_ID 0x02 -#define PCI_COMMAND 0x04 -#define PCI_STATUS 0x06 -#define PCI_REVISION_ID 0x08 -#define PCI_PROG_IF 0x09 -#define PCI_SUBCLASS 0x0A -#define PCI_CLASS 0x0B -#define PCI_CACHELINE 0x0C -#define PCI_LATENCY 0x0D -#define PCI_HEADER_TYPE 0x0E -#define PCI_BIST 0x0F -#define PCI_BAR0 0x10 -#define PCI_BAR1 0x14 -#define PCI_BAR2 0x18 -#define PCI_BAR3 0x1C -#define PCI_BAR4 0x20 -#define PCI_BAR5 0x24 -#define PCI_INTERRUPT 0x3C -#define PCI_SECONDARY_BUS 0x09 +#define PCI_VENDOR_ID 0x00 +#define PCI_DEVICE_ID 0x02 +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_REVISION_ID 0x08 +#define PCI_PROG_IF 0x09 +#define PCI_SUBCLASS 0x0A +#define PCI_CLASS 0x0B +#define PCI_CACHELINE 0x0C +#define PCI_LATENCY 0x0D +#define PCI_HEADER_TYPE 0x0E +#define PCI_BIST 0x0F +#define PCI_BAR0 0x10 +#define PCI_BAR1 0x14 +#define PCI_BAR2 0x18 +#define PCI_BAR3 0x1C +#define PCI_BAR4 0x20 +#define PCI_BAR5 0x24 +#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[]; diff --git a/kernel/device/pci_ide.c b/kernel/device/pci_ide.c index 1e56daa..5b6dcd9 100644 --- a/kernel/device/pci_ide.c +++ b/kernel/device/pci_ide.c @@ -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; - ioapic_route_irq (IDE_DRIVE_PRIM, 14, 0, thiscpu->lapic_id); - ioapic_route_irq (IDE_DRIVE_SCND, 15, 0, thiscpu->lapic_id); + + 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);