Page 1 of 1

Better way of scanning PCE?

Posted: Fri Aug 14, 2020 7:12 pm
by Ethin
So, I've just managed to get PCE working. (Hooray!) I'mable to enumerate all possible PCI devices on the system. The problem is, of course... that its, well... really, reaaaaally slow. Right now I scan for all 16,777,216 possible devices like this:

Code: Select all

pub fn probe() {
    printkln!("Init: PCI scan started");
    if let Ok(table) = acpi::init() {
        if let Some(regions) = table.pci_config_regions {
            for sg in 0..MAX_SG {
                for bus in 0..MAX_BUS {
                    for device in 0..MAX_DEVICE {
                        for function in 0..MAX_FUNCTION {
                            if let Some(addr) = regions.physical_address(
                                sg as u16,
                                bus as u8,
                                device as u8,
                                function as u8,
                            ) {
                                // Do this check anyway
                                use crate::memory::{allocate_phys_range, free_range};
                                allocate_phys_range(addr.clone(), addr.clone() + 4096);
                                if (read_dword(addr as usize, VENDOR_ID) & 0xFFFF) == 0xFFFF {
                                    free_range(addr.clone(), addr.clone() + 4096);
                                    continue;
                                }
                                // Add the device...
                            } else {
                                continue;
                            }
                        }
                    }
                }
            }
            let devs = PCI_DEVICES.read();
            printkln!("init: PCI scan complete; {} devices found", devs.len());
        } else {
            printkln!("init: error: no PCI regions");
        }
    } else {
        printkln!("init: error: ACPI unsupported");
    }
}
As you can imagine, this is absolutely insane. Is there a better way of doing this that doesn't require me to scan segment groups that don't exist?
Edit: Also, if I scan a segment group and ask for all devices on BDF 0:0:0, can I safely assume that no devices exist if I ask for <sg here>:0:0:0 but I don't get anything on that sg:bus:dev:func? Like, if I ask the system for segment group 32, and BDF 0:0:0, can I safely assume that there are no devices in SG 32 if I get nothing back?

Re: Better way of scanning PCE?

Posted: Fri Aug 14, 2020 9:53 pm
by Octocontrabass
You meant PCIe instead of PCE, right?

The ACPI MCFG table describes all valid sg:bus combinations and their MMIO addresses. You can't scan segment groups or buses that don't exist, since they have no MMIO address, so your scan will be quite fast even if you do scan all existing segment groups and buses.

The MCFG table doesn't describe hot-pluggable devices, in case you have some of those and want to know why your scan doesn't find them.

Re: Better way of scanning PCE?

Posted: Fri Aug 14, 2020 10:19 pm
by Ethin
Octocontrabass wrote:You meant PCIe instead of PCE, right?

The ACPI MCFG table describes all valid sg:bus combinations and their MMIO addresses. You can't scan segment groups or buses that don't exist, since they have no MMIO address, so your scan will be quite fast even if you do scan all existing segment groups and buses.

The MCFG table doesn't describe hot-pluggable devices, in case you have some of those and want to know why your scan doesn't find them.
That's odd because if I loop through everything in a nested loop the PCI code appears to take forever to scan through all possible segments. That just might be TCG though. And yes, I did mean PCIe. And thanks for that little tidbit about hot-pluggable devices.

Re: Better way of scanning PCE?

Posted: Fri Aug 14, 2020 10:45 pm
by nullplan
You can reduce the amount of stuff to scan quite significantly:
  1. You only need to scan function 0. If the header for function 0 has the multi-function bit set, then you also need to scan the other functions, but if that bit is not set, or the device doesn't exist, then you don't.
  2. You only need to scan the busses that actually exist. On PCI, this means you only scan the root busses. If you find a PCI bridge, you raise the bus limit up to the bridge's subordinate bus number. All existing busses have consecutive numbers.
I don't know what segment groups are about. I only ever found machines with a single segment group.

Re: Better way of scanning PCE?

Posted: Fri Aug 14, 2020 10:52 pm
by Octocontrabass
Ethin wrote:That's odd because if I loop through everything in a nested loop the PCI code appears to take forever to scan through all possible segments.
That's because you're looping through impossible segment groups as well. Use the MCFG table to limit your search space.