xref: /aosp_15_r20/external/coreboot/src/soc/intel/common/block/pcie/pcie_rp.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <stdint.h>
4 
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>
12 
pcie_rp_original_idx(const struct pcie_rp_group * const group,const unsigned int offset,const pci_devfn_t dev)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)
17 {
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;
24 	}
25 
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;
31 	}
32 
33 	const uint32_t lcap = pci_s_read_config32(dev, clist + PCI_EXP_LNKCAP);
34 
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;
40 
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;
43 
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;
50 	}
51 
52 	return port_idx;
53 }
54 
55 /* Scan actual PCI config space to reconstruct current mapping */
pcie_rp_scan_groups(int mapping[],const struct pcie_rp_group * const groups)56 static void pcie_rp_scan_groups(int mapping[], const struct pcie_rp_group *const groups)
57 {
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;
69 			}
70 
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;
80 			}
81 
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;
85 		}
86 		offset += group->count;
87 	}
88 }
89 
90 /* Returns `true` if the device should be unlinked. */
pcie_rp_update_dev(struct device * const dev,const struct pcie_rp_group * const groups,const int mapping[])91 static bool pcie_rp_update_dev(
92 		struct device *const dev,
93 		const struct pcie_rp_group *const groups,
94 		const int mapping[])
95 {
96 	if (dev->path.type != DEVICE_PATH_PCI)
97 		return false;
98 
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;
108 	}
109 	if (!group->count)
110 		return false;
111 
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;
121 		}
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);
128 	}
129 	return false;
130 }
131 
pcie_rp_update_devicetree(const struct pcie_rp_group * const groups)132 void pcie_rp_update_devicetree(const struct pcie_rp_group *const groups)
133 {
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;
138 
139 	if (!groups || !groups->count)
140 		return;
141 
142 	struct bus *const root = pci_root_bus();
143 	if (!root)
144 		return;
145 
146 	offset = 0;
147 	const struct pcie_rp_group *group;
148 	for (group = groups; group->count; ++group)
149 		offset += group->count;
150 
151 	if (offset > ARRAY_SIZE(mapping)) {
152 		printk(BIOS_ERR, "%s: Error: Group exceeds CONFIG_MAX_ROOT_PORTS.\n", __func__);
153 		return;
154 	}
155 
156 	/* Assume everything we don't encounter later is disabled */
157 	for (i = 0; i < ARRAY_SIZE(mapping); ++i)
158 		mapping[i] = -1;
159 
160 	pcie_rp_scan_groups(mapping, groups);
161 
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;
170 		}
171 
172 		link = &dev->sibling;
173 	}
174 }
175