1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
4 #include <device/device.h>
5 #include <device/pci_ops.h>
6 #include <device/pci.h>
7 #include <device/pciexp.h>
8 #include <soc/chip_common.h>
10 #include <soc/soc_util.h>
14 static void dump_pds(void)
16 printk(BIOS_DEBUG
, "====== Proximity Domain Dump ======\n");
17 printk(BIOS_DEBUG
, "number of proximity domains: %d\n", pds
.num_pds
);
18 for (uint8_t i
= 0; i
< pds
.num_pds
; i
++) {
19 printk(BIOS_DEBUG
, "\tproximity domain %d:\n", i
);
20 printk(BIOS_DEBUG
, "\t\ttype:%d\n", pds
.pds
[i
].pd_type
);
21 printk(BIOS_DEBUG
, "\t\tsocket_bitmap:0x%x\n", pds
.pds
[i
].socket_bitmap
);
22 if (pds
.pds
[i
].pd_type
== PD_TYPE_GENERIC_INITIATOR
) {
23 printk(BIOS_DEBUG
, "\t\tdevice:%s\n",
24 pds
.pds
[i
].dev
? dev_path(pds
.pds
[i
].dev
) : "");
25 printk(BIOS_DEBUG
, "\t\tbase(64MB):0x%x\n", pds
.pds
[i
].base
);
26 printk(BIOS_DEBUG
, "\t\tsize(64MB):0x%x\n", pds
.pds
[i
].size
);
28 if (pds
.pds
[i
].pd_type
== PD_TYPE_CLUSTER
) {
29 printk(BIOS_DEBUG
, "\t\tcluster_bitmap:0x%x\n", pds
.pds
[i
].cluster_bitmap
);
34 static void fill_pds(void)
36 uint8_t num_sockets
= soc_get_num_cpus();
37 uint8_t num_cxlnodes
= get_cxl_node_count();
38 uint8_t num_clusters
= soc_get_cluster_count();
39 const IIO_UDS
*hob
= get_iio_uds();
43 * 1. Each socket has a processor proximity domain regardless whether
44 * a processor has DIMM attached to it or not.
45 * 2. When sub-NUMA cluster (SNC) is on, soc_get_cluster_count() will return a
46 * non-zero value and each SNC cluster will have one proximity domain.
47 * For SNC case, DIMMs and CPU cores are attached to SNC proximity domains instead
48 * of the processor proximity domains.
49 * 3. All system memory map elements are either from processor attached memory,
50 * or from CXL memory. Each CXL node info entry has a corresponding entry
51 * in system memory map elements.
52 * 4. Each CXL device may have multiple HDMs (Host-managed Device Memory). Each
53 * HDM has one and only one CXL node info entry. Each CXL node info entry
54 * represents a generic initiator proximity domain.
56 pds
.num_pds
= num_cxlnodes
+ num_sockets
+ num_sockets
* num_clusters
;
57 pds
.pds
= xmalloc(sizeof(struct proximity_domain
) * pds
.num_pds
);
59 die("%s %d out of memory.", __FILE__
, __LINE__
);
61 memset(pds
.pds
, 0, sizeof(struct proximity_domain
) * pds
.num_pds
);
63 /* Fill in processor domains */
65 for (uint8_t socket
= 0; socket
< num_sockets
; socket
++) {
66 if (!soc_cpu_is_enabled(socket
))
68 const uint8_t socket_id
= hob
->PlatformData
.IIO_resource
[socket
].SocketID
;
69 pds
.pds
[i
].pd_type
= PD_TYPE_PROCESSOR
;
70 pds
.pds
[i
].socket_bitmap
= 1 << socket_id
;
71 pds
.pds
[i
].distances
= malloc(sizeof(uint8_t) * pds
.num_pds
);
72 if (!pds
.pds
[i
].distances
)
73 die("%s %d out of memory.", __FILE__
, __LINE__
);
75 /* Fill in cluster domains */
76 for (uint8_t cluster
= 0; cluster
< num_clusters
; cluster
++) {
77 pds
.pds
[i
].pd_type
= PD_TYPE_CLUSTER
;
78 pds
.pds
[i
].socket_bitmap
= 1 << socket_id
;
79 pds
.pds
[i
].cluster_bitmap
= 1 << cluster
;
80 pds
.pds
[i
].distances
= malloc(sizeof(uint8_t) * pds
.num_pds
);
81 if (!pds
.pds
[i
].distances
)
82 die("%s %d out of memory.", __FILE__
, __LINE__
);
87 /* If there are no CXL nodes, we are done */
88 if (num_cxlnodes
== 0)
91 #if CONFIG(SOC_INTEL_HAS_CXL)
92 /* There are CXL nodes, fill in generic initiator domain after the processors pds */
93 const CXL_NODE_SOCKET
*cxl_hob
= get_cxl_node();
94 for (uint8_t skt_id
= 0; skt_id
< MAX_SOCKET
; skt_id
++) {
95 for (uint8_t cxl_id
= 0; cxl_id
< cxl_hob
[skt_id
].CxlNodeCount
; ++cxl_id
) {
96 const CXL_NODE_INFO node
= cxl_hob
[skt_id
].CxlNodeInfo
[cxl_id
];
97 pds
.pds
[i
].pd_type
= PD_TYPE_GENERIC_INITIATOR
;
98 pds
.pds
[i
].socket_bitmap
= node
.SocketBitmap
;
99 pds
.pds
[i
].base
= node
.Address
;
100 pds
.pds
[i
].size
= node
.Size
;
101 struct device
*dev
= pcie_find_dsn(node
.SerialNumber
, node
.VendorId
, 0);
102 pds
.pds
[i
].dev
= dev
;
103 pds
.pds
[i
].distances
= malloc(sizeof(uint8_t) * pds
.num_pds
);
104 if (!pds
.pds
[i
].distances
)
105 die("%s %d out of memory.", __FILE__
, __LINE__
);
113 * Return the total size of memory regions in generic initiator affinity domains.
114 * The size is in unit of 64MB.
116 uint32_t get_generic_initiator_mem_size(void)
121 for (i
= 0; i
< pds
.num_pds
; i
++) {
122 if (pds
.pds
[i
].pd_type
!= PD_TYPE_GENERIC_INITIATOR
)
124 size
+= pds
.pds
[i
].size
;
130 static uint32_t socket_to_pd(uint8_t socket
)
132 for (uint8_t i
= 0; i
< pds
.num_pds
; i
++) {
133 if (pds
.pds
[i
].pd_type
!= PD_TYPE_PROCESSOR
)
135 if (pds
.pds
[i
].socket_bitmap
== (1 << socket
))
139 printk(BIOS_ERR
, "%s: could not find proximity domain for socket %d.\n",
142 return XEONSP_INVALID_PD_INDEX
;
145 static uint32_t cluster_to_pd(uint8_t socket
, uint8_t cluster
)
147 for (uint8_t i
= 0; i
< pds
.num_pds
; i
++) {
148 if (pds
.pds
[i
].pd_type
!= PD_TYPE_CLUSTER
)
150 if (pds
.pds
[i
].socket_bitmap
== (1 << socket
) &&
151 pds
.pds
[i
].cluster_bitmap
== (1 << cluster
))
155 printk(BIOS_ERR
, "%s: could not find proximity domain for socket/cluster %d/%d.\n",
156 __func__
, socket
, cluster
);
158 return XEONSP_INVALID_PD_INDEX
;
161 uint32_t device_to_pd(const struct device
*dev
)
163 /* first to see if the dev is bound to specific pd */
164 for (int i
= 0; i
< pds
.num_pds
; i
++)
165 if (pds
.pds
[i
].dev
== dev
)
168 if (dev
->path
.type
== DEVICE_PATH_APIC
) {
169 if (soc_get_cluster_count())
170 return cluster_to_pd(dev
->path
.apic
.package_id
, dev
->path
.apic
.node_id
);
172 return socket_to_pd(dev
->path
.apic
.package_id
);
175 if ((dev
->path
.type
== DEVICE_PATH_DOMAIN
) ||
176 (dev
->path
.type
== DEVICE_PATH_PCI
))
177 return socket_to_pd(iio_pci_domain_socket_from_dev(dev
));
179 printk(BIOS_ERR
, "%s: could not find proximity domain for device %s.\n",
180 __func__
, dev_path(dev
));
182 return XEONSP_INVALID_PD_INDEX
;
185 __weak
uint32_t memory_to_pd(const struct SystemMemoryMapElement
*mem
)
188 * TODO: For SNC case, link DRAM range to cluster id instead of socket id
191 return socket_to_pd(mem
->SocketId
);
194 #define PD_DISTANCE_SELF 0x0A
195 #define PD_DISTANCE_SAME_SOCKET 0x0C
196 #define PD_DISTANCE_CROSS_SOCKET 0x14
197 #define PD_DISTANCE_MAX 0xFF
198 #define PD_DISTANCE_IO_EXTRA 0x01
200 static void fill_pd_distances(void)
202 for (int i
= 0; i
< pds
.num_pds
; i
++) {
203 for (int j
= 0; j
< pds
.num_pds
; j
++) {
205 pds
.pds
[i
].distances
[j
] = PD_DISTANCE_SELF
;
209 if (pds
.pds
[i
].socket_bitmap
== pds
.pds
[j
].socket_bitmap
)
210 pds
.pds
[i
].distances
[j
] = PD_DISTANCE_SAME_SOCKET
;
212 pds
.pds
[i
].distances
[j
] = PD_DISTANCE_CROSS_SOCKET
;
214 if (pds
.pds
[i
].pd_type
== PD_TYPE_GENERIC_INITIATOR
)
215 pds
.pds
[i
].distances
[j
] += PD_DISTANCE_IO_EXTRA
;
217 if (pds
.pds
[j
].pd_type
== PD_TYPE_GENERIC_INITIATOR
)
218 pds
.pds
[i
].distances
[j
] += PD_DISTANCE_IO_EXTRA
;
230 __weak
uint8_t soc_get_cluster_count(void)
232 //TODO: Implement in SoC codes.
236 __weak
void soc_set_cpu_node_id(struct device
*cpu
)
238 //TODO: Implement in SoC codes.