PCI check for MSIs and enable if possible
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include <libk/lengthof.h>
|
#include <libk/lengthof.h>
|
||||||
#include <libk/std.h>
|
#include <libk/std.h>
|
||||||
#include <libk/string.h>
|
#include <libk/string.h>
|
||||||
|
#include <limine/requests.h>
|
||||||
#include <sync/spin_lock.h>
|
#include <sync/spin_lock.h>
|
||||||
#include <sys/debug.h>
|
#include <sys/debug.h>
|
||||||
#include <sys/smp.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);
|
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,
|
static void pci_check_bus (struct proc* proc, struct reschedule_ctx* rctx, uint8_t bus,
|
||||||
pci_cb_func_t cb);
|
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.device, pci_info.class, pci_info.subclass, pci_info.bus, pci_info.slot,
|
||||||
pci_info.func, vname, dname, cname);
|
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++) {
|
for (size_t driver = 0; driver < lengthof (pci_driver_infos); driver++) {
|
||||||
if (pci_driver_infos[driver].class == pci_info.class &&
|
if (pci_driver_infos[driver].class == pci_info.class &&
|
||||||
pci_driver_infos[driver].subclass == pci_info.subclass) {
|
pci_driver_infos[driver].subclass == pci_info.subclass) {
|
||||||
|
|||||||
@@ -27,14 +27,17 @@
|
|||||||
#define PCI_BAR3 0x1C
|
#define PCI_BAR3 0x1C
|
||||||
#define PCI_BAR4 0x20
|
#define PCI_BAR4 0x20
|
||||||
#define PCI_BAR5 0x24
|
#define PCI_BAR5 0x24
|
||||||
#define PCI_INTERRUPT 0x3C
|
#define PCI_CAPABILITY 0x34
|
||||||
#define PCI_SECONDARY_BUS 0x09
|
#define PCI_INTERRUPT_LINE 0x3C
|
||||||
|
#define PCI_INTERRUPT_PIN 0x3D
|
||||||
|
|
||||||
#define PCI_BAR_IO 0x01
|
#define PCI_BAR_IO 0x01
|
||||||
#define PCI_BAR_MEM32 0x02
|
#define PCI_BAR_MEM32 0x02
|
||||||
#define PCI_BAR_MEM64 0x04
|
#define PCI_BAR_MEM64 0x04
|
||||||
#define PCI_BAR_PREFETCH 0x08
|
#define PCI_BAR_PREFETCH 0x08
|
||||||
|
|
||||||
|
#define PCI_CAP_MSI 0x05
|
||||||
|
|
||||||
struct pci_vendor {
|
struct pci_vendor {
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
const char* name;
|
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);
|
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_vendor pci_vendors[];
|
||||||
|
|
||||||
extern const struct pci_device_id pci_device_names[];
|
extern const struct pci_device_id pci_device_names[];
|
||||||
|
|||||||
@@ -123,8 +123,13 @@ bool pci_ide_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_in
|
|||||||
irqs_support = false;
|
irqs_support = false;
|
||||||
} else {
|
} else {
|
||||||
irqs_support = true;
|
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_PRIM, 14, 0, thiscpu->lapic_id);
|
||||||
ioapic_route_irq (IDE_DRIVE_SCND, 15, 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);
|
DEBUG ("pcmd=%x, pctrl=%x\n", pcmd, pctrl);
|
||||||
|
|||||||
Reference in New Issue
Block a user