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