1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::str::FromStr;
6 use std::sync::Arc;
7
8 use base::error;
9 use base::warn;
10 use base::Event;
11 use resources::SystemAllocator;
12 use sync::Mutex;
13
14 use crate::pci::pci_configuration::PciCapConfig;
15 use crate::pci::pci_configuration::PciCapConfigWriteResult;
16 use crate::pci::pci_configuration::PciCapMapping;
17 use crate::pci::pci_configuration::PciCapability;
18 use crate::pci::pcie::pci_bridge::PciBridgeBusRange;
19 use crate::pci::pcie::pcie_device::PcieCap;
20 use crate::pci::pcie::pcie_device::PcieDevice;
21 use crate::pci::pcie::pcie_host::PcieHostPort;
22 use crate::pci::pcie::*;
23 use crate::pci::pm::PciDevicePower;
24 use crate::pci::pm::PciPmCap;
25 use crate::pci::pm::PmConfig;
26 use crate::pci::pm::PmStatusChange;
27 use crate::pci::MsiConfig;
28 use crate::pci::PciAddress;
29 use crate::pci::PciDeviceError;
30
31 // reserve 8MB memory window
32 const PCIE_BR_MEM_SIZE: u64 = 0x80_0000;
33 // reserve 64MB prefetch window
34 const PCIE_BR_PREF_MEM_SIZE: u64 = 0x400_0000;
35
trigger_interrupt(msi: &Option<Arc<Mutex<MsiConfig>>>)36 fn trigger_interrupt(msi: &Option<Arc<Mutex<MsiConfig>>>) {
37 if let Some(msi_config) = msi {
38 let msi_config = msi_config.lock();
39 if msi_config.is_msi_enabled() {
40 msi_config.trigger()
41 }
42 }
43 }
44
45 struct PcieRootCap {
46 secondary_bus_num: u8,
47 subordinate_bus_num: u8,
48
49 control: u16,
50 status: u32,
51 pme_pending_requester_id: Option<u16>,
52
53 msi_config: Option<Arc<Mutex<MsiConfig>>>,
54 }
55
56 impl PcieRootCap {
new(secondary_bus_num: u8, subordinate_bus_num: u8) -> Self57 fn new(secondary_bus_num: u8, subordinate_bus_num: u8) -> Self {
58 PcieRootCap {
59 secondary_bus_num,
60 subordinate_bus_num,
61 control: 0,
62 status: 0,
63 pme_pending_requester_id: None,
64 msi_config: None,
65 }
66 }
67
clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>)68 fn clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>) {
69 self.msi_config = Some(msi_config);
70 }
71
trigger_pme_interrupt(&self)72 fn trigger_pme_interrupt(&self) {
73 if (self.control & PCIE_ROOTCTL_PME_ENABLE) != 0
74 && (self.status & PCIE_ROOTSTA_PME_STATUS) != 0
75 {
76 trigger_interrupt(&self.msi_config)
77 }
78 }
79 }
80
81 static PCIE_ROOTS_CAP: Mutex<Vec<Arc<Mutex<PcieRootCap>>>> = Mutex::new(Vec::new());
82
push_pcie_root_cap(root_cap: Arc<Mutex<PcieRootCap>>)83 fn push_pcie_root_cap(root_cap: Arc<Mutex<PcieRootCap>>) {
84 PCIE_ROOTS_CAP.lock().push(root_cap);
85 }
86
get_pcie_root_cap(bus_num: u8) -> Option<Arc<Mutex<PcieRootCap>>>87 fn get_pcie_root_cap(bus_num: u8) -> Option<Arc<Mutex<PcieRootCap>>> {
88 for root_cap in PCIE_ROOTS_CAP.lock().iter() {
89 let root_cap_lock = root_cap.lock();
90 if root_cap_lock.secondary_bus_num <= bus_num
91 && root_cap_lock.subordinate_bus_num >= bus_num
92 {
93 return Some(root_cap.clone());
94 }
95 }
96
97 None
98 }
99
100 pub struct PciePort {
101 device_id: u16,
102 debug_label: String,
103 preferred_address: Option<PciAddress>,
104 pci_address: Option<PciAddress>,
105 bus_range: PciBridgeBusRange,
106 pcie_host: Option<PcieHostPort>,
107 pcie_config: Arc<Mutex<PcieConfig>>,
108 pm_config: Arc<Mutex<PmConfig>>,
109
110 msi_config: Option<Arc<Mutex<MsiConfig>>>,
111
112 // For PcieRootPort, root_cap point to itself
113 // For PcieDownstreamPort or PciDownstreamPort, root_cap point to PcieRootPort its behind.
114 root_cap: Arc<Mutex<PcieRootCap>>,
115 port_type: PcieDevicePortType,
116
117 prepare_hotplug: bool,
118 }
119
120 impl PciePort {
121 /// Constructs a new PCIE port
new( device_id: u16, debug_label: String, primary_bus_num: u8, secondary_bus_num: u8, slot_implemented: bool, port_type: PcieDevicePortType, ) -> Self122 pub fn new(
123 device_id: u16,
124 debug_label: String,
125 primary_bus_num: u8,
126 secondary_bus_num: u8,
127 slot_implemented: bool,
128 port_type: PcieDevicePortType,
129 ) -> Self {
130 let bus_range = PciBridgeBusRange {
131 primary: primary_bus_num,
132 secondary: secondary_bus_num,
133 subordinate: secondary_bus_num,
134 };
135
136 let root_cap = if port_type == PcieDevicePortType::RootPort {
137 let cap = Arc::new(Mutex::new(PcieRootCap::new(
138 secondary_bus_num,
139 secondary_bus_num,
140 )));
141 push_pcie_root_cap(cap.clone());
142 cap
143 } else {
144 get_pcie_root_cap(primary_bus_num).expect("Pcie root port should be created at first")
145 };
146
147 PciePort {
148 device_id,
149 debug_label,
150 preferred_address: None,
151 pci_address: None,
152 bus_range,
153 pcie_host: None,
154 msi_config: None,
155 pcie_config: Arc::new(Mutex::new(PcieConfig::new(
156 root_cap.clone(),
157 slot_implemented,
158 port_type,
159 ))),
160 pm_config: Arc::new(Mutex::new(PmConfig::new(false))),
161
162 root_cap,
163 port_type,
164
165 prepare_hotplug: false,
166 }
167 }
168
new_from_host( pcie_host: PcieHostPort, slot_implemented: bool, port_type: PcieDevicePortType, ) -> std::result::Result<Self, PciDeviceError>169 pub fn new_from_host(
170 pcie_host: PcieHostPort,
171 slot_implemented: bool,
172 port_type: PcieDevicePortType,
173 ) -> std::result::Result<Self, PciDeviceError> {
174 let bus_range = pcie_host.get_bus_range();
175 let host_address = PciAddress::from_str(&pcie_host.host_name())
176 .map_err(|e| PciDeviceError::PciAddressParseFailure(pcie_host.host_name(), e))?;
177 let root_cap = if port_type == PcieDevicePortType::RootPort {
178 let cap = Arc::new(Mutex::new(PcieRootCap::new(
179 bus_range.secondary,
180 bus_range.subordinate,
181 )));
182 push_pcie_root_cap(cap.clone());
183 cap
184 } else {
185 get_pcie_root_cap(bus_range.primary).expect("Pcie root port should be created at first")
186 };
187
188 Ok(PciePort {
189 device_id: pcie_host.read_device_id(),
190 debug_label: pcie_host.host_name(),
191 preferred_address: Some(host_address),
192 pci_address: None,
193 bus_range,
194 pcie_host: Some(pcie_host),
195 msi_config: None,
196 pcie_config: Arc::new(Mutex::new(PcieConfig::new(
197 root_cap.clone(),
198 slot_implemented,
199 port_type,
200 ))),
201 pm_config: Arc::new(Mutex::new(PmConfig::new(false))),
202
203 root_cap,
204 port_type,
205
206 prepare_hotplug: false,
207 })
208 }
209
get_device_id(&self) -> u16210 pub fn get_device_id(&self) -> u16 {
211 self.device_id
212 }
213
get_address(&self) -> Option<PciAddress>214 pub fn get_address(&self) -> Option<PciAddress> {
215 self.pci_address
216 }
217
debug_label(&self) -> String218 pub fn debug_label(&self) -> String {
219 self.debug_label.clone()
220 }
221
preferred_address(&self) -> Option<PciAddress>222 pub fn preferred_address(&self) -> Option<PciAddress> {
223 self.preferred_address
224 }
225
allocate_address( &mut self, resources: &mut SystemAllocator, ) -> std::result::Result<PciAddress, PciDeviceError>226 pub fn allocate_address(
227 &mut self,
228 resources: &mut SystemAllocator,
229 ) -> std::result::Result<PciAddress, PciDeviceError> {
230 if self.pci_address.is_none() {
231 if let Some(address) = self.preferred_address {
232 if resources.reserve_pci(address, self.debug_label()) {
233 self.pci_address = Some(address);
234 } else {
235 self.pci_address = None;
236 }
237 } else {
238 self.pci_address =
239 resources.allocate_pci(self.bus_range.primary, self.debug_label());
240 }
241 }
242 self.pci_address.ok_or(PciDeviceError::PciAllocationFailed)
243 }
244
read_config(&self, reg_idx: usize, data: &mut u32)245 pub fn read_config(&self, reg_idx: usize, data: &mut u32) {
246 if let Some(host) = &self.pcie_host {
247 host.read_config(reg_idx, data);
248 }
249 }
250
write_config(&mut self, reg_idx: usize, offset: u64, data: &[u8])251 pub fn write_config(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
252 if let Some(host) = self.pcie_host.as_mut() {
253 host.write_config(reg_idx, offset, data);
254 }
255 }
256
handle_cap_write_result(&mut self, res: Box<dyn PciCapConfigWriteResult>)257 pub fn handle_cap_write_result(&mut self, res: Box<dyn PciCapConfigWriteResult>) {
258 if let Some(status) = res.downcast_ref::<PmStatusChange>() {
259 if status.from == PciDevicePower::D3
260 && status.to == PciDevicePower::D0
261 && self.prepare_hotplug
262 {
263 if let Some(host) = self.pcie_host.as_mut() {
264 host.hotplug_probe();
265 self.prepare_hotplug = false;
266 }
267 }
268 }
269 }
270
get_caps(&self) -> Vec<(Box<dyn PciCapability>, Option<Box<dyn PciCapConfig>>)>271 pub fn get_caps(&self) -> Vec<(Box<dyn PciCapability>, Option<Box<dyn PciCapConfig>>)> {
272 vec![
273 (
274 Box::new(PcieCap::new(self.port_type, self.hotplug_implemented(), 0)),
275 Some(Box::new(self.pcie_config.clone())),
276 ),
277 (
278 Box::new(PciPmCap::new()),
279 Some(Box::new(self.pm_config.clone())),
280 ),
281 ]
282 }
283
get_bus_range(&self) -> Option<PciBridgeBusRange>284 pub fn get_bus_range(&self) -> Option<PciBridgeBusRange> {
285 Some(self.bus_range)
286 }
287
get_bridge_window_size(&self) -> (u64, u64)288 pub fn get_bridge_window_size(&self) -> (u64, u64) {
289 if let Some(host) = &self.pcie_host {
290 host.get_bridge_window_size()
291 } else {
292 (PCIE_BR_MEM_SIZE, PCIE_BR_PREF_MEM_SIZE)
293 }
294 }
295
get_slot_control(&self) -> u16296 pub fn get_slot_control(&self) -> u16 {
297 self.pcie_config.lock().get_slot_control()
298 }
299
clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>)300 pub fn clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>) {
301 if self.port_type == PcieDevicePortType::RootPort {
302 self.root_cap.lock().clone_interrupt(msi_config.clone());
303 }
304 self.pcie_config.lock().msi_config = Some(msi_config.clone());
305 self.msi_config = Some(msi_config);
306 }
307
hotplug_implemented(&self) -> bool308 pub fn hotplug_implemented(&self) -> bool {
309 self.pcie_config.lock().slot_control.is_some()
310 }
311
inject_pme(&mut self, requester_id: u16)312 pub fn inject_pme(&mut self, requester_id: u16) {
313 let mut r = self.root_cap.lock();
314 if (r.status & PCIE_ROOTSTA_PME_STATUS) != 0 {
315 r.status |= PCIE_ROOTSTA_PME_PENDING;
316 r.pme_pending_requester_id = Some(requester_id);
317 } else {
318 r.status &= !PCIE_ROOTSTA_PME_REQ_ID_MASK;
319 r.status |= requester_id as u32;
320 r.pme_pending_requester_id = None;
321 r.status |= PCIE_ROOTSTA_PME_STATUS;
322 r.trigger_pme_interrupt();
323 }
324 }
325
326 /// Has command completion pending.
is_hpc_pending(&self) -> bool327 pub fn is_hpc_pending(&self) -> bool {
328 self.pcie_config.lock().hpc_sender.is_some()
329 }
330
331 /// Sets a sender for hot plug or unplug complete.
set_hpc_sender(&mut self, event: Event)332 pub fn set_hpc_sender(&mut self, event: Event) {
333 self.pcie_config
334 .lock()
335 .hpc_sender
336 .replace(HotPlugCompleteSender::new(event));
337 }
338
trigger_hp_or_pme_interrupt(&mut self)339 pub fn trigger_hp_or_pme_interrupt(&mut self) {
340 if self.pm_config.lock().should_trigger_pme() {
341 self.pcie_config.lock().hp_interrupt_pending = true;
342 self.inject_pme(self.pci_address.unwrap().pme_requester_id());
343 } else {
344 self.pcie_config.lock().trigger_hp_interrupt();
345 }
346 }
347
is_host(&self) -> bool348 pub fn is_host(&self) -> bool {
349 self.pcie_host.is_some()
350 }
351
352 /// Checks if the slot is enabled by guest and ready for hotplug events.
is_hotplug_ready(&self) -> bool353 pub fn is_hotplug_ready(&self) -> bool {
354 self.pcie_config.lock().is_hotplug_ready()
355 }
356
357 /// Gets a notification when the port is ready for hotplug. If the port is already ready, then
358 /// the notification event is triggerred immediately.
get_ready_notification(&mut self) -> std::result::Result<Event, PciDeviceError>359 pub fn get_ready_notification(&mut self) -> std::result::Result<Event, PciDeviceError> {
360 self.pcie_config.lock().get_ready_notification()
361 }
362
hot_unplug(&mut self)363 pub fn hot_unplug(&mut self) {
364 if let Some(host) = self.pcie_host.as_mut() {
365 host.hot_unplug()
366 }
367 }
368
is_match(&self, host_addr: PciAddress) -> Option<u8>369 pub fn is_match(&self, host_addr: PciAddress) -> Option<u8> {
370 if host_addr.bus == self.bus_range.secondary || self.pcie_host.is_none() {
371 Some(self.bus_range.secondary)
372 } else {
373 None
374 }
375 }
376
removed_downstream_valid(&self) -> bool377 pub fn removed_downstream_valid(&self) -> bool {
378 self.pcie_config.lock().removed_downstream_valid
379 }
380
mask_slot_status(&mut self, mask: u16)381 pub fn mask_slot_status(&mut self, mask: u16) {
382 self.pcie_config.lock().mask_slot_status(mask);
383 }
384
set_slot_status(&mut self, flag: u16)385 pub fn set_slot_status(&mut self, flag: u16) {
386 self.pcie_config.lock().set_slot_status(flag);
387 }
388
should_trigger_pme(&mut self) -> bool389 pub fn should_trigger_pme(&mut self) -> bool {
390 self.pm_config.lock().should_trigger_pme()
391 }
392
prepare_hotplug(&mut self)393 pub fn prepare_hotplug(&mut self) {
394 self.prepare_hotplug = true;
395 }
396 }
397
398 struct HotPlugCompleteSender {
399 sender: Event,
400 armed: bool,
401 }
402
403 impl HotPlugCompleteSender {
new(sender: Event) -> Self404 fn new(sender: Event) -> Self {
405 Self {
406 sender,
407 armed: false,
408 }
409 }
410
arm(&mut self)411 fn arm(&mut self) {
412 self.armed = true;
413 }
414
armed(&self) -> bool415 fn armed(&self) -> bool {
416 self.armed
417 }
418
signal(&self) -> base::Result<()>419 fn signal(&self) -> base::Result<()> {
420 self.sender.signal()
421 }
422 }
423
424 pub struct PcieConfig {
425 msi_config: Option<Arc<Mutex<MsiConfig>>>,
426
427 slot_control: Option<u16>,
428 slot_status: u16,
429
430 // For PcieRootPort, root_cap point to itself
431 // For PcieDownstreamPort or PciDownstreamPort, root_cap point to PcieRootPort its behind.
432 root_cap: Arc<Mutex<PcieRootCap>>,
433 port_type: PcieDevicePortType,
434
435 hpc_sender: Option<HotPlugCompleteSender>,
436 hp_interrupt_pending: bool,
437 removed_downstream_valid: bool,
438
439 enabled: bool,
440 hot_plug_ready_notifications: Vec<Event>,
441 cap_mapping: Option<PciCapMapping>,
442 }
443
444 impl PcieConfig {
new( root_cap: Arc<Mutex<PcieRootCap>>, slot_implemented: bool, port_type: PcieDevicePortType, ) -> Self445 fn new(
446 root_cap: Arc<Mutex<PcieRootCap>>,
447 slot_implemented: bool,
448 port_type: PcieDevicePortType,
449 ) -> Self {
450 PcieConfig {
451 msi_config: None,
452
453 slot_control: if slot_implemented {
454 Some(PCIE_SLTCTL_PIC_OFF | PCIE_SLTCTL_AIC_OFF)
455 } else {
456 None
457 },
458 slot_status: 0,
459
460 root_cap,
461 port_type,
462
463 hpc_sender: None,
464 hp_interrupt_pending: false,
465 removed_downstream_valid: false,
466
467 enabled: false,
468 hot_plug_ready_notifications: Vec::new(),
469 cap_mapping: None,
470 }
471 }
472
read_pcie_cap(&self, offset: usize, data: &mut u32)473 fn read_pcie_cap(&self, offset: usize, data: &mut u32) {
474 if offset == PCIE_SLTCTL_OFFSET {
475 *data = ((self.slot_status as u32) << 16) | (self.get_slot_control() as u32);
476 } else if offset == PCIE_ROOTCTL_OFFSET {
477 *data = match self.port_type {
478 PcieDevicePortType::RootPort => self.root_cap.lock().control as u32,
479 _ => 0,
480 };
481 } else if offset == PCIE_ROOTSTA_OFFSET {
482 *data = match self.port_type {
483 PcieDevicePortType::RootPort => self.root_cap.lock().status,
484 _ => 0,
485 };
486 }
487 }
488
489 // Checks if the slot is enabled by guest and ready for hotplug events.
is_hotplug_ready(&self) -> bool490 fn is_hotplug_ready(&self) -> bool {
491 // The hotplug capability flags are set when the guest enables the device. Checks all flags
492 // required by the hotplug mechanism.
493 let slot_control = self.get_slot_control();
494 (slot_control & (PCIE_SLTCTL_PDCE | PCIE_SLTCTL_ABPE)) != 0
495 && (slot_control & PCIE_SLTCTL_CCIE) != 0
496 && (slot_control & PCIE_SLTCTL_HPIE) != 0
497 }
498
499 /// Gets a notification when the port is ready for hotplug. If the port is already ready, then
500 /// the notification event is triggerred immediately.
get_ready_notification(&mut self) -> std::result::Result<Event, PciDeviceError>501 fn get_ready_notification(&mut self) -> std::result::Result<Event, PciDeviceError> {
502 let event = Event::new().map_err(|e| PciDeviceError::EventCreationFailed(e.errno()))?;
503 if self.is_hotplug_ready() {
504 event
505 .signal()
506 .map_err(|e| PciDeviceError::EventSignalFailed(e.errno()))?;
507 } else {
508 self.hot_plug_ready_notifications.push(
509 event
510 .try_clone()
511 .map_err(|e| PciDeviceError::EventCloneFailed(e.errno()))?,
512 );
513 }
514 Ok(event)
515 }
516
write_pcie_cap(&mut self, offset: usize, data: &[u8])517 fn write_pcie_cap(&mut self, offset: usize, data: &[u8]) {
518 self.removed_downstream_valid = false;
519 match offset {
520 PCIE_SLTCTL_OFFSET => {
521 let Ok(value) = data.try_into().map(u16::from_le_bytes) else {
522 warn!("write SLTCTL isn't word, len: {}", data.len());
523 return;
524 };
525 if !self.enabled
526 && (value & (PCIE_SLTCTL_PDCE | PCIE_SLTCTL_ABPE)) != 0
527 && (value & PCIE_SLTCTL_CCIE) != 0
528 && (value & PCIE_SLTCTL_HPIE) != 0
529 {
530 // Device is getting enabled by the guest.
531 for notf_event in self.hot_plug_ready_notifications.drain(..) {
532 if let Err(e) = notf_event.signal() {
533 error!("Failed to signal hot plug ready: {}", e);
534 }
535 }
536 self.enabled = true;
537 }
538
539 // if slot is populated, power indicator is off,
540 // it will detach devices
541 let old_control = self.get_slot_control();
542 match self.slot_control.as_mut() {
543 Some(v) => *v = value,
544 None => return,
545 }
546 if (self.slot_status & PCIE_SLTSTA_PDS != 0)
547 && (value & PCIE_SLTCTL_PIC == PCIE_SLTCTL_PIC_OFF)
548 && (old_control & PCIE_SLTCTL_PIC != PCIE_SLTCTL_PIC_OFF)
549 {
550 self.removed_downstream_valid = true;
551 self.slot_status &= !PCIE_SLTSTA_PDS;
552 self.trigger_hp_interrupt();
553 }
554
555 // Guest enable hotplug interrupt and has hotplug interrupt
556 // pending, inject it right row.
557 if (old_control & PCIE_SLTCTL_HPIE == 0)
558 && (value & PCIE_SLTCTL_HPIE == PCIE_SLTCTL_HPIE)
559 && self.hp_interrupt_pending
560 {
561 self.hp_interrupt_pending = false;
562 self.trigger_hp_interrupt();
563 }
564
565 if old_control != value {
566 let old_pic_state = old_control & PCIE_SLTCTL_PIC;
567 let pic_state = value & PCIE_SLTCTL_PIC;
568 if old_pic_state == PCIE_SLTCTL_PIC_BLINK && old_pic_state != pic_state {
569 // The power indicator (PIC) is controled by the guest to indicate the power
570 // state of the slot.
571 // For successful hotplug: OFF => BLINK => (board enabled) => ON
572 // For failed hotplug: OFF => BLINK => (board enable failed) => OFF
573 // For hot unplug: ON => BLINK => (board disabled) => OFF
574 // hot (un)plug is completed at next slot status write after it changed to
575 // ON or OFF state.
576
577 if let Some(sender) = self.hpc_sender.as_mut() {
578 sender.arm();
579 }
580 }
581 self.slot_status |= PCIE_SLTSTA_CC;
582 self.trigger_cc_interrupt();
583 }
584 }
585 PCIE_SLTSTA_OFFSET => {
586 if self.slot_control.is_none() {
587 return;
588 }
589 if let Some(hpc_sender) = self.hpc_sender.as_mut() {
590 if hpc_sender.armed() {
591 if let Err(e) = hpc_sender.signal() {
592 error!("Failed to send hot un/plug complete signal: {}", e);
593 }
594 self.hpc_sender = None;
595 }
596 }
597 let Ok(value) = data.try_into().map(u16::from_le_bytes) else {
598 warn!("write SLTSTA isn't word, len: {}", data.len());
599 return;
600 };
601 if value & PCIE_SLTSTA_ABP != 0 {
602 self.slot_status &= !PCIE_SLTSTA_ABP;
603 }
604 if value & PCIE_SLTSTA_PFD != 0 {
605 self.slot_status &= !PCIE_SLTSTA_PFD;
606 }
607 if value & PCIE_SLTSTA_PDC != 0 {
608 self.slot_status &= !PCIE_SLTSTA_PDC;
609 }
610 if value & PCIE_SLTSTA_CC != 0 {
611 self.slot_status &= !PCIE_SLTSTA_CC;
612 }
613 if value & PCIE_SLTSTA_DLLSC != 0 {
614 self.slot_status &= !PCIE_SLTSTA_DLLSC;
615 }
616 }
617 PCIE_ROOTCTL_OFFSET => {
618 let Ok(v) = data.try_into().map(u16::from_le_bytes) else {
619 warn!("write root control isn't word, len: {}", data.len());
620 return;
621 };
622 if self.port_type == PcieDevicePortType::RootPort {
623 self.root_cap.lock().control = v;
624 } else {
625 warn!("write root control register while device isn't root port");
626 }
627 }
628 PCIE_ROOTSTA_OFFSET => {
629 let Ok(v) = data.try_into().map(u32::from_le_bytes) else {
630 warn!("write root status isn't dword, len: {}", data.len());
631 return;
632 };
633 if self.port_type == PcieDevicePortType::RootPort {
634 if v & PCIE_ROOTSTA_PME_STATUS != 0 {
635 let mut r = self.root_cap.lock();
636 if let Some(requester_id) = r.pme_pending_requester_id {
637 r.status &= !PCIE_ROOTSTA_PME_PENDING;
638 r.status &= !PCIE_ROOTSTA_PME_REQ_ID_MASK;
639 r.status |= requester_id as u32;
640 r.status |= PCIE_ROOTSTA_PME_STATUS;
641 r.pme_pending_requester_id = None;
642 r.trigger_pme_interrupt();
643 } else {
644 r.status &= !PCIE_ROOTSTA_PME_STATUS;
645 }
646 }
647 } else {
648 warn!("write root status register while device isn't root port");
649 }
650 }
651 _ => (),
652 }
653 }
654
get_slot_control(&self) -> u16655 fn get_slot_control(&self) -> u16 {
656 if let Some(slot_control) = self.slot_control {
657 return slot_control;
658 }
659 0
660 }
661
trigger_cc_interrupt(&self)662 fn trigger_cc_interrupt(&self) {
663 if (self.get_slot_control() & PCIE_SLTCTL_CCIE) != 0
664 && (self.slot_status & PCIE_SLTSTA_CC) != 0
665 {
666 trigger_interrupt(&self.msi_config)
667 }
668 }
669
trigger_hp_interrupt(&mut self)670 fn trigger_hp_interrupt(&mut self) {
671 let slot_control = self.get_slot_control();
672 if (slot_control & PCIE_SLTCTL_HPIE) != 0 {
673 self.set_slot_status(PCIE_SLTSTA_PDC);
674 if (self.slot_status & slot_control & (PCIE_SLTCTL_ABPE | PCIE_SLTCTL_PDCE)) != 0 {
675 trigger_interrupt(&self.msi_config)
676 }
677 }
678 }
679
mask_slot_status(&mut self, mask: u16)680 fn mask_slot_status(&mut self, mask: u16) {
681 self.slot_status &= mask;
682 if let Some(mapping) = self.cap_mapping.as_mut() {
683 mapping.set_reg(
684 PCIE_SLTCTL_OFFSET / 4,
685 (self.slot_status as u32) << 16,
686 0xffff0000,
687 );
688 }
689 }
690
set_slot_status(&mut self, flag: u16)691 fn set_slot_status(&mut self, flag: u16) {
692 self.slot_status |= flag;
693 if let Some(mapping) = self.cap_mapping.as_mut() {
694 mapping.set_reg(
695 PCIE_SLTCTL_OFFSET / 4,
696 (self.slot_status as u32) << 16,
697 0xffff0000,
698 );
699 }
700 }
701 }
702
703 const PCIE_CONFIG_READ_MASK: [u32; PCIE_CAP_LEN / 4] = {
704 let mut arr: [u32; PCIE_CAP_LEN / 4] = [0; PCIE_CAP_LEN / 4];
705 arr[PCIE_SLTCTL_OFFSET / 4] = 0xffffffff;
706 arr[PCIE_ROOTCTL_OFFSET / 4] = 0xffffffff;
707 arr[PCIE_ROOTSTA_OFFSET / 4] = 0xffffffff;
708 arr
709 };
710
711 impl PciCapConfig for PcieConfig {
read_mask(&self) -> &'static [u32]712 fn read_mask(&self) -> &'static [u32] {
713 &PCIE_CONFIG_READ_MASK
714 }
715
read_reg(&self, reg_idx: usize) -> u32716 fn read_reg(&self, reg_idx: usize) -> u32 {
717 let mut data = 0;
718 self.read_pcie_cap(reg_idx * 4, &mut data);
719 data
720 }
721
write_reg( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> Option<Box<dyn PciCapConfigWriteResult>>722 fn write_reg(
723 &mut self,
724 reg_idx: usize,
725 offset: u64,
726 data: &[u8],
727 ) -> Option<Box<dyn PciCapConfigWriteResult>> {
728 self.write_pcie_cap(reg_idx * 4 + offset as usize, data);
729 None
730 }
731
set_cap_mapping(&mut self, mapping: PciCapMapping)732 fn set_cap_mapping(&mut self, mapping: PciCapMapping) {
733 self.cap_mapping = Some(mapping);
734 }
735 }
736
737 /// Helper trait for implementing PcieDevice where most functions
738 /// are proxied directly to a PciePort instance.
739 pub trait PciePortVariant: Send {
get_pcie_port(&self) -> &PciePort740 fn get_pcie_port(&self) -> &PciePort;
get_pcie_port_mut(&mut self) -> &mut PciePort741 fn get_pcie_port_mut(&mut self) -> &mut PciePort;
742
743 /// Called via PcieDevice.get_removed_devices
get_removed_devices_impl(&self) -> Vec<PciAddress>744 fn get_removed_devices_impl(&self) -> Vec<PciAddress>;
745
746 /// Called via PcieDevice.hotplug_implemented
hotplug_implemented_impl(&self) -> bool747 fn hotplug_implemented_impl(&self) -> bool;
748
749 /// Called via PcieDevice.hotplug
hotplugged_impl(&self) -> bool750 fn hotplugged_impl(&self) -> bool;
751 }
752
753 impl<T: PciePortVariant> PcieDevice for T {
get_device_id(&self) -> u16754 fn get_device_id(&self) -> u16 {
755 self.get_pcie_port().get_device_id()
756 }
757
debug_label(&self) -> String758 fn debug_label(&self) -> String {
759 self.get_pcie_port().debug_label()
760 }
761
preferred_address(&self) -> Option<PciAddress>762 fn preferred_address(&self) -> Option<PciAddress> {
763 self.get_pcie_port().preferred_address()
764 }
765
allocate_address( &mut self, resources: &mut SystemAllocator, ) -> std::result::Result<PciAddress, PciDeviceError>766 fn allocate_address(
767 &mut self,
768 resources: &mut SystemAllocator,
769 ) -> std::result::Result<PciAddress, PciDeviceError> {
770 self.get_pcie_port_mut().allocate_address(resources)
771 }
772
clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>)773 fn clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>) {
774 self.get_pcie_port_mut().clone_interrupt(msi_config);
775 }
776
read_config(&self, reg_idx: usize, data: &mut u32)777 fn read_config(&self, reg_idx: usize, data: &mut u32) {
778 self.get_pcie_port().read_config(reg_idx, data);
779 }
780
write_config(&mut self, reg_idx: usize, offset: u64, data: &[u8])781 fn write_config(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
782 self.get_pcie_port_mut().write_config(reg_idx, offset, data);
783 }
784
get_caps(&self) -> Vec<(Box<dyn PciCapability>, Option<Box<dyn PciCapConfig>>)>785 fn get_caps(&self) -> Vec<(Box<dyn PciCapability>, Option<Box<dyn PciCapConfig>>)> {
786 self.get_pcie_port().get_caps()
787 }
788
handle_cap_write_result(&mut self, res: Box<dyn PciCapConfigWriteResult>)789 fn handle_cap_write_result(&mut self, res: Box<dyn PciCapConfigWriteResult>) {
790 self.get_pcie_port_mut().handle_cap_write_result(res)
791 }
792
get_bus_range(&self) -> Option<PciBridgeBusRange>793 fn get_bus_range(&self) -> Option<PciBridgeBusRange> {
794 self.get_pcie_port().get_bus_range()
795 }
796
get_removed_devices(&self) -> Vec<PciAddress>797 fn get_removed_devices(&self) -> Vec<PciAddress> {
798 self.get_removed_devices_impl()
799 }
800
hotplug_implemented(&self) -> bool801 fn hotplug_implemented(&self) -> bool {
802 self.hotplug_implemented_impl()
803 }
804
hotplugged(&self) -> bool805 fn hotplugged(&self) -> bool {
806 self.hotplugged_impl()
807 }
808
get_bridge_window_size(&self) -> (u64, u64)809 fn get_bridge_window_size(&self) -> (u64, u64) {
810 self.get_pcie_port().get_bridge_window_size()
811 }
812 }
813