1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "pci_scan.h"
4
5#include <mos/types.h>
6
7static 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
13static 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
19void 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
25void 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 header_type = 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
50void 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
67void scan_pci(pci_scan_callback_t callback)
68{
69 const u8 header_type = 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