blob: aabc54d6817cd4b040a57db05c00ee616ee9746e [file] [log] [blame]
Marc Jones1f500842020-10-15 14:32:51 -06001/* SPDX-License-Identifier: GPL-2.0-or-later */
2
Patrick Rudolphe357ac32024-02-23 09:47:24 +01003#include <acpi/acpigen_pci.h>
Marc Jones1f500842020-10-15 14:32:51 -06004#include <assert.h>
5#include <console/console.h>
Marc Jones1f500842020-10-15 14:32:51 -06006#include <device/pci.h>
Patrick Rudolph40e07482024-02-23 09:23:41 +01007#include <intelblocks/acpi.h>
Patrick Rudolph40e07482024-02-23 09:23:41 +01008#include <soc/acpi.h>
Marc Jones1f500842020-10-15 14:32:51 -06009#include <soc/chip_common.h>
10#include <soc/soc_util.h>
11#include <soc/util.h>
12#include <stdlib.h>
13
Patrick Rudolph9fa40482024-01-18 08:55:08 +010014/**
Shuo Liu7f922102024-03-04 23:59:48 +080015 * Find all device of a given vendor and type for the specified socket.
Patrick Rudolph9fa40482024-01-18 08:55:08 +010016 * The function iterates over all PCI domains of the specified socket
17 * and matches the PCI vendor and device ID.
18 *
19 * @param socket The socket where to search for the device.
20 * @param vendor A PCI vendor ID (e.g. 0x8086 for Intel).
21 * @param device A PCI device ID.
Shuo Liu7f922102024-03-04 23:59:48 +080022 * @param from The device pointer to start search from.
23 *
24 * @return Pointer to the device struct. When there are multiple device
25 * instances, the caller should continue search upon a non-NULL match.
26 */
27struct device *dev_find_all_devices_on_socket(uint8_t socket, u16 vendor, u16 device,
28 struct device *from)
29{
30 return dev_find_all_devices_on_stack(socket, XEONSP_STACK_MAX, vendor, device, from);
31}
32
33/*
34 * Find device of a given vendor and type for the specified socket.
35 * The function will return at the 1st match.
Patrick Rudolph9fa40482024-01-18 08:55:08 +010036 */
37struct device *dev_find_device_on_socket(uint8_t socket, u16 vendor, u16 device)
38{
Shuo Liu7f922102024-03-04 23:59:48 +080039 return dev_find_all_devices_on_socket(socket, vendor, device, NULL);
40}
Patrick Rudolph9fa40482024-01-18 08:55:08 +010041
Shuo Liu7f922102024-03-04 23:59:48 +080042static int filter_device_on_stack(struct device *dev, uint8_t socket, uint8_t stack,
43 u16 vendor, u16 device)
44{
45 struct device *domain = dev_get_pci_domain(dev);
46 if (!domain)
47 return 0;
48 if (dev->path.type != DEVICE_PATH_PCI)
49 return 0;
50
51 union xeon_domain_path dn;
52 dn.domain_path = domain->path.domain.domain;
53
54 if (socket != XEONSP_SOCKET_MAX && dn.socket != socket)
55 return 0;
56 if (stack != XEONSP_STACK_MAX && dn.stack != stack)
57 return 0;
58 if (vendor != XEONSP_VENDOR_MAX && dev->vendor != vendor)
59 return 0;
60 if (device != XEONSP_DEVICE_MAX && dev->device != device)
61 return 0;
62
63 return 1;
64};
65
66/**
67 * Find all device of a given vendor and type for the specified socket and stack.
68 *
69 * @param socket The socket where to search for the device.
70 * XEONSP_SOCKET_MAX indicates any socket.
71 * @param stack The stack where to search for the device.
72 * XEONSP_STACK_MAX indicates any stack.
73 * @param vendor A PCI vendor ID (e.g. 0x8086 for Intel).
74 * XEONSP_VENDOR_MAX indicates any vendor.
75 * @param device A PCI device ID.
76 * XEONSP_DEVICE_MAX indicates any device.
77 * @param from The device pointer to start search from.
78 *
79 * @return Pointer to the device struct. When there are multiple device
80 * instances, the caller should continue search upon a non-NULL match.
81 */
82struct device *dev_find_all_devices_on_stack(uint8_t socket, uint8_t stack,
83 u16 vendor, u16 device, struct device *from)
84{
85 if (!from)
86 from = all_devices;
87 else
88 from = from->next;
89
90 while (from && (!filter_device_on_stack(from, socket, stack,
91 vendor, device)))
92 from = from->next;
93
94 return from;
95}
96
97/**
98 * Find all device of a given vendor and type for the specific domain
99 * Only the direct child of the input domain is iterated
100 *
101 * @param domain Pointer to the input domain
102 * @param vendor A PCI vendor ID
103 * XEONSP_VENDOR_MAX indicates any vendor
104 * @param vendor A PCI device ID
105 * XEONSP_DEVICE_MAX indicates any vendor
106 * @param from The device pointer to start search from.
107 *
108 * @return Pointer to the device struct. When there are multiple device
109 * instances, the caller should continue search upon a non-NULL match.
110 */
111struct device *dev_find_all_devices_on_domain(struct device *domain, u16 vendor,
112 u16 device, struct device *from)
113{
114 struct device *dev = from;
115 while ((dev = dev_bus_each_child(domain->downstream, dev))) {
116 if (vendor != XEONSP_VENDOR_MAX && dev->vendor != vendor)
Patrick Rudolph9fa40482024-01-18 08:55:08 +0100117 continue;
Shuo Liu7f922102024-03-04 23:59:48 +0800118 if (device != XEONSP_DEVICE_MAX && dev->device != device)
Patrick Rudolph9fa40482024-01-18 08:55:08 +0100119 continue;
Shuo Liu7f922102024-03-04 23:59:48 +0800120 break;
Patrick Rudolph9fa40482024-01-18 08:55:08 +0100121 }
122
Shuo Liu7f922102024-03-04 23:59:48 +0800123 return dev;
Patrick Rudolph9fa40482024-01-18 08:55:08 +0100124}
125
126/**
127 * Returns the socket ID where the specified device is connected to.
128 * This is an integer in the range [0, CONFIG_MAX_SOCKET).
129 *
130 * @param dev The device to look up
131 *
132 * @return Socket ID the device is attached to, negative number on error.
133 */
134int iio_pci_domain_socket_from_dev(struct device *dev)
135{
136 struct device *domain;
137 union xeon_domain_path dn;
138
139 if (dev->path.type == DEVICE_PATH_DOMAIN)
140 domain = dev;
141 else
142 domain = dev_get_pci_domain(dev);
143
144 if (!domain)
145 return -1;
146
147 dn.domain_path = domain->path.domain.domain;
148
149 return dn.socket;
150}
151
152/**
153 * Returns the stack ID where the specified device is connected to.
154 * This is an integer in the range [0, MAX_IIO_STACK).
155 *
156 * @param dev The device to look up
157 *
158 * @return Stack ID the device is attached to, negative number on error.
159 */
160int iio_pci_domain_stack_from_dev(struct device *dev)
161{
162 struct device *domain;
163 union xeon_domain_path dn;
164
165 if (dev->path.type == DEVICE_PATH_DOMAIN)
166 domain = dev;
167 else
168 domain = dev_get_pci_domain(dev);
169
170 if (!domain)
171 return -1;
172
173 dn.domain_path = domain->path.domain.domain;
174
175 return dn.stack;
176}
177
Shuo Liuec58beb2024-03-11 07:14:07 +0800178void create_domain(const union xeon_domain_path dp, struct bus *upstream,
Patrick Rudolph80619572024-03-12 18:32:35 +0100179 int bus_base, int bus_limit, const char *type,
180 struct device_operations *ops,
181 const size_t pci_segment_group)
Shuo Liu255f9272023-03-29 20:14:11 +0800182{
Shuo Liua454b622024-03-07 07:38:36 +0800183 struct device_path path;
184 init_xeon_domain_path(&path, dp.socket, dp.stack, bus_base);
Shuo Liu255f9272023-03-29 20:14:11 +0800185
186 struct device *const domain = alloc_find_dev(upstream, &path);
187 if (!domain)
188 die("%s: out of memory.\n", __func__);
189
Shuo Liua454b622024-03-07 07:38:36 +0800190 domain->ops = ops;
191 iio_domain_set_acpi_name(domain, type);
Shuo Liu255f9272023-03-29 20:14:11 +0800192
193 struct bus *const bus = alloc_bus(domain);
Shuo Liua454b622024-03-07 07:38:36 +0800194 bus->secondary = bus_base;
195 bus->subordinate = bus_base;
196 bus->max_subordinate = bus_limit;
Patrick Rudolph80619572024-03-12 18:32:35 +0100197 bus->segment_group = pci_segment_group;
Shuo Liua454b622024-03-07 07:38:36 +0800198}
199
Patrick Rudolph15672592024-01-18 07:57:07 +0100200/* Attach stack as domains */
Shuo Liu255f9272023-03-29 20:14:11 +0800201void attach_iio_stacks(void)
Marc Jones1f500842020-10-15 14:32:51 -0600202{
Arthur Heymans550f55e2022-08-24 14:44:26 +0200203 const IIO_UDS *hob = get_iio_uds();
Patrick Rudolph8c99ebc2024-01-19 17:28:47 +0100204 union xeon_domain_path dn = { .domain_path = 0 };
Arthur Heymans550f55e2022-08-24 14:44:26 +0200205 if (!hob)
206 return;
Marc Jones1f500842020-10-15 14:32:51 -0600207
Shuo Liu255f9272023-03-29 20:14:11 +0800208 struct bus *root_bus = dev_root.downstream;
Patrick Rudolphabc27442024-03-12 14:48:16 +0100209 for (int s = 0; s < CONFIG_MAX_SOCKET; ++s) {
210 if (!soc_cpu_is_enabled(s))
211 continue;
Arthur Heymans550f55e2022-08-24 14:44:26 +0200212 for (int x = 0; x < MAX_LOGIC_IIO_STACK; ++x) {
Shuo Liuf2daf242024-03-20 19:03:31 +0800213 const xSTACK_RES *ri = &hob->PlatformData.IIO_resource[s].StackRes[x];
Patrick Rudolph80619572024-03-12 18:32:35 +0100214 const size_t seg = hob->PlatformData.CpuQpiInfo[s].PcieSegment;
215
Arthur Heymans470f1d32023-08-31 18:19:09 +0200216 if (ri->BusBase > ri->BusLimit)
Arthur Heymans550f55e2022-08-24 14:44:26 +0200217 continue;
Jonathan Zhang532e8c02023-01-25 11:28:49 -0800218
Patrick Rudolph8c99ebc2024-01-19 17:28:47 +0100219 /* Prepare domain path */
220 dn.socket = s;
221 dn.stack = x;
Patrick Rudolph8c99ebc2024-01-19 17:28:47 +0100222
Shuo Liuec58beb2024-03-11 07:14:07 +0800223 create_xeonsp_domains(dn, root_bus, ri, seg);
Marc Jones1f500842020-10-15 14:32:51 -0600224 }
225 }
Marc Jones1f500842020-10-15 14:32:51 -0600226}
Shuo Liue0c935b2024-03-08 02:11:36 +0800227
228bool is_pcie_domain(struct device *dev)
229{
230 if ((!dev) || (dev->path.type != DEVICE_PATH_DOMAIN))
231 return false;
232
233 return strstr(dev->name, DOMAIN_TYPE_PCIE);
234}
235
236bool is_ioat_domain(struct device *dev)
237{
238 if ((!dev) || (dev->path.type != DEVICE_PATH_DOMAIN))
239 return false;
240
241 return (strstr(dev->name, DOMAIN_TYPE_CPM0) ||
242 strstr(dev->name, DOMAIN_TYPE_CPM1) ||
243 strstr(dev->name, DOMAIN_TYPE_DINO) ||
244 strstr(dev->name, DOMAIN_TYPE_HQM0) ||
245 strstr(dev->name, DOMAIN_TYPE_HQM1));
246}
247
248bool is_ubox_domain(struct device *dev)
249{
250 if ((!dev) || (dev->path.type != DEVICE_PATH_DOMAIN))
251 return false;
252
253 return (strstr(dev->name, DOMAIN_TYPE_UBX0) ||
254 strstr(dev->name, DOMAIN_TYPE_UBX1));
Shuo Liue0c935b2024-03-08 02:11:36 +0800255}
256
257bool is_cxl_domain(struct device *dev)
258{
259 if ((!dev) || (dev->path.type != DEVICE_PATH_DOMAIN))
260 return false;
261
262 return strstr(dev->name, DOMAIN_TYPE_CXL);
263}