1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "pci_scan.h" |
4 | |
5 | #include <mos/types.h> |
6 | |
7 | static u8 pcie_read8(u8 bus, u8 slot, u8 func, u8 offset) |
8 | { |
9 | const ptr_t addr = mmio_base + (bus << 20) + (slot << 15) + (func << 12) + offset; // PCI Express Extended Configuration Space |
10 | return *((volatile u8 *) addr); |
11 | } |
12 | |
13 | static u16 pci_read16(u8 bus, u8 slot, u8 func, u8 offset) |
14 | { |
15 | const ptr_t addr = mmio_base + (bus << 20) + (slot << 15) + (func << 12) + offset; |
16 | return *((volatile u16 *) addr); |
17 | } |
18 | |
19 | void scan_bus(u8 bus, pci_scan_callback_t callback) |
20 | { |
21 | for (u8 device = 0; device < 32; device++) |
22 | scan_device(bus, device, callback); |
23 | } |
24 | |
25 | void scan_device(u8 bus, u8 device, pci_scan_callback_t callback) |
26 | { |
27 | u8 function = 0; |
28 | const u16 vendor = pci_read16(bus, slot: device, func: function, PCI_OFFSET_VENDOR_ID); |
29 | if (vendor == 0xFFFF) |
30 | return; |
31 | |
32 | scan_function(bus, device, function, callback); |
33 | function++; |
34 | |
35 | const u8 = pcie_read8(bus, slot: device, func: function, PCI_OFFSET_HEADER_TYPE); |
36 | if (header_type & PCI_HEADER_TYPE_MULTIFUNC) |
37 | { |
38 | // check remaining functions if this is a multi-function device |
39 | for (; function < 8; function++) |
40 | { |
41 | u16 vendor = pci_read16(bus, slot: device, func: function, PCI_OFFSET_VENDOR_ID); |
42 | if (vendor == 0xFFFF) |
43 | continue; |
44 | |
45 | scan_function(bus, device, function, callback); |
46 | } |
47 | } |
48 | } |
49 | |
50 | void scan_function(u8 bus, u8 device, u8 function, pci_scan_callback_t callback) |
51 | { |
52 | const u8 baseClass = pcie_read8(bus, slot: device, func: function, PCI_OFFSET_BASE_CLASS); |
53 | const u8 subClass = pcie_read8(bus, slot: device, func: function, PCI_OFFSET_SUB_CLASS); |
54 | const u8 progIF = pcie_read8(bus, slot: device, func: function, PCI_OFFSET_PROG_IF); |
55 | const u16 deviceID = pci_read16(bus, slot: device, func: function, PCI_OFFSET_DEVICE_ID); |
56 | const u16 vendorID = pci_read16(bus, slot: device, func: function, PCI_OFFSET_VENDOR_ID); |
57 | |
58 | callback(bus, device, function, vendorID, deviceID, baseClass, subClass, progIF); |
59 | |
60 | if ((baseClass == 0x6) && (subClass == 0x4)) |
61 | { |
62 | const u8 secondaryBus = pcie_read8(bus, slot: device, func: function, offset: 0x19); |
63 | scan_bus(bus: secondaryBus, callback); |
64 | } |
65 | } |
66 | |
67 | void scan_pci(pci_scan_callback_t callback) |
68 | { |
69 | const u8 = pcie_read8(bus: 0, slot: 0, func: 0, offset: 0xE); |
70 | if ((header_type & 0x80) == 0) |
71 | { |
72 | scan_bus(bus: 0, callback); |
73 | } |
74 | else |
75 | { |
76 | for (u8 function = 0; function < 8; function++) |
77 | { |
78 | u16 vendor = pci_read16(bus: 0, slot: 0, func: function, offset: 0); |
79 | if (vendor != 0xFFFF) |
80 | break; |
81 | scan_bus(bus: function, callback); |
82 | } |
83 | } |
84 | } |
85 | |