![]() |
RT-Thread RTOS
An open source embedded real-time operating system
|
End-to-end host bring-up → bus scan → BAR assignment → driver probe. Sources: **probe.c** (scan/host), **pci.c** (regions, register, bus), **ofw.c** (DT windows).
Typical ECAM host (**pci_host_common_probe** in host/pci-host-common.c):
DesignWare and other hosts follow the same pattern after link/DBI setup (PCI host controllers).
**rt_pci_host_bridge_probe** → **rt_pci_scan_root_bus_bridge**:
Depth-first: all devices on bus N are scanned, then each bridge opens bus N+1 and recurses.
If **rt_pci_setup_device** fails, the **rt_pci_device** is freed and the slot is skipped.
Order inside **probe.c** / **pci.c**:
| Step | Action |
|---|---|
| 1 | **rt_pci_ofw_device_init** — bind OFW node if any |
| 2 | Read class, hdr_type, clear STATUS errors |
| 3 | **pci_read_irq** — read INTPIN / INTLINE from config only (not mapped yet) |
| 4 | **rt_pci_device_alloc_resource** — size BARs, **rt_pci_region_alloc**, write BAR registers, enable bridge windows |
| 5 | **pci_init_capabilities** — **rt_pci_pme_init**, **rt_pci_msi_init/msix_init** (disabled), PCIe cap, cfg_size, ARI |
Device name set to **domain:bus:slot.func**.
When **rt_pci_device_register** adds the device to the PCI bus:
Important: function driver **probe** runs after BARs are assigned and after **rt_pci_assign_irq**. Use **rt_pci_iomap** / **rt_pci_alloc_vector** here, not during scan.
| When | What |
|---|---|
**rt_pci_setup_device** | **pci_read_irq** — raw config pin/line |
**pci_probe (bus)** | **rt_pci_assign_irq** — **irq_map** / OFW → **pdev->irq**, **intx_pic** |
Function **pdrv->probe** | MSI/MSI-X enable, **rt_pic_*** register |
| API | Role |
|---|---|
**rt_pci_host_bridge_alloc(priv_size)** | Allocate host bridge + private tail |
**rt_pci_host_bridge_init** | OFW: **rt_pci_ofw_host_bridge_init** |
**rt_pci_host_bridge_probe** | **rt_pci_scan_root_bus_bridge** |
**rt_pci_host_bridge_register** | Create root **rt_pci_bus** |
**rt_pci_host_bridge_remove** | Enum remove all devices |
| API | Role |
|---|---|
**rt_pci_scan_child_bus(bus)** | Entry: scan one bus + bridges |
**rt_pci_scan_child_buses** | Slots 0–30, then bridge extend |
**rt_pci_scan_slot** | All functions on one devfn (MF/ARI) |
**rt_pci_scan_single_device** | One function if vendor valid |
**rt_pci_scan_bridge** | Bridge secondary bus setup |
**rt_pci_alloc_device** | Allocate **rt_pci_device**, link to bus |
Bridges: **pdev->subbus** after **pci_scan_bridge_extend**. Endpoints: **subbus == NULL**.
See Phase D above. Invalid header/class → error, device discarded.
| API | Role |
|---|---|
**rt_pci_region_setup** | After OFW **ranges**: log pools, **bus_start ≥ 0x1000** |
**rt_pci_region_alloc** | Carve BAR/bus address from **bus_regions** |
**rt_pci_device_alloc_resource** | Probe BAR sizes, assign, write config |
**rt_pci_find_bar** | Lookup assigned BAR by flags/index |
| API | Role |
|---|---|
**rt_pci_match_ids** | Match during **pci_match** |
**rt_pci_driver_register** | Register on PCI bus (export macro at init) |
**rt_pci_device_register** | After scan — triggers bus **probe** |
**rt_pci_enum_device** | Walk tree callback |
| API | Role |
|---|---|
**rt_pci_domain**, **rt_pci_find_host_bridge** | Domain / host lookup |
**rt_pci_is_bridge**, **rt_pci_is_pcie** | Type checks |
**rt_pci_find_capability** | Capability walk |
| Issue | Mitigation |
|---|---|
MMIO in scan before **device_register** | Wait for function **probe** |
| BARs empty | Fix DT **ranges** + **rt_pci_region_setup** |
**irq == 0** after probe | Check **interrupt-map** / use MSI |
| Bridge bus exhausted | **bus-range** too small in DTS |
| Scan order vs driver | **RT_PCI_DRIVER_EXPORT** drivers already registered before host probe |