summaryrefslogtreecommitdiff
path: root/documentation/6.components/device-driver/pci/pci_access.md
blob: 3aebdff1d9da8cdbb0c71421a879fc1d087900d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
@page page_device_pci_access PCI config space access

# Config space (`access.c`, `rt_pci_ops`)

All enumeration and drivers reach hardware through **`struct rt_pci_ops`** on each **`rt_pci_bus`**.

Sources: **`components/drivers/pci/access.c`**, **`ecam.c`** (typical **`ops`** implementation).

---

## `struct rt_pci_ops`

| Callback | Role |
| --- | --- |
| **`map(bus, devfn, reg)`** | Optional MMIO pointer to config dword (ECAM) |
| **`read(bus, devfn, reg, width, &value)`** | Config read |
| **`write(bus, devfn, reg, width, value)`** | Config write |
| **`add` / `remove`** | Bus hook (optional) |

Host bridge sets **`host_bridge->ops`**; child buses inherit or use **`child_ops`**.

---

## Locked accessors (`access.c`)

| API | Role |
| --- | --- |
| **`rt_pci_bus_read_config_u8/u16/u32`** | Bus-level read |
| **`rt_pci_bus_write_config_u8/u16/u32`** | Bus-level write |
| **`rt_pci_bus_read_config_uxx`** | Width 1/2/4; uses **`map`** if implemented |
| **`rt_pci_read_config_* (pdev, …)`** | Inline wrappers using **`pdev->devfn`** |

Global **`rt_pci_lock`** serializes config unless **`RT_PCI_LOCKLESS=y`**.

On read error, typed helpers may return **`~0`** — check **`rt_err_t`** from **`bus->ops->read`** when critical.

---

## ECAM fast path

**`pci_ecam_map`** computes:

```text
win + (bus_offset | devfn_offset | reg_offset)
```

**`rt_pci_bus_read_config_uxx`** reads via **`HWREG8/16/32`** when **`map`** is non-NULL.

See @ref page_device_pci_host for **`pci_generic_ecam_ops`** and DesignWare **`bus_shift`** variants.

---

## Config space size

**`pdev->cfg_size`** set in **`rt_pci_setup_device`**:

- Standard 256 bytes, or extended 4 KiB if extended capability present.

Use **`rt_pci_find_capability`** only within valid size.

---

## MMIO from BAR (not config)

| API | Role |
| --- | --- |
| **`rt_pci_iomap(pdev, bar_idx)`** | **`rt_ioremap(resource[bar].base, size)`** |

BAR CPU addresses come from enumeration — do not confuse with ECAM config window.

---

## Pitfalls

| Issue | Mitigation |
| --- | --- |
| Config during IRQ | Lock held by **`access.c`** — avoid long callbacks under lock |
| **`map` returns NULL** | Fall back to **`read`/`write`** ops only |
| Wrong **`devfn`** on secondary bus | Always use **`pdev->devfn`** on device's bus |
| Byte enables on IO | Use correct width API for register layout |

## See also

- @ref page_device_pci_probe
- @ref page_device_pci_host
- @ref page_device_pci