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
74
75
76
77
|
#include "drivers/pcie.h"
#include <drivers/pcie.h>
#include <main/acpi.h>
#include <mm/kmalloc.h>
#include <mm/pagetable.h>
#include <util/debug.h>
#define MCFG_SIGNATURE (*(uint32_t *)"MCFG")
static uintptr_t pcie_base_addr;
typedef struct pcie_table
{
pcie_device_t devices[PCI_NUM_BUSES][PCI_NUM_DEVICES_PER_BUS]
[PCI_NUM_FUNCTIONS_PER_DEVICE];
} pcie_table_t;
static pcie_table_t *pcie_table;
#define PCIE_DEV(bus, device, func) \
(&pcie_table->devices[(bus)][(device)][(func)])
static list_t pcie_wrapper_list;
void pci_init(void)
{
// TODO document; needs -machine type=q35 flag in qemu!
void *table = acpi_table(MCFG_SIGNATURE, 0);
KASSERT(table);
pcie_base_addr = *(uintptr_t *)((uintptr_t)table + 44) + PHYS_OFFSET;
pcie_table = (pcie_table_t *)pcie_base_addr;
pt_map_range(pt_get(), pcie_base_addr - PHYS_OFFSET, pcie_base_addr,
pcie_base_addr + PAGE_SIZE_1GB, PT_WRITE | PT_PRESENT,
PT_WRITE | PT_PRESENT);
list_init(&pcie_wrapper_list);
for (unsigned bus = 0; bus < PCI_NUM_BUSES; bus++)
{
for (unsigned device = 0; device < PCI_NUM_DEVICES_PER_BUS; device++)
{
unsigned int max_functions =
(PCIE_DEV(bus, device, 0)->standard.header_type & 0x80)
? PCI_NUM_DEVICES_PER_BUS
: 1;
for (unsigned function = 0; function < max_functions; function++)
{
pcie_device_t *dev = PCIE_DEV(bus, device, function);
if (!dev->standard.vendor_id ||
dev->standard.vendor_id == (uint16_t)-1)
continue;
pcie_device_wrapper_t *wrapper =
kmalloc(sizeof(pcie_device_wrapper_t));
wrapper->dev = dev;
wrapper->class = dev->standard.class;
wrapper->subclass = dev->standard.subclass;
wrapper->interface = dev->standard.prog_if;
list_link_init(&wrapper->link);
list_insert_tail(&pcie_wrapper_list, &wrapper->link);
}
}
}
}
pcie_device_t *pcie_lookup(uint8_t class, uint8_t subclass, uint8_t interface)
{
list_iterate(&pcie_wrapper_list, wrapper, pcie_device_wrapper_t, link)
{
/* verify the class subclass and interface are correct */
if (((class == PCI_LOOKUP_WILDCARD) || (wrapper->class == class)) &&
((subclass == PCI_LOOKUP_WILDCARD) ||
(wrapper->subclass == subclass)) &&
((interface == PCI_LOOKUP_WILDCARD) ||
(wrapper->interface == interface)))
{
return wrapper->dev;
}
}
return NULL;
}
|