soc/intel/pantherlake: Remove soc_info.[hc] interface
[coreboot2.git] / src / soc / intel / common / block / pcie / pcie_rp.c
blob650da1ff9149cf5bb67ed6487e02e44b41f1cbd1
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <stdint.h>
5 #include <commonlib/helpers.h>
6 #include <console/console.h>
7 #include <device/device.h>
8 #include <device/pci_def.h>
9 #include <device/pci_ops.h>
10 #include <device/pci_type.h>
11 #include <intelblocks/pcie_rp.h>
13 static int pcie_rp_original_idx(
14 const struct pcie_rp_group *const group,
15 const unsigned int offset,
16 const pci_devfn_t dev)
18 const uint16_t clist = pci_s_find_capability(dev, PCI_CAP_ID_PCIE);
19 if (clist == 0) {
20 printk(BIOS_WARNING,
21 "%s: Can't find PCIe capapilities for PCI: 00:%02x.%x, ignoring.\n",
22 __func__, group->slot, PCI_FUNC(PCI_DEV2DEVFN(dev)));
23 return -1;
26 const uint16_t xcap = pci_s_read_config16(dev, clist + PCI_EXP_FLAGS);
27 if ((xcap & PCI_EXP_FLAGS_TYPE) >> 4 != PCI_EXP_TYPE_ROOT_PORT) {
28 printk(BIOS_WARNING, "%s: Non root-port found at PCI: 00:%02x.%x, ignoring.\n",
29 __func__, group->slot, PCI_FUNC(PCI_DEV2DEVFN(dev)));
30 return -1;
33 const uint32_t lcap = pci_s_read_config32(dev, clist + PCI_EXP_LNKCAP);
35 /* Read n-based absolute port number from LCAP register.
36 This reflects the numbering scheme that Intel uses in their
37 documentation and what we use as index (0-based, though) in
38 our mapping. */
39 const unsigned int port_num = (lcap & PCI_EXP_LNKCAP_PORT) >> 24;
41 /* Subtract lcap_port_base from port_num to get 0-based index */
42 const unsigned int port_idx = port_num - group->lcap_port_base;
44 /* Check if port_idx (0-based) is out of bounds */
45 if (port_idx < offset || port_idx >= offset + group->count) {
46 printk(BIOS_WARNING, "%s: Unexpected root-port number '%u'"
47 " at PCI: 00:%02x.%x, ignoring.\n",
48 __func__, port_num, group->slot, PCI_FUNC(PCI_DEV2DEVFN(dev)));
49 return -1;
52 return port_idx;
55 /* Scan actual PCI config space to reconstruct current mapping */
56 static void pcie_rp_scan_groups(int mapping[], const struct pcie_rp_group *const groups)
58 unsigned int offset = 0;
59 const struct pcie_rp_group *group;
60 for (group = groups; group->count; ++group) {
61 unsigned int fn;
62 for (fn = rp_start_fn(group); fn <= rp_end_fn(group); ++fn) {
63 const pci_devfn_t dev = PCI_DEV(0, group->slot, fn);
64 const uint16_t did = pci_s_read_config16(dev, PCI_DEVICE_ID);
65 if (did == 0xffff) {
66 if (fn == 0)
67 break;
68 continue;
71 const int rp_idx = pcie_rp_original_idx(group, offset, dev);
72 if (rp_idx < 0)
73 continue;
74 if (mapping[rp_idx] != -1) {
75 printk(BIOS_WARNING, "%s: Root Port #%u reported by PCI: "
76 "00:%02x.%x already reported by PCI: 00:%02x.%x!\n",
77 __func__, rp_idx + 1, group->slot, fn,
78 group->slot, mapping[rp_idx]);
79 continue;
82 printk(BIOS_INFO, "Found PCIe Root Port #%u at PCI: 00:%02x.%x.\n",
83 rp_idx + 1, group->slot, fn);
84 mapping[rp_idx] = fn;
86 offset += group->count;
90 /* Returns `true` if the device should be unlinked. */
91 static bool pcie_rp_update_dev(
92 struct device *const dev,
93 const struct pcie_rp_group *const groups,
94 const int mapping[])
96 if (dev->path.type != DEVICE_PATH_PCI)
97 return false;
99 /* Find matching group and offset. */
100 unsigned int offset = 0;
101 const struct pcie_rp_group *group;
102 for (group = groups; group->count; ++group) {
103 if (PCI_SLOT(dev->path.pci.devfn) == group->slot &&
104 PCI_FUNC(dev->path.pci.devfn) >= rp_start_fn(group) &&
105 PCI_FUNC(dev->path.pci.devfn) <= rp_end_fn(group))
106 break;
107 offset += group->count;
109 if (!group->count)
110 return false;
112 /* Now update based on what we know. */
113 const int rp_idx = offset + PCI_FUNC(dev->path.pci.devfn);
114 const int new_fn = mapping[rp_idx];
115 if (new_fn < 0) {
116 if (dev->enabled) {
117 printk(BIOS_NOTICE, "%s: Couldn't find PCIe Root Port #%u "
118 "(originally %s) which was enabled in devicetree, removing and disabling.\n",
119 __func__, rp_idx + 1, dev_path(dev));
120 dev->enabled = 0;
122 return true;
123 } else if (PCI_FUNC(dev->path.pci.devfn) != new_fn) {
124 printk(BIOS_INFO,
125 "Remapping PCIe Root Port #%u from %s to new function number %u.\n",
126 rp_idx + 1, dev_path(dev), new_fn);
127 dev->path.pci.devfn = PCI_DEVFN(PCI_SLOT(dev->path.pci.devfn), new_fn);
129 return false;
132 void pcie_rp_update_devicetree(const struct pcie_rp_group *const groups)
134 /* Maps absolute root-port numbers to function numbers.
135 Negative if disabled, new function number otherwise. */
136 int mapping[CONFIG_MAX_ROOT_PORTS];
137 unsigned int offset, i;
139 if (!groups || !groups->count)
140 return;
142 struct bus *const root = pci_root_bus();
143 if (!root)
144 return;
146 offset = 0;
147 const struct pcie_rp_group *group;
148 for (group = groups; group->count; ++group)
149 offset += group->count;
151 if (offset > ARRAY_SIZE(mapping)) {
152 printk(BIOS_ERR, "%s: Error: Group exceeds CONFIG_MAX_ROOT_PORTS.\n", __func__);
153 return;
156 /* Assume everything we don't encounter later is disabled */
157 for (i = 0; i < ARRAY_SIZE(mapping); ++i)
158 mapping[i] = -1;
160 pcie_rp_scan_groups(mapping, groups);
162 struct device *dev;
163 struct device **link = &root->children;
164 for (dev = *link; dev; dev = *link) {
165 if (pcie_rp_update_dev(dev, groups, mapping)) {
166 /* Unlink vanished device. */
167 *link = dev->sibling;
168 dev->sibling = NULL;
169 continue;
172 link = &dev->sibling;