mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 06:58:22 +00:00
pci: device enumeration with MCFG and legacy access
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
#include <kernel/dpc.h>
|
#include <kernel/dpc.h>
|
||||||
#include <kernel/pipefs.h>
|
#include <kernel/pipefs.h>
|
||||||
#include <kernel/fb.h>
|
#include <kernel/fb.h>
|
||||||
|
#include <kernel/pci.h>
|
||||||
|
|
||||||
static cpu_t bsp_cpu;
|
static cpu_t bsp_cpu;
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ void kernel_entry() {
|
|||||||
__assert(vfs_mount(NULL, vfsroot, "/dev", "devfs", NULL) == 0);
|
__assert(vfs_mount(NULL, vfsroot, "/dev", "devfs", NULL) == 0);
|
||||||
|
|
||||||
pseudodevices_init();
|
pseudodevices_init();
|
||||||
|
pci_init();
|
||||||
keyboard_init();
|
keyboard_init();
|
||||||
arch_ps2_init();
|
arch_ps2_init();
|
||||||
fb_init();
|
fb_init();
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#ifndef _PCI_H
|
||||||
|
#define _PCI_H
|
||||||
|
|
||||||
|
// 2 byte fields
|
||||||
|
#define PCI_CONFIG_VENDOR 0x0
|
||||||
|
#define PCI_CONFIG_DEVICEID 0x2
|
||||||
|
|
||||||
|
// 1 byte fields
|
||||||
|
#define PCI_CONFIG_REVISION 0x8
|
||||||
|
#define PCI_CONFIG_PROGIF 0x9
|
||||||
|
#define PCI_CONFIG_SUBCLASS 0xa
|
||||||
|
#define PCI_CONFIG_CLASS 0xb
|
||||||
|
#define PCI_CONFIG_HEADERTYPE 0xe
|
||||||
|
|
||||||
|
#define PCI_HEADERTYPE_MULTIFUNCTION_MASK 0x80
|
||||||
|
#define PCI_HEADERTYPE_MASK 0x7f
|
||||||
|
#define PCI_HEADERTYPE_STANDARD 0
|
||||||
|
|
||||||
|
typedef struct pcienum_t {
|
||||||
|
struct pcienum_t *next;
|
||||||
|
int bus;
|
||||||
|
int device;
|
||||||
|
int function;
|
||||||
|
int type;
|
||||||
|
int class;
|
||||||
|
int subclass;
|
||||||
|
int progif;
|
||||||
|
int vendor;
|
||||||
|
int deviceid;
|
||||||
|
int revision;
|
||||||
|
} pcienum_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);
|
||||||
|
void pci_init();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#ifdef _PCIARCH_H
|
||||||
|
#error this file should only be included ONCE and only in the io/pci.c file
|
||||||
|
#else
|
||||||
|
#define _PCIARCH_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <arch/acpi.h>
|
||||||
|
#include <kernel/pmm.h>
|
||||||
|
|
||||||
|
static size_t mcfgentrycount;
|
||||||
|
static mcfgentry_t *mcfgentries;
|
||||||
|
static uint32_t (*pci_archread32)(int bus, int device, int function, uint32_t offset);
|
||||||
|
static void (*pci_archwrite32)(int bus, int device, int function, uint32_t offset, uint32_t value);
|
||||||
|
|
||||||
|
#define CONFADD 0xcf8
|
||||||
|
#define CONFDATA 0xcfc
|
||||||
|
|
||||||
|
static uint32_t legacy_read32(int bus, int device, int function, uint32_t offset) {
|
||||||
|
uint32_t confadd = 0x80000000 | (offset & ~0x3) | (function << 8) | (device << 11) | (bus << 16);
|
||||||
|
outd(CONFADD, confadd);
|
||||||
|
return ind(CONFDATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void legacy_write32(int bus, int device, int function, uint32_t offset, uint32_t value) {
|
||||||
|
uint32_t confadd = 0x80000000 | (offset & ~0x3) | (function << 8) | (device << 11) | (bus << 16);
|
||||||
|
outd(CONFADD, confadd);
|
||||||
|
outd(CONFDATA, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline mcfgentry_t *getmcfgentry(int bus) {
|
||||||
|
mcfgentry_t *entry;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < mcfgentrycount; ++i) {
|
||||||
|
entry = &mcfgentries[i];
|
||||||
|
if (bus >= entry->startbus && bus <= entry->endbus)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == mcfgentrycount)
|
||||||
|
entry = NULL;
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t mcfg_read32(int bus, int device, int function, uint32_t offset) {
|
||||||
|
mcfgentry_t *entry = getmcfgentry(bus);
|
||||||
|
if (entry == NULL)
|
||||||
|
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));
|
||||||
|
|
||||||
|
return *address;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mcfg_write32(int bus, int device, int function, uint32_t offset, uint32_t value) {
|
||||||
|
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));
|
||||||
|
|
||||||
|
*address = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_archinit() {
|
||||||
|
mcfg_t *mcfg = arch_acpi_findtable("MCFG", 0);
|
||||||
|
if (mcfg) {
|
||||||
|
printf("pci: MCFG table found. Using extended configuration space\n");
|
||||||
|
mcfgentries = mcfg->entries;
|
||||||
|
pci_archread32 = mcfg_read32;
|
||||||
|
pci_archwrite32 = mcfg_write32;
|
||||||
|
mcfgentrycount = (mcfg->header.length - sizeof(sdtheader_t)) / sizeof(mcfgentry_t);
|
||||||
|
// TODO map mcfg entries as UC
|
||||||
|
} else {
|
||||||
|
printf("pci: MCFG table not found. Falling back to legacy access mechanism\n");
|
||||||
|
pci_archread32 = legacy_read32;
|
||||||
|
pci_archwrite32 = legacy_write32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#include <logging.h>
|
||||||
|
#include <arch/pci.h>
|
||||||
|
#include <kernel/pci.h>
|
||||||
|
#include <kernel/alloc.h>
|
||||||
|
|
||||||
|
uint8_t pci_read8(int bus, int device, int function, uint32_t offset) {
|
||||||
|
return (pci_archread32(bus, device, function, offset) >> ((offset & 0b11) * 8)) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t pci_read16(int bus, int device, int function, uint32_t offset) {
|
||||||
|
return (pci_archread32(bus, device, function, offset) >> ((offset & 0b11) * 8)) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pci_write8(int bus, int device, int function, uint32_t offset, uint8_t v) {
|
||||||
|
uint32_t old = pci_archread32(bus, device, function, offset);
|
||||||
|
int bitoffset = 8 * (offset & 0b11);
|
||||||
|
old &= ~(0xff << bitoffset);
|
||||||
|
old |= v << bitoffset;
|
||||||
|
pci_archwrite32(bus, device, function, offset, old);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pci_write16(int bus, int device, int function, uint32_t offset, uint16_t v) {
|
||||||
|
uint32_t old = pci_archread32(bus, device, function, offset);
|
||||||
|
int bitoffset = 8 * (offset & 0b11);
|
||||||
|
old &= ~(0xffff << bitoffset);
|
||||||
|
old |= v << bitoffset;
|
||||||
|
pci_archwrite32(bus, device, function, offset, old);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pcienum_t *enums;
|
||||||
|
|
||||||
|
// reads all 1s if a function doesn't exist
|
||||||
|
#define DOESNTEXIST(bus, device, function) (pci_read32(bus, device, function, 0) == 0xffffffff)
|
||||||
|
|
||||||
|
static void enumeratefunction(int bus, int device, int function) {
|
||||||
|
pcienum_t *e = alloc(sizeof(pcienum_t));
|
||||||
|
__assert(e);
|
||||||
|
e->bus = bus;
|
||||||
|
e->device = device;
|
||||||
|
e->function = function;
|
||||||
|
e->next = enums;
|
||||||
|
e->class = pci_read8(bus, device, function, PCI_CONFIG_CLASS);
|
||||||
|
e->subclass = pci_read8(bus, device, function, PCI_CONFIG_SUBCLASS);
|
||||||
|
e->progif = pci_read8(bus, device, function, PCI_CONFIG_PROGIF);
|
||||||
|
e->vendor = pci_read16(bus, device, function, PCI_CONFIG_VENDOR);
|
||||||
|
e->deviceid = pci_read16(bus, device, function, PCI_CONFIG_DEVICEID);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (int i = 0; i < testcount; ++i) {
|
||||||
|
if (DOESNTEXIST(bus, device, i))
|
||||||
|
continue;
|
||||||
|
enumeratefunction(bus, device, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pci_init() {
|
||||||
|
pci_archinit();
|
||||||
|
for (size_t bus = 0; bus < 1; ++bus) {
|
||||||
|
for (size_t device = 0; device < 32; ++device) {
|
||||||
|
if (DOESNTEXIST(bus, device, 0))
|
||||||
|
continue;
|
||||||
|
enumeratedevice(bus, device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user