Missing PCI devices when enumerating

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
pdd99
Posts: 1
Joined: Wed Dec 18, 2024 9:22 am
Libera.chat IRC: pdd99

Missing PCI devices when enumerating

Post by pdd99 »

I'm learning about PCI, starting with PCI enumeration. I have implemented a linux kernel module for this task, using the IO port approach:

Code: Select all

#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>

#define PCI_CONFIG_ADDRESS 0xCF8
#define PCI_CONFIG_DATA 0xCFC

#define MAX_BUS 256
#define MAX_DEVICE 32
#define MAX_FUNCTION 8

// Function to read a 32-bit value from the PCI configuration space using I/O ports
static u32 pci_config_read_u32(u8 bus, u8 device, u8 function, u8 offset) {
  u32 address = (1 << 31) | (bus << 16) | (device << 11) | (function << 8) | (offset & ~3);
  outl(address, PCI_CONFIG_ADDRESS);  // Write address to 0xCF8
  return inl(PCI_CONFIG_DATA);        // Read data from 0xCFC
}

// Function to enumerate PCI devices using I/O ports
static void enumerate_pci_devices(void) {
  int bus, device, function;
  u32 vendor_device_id;

  for (bus = 0; bus < MAX_BUS; bus++) {
    for (device = 0; device < MAX_DEVICE; device++) {
      for (function = 0; function < MAX_FUNCTION; function++) {
        // Read the first 4 bytes of the PCI configuration space (Vendor ID + Device ID)
        vendor_device_id = pci_config_read_u32(bus, device, function, 0);

        // Extract Vendor ID and Device ID
        u16 vendor_id = vendor_device_id & 0xFFFF;
        u16 device_id = (vendor_device_id >> 16) & 0xFFFF;

        // Check if a device is present (Vendor ID must not be 0xFFFF)
        if (vendor_id == 0xFFFF)
          continue;

        pr_info("PCI Device Found: Bus %02x Device %02x Function %x Vendor ID: %04x Device ID: %04x\n",
                bus, device, function, vendor_id, device_id);
      }
    }
  }
}

static int __init pci_io_driver_init(void) {
  pr_info("Initializing PCI I/O Port Driver\n");

  // Enumerate all PCI devices using I/O ports
  enumerate_pci_devices();

  return 0;
}

static void __exit pci_io_driver_exit(void) {
  pr_info("PCI I/O Port Driver Unloaded\n");
}

module_init(pci_io_driver_init);
module_exit(pci_io_driver_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("PCI Enumeration Driver using I/O Ports");
MODULE_AUTHOR("Linux User");
The module log using dmesg:

Code: Select all

# dmesg
[ 5602.968050] Initializing PCI I/O Port Driver
[ 5602.968054] PCI Device Found: Bus 00 Device 00 Function 0 Vendor ID: 8086 Device ID: 9a14
[ 5602.968056] PCI Device Found: Bus 00 Device 00 Function 1 Vendor ID: 0002 Device ID: 0401
[ 5602.968068] PCI Device Found: Bus 00 Device 00 Function 3 Vendor ID: 0000 Device ID: 0000
[ 5602.968070] PCI Device Found: Bus 00 Device 00 Function 4 Vendor ID: 0000 Device ID: 0000
[ 5602.968073] PCI Device Found: Bus 00 Device 00 Function 5 Vendor ID: 0010 Device ID: 0000
[ 5602.968109] PCI Device Found: Bus 00 Device 02 Function 0 Vendor ID: 8086 Device ID: 9a49
[ 5602.968140] PCI Device Found: Bus 00 Device 04 Function 0 Vendor ID: 8086 Device ID: 9a03
[ 5602.968196] PCI Device Found: Bus 00 Device 06 Function 0 Vendor ID: 8086 Device ID: 9a09
[ 5602.968289] PCI Device Found: Bus 00 Device 0a Function 0 Vendor ID: 8086 Device ID: 9a0d
[ 5602.968363] PCI Device Found: Bus 00 Device 0d Function 0 Vendor ID: 8086 Device ID: 9a13
[ 5602.968411] PCI Device Found: Bus 00 Device 0e Function 0 Vendor ID: 8086 Device ID: 9a0b
[ 5602.968557] PCI Device Found: Bus 00 Device 14 Function 0 Vendor ID: 8086 Device ID: a0ed
[ 5602.968570] PCI Device Found: Bus 00 Device 14 Function 2 Vendor ID: 8086 Device ID: a0ef
[ 5602.968640] PCI Device Found: Bus 00 Device 14 Function 3 Vendor ID: 8086 Device ID: a0f0
[ 5602.968702] PCI Device Found: Bus 00 Device 15 Function 0 Vendor ID: 8086 Device ID: a0e8
[ 5602.968738] PCI Device Found: Bus 00 Device 16 Function 0 Vendor ID: 8086 Device ID: a0e0
[ 5602.968884] PCI Device Found: Bus 00 Device 1c Function 0 Vendor ID: 8086 Device ID: a0bd
[ 5602.968909] PCI Device Found: Bus 00 Device 1c Function 7 Vendor ID: 8086 Device ID: a0bf
[ 5602.968912] PCI Device Found: Bus 00 Device 1d Function 0 Vendor ID: 8086 Device ID: a0b0
[ 5602.968958] PCI Device Found: Bus 00 Device 1f Function 0 Vendor ID: 8086 Device ID: a082
[ 5602.968982] PCI Device Found: Bus 00 Device 1f Function 3 Vendor ID: 8086 Device ID: a0c8
[ 5602.968987] PCI Device Found: Bus 00 Device 1f Function 4 Vendor ID: 8086 Device ID: a0a3
[ 5602.968990] PCI Device Found: Bus 00 Device 1f Function 5 Vendor ID: 8086 Device ID: a0a4
[ 5602.970453] PCI Device Found: Bus 03 Device 00 Function 0 Vendor ID: 10ec Device ID: 8168
[ 5602.970687] PCI Device Found: Bus 04 Device 00 Function 0 Vendor ID: 1e0f Device ID: 0001
But when I list all pci devices using lspci, I found out that my NVIDIA MX450 (bus 1) and Realtek PCIe Card Reader (bus 2) are missing in the kernel module log:

Code: Select all

# lspci -tv
-[0000:00]-+-00.0  Intel Corporation 11th Gen Core Processor Host Bridge/DRAM Registers
           +-02.0  Intel Corporation TigerLake-LP GT2 [Iris Xe Graphics]
           +-04.0  Intel Corporation TigerLake-LP Dynamic Tuning Processor Participant
           +-06.0-[01]----00.0  NVIDIA Corporation TU117M [GeForce MX450]
           +-0a.0  Intel Corporation Tigerlake Telemetry Aggregator Driver
           +-0d.0  Intel Corporation Tiger Lake-LP Thunderbolt 4 USB Controller
           +-0e.0  Intel Corporation Volume Management Device NVMe RAID Controller
           +-14.0  Intel Corporation Tiger Lake-LP USB 3.2 Gen 2x1 xHCI Host Controller
           +-14.2  Intel Corporation Tiger Lake-LP Shared SRAM
           +-14.3  Intel Corporation Wi-Fi 6 AX201
           +-15.0  Intel Corporation Tiger Lake-LP Serial IO I2C Controller #0
           +-16.0  Intel Corporation Tiger Lake-LP Management Engine Interface
           +-1c.0-[02]----00.0  Realtek Semiconductor Co., Ltd. RTS522A PCI Express Card Reader
           +-1c.7-[03]----00.0  Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller
           +-1d.0-[04]----00.0  KIOXIA Corporation Device 0001
           +-1f.0  Intel Corporation Tiger Lake-LP LPC Controller
           +-1f.3  Intel Corporation Tiger Lake-LP Smart Sound Technology Audio Controller
           +-1f.4  Intel Corporation Tiger Lake-LP SMBus Controller
           \-1f.5  Intel Corporation Tiger Lake-LP SPI Controller
What am I missing here? Does linux have some kind of architecture specific code for PCI detection? Thanks in advance.
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Missing PCI devices when enumerating

Post by Octocontrabass »

The legacy PCI configuration access mechanism has concurrency issues. You need to lock it for exclusive access to prevent other drivers from using it.

The legacy PCI configuration access mechanism might not work in the first place, since modern OSes will prefer the PCIe extended configuration access method.

Your code is trying to enumerate multiple functions without first making sure the device in question supports multiple functions. While this isn't supposed to cause any problems, it's not how anyone else enumerates PCI, and hardware sometimes gets confused when you don't do things the same as everyone else.
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: Missing PCI devices when enumerating

Post by nullplan »

I am also pretty sure that Linux already has code that does that, so why not study that instead? It even has code to initialize PCI, if you are interested in that.
Carpe diem!
rdos
Member
Member
Posts: 3297
Joined: Wed Oct 01, 2008 1:55 pm

Re: Missing PCI devices when enumerating

Post by rdos »

I also use the legacy interface to enumerate PCI. It will work with all PCI versions, back to the original, while the extended method will not.
Post Reply