mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
pci: pci_getenum, pci_getcapoffset and finding msi and msix on function enumeration
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
// 2 byte fields
|
||||
#define PCI_CONFIG_VENDOR 0x0
|
||||
#define PCI_CONFIG_DEVICEID 0x2
|
||||
#define PCI_CONFIG_STATUS 0x6
|
||||
#define PCI_STATUS_HASCAP 0x10
|
||||
|
||||
// 1 byte fields
|
||||
#define PCI_CONFIG_REVISION 0x8
|
||||
@@ -16,6 +18,16 @@
|
||||
#define PCI_HEADERTYPE_MASK 0x7f
|
||||
#define PCI_HEADERTYPE_STANDARD 0
|
||||
|
||||
#define PCI_CONFIG_CAP 0x34
|
||||
|
||||
#define PCI_CAP_MSI 0x5
|
||||
#define PCI_CAP_MSIX 0x11
|
||||
|
||||
typedef struct {
|
||||
bool exists;
|
||||
int offset;
|
||||
} pcicap_t;
|
||||
|
||||
typedef struct pcienum_t {
|
||||
struct pcienum_t *next;
|
||||
int bus;
|
||||
@@ -28,14 +40,25 @@ typedef struct pcienum_t {
|
||||
int vendor;
|
||||
int deviceid;
|
||||
int revision;
|
||||
pcicap_t msi;
|
||||
pcicap_t msix;
|
||||
} pcienum_t;
|
||||
|
||||
typedef struct {
|
||||
uintptr_t address;
|
||||
size_t length;
|
||||
bool mmio;
|
||||
} pcibar_t;
|
||||
|
||||
uint8_t pci_read8(int bus, int device, int function, uint32_t offset);
|
||||
uint16_t pci_read16(int bus, int device, int function, uint32_t offset);
|
||||
uint32_t pci_read32(int bus, int device, int function, uint32_t offset);
|
||||
void pci_write8(int bus, int device, int function, uint32_t offset, uint8_t v);
|
||||
void pci_write16(int bus, int device, int function, uint32_t offset, uint16_t v);
|
||||
void pci_write32(int bus, int device, int function, uint32_t offset, uint32_t value);
|
||||
pcienum_t *pci_getenum(int class, int subclass, int progif, int vendor, int deviceid, int revision, int n);
|
||||
int pci_getcapoffset(pcienum_t *e, int cap, int n);
|
||||
pcibar_t pci_getbar(pcienum_t *e, int bar);
|
||||
void pci_init();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -51,7 +51,7 @@ static uint32_t mcfg_read32(int bus, int device, int function, uint32_t offset)
|
||||
return 0xffffffff;
|
||||
|
||||
uint64_t base = (uint64_t)MAKE_HHDM(entry->address);
|
||||
uint32_t *address = (uint32_t *)(base + ((bus - entry->startbus) << 20) + (device << 15) + (function << 12));
|
||||
uint32_t *address = (uint32_t *)(base | ((bus - entry->startbus) << 20) | (device << 15) | (function << 12) | (offset & ~0x3));
|
||||
|
||||
return *address;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ static void mcfg_write32(int bus, int device, int function, uint32_t offset, uin
|
||||
mcfgentry_t *entry = getmcfgentry(bus);
|
||||
|
||||
uint64_t base = (uint64_t)MAKE_HHDM(entry->address);
|
||||
uint32_t *address = (uint32_t *)(base + ((bus - entry->startbus) << 20) + (device << 15) + (function << 12));
|
||||
uint32_t *address = (uint32_t *)(base | ((bus - entry->startbus) << 20) | (device << 15) | (function << 12) | (offset & ~0x3));
|
||||
|
||||
*address = value;
|
||||
}
|
||||
|
||||
+84
-4
@@ -30,12 +30,79 @@ void pci_write16(int bus, int device, int function, uint32_t offset, uint16_t v)
|
||||
uint32_t pci_read32(int bus, int device, int function, uint32_t offset) {
|
||||
return pci_archread32(bus, device, function, offset);
|
||||
}
|
||||
|
||||
void pci_write32(int bus, int device, int function, uint32_t offset, uint32_t value) {
|
||||
return pci_archwrite32(bus, device, function, offset, value);
|
||||
pci_archwrite32(bus, device, function, offset, value);
|
||||
}
|
||||
|
||||
int pci_getcapoffset(pcienum_t *e, int cap, int n) {
|
||||
if ((pci_read16(e->bus, e->device, e->function, PCI_CONFIG_STATUS) & PCI_STATUS_HASCAP) == 0)
|
||||
return 0;
|
||||
|
||||
int offset = pci_read8(e->bus, e->device, e->function, PCI_CONFIG_CAP);
|
||||
while (offset) {
|
||||
if (pci_read8(e->bus, e->device, e->function, offset) == cap) {
|
||||
if (n-- == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
offset = pci_read8(e->bus, e->device, e->function, offset + 1);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
#define BAR_IO 1
|
||||
#define BAR_TYPE_MASK 0x6
|
||||
#define BAR_TYPE_64BIT 0x4
|
||||
|
||||
pcibar_t pci_getbar(pcienum_t *e, int n) {
|
||||
// TODO map bars (also taking in count the prefetchable flag)
|
||||
pcibar_t ret;
|
||||
int offset = 0x10 + n * 4;
|
||||
|
||||
uint32_t bar = pci_read32(e->bus, e->device, e->function, offset);
|
||||
if (bar & BAR_IO) {
|
||||
ret.mmio = false;
|
||||
ret.address = bar & 0xfffffffc;
|
||||
pci_write32(e->bus, e->device, e->function, offset, -1);
|
||||
ret.length = ~(pci_read32(e->bus, e->device, e->function, offset) & 0xfffffffc) + 1;
|
||||
pci_write32(e->bus, e->device, e->function, offset, bar);
|
||||
} else {
|
||||
ret.mmio = true;
|
||||
ret.address = bar & 0xfffffff0;
|
||||
ret.length = -1;
|
||||
if ((bar & BAR_TYPE_MASK) == BAR_TYPE_64BIT)
|
||||
ret.address = (uint64_t)pci_read32(e->bus, e->device, e->function, offset + 4) << 32;
|
||||
|
||||
pci_write32(e->bus, e->device, e->function, offset, -1);
|
||||
ret.length = ~(pci_read32(e->bus, e->device, e->function, offset) & 0xfffffff0) + 1;
|
||||
pci_write32(e->bus, e->device, e->function, offset, bar);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static pcienum_t *enums;
|
||||
|
||||
pcienum_t *pci_getenum(int class, int subclass, int progif, int vendor, int deviceid, int revision, int n) {
|
||||
pcienum_t *e;
|
||||
for (e = enums; e; e = e->next) {
|
||||
if (
|
||||
(class == -1 || e->class == class) &&
|
||||
(subclass == -1 || e->subclass == subclass) &&
|
||||
(progif == -1 || e->progif == progif) &&
|
||||
(vendor == -1 || e->vendor == vendor) &&
|
||||
(deviceid == -1 || e->deviceid == deviceid) &&
|
||||
(revision == -1 || e->revision == revision)) {
|
||||
if (n-- == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
// reads all 1s if a function doesn't exist
|
||||
#define DOESNTEXIST(bus, device, function) (pci_read32(bus, device, function, 0) == 0xffffffff)
|
||||
|
||||
@@ -54,12 +121,25 @@ static void enumeratefunction(int bus, int device, int function) {
|
||||
e->revision = pci_read8(bus, device, function, PCI_CONFIG_REVISION);
|
||||
enums = e;
|
||||
|
||||
printf("pci: found %02x:%02x.%x %02x%02x: %04x:%04x (rev %2x) \n", bus, device, function, e->class, e->subclass, e->vendor, e->device, e->revision);
|
||||
int offset = pci_getcapoffset(e, PCI_CAP_MSIX, 0);
|
||||
if (offset) {
|
||||
e->msix.exists = true;
|
||||
e->msix.offset = offset;
|
||||
}
|
||||
|
||||
offset = pci_getcapoffset(e, PCI_CAP_MSI, 0);
|
||||
if (offset) {
|
||||
e->msi.exists = true;
|
||||
e->msi.offset = offset;
|
||||
}
|
||||
|
||||
char *irqtype = e->msix.exists ? "msi-x" : (e->msi.exists ? "msi" : "no interrupts");
|
||||
printf("pci: found %02x:%02x.%x %02x%02x: %04x:%04x (rev %2x) (%s)\n", bus, device, function, e->class, e->subclass, e->vendor, e->device, e->revision, irqtype);
|
||||
}
|
||||
|
||||
static void enumeratedevice(int bus, int device) {
|
||||
bool multifunction = pci_read32(bus, device, 0, PCI_CONFIG_HEADERTYPE) & PCI_HEADERTYPE_MULTIFUNCTION_MASK;
|
||||
size_t testcount = multifunction ? 1 : 8;
|
||||
bool multifunction = pci_read8(bus, device, 0, PCI_CONFIG_HEADERTYPE) & PCI_HEADERTYPE_MULTIFUNCTION_MASK;
|
||||
size_t testcount = multifunction ? 8 : 1;
|
||||
|
||||
for (int i = 0; i < testcount; ++i) {
|
||||
if (DOESNTEXIST(bus, device, i))
|
||||
|
||||
Reference in New Issue
Block a user