PCI driver rewrite
This commit is contained in:
242
kernel/pci/pci.c
242
kernel/pci/pci.c
@ -1,126 +1,182 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "pci/pci.h"
|
||||
#include "pci/reg.h"
|
||||
#include "pci/ata.h"
|
||||
#include "io/io.h"
|
||||
#include "std/string.h"
|
||||
#include "util/util.h"
|
||||
#include "pci/ide.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));
|
||||
static PciDev PCI_DEV_ZERO = {0};
|
||||
uint32_t PCI_SIZE_MAP[100] = {0};
|
||||
|
||||
uint32_t pci_read(PciDev dev, uint32_t field) {
|
||||
dev.fieldnum = (field & 0xFC) >> 2;
|
||||
dev.enable = 1;
|
||||
io_out32(PCI_CFG_ADDR, dev.bits);
|
||||
|
||||
uint32_t size = PCI_SIZE_MAP[field];
|
||||
uint8_t u8; uint16_t u16; uint32_t u32;
|
||||
switch (size) {
|
||||
case 1:
|
||||
u8 = io_in8(PCI_CFG_DATA + (field & 0x3));
|
||||
return (uint32_t)u8;
|
||||
case 2:
|
||||
u16 = io_in16(PCI_CFG_DATA + (field & 0x2));
|
||||
return (uint32_t)u16;
|
||||
case 4:
|
||||
u32 = io_in32(PCI_CFG_DATA);
|
||||
return u32;
|
||||
default:
|
||||
return 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
void pci_write(PciDev dev, uint32_t field, uint32_t v) {
|
||||
dev.fieldnum = (field & 0xFC) >> 2;
|
||||
dev.enable = 1;
|
||||
io_out32(PCI_CFG_ADDR, dev.bits);
|
||||
io_out32(PCI_CFG_DATA, v);
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t pci_devtype(PciDev dev) {
|
||||
uint32_t a = pci_read(dev, PCI_CLASS) << 8;
|
||||
uint32_t b = pci_read(dev, PCI_SUBCLASS);
|
||||
return a | b;
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t pci_scndrybus(PciDev dev) {
|
||||
return pci_read(dev, PCI_SCNDRY_BUS);
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t pci_isend(PciDev dev) {
|
||||
return !(pci_read(dev, PCI_HDRTYPE));
|
||||
}
|
||||
|
||||
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);
|
||||
PciDev pci_scanfn(uint16_t vendorid, uint16_t deviceid, uint32_t bus,
|
||||
uint32_t device, uint32_t fn, int devtype) {
|
||||
PciDev dev; memset(&dev, 0, sizeof(dev));
|
||||
dev.busnum = bus;
|
||||
dev.devnum = device;
|
||||
dev.fnnum = fn;
|
||||
|
||||
// bridge
|
||||
if (pci_devtype(dev) == 0x0604) {
|
||||
pci_scanbus(vendorid, deviceid, pci_scndrybus(dev), devtype);
|
||||
}
|
||||
if (devtype == -1 || (uint32_t)devtype == pci_devtype(dev)) {
|
||||
uint32_t venid = pci_read(dev, PCI_VENDORID);
|
||||
uint32_t devid = pci_read(dev, PCI_DEVICEID);
|
||||
|
||||
if (devid == deviceid && venid == vendorid) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
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);
|
||||
PciDev pci_scanbus(uint16_t vendorid, uint16_t deviceid,
|
||||
uint32_t bus, int devtype) {
|
||||
for (uint32_t device = 0; device < PCI_DEV_PER_BUS; device++) {
|
||||
PciDev d = pci_scandev(vendorid, deviceid, bus, device, devtype);
|
||||
if (d.bits) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
void pci_getbar(PciBar *bar, uint32_t id, uint32_t idx) {
|
||||
uint32_t addrlo;
|
||||
uint32_t masklo;
|
||||
pci_readbar(id, idx, &addrlo, &masklo);
|
||||
PciDev pci_scandev(uint16_t vendorid, uint16_t deviceid,
|
||||
uint32_t bus, uint32_t device, int devtype) {
|
||||
PciDev dev; memset(&dev, 0, sizeof(dev));
|
||||
dev.busnum = bus;
|
||||
dev.devnum = device;
|
||||
|
||||
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[] = {
|
||||
{ 0x8086, 0x7010, &pci_ide_init },
|
||||
};
|
||||
|
||||
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;
|
||||
if (pci_read(dev, PCI_VENDORID) == 0xFFFF) {
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
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);
|
||||
PciDev d = pci_scanfn(vendorid, deviceid, bus, device, 0, devtype);
|
||||
if (d.bits) {
|
||||
return d;
|
||||
}
|
||||
|
||||
devinfo.bus = bus;
|
||||
devinfo.dev = dev;
|
||||
devinfo.fn = fn;
|
||||
if (pci_isend(dev)) {
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
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].initfn(&devinfo);
|
||||
for (uint32_t fn = 1; fn < PCI_FN_PER_DEV; fn++) {
|
||||
if (pci_read(dev, PCI_VENDORID) != 0xFFFF) {
|
||||
d = pci_scanfn(vendorid, deviceid, bus, device, fn, devtype);
|
||||
if (d.bits) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
PciDev pci_getdev(uint16_t vendorid, uint16_t deviceid, int devtype) {
|
||||
PciDev d = pci_scanbus(vendorid, deviceid, 0, devtype);
|
||||
if (d.bits) {
|
||||
return d;
|
||||
}
|
||||
|
||||
if (pci_isend(PCI_DEV_ZERO)) {
|
||||
ERR("pci", "pci_getdev() failed\n");
|
||||
}
|
||||
|
||||
for (uint32_t fn = 1; fn < PCI_FN_PER_DEV; fn++) {
|
||||
PciDev d2; memset(&d2, 0, sizeof(d2));
|
||||
d2.fnnum = fn;
|
||||
|
||||
if (pci_read(d2, PCI_VENDORID) == 0xFFFF) {
|
||||
break;
|
||||
}
|
||||
|
||||
d = pci_scanbus(vendorid, deviceid, fn, devtype);
|
||||
if (d.bits) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
void pci_init_size_map(void) {
|
||||
PCI_SIZE_MAP[PCI_VENDORID] = 2;
|
||||
PCI_SIZE_MAP[PCI_DEVICEID] = 2;
|
||||
PCI_SIZE_MAP[PCI_CMD] = 2;
|
||||
PCI_SIZE_MAP[PCI_STATUS] = 2;
|
||||
PCI_SIZE_MAP[PCI_SUBCLASS] = 1;
|
||||
PCI_SIZE_MAP[PCI_CLASS] = 1;
|
||||
PCI_SIZE_MAP[PCI_CACHELINESZ] = 1;
|
||||
PCI_SIZE_MAP[PCI_LTNCY_TIMER] = 1;
|
||||
PCI_SIZE_MAP[PCI_HDRTYPE] = 1;
|
||||
PCI_SIZE_MAP[PCI_BIST] = 1;
|
||||
PCI_SIZE_MAP[PCI_BAR0] = 4;
|
||||
PCI_SIZE_MAP[PCI_BAR1] = 4;
|
||||
PCI_SIZE_MAP[PCI_BAR2] = 4;
|
||||
PCI_SIZE_MAP[PCI_BAR3] = 4;
|
||||
PCI_SIZE_MAP[PCI_BAR4] = 4;
|
||||
PCI_SIZE_MAP[PCI_BAR5] = 4;
|
||||
PCI_SIZE_MAP[PCI_INTRLINE] = 1;
|
||||
PCI_SIZE_MAP[PCI_SCNDRY_BUS] = 1;
|
||||
}
|
||||
|
||||
|
||||
PciInitFn PCI_INIT_ARRAY[PCI_INIT_ARRAY_MAX] = {
|
||||
&pci_ata_init,
|
||||
};
|
||||
|
||||
void pci_init_devs(void) {
|
||||
for (size_t i = 0; i < LEN(PCI_INIT_ARRAY); i++) {
|
||||
if (PCI_INIT_ARRAY[i] != NULL)
|
||||
PCI_INIT_ARRAY[i]();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
pci_init_size_map();
|
||||
pci_init_devs();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user