1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
#include <kernel/arch/amd64/driver/rtl8139.h>
#include <kernel/arch/amd64/interrupts/irq.h>
#include <kernel/arch/amd64/pci.h>
#include <kernel/arch/amd64/port_io.h>
#include <kernel/arch/generic.h>
#include <kernel/panic.h>
static const uint16_t CONFIG_ADDRESS = 0xCF8;
static const uint16_t CONFIG_DATA = 0xCFC;
uint8_t pcicfg_r8(uint32_t bdf, uint32_t offset) {
return pcicfg_r32(bdf, offset) >> ((offset & 3) * 8);
}
uint16_t pcicfg_r16(uint32_t bdf, uint32_t offset) {
return pcicfg_r32(bdf, offset) >> ((offset & 2) * 8);
}
uint32_t pcicfg_r32(uint32_t bdf, uint32_t offset) {
port_out32(CONFIG_ADDRESS, 0x80000000 | bdf | (offset & ~3));
return port_in32(CONFIG_DATA);
}
void pcicfg_w32(uint32_t bdf, uint32_t offset, uint32_t value) {
port_out32(CONFIG_ADDRESS, 0x80000000 | bdf | (offset & ~3));
port_out32(CONFIG_DATA, value);
}
uint16_t pcicfg_iobase(uint32_t bdf) {
/* cuts corners, assumes header type 0, etc */
uint32_t bar = pcicfg_r32(bdf, 0x10);
if (!(bar & 1))
panic_unimplemented(); /* not an io bar */
return bar & ~3;
}
static uint32_t bdf_of(uint32_t bus, uint32_t device, uint32_t func) {
return (bus << 16) | (device << 11) | (func << 8);
}
static void scan_bus(uint32_t bus) {
for (int slot = 0; slot < 32; slot++) {
int fn_amt = 1;
for (int fn = 0; fn < fn_amt; fn++) {
uint32_t bdf = bdf_of(bus, slot, fn);
uint32_t id = pcicfg_r32(bdf, 0);
if (id == 0xFFFFFFFF) break;
kprintf("pci %02x:%02x.%x\t%x\n", bus, slot, fn, id);
uint8_t hdr_type = pcicfg_r8(bdf, 0xE);
if (hdr_type & 0x80) {
fn_amt = 8;
hdr_type &= ~0x80;
}
if (hdr_type != 0) {
kprintf("pci: skipping unknown header %x\n", hdr_type);
continue;
}
if (id == 0x813910ec) {
pcicfg_w32(bdf, 0x3C, IRQ_RTL8139);
rtl8139_init(bdf);
}
}
}
}
void pci_init(void) {
scan_bus(0);
// TODO multiple host controllers
}
|