1use super::ArchTopology;
7use super::InvalidTopology;
8use super::ProcessorTopology;
9use super::TopologyBuilder;
10use super::VpIndex;
11use super::VpInfo;
12use super::VpTopologyInfo;
13use aarch64defs::MpidrEl1;
14
15#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
17#[derive(Debug, Copy, Clone)]
18#[non_exhaustive]
19pub struct Aarch64Topology {
20 platform: Aarch64PlatformConfig,
21}
22
23impl ArchTopology for Aarch64Topology {
24 type ArchVpInfo = Aarch64VpInfo;
25 type BuilderState = Aarch64TopologyBuilderState;
26
27 fn vp_topology(_topology: &ProcessorTopology<Self>, info: &Self::ArchVpInfo) -> VpTopologyInfo {
28 VpTopologyInfo {
29 socket: info.mpidr.aff2().into(),
30 core: info.mpidr.aff1().into(),
31 thread: info.mpidr.aff0().into(),
32 }
33 }
34}
35
36pub struct Aarch64TopologyBuilderState {
38 platform: Aarch64PlatformConfig,
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
44#[cfg_attr(feature = "inspect", inspect(external_tag))]
45pub enum GicVersion {
46 V2 {
49 #[cfg_attr(feature = "inspect", inspect(hex))]
51 cpu_interface_base: u64,
52 },
53 V3 {
55 #[cfg_attr(feature = "inspect", inspect(hex))]
57 redistributors_base: u64,
58 },
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
68pub struct Aarch64PlatformConfig {
69 #[cfg_attr(feature = "inspect", inspect(hex))]
71 pub gic_distributor_base: u64,
72 pub gic_version: GicVersion,
74 pub gic_msi: GicMsiController,
76 pub pmu_gsiv: Option<u32>,
78 pub virt_timer_ppi: u32,
80 pub gic_nr_irqs: u32,
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
90pub struct GicV2mInfo {
91 #[cfg_attr(feature = "inspect", inspect(hex))]
93 pub frame_base: u64,
94 #[cfg_attr(feature = "inspect", inspect(hex))]
98 pub doorbell_base: u64,
99 pub spi_base: u32,
101 pub spi_count: u32,
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
108pub struct GicItsInfo {
109 #[cfg_attr(feature = "inspect", inspect(hex))]
111 pub its_base: u64,
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
117#[cfg_attr(feature = "inspect", inspect(external_tag))]
118pub enum GicMsiController {
119 None,
121 V2m(GicV2mInfo),
123 Its(GicItsInfo),
125}
126
127#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
129#[derive(Debug, Copy, Clone)]
130pub struct Aarch64VpInfo {
131 #[cfg_attr(feature = "inspect", inspect(flatten))]
133 pub base: VpInfo,
134 #[cfg_attr(feature = "inspect", inspect(hex, with = "|&x| u64::from(x)"))]
136 pub mpidr: MpidrEl1,
137 #[cfg_attr(feature = "inspect", inspect(hex))]
139 pub gicr: Option<u64>,
140 #[cfg_attr(feature = "inspect", inspect(hex))]
142 pub pmu_gsiv: Option<u32>,
143}
144
145impl AsRef<VpInfo> for Aarch64VpInfo {
146 fn as_ref(&self) -> &VpInfo {
147 &self.base
148 }
149}
150
151impl AsMut<VpInfo> for Aarch64VpInfo {
152 fn as_mut(&mut self) -> &mut VpInfo {
153 &mut self.base
154 }
155}
156
157impl TopologyBuilder<Aarch64Topology> {
158 pub fn new_aarch64(platform: Aarch64PlatformConfig) -> Self {
160 Self {
161 vps_per_socket: 1,
162 smt_enabled: false,
163 arch: Aarch64TopologyBuilderState { platform },
164 }
165 }
166
167 pub fn build(
169 &self,
170 proc_count: u32,
171 ) -> Result<ProcessorTopology<Aarch64Topology>, InvalidTopology> {
172 if proc_count >= 256 {
173 return Err(InvalidTopology::TooManyVps {
174 requested: proc_count,
175 max: u8::MAX.into(),
176 });
177 }
178 if let GicVersion::V2 { .. } = self.arch.platform.gic_version {
179 if proc_count > 8 {
180 return Err(InvalidTopology::TooManyCpusForGicV2(proc_count));
181 }
182 }
183 if !(16..32).contains(&self.arch.platform.virt_timer_ppi) {
184 return Err(InvalidTopology::InvalidPpiIntid(
185 self.arch.platform.virt_timer_ppi,
186 ));
187 }
188 if let Some(gsiv) = self.arch.platform.pmu_gsiv {
189 if !(16..32).contains(&gsiv) {
190 return Err(InvalidTopology::InvalidPpiIntid(gsiv));
191 }
192 }
193 let nr = self.arch.platform.gic_nr_irqs;
194 if !(64..=992).contains(&nr) || !nr.is_multiple_of(32) {
195 return Err(InvalidTopology::InvalidGicNrIrqs(nr));
196 }
197 let mpidrs = (0..proc_count).map(|vp_index| {
198 let uni_proc = proc_count == 1;
201 let mut aff = (0..4).map(|i| (vp_index >> (8 * i)) as u8);
202 MpidrEl1::new()
203 .with_res1_31(true)
204 .with_u(uni_proc)
205 .with_aff0(aff.next().unwrap())
206 .with_aff1(aff.next().unwrap())
207 .with_aff2(aff.next().unwrap())
208 .with_aff3(aff.next().unwrap())
209 });
210 let gic_version = self.arch.platform.gic_version;
211 self.build_with_vp_info(mpidrs.enumerate().map(move |(id, mpidr)| {
212 let gicr = match gic_version {
215 GicVersion::V3 {
216 redistributors_base,
217 } => Some(redistributors_base + id as u64 * aarch64defs::GIC_REDISTRIBUTOR_SIZE),
218 GicVersion::V2 { .. } => None,
219 };
220 Aarch64VpInfo {
221 base: VpInfo {
222 vp_index: VpIndex::new(id as u32),
223 vnode: 0,
224 },
225 mpidr,
226 gicr,
227 pmu_gsiv: self.arch.platform.pmu_gsiv,
228 }
229 }))
230 }
231
232 pub fn build_with_vp_info(
234 &self,
235 vps: impl IntoIterator<Item = Aarch64VpInfo>,
236 ) -> Result<ProcessorTopology<Aarch64Topology>, InvalidTopology> {
237 let vps = Vec::from_iter(vps);
238 let mut smt_enabled = false;
239 for (i, vp) in vps.iter().enumerate() {
240 if i != vp.base.vp_index.index() as usize {
241 return Err(InvalidTopology::InvalidVpIndices);
242 }
243
244 if vp.mpidr.mt() {
245 smt_enabled = true;
246 }
247 }
248
249 Ok(ProcessorTopology {
250 vps,
251 smt_enabled,
252 vps_per_socket: self.vps_per_socket,
253 arch: Aarch64Topology {
254 platform: self.arch.platform,
255 },
256 })
257 }
258}
259
260impl ProcessorTopology<Aarch64Topology> {
261 pub fn gic_version(&self) -> GicVersion {
263 self.arch.platform.gic_version
264 }
265
266 pub fn gic_distributor_base(&self) -> u64 {
268 self.arch.platform.gic_distributor_base
269 }
270
271 pub fn pmu_gsiv(&self) -> Option<u32> {
273 self.arch.platform.pmu_gsiv
274 }
275
276 pub fn gic_msi(&self) -> GicMsiController {
278 self.arch.platform.gic_msi
279 }
280
281 pub fn virt_timer_ppi(&self) -> u32 {
283 self.arch.platform.virt_timer_ppi
284 }
285
286 pub fn gic_nr_irqs(&self) -> u32 {
288 self.arch.platform.gic_nr_irqs
289 }
290}