devices/pci/pcie/
pcie_port.rs

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
5use std::str::FromStr;
6use std::sync::Arc;
7
8use base::error;
9use base::warn;
10use base::Event;
11use resources::SystemAllocator;
12use sync::Mutex;
13
14use crate::pci::pci_configuration::PciCapConfig;
15use crate::pci::pci_configuration::PciCapConfigWriteResult;
16use crate::pci::pci_configuration::PciCapMapping;
17use crate::pci::pci_configuration::PciCapability;
18use crate::pci::pcie::pci_bridge::PciBridgeBusRange;
19use crate::pci::pcie::pcie_device::PcieCap;
20use crate::pci::pcie::pcie_device::PcieDevice;
21use crate::pci::pcie::pcie_host::PcieHostPort;
22use crate::pci::pcie::*;
23use crate::pci::pm::PciDevicePower;
24use crate::pci::pm::PciPmCap;
25use crate::pci::pm::PmConfig;
26use crate::pci::pm::PmStatusChange;
27use crate::pci::MsiConfig;
28use crate::pci::PciAddress;
29use crate::pci::PciDeviceError;
30
31// reserve 8MB memory window
32const PCIE_BR_MEM_SIZE: u64 = 0x80_0000;
33// reserve 64MB prefetch window
34const PCIE_BR_PREF_MEM_SIZE: u64 = 0x400_0000;
35
36fn 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
45struct 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
56impl PcieRootCap {
57    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
68    fn clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>) {
69        self.msi_config = Some(msi_config);
70    }
71
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
81static PCIE_ROOTS_CAP: Mutex<Vec<Arc<Mutex<PcieRootCap>>>> = Mutex::new(Vec::new());
82
83fn push_pcie_root_cap(root_cap: Arc<Mutex<PcieRootCap>>) {
84    PCIE_ROOTS_CAP.lock().push(root_cap);
85}
86
87fn 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
100pub 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
120impl PciePort {
121    /// Constructs a new PCIE port
122    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
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
210    pub fn get_device_id(&self) -> u16 {
211        self.device_id
212    }
213
214    pub fn get_address(&self) -> Option<PciAddress> {
215        self.pci_address
216    }
217
218    pub fn debug_label(&self) -> String {
219        self.debug_label.clone()
220    }
221
222    pub fn preferred_address(&self) -> Option<PciAddress> {
223        self.preferred_address
224    }
225
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
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
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
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
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
284    pub fn get_bus_range(&self) -> Option<PciBridgeBusRange> {
285        Some(self.bus_range)
286    }
287
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
296    pub fn get_slot_control(&self) -> u16 {
297        self.pcie_config.lock().get_slot_control()
298    }
299
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
308    pub fn hotplug_implemented(&self) -> bool {
309        self.pcie_config.lock().slot_control.is_some()
310    }
311
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.
327    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.
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
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
348    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.
353    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.
359    pub fn get_ready_notification(&mut self) -> std::result::Result<Event, PciDeviceError> {
360        self.pcie_config.lock().get_ready_notification()
361    }
362
363    pub fn hot_unplug(&mut self) {
364        if let Some(host) = self.pcie_host.as_mut() {
365            host.hot_unplug()
366        }
367    }
368
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
377    pub fn removed_downstream_valid(&self) -> bool {
378        self.pcie_config.lock().removed_downstream_valid
379    }
380
381    pub fn mask_slot_status(&mut self, mask: u16) {
382        self.pcie_config.lock().mask_slot_status(mask);
383    }
384
385    pub fn set_slot_status(&mut self, flag: u16) {
386        self.pcie_config.lock().set_slot_status(flag);
387    }
388
389    pub fn should_trigger_pme(&mut self) -> bool {
390        self.pm_config.lock().should_trigger_pme()
391    }
392
393    pub fn prepare_hotplug(&mut self) {
394        self.prepare_hotplug = true;
395    }
396}
397
398struct HotPlugCompleteSender {
399    sender: Event,
400    armed: bool,
401}
402
403impl HotPlugCompleteSender {
404    fn new(sender: Event) -> Self {
405        Self {
406            sender,
407            armed: false,
408        }
409    }
410
411    fn arm(&mut self) {
412        self.armed = true;
413    }
414
415    fn armed(&self) -> bool {
416        self.armed
417    }
418
419    fn signal(&self) -> base::Result<()> {
420        self.sender.signal()
421    }
422}
423
424pub 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
444impl PcieConfig {
445    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
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.
490    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.
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
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
655    fn get_slot_control(&self) -> u16 {
656        if let Some(slot_control) = self.slot_control {
657            return slot_control;
658        }
659        0
660    }
661
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
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
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
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
703const 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
711impl PciCapConfig for PcieConfig {
712    fn read_mask(&self) -> &'static [u32] {
713        &PCIE_CONFIG_READ_MASK
714    }
715
716    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
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
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.
739pub trait PciePortVariant: Send {
740    fn get_pcie_port(&self) -> &PciePort;
741    fn get_pcie_port_mut(&mut self) -> &mut PciePort;
742
743    /// Called via PcieDevice.get_removed_devices
744    fn get_removed_devices_impl(&self) -> Vec<PciAddress>;
745
746    /// Called via PcieDevice.hotplug_implemented
747    fn hotplug_implemented_impl(&self) -> bool;
748
749    /// Called via PcieDevice.hotplug
750    fn hotplugged_impl(&self) -> bool;
751}
752
753impl<T: PciePortVariant> PcieDevice for T {
754    fn get_device_id(&self) -> u16 {
755        self.get_pcie_port().get_device_id()
756    }
757
758    fn debug_label(&self) -> String {
759        self.get_pcie_port().debug_label()
760    }
761
762    fn preferred_address(&self) -> Option<PciAddress> {
763        self.get_pcie_port().preferred_address()
764    }
765
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
773    fn clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>) {
774        self.get_pcie_port_mut().clone_interrupt(msi_config);
775    }
776
777    fn read_config(&self, reg_idx: usize, data: &mut u32) {
778        self.get_pcie_port().read_config(reg_idx, data);
779    }
780
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
785    fn get_caps(&self) -> Vec<(Box<dyn PciCapability>, Option<Box<dyn PciCapConfig>>)> {
786        self.get_pcie_port().get_caps()
787    }
788
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
793    fn get_bus_range(&self) -> Option<PciBridgeBusRange> {
794        self.get_pcie_port().get_bus_range()
795    }
796
797    fn get_removed_devices(&self) -> Vec<PciAddress> {
798        self.get_removed_devices_impl()
799    }
800
801    fn hotplug_implemented(&self) -> bool {
802        self.hotplug_implemented_impl()
803    }
804
805    fn hotplugged(&self) -> bool {
806        self.hotplugged_impl()
807    }
808
809    fn get_bridge_window_size(&self) -> (u64, u64) {
810        self.get_pcie_port().get_bridge_window_size()
811    }
812}