| 1067 | } |
| 1068 | |
| 1069 | fn create_distance_map_node(fdt: &mut FdtWriter, numa_nodes: &NumaNodes) -> FdtWriterResult<()> { |
| 1070 | // When Generic Initiator nodes are present, skip ALL FDT NUMA information. |
| 1071 | // Let ACPI (which supports Generic Initiator via SRAT Type 5) handle the entire NUMA topology. |
| 1072 | // FDT cannot represent Generic Initiator nodes, and mixing FDT + ACPI NUMA info causes conflicts. |
| 1073 | let has_generic_initiator = numa_nodes.values().any(|node| node.device_id.is_some()); |
| 1074 | if has_generic_initiator { |
| 1075 | info!("Skipping NUMA distance map encoding in FDT with Generic Initiator devices"); |
| 1076 | return Ok(()); |
| 1077 | } |
| 1078 | // At this point, we know there are no Generic Initiator nodes |
| 1079 | let mut numa_ids: Vec<u32> = numa_nodes.keys().cloned().collect(); |
| 1080 | |
| 1081 | // If we only have one node, no distance map is needed |
| 1082 | if numa_ids.len() <= 1 { |
| 1083 | return Ok(()); |
| 1084 | } |
| 1085 | |
| 1086 | let distance_map_node = fdt.begin_node("distance-map")?; |
| 1087 | fdt.property_string("compatible", "numa-distance-map-v1")?; |
| 1088 | // Construct the distance matrix. |
| 1089 | // 1. We use the word entry to describe a distance from a node to |
| 1090 | // its destination, e.g. 0 -> 1 = 20 is described as <0 1 20>. |
| 1091 | // 2. Each entry represents distance from first node to second node. |
| 1092 | // The distances are equal in either direction. |
| 1093 | // 3. The distance from a node to self (local distance) is represented |
| 1094 | // with value 10 and all internode distance should be represented with |
| 1095 | // a value greater than 10. |
| 1096 | // 4. distance-matrix should have entries in lexicographical ascending |
| 1097 | // order of nodes. |
| 1098 | numa_ids.sort_unstable(); // lexicographical order |
| 1099 | let mut distance_matrix = Vec::new(); |
| 1100 | // Iterate over actual numa IDs instead of 0..len() |
| 1101 | for numa_id in numa_ids.iter() { |
| 1102 | let numa_node = &numa_nodes[numa_id]; |
| 1103 | for dest_numa_id in numa_ids.iter() { |
| 1104 | if *numa_id == *dest_numa_id { |
| 1105 | distance_matrix.push(*numa_id); |
| 1106 | distance_matrix.push(*dest_numa_id); |
| 1107 | distance_matrix.push(10_u32); |
| 1108 | continue; |
| 1109 | } |
| 1110 | |
| 1111 | distance_matrix.push(*numa_id); |
| 1112 | distance_matrix.push(*dest_numa_id); |
| 1113 | // Use user-specified distance, checking both directions for symmetry |
| 1114 | let distance = if let Some(&dist) = numa_node.distances.get(dest_numa_id) { |
| 1115 | // Forward direction: current node -> dest node |
| 1116 | dist |
| 1117 | } else if let Some(dest_node) = numa_nodes.get(dest_numa_id) { |
| 1118 | // Reverse direction for symmetry: dest node -> current node |
| 1119 | dest_node.distances.get(numa_id).copied().unwrap_or(20) |
| 1120 | } else { |
| 1121 | // Default distance when neither direction is specified |
| 1122 | 20 |
| 1123 | }; |
| 1124 | distance_matrix.push(distance as u32); |
| 1125 | } |
| 1126 | } |