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 pub spi_base: u32,
96 pub spi_count: u32,
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
103pub struct GicItsInfo {
104 #[cfg_attr(feature = "inspect", inspect(hex))]
106 pub its_base: u64,
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
112#[cfg_attr(feature = "inspect", inspect(external_tag))]
113pub enum GicMsiController {
114 None,
116 V2m(GicV2mInfo),
118 Its(GicItsInfo),
120}
121
122#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
124#[derive(Debug, Copy, Clone)]
125pub struct Aarch64VpInfo {
126 #[cfg_attr(feature = "inspect", inspect(flatten))]
128 pub base: VpInfo,
129 #[cfg_attr(feature = "inspect", inspect(hex, with = "|&x| u64::from(x)"))]
131 pub mpidr: MpidrEl1,
132 #[cfg_attr(feature = "inspect", inspect(hex))]
134 pub gicr: Option<u64>,
135 #[cfg_attr(feature = "inspect", inspect(hex))]
137 pub pmu_gsiv: Option<u32>,
138}
139
140impl AsRef<VpInfo> for Aarch64VpInfo {
141 fn as_ref(&self) -> &VpInfo {
142 &self.base
143 }
144}
145
146impl AsMut<VpInfo> for Aarch64VpInfo {
147 fn as_mut(&mut self) -> &mut VpInfo {
148 &mut self.base
149 }
150}
151
152impl TopologyBuilder<Aarch64Topology> {
153 pub fn new_aarch64(platform: Aarch64PlatformConfig) -> Self {
155 Self {
156 vps_per_socket: 1,
157 smt_enabled: false,
158 arch: Aarch64TopologyBuilderState { platform },
159 }
160 }
161
162 pub fn build(
164 &self,
165 proc_count: u32,
166 ) -> Result<ProcessorTopology<Aarch64Topology>, InvalidTopology> {
167 if proc_count >= 256 {
168 return Err(InvalidTopology::TooManyVps {
169 requested: proc_count,
170 max: u8::MAX.into(),
171 });
172 }
173 if let GicVersion::V2 { .. } = self.arch.platform.gic_version {
174 if proc_count > 8 {
175 return Err(InvalidTopology::TooManyCpusForGicV2(proc_count));
176 }
177 }
178 if !(16..32).contains(&self.arch.platform.virt_timer_ppi) {
179 return Err(InvalidTopology::InvalidPpiIntid(
180 self.arch.platform.virt_timer_ppi,
181 ));
182 }
183 if let Some(gsiv) = self.arch.platform.pmu_gsiv {
184 if !(16..32).contains(&gsiv) {
185 return Err(InvalidTopology::InvalidPpiIntid(gsiv));
186 }
187 }
188 let nr = self.arch.platform.gic_nr_irqs;
189 if !(64..=992).contains(&nr) || !nr.is_multiple_of(32) {
190 return Err(InvalidTopology::InvalidGicNrIrqs(nr));
191 }
192 let mpidrs = (0..proc_count).map(|vp_index| {
193 let uni_proc = proc_count == 1;
196 let mut aff = (0..4).map(|i| (vp_index >> (8 * i)) as u8);
197 MpidrEl1::new()
198 .with_res1_31(true)
199 .with_u(uni_proc)
200 .with_aff0(aff.next().unwrap())
201 .with_aff1(aff.next().unwrap())
202 .with_aff2(aff.next().unwrap())
203 .with_aff3(aff.next().unwrap())
204 });
205 let gic_version = self.arch.platform.gic_version;
206 self.build_with_vp_info(mpidrs.enumerate().map(move |(id, mpidr)| {
207 let gicr = match gic_version {
210 GicVersion::V3 {
211 redistributors_base,
212 } => Some(redistributors_base + id as u64 * aarch64defs::GIC_REDISTRIBUTOR_SIZE),
213 GicVersion::V2 { .. } => None,
214 };
215 Aarch64VpInfo {
216 base: VpInfo {
217 vp_index: VpIndex::new(id as u32),
218 vnode: 0,
219 },
220 mpidr,
221 gicr,
222 pmu_gsiv: self.arch.platform.pmu_gsiv,
223 }
224 }))
225 }
226
227 pub fn build_with_vp_info(
229 &self,
230 vps: impl IntoIterator<Item = Aarch64VpInfo>,
231 ) -> Result<ProcessorTopology<Aarch64Topology>, InvalidTopology> {
232 let vps = Vec::from_iter(vps);
233 let mut smt_enabled = false;
234 for (i, vp) in vps.iter().enumerate() {
235 if i != vp.base.vp_index.index() as usize {
236 return Err(InvalidTopology::InvalidVpIndices);
237 }
238
239 if vp.mpidr.mt() {
240 smt_enabled = true;
241 }
242 }
243
244 Ok(ProcessorTopology {
245 vps,
246 smt_enabled,
247 vps_per_socket: self.vps_per_socket,
248 arch: Aarch64Topology {
249 platform: self.arch.platform,
250 },
251 })
252 }
253}
254
255impl ProcessorTopology<Aarch64Topology> {
256 pub fn gic_version(&self) -> GicVersion {
258 self.arch.platform.gic_version
259 }
260
261 pub fn gic_distributor_base(&self) -> u64 {
263 self.arch.platform.gic_distributor_base
264 }
265
266 pub fn pmu_gsiv(&self) -> Option<u32> {
268 self.arch.platform.pmu_gsiv
269 }
270
271 pub fn gic_msi(&self) -> GicMsiController {
273 self.arch.platform.gic_msi
274 }
275
276 pub fn virt_timer_ppi(&self) -> u32 {
278 self.arch.platform.virt_timer_ppi
279 }
280
281 pub fn gic_nr_irqs(&self) -> u32 {
283 self.arch.platform.gic_nr_irqs
284 }
285}