126 lines
3.7 KiB
C
126 lines
3.7 KiB
C
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include "pci/pci.h"
|
|
#include "pci/reg.h"
|
|
#include "io/io.h"
|
|
#include "std/string.h"
|
|
#include "util/util.h"
|
|
#include "kprintf.h"
|
|
|
|
uint8_t pci_read8(uint32_t id, uint32_t reg) {
|
|
uint32_t addr = 0x80000000 | id | (reg & 0xFC);
|
|
io_out32(PCI_CONFIG_ADDR, addr);
|
|
return io_in8(PCI_CONFIG_DATA + (reg & 0x03));
|
|
}
|
|
|
|
uint16_t pci_read16(uint32_t id, uint32_t reg) {
|
|
uint32_t addr = 0x80000000 | id | (reg & 0xFC);
|
|
io_out32(PCI_CONFIG_ADDR, addr);
|
|
return io_in16(PCI_CONFIG_DATA + (reg & 0x02));
|
|
}
|
|
|
|
uint32_t pci_read32(uint32_t id, uint32_t reg) {
|
|
uint32_t addr = 0x80000000 | id | (reg & 0xFC);
|
|
io_out32(PCI_CONFIG_ADDR, addr);
|
|
return io_in32(PCI_CONFIG_DATA + reg);
|
|
}
|
|
|
|
void pci_write8(uint32_t id, uint32_t reg, uint8_t v) {
|
|
uint32_t addr = 0x80000000 | id | (reg & 0xFC);
|
|
io_out32(PCI_CONFIG_ADDR, addr);
|
|
io_out8(PCI_CONFIG_DATA + (reg & 0x03), v);
|
|
}
|
|
|
|
void pci_write16(uint32_t id, uint32_t reg, uint16_t v) {
|
|
uint32_t addr = 0x80000000 | id | (reg & 0xFC);
|
|
io_out32(PCI_CONFIG_ADDR, addr);
|
|
io_out16(PCI_CONFIG_DATA + (reg & 0x02), v);
|
|
}
|
|
|
|
void pci_write32(uint32_t id, uint32_t reg, uint32_t v) {
|
|
uint32_t addr = 0x80000000 | id | (reg & 0xFC);
|
|
io_out32(PCI_CONFIG_ADDR, addr);
|
|
io_out32(PCI_CONFIG_DATA + reg, v);
|
|
}
|
|
|
|
void pci_readbar(uint32_t id, uint32_t idx, uint32_t *addr, uint32_t *mask) {
|
|
uint32_t reg = PCI_BAR0 + idx * sizeof(uint32_t);
|
|
*addr = pci_read32(id, reg);
|
|
pci_write32(id, reg, 0xffffffff);
|
|
*mask = pci_read32(id, reg);
|
|
pci_write32(id, reg, *addr);
|
|
}
|
|
|
|
void pci_getbar(PciBar *bar, uint32_t id, uint32_t idx) {
|
|
uint32_t addrlo;
|
|
uint32_t masklo;
|
|
pci_readbar(id, idx, &addrlo, &masklo);
|
|
|
|
if (addrlo & PCI_BAR_MEM32) {
|
|
bar->u.addr = (void *)((uint64_t)(addrlo & ~0x3));
|
|
bar->size = ~(masklo & ~0xF) + 1;
|
|
bar->flags = addrlo & 0xF;
|
|
} else if (addrlo & PCI_BAR_MEM64) {
|
|
uint32_t addrhi;
|
|
uint32_t maskhi;
|
|
pci_readbar(id, idx+1, &addrhi, &maskhi);
|
|
|
|
bar->u.addr = (void *)(((uint64_t)addrhi << 32) | ((uint64_t)addrlo & ~0xF));
|
|
bar->size = ~(((uint64_t)maskhi << 32) | ((uint64_t)masklo & ~0xF)) + 1;
|
|
bar->flags = addrlo & 0xF;
|
|
} else if (addrlo & PCI_BAR_IO) {
|
|
bar->u.port = (uint16_t)(addrlo & ~0x3);
|
|
bar->size = (uint16_t)(~(masklo & ~0x3) + 1);
|
|
bar->flags = addrlo & 0x3;
|
|
}
|
|
}
|
|
|
|
static PciMatch PCI_MATCHES[] = {
|
|
};
|
|
|
|
void pci_visit(uint32_t bus, uint32_t dev, uint32_t fn) {
|
|
uint32_t id = PCI_MAKE_ID(bus, dev, fn);
|
|
|
|
PciDevInfo devinfo;
|
|
memset(&devinfo, 0, sizeof(devinfo));
|
|
|
|
devinfo.vendorid = pci_read16(id, PCI_VENDORID);
|
|
if (devinfo.vendorid == 0xffff) {
|
|
return;
|
|
}
|
|
|
|
devinfo.deviceid = pci_read16(id, PCI_DEVICEID);
|
|
devinfo.progintf = pci_read8(id, PCI_PROGINTF);
|
|
devinfo.subclass = pci_read8(id, PCI_SUBCLASS);
|
|
devinfo.classcode = pci_read8(id, PCI_CLASSCODE);
|
|
|
|
devinfo.bus = bus;
|
|
devinfo.dev = dev;
|
|
devinfo.fn = fn;
|
|
|
|
LOG("pci", "%02X:%02X:%u 0x%04X/0x%04X: %s\n",
|
|
bus, dev, fn, devinfo.vendorid, devinfo.deviceid,
|
|
pci_classname(devinfo.classcode, devinfo.subclass, devinfo.progintf));
|
|
|
|
for (size_t i = 0; i < LEN(PCI_MATCHES); i++) {
|
|
if ((PCI_MATCHES[i].k1 == devinfo.vendorid && PCI_MATCHES[i].k2 == devinfo.deviceid)
|
|
|| (PCI_MATCHES[i].k1 == devinfo.classcode && PCI_MATCHES[i].k2 == devinfo.subclass)) {
|
|
PCI_MATCHES[i].initfn(&devinfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
void pci_init(void) {
|
|
for (uint32_t bus = 0; bus < 0x100; bus++) {
|
|
for (uint32_t dev = 0; dev < 32; dev++) {
|
|
uint32_t baseid = PCI_MAKE_ID(bus, dev, 0);
|
|
uint8_t hdrtype = pci_read8(baseid, PCI_HDRTYPE);
|
|
uint32_t fncount = hdrtype & PCI_MULTIFN ? 8 : 1;
|
|
|
|
for (uint32_t fn = 0; fn < fncount; fn++) {
|
|
pci_visit(bus, dev, fn);
|
|
}
|
|
}
|
|
}
|
|
}
|