pci_core/capabilities/
pci_express.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! PCI Express Capability with Function Level Reset (FLR) support.
5
6use super::PciCapability;
7use crate::spec::caps::CapabilityId;
8use crate::spec::caps::pci_express;
9use crate::spec::caps::pci_express::{
10    LinkSpeed, LinkWidth, PciExpressCapabilityHeader, SupportedLinkSpeedsVector,
11};
12use inspect::Inspect;
13use parking_lot::Mutex;
14use std::sync::Arc;
15
16/// FLR bit is the 28th bit in the Device Capabilities register (0 indexed).
17pub const PCI_EXPRESS_DEVICE_CAPS_FLR_BIT_MASK: u32 = 1 << 28;
18
19/// Callback interface for handling Function Level Reset (FLR) events.
20pub trait FlrHandler: Send + Sync + Inspect {
21    /// Called when Function Level Reset is initiated.
22    fn initiate_flr(&self);
23}
24
25#[derive(Debug, Inspect)]
26struct PciExpressState {
27    device_control: pci_express::DeviceControl,
28    device_status: pci_express::DeviceStatus,
29    link_control: pci_express::LinkControl,
30    link_status: pci_express::LinkStatus,
31    slot_control: pci_express::SlotControl,
32    slot_status: pci_express::SlotStatus,
33    root_control: pci_express::RootControl,
34    root_status: pci_express::RootStatus,
35    device_control_2: pci_express::DeviceControl2,
36    device_status_2: pci_express::DeviceStatus2,
37    link_control_2: pci_express::LinkControl2,
38    link_status_2: pci_express::LinkStatus2,
39    slot_control_2: pci_express::SlotControl2,
40    slot_status_2: pci_express::SlotStatus2,
41}
42
43impl PciExpressState {
44    fn new() -> Self {
45        Self {
46            device_control: pci_express::DeviceControl::new(),
47            device_status: pci_express::DeviceStatus::new(),
48            link_control: pci_express::LinkControl::new(),
49            link_status: pci_express::LinkStatus::new()
50                .with_current_link_speed(LinkSpeed::Speed32_0GtS.into_bits() as u16)
51                .with_negotiated_link_width(LinkWidth::X16.into_bits() as u16),
52            slot_control: pci_express::SlotControl::new(),
53            slot_status: pci_express::SlotStatus::new(),
54            root_control: pci_express::RootControl::new(),
55            root_status: pci_express::RootStatus::new(),
56            device_control_2: pci_express::DeviceControl2::new(),
57            device_status_2: pci_express::DeviceStatus2::new(),
58            link_control_2: pci_express::LinkControl2::new()
59                .with_target_link_speed(LinkSpeed::Speed32_0GtS.into_bits() as u16),
60            link_status_2: pci_express::LinkStatus2::new(),
61            slot_control_2: pci_express::SlotControl2::new(),
62            slot_status_2: pci_express::SlotStatus2::new(),
63        }
64    }
65}
66
67#[derive(Inspect)]
68/// Configurable PCI Express capability.
69pub struct PciExpressCapability {
70    pcie_capabilities: pci_express::PciExpressCapabilities,
71    device_capabilities: pci_express::DeviceCapabilities,
72    link_capabilities: pci_express::LinkCapabilities,
73    slot_capabilities: pci_express::SlotCapabilities,
74    root_capabilities: pci_express::RootCapabilities,
75    device_capabilities_2: pci_express::DeviceCapabilities2,
76    link_capabilities_2: pci_express::LinkCapabilities2,
77    slot_capabilities_2: pci_express::SlotCapabilities2,
78    state: Arc<Mutex<PciExpressState>>,
79    #[inspect(skip)]
80    flr_handler: Option<Arc<dyn FlrHandler>>,
81}
82
83impl PciExpressCapability {
84    /// Creates a new PCI Express capability with FLR support.
85    ///
86    /// # Arguments
87    /// * `typ` - The spec-defined device or port type.
88    /// * `flr_handler` - Optional handler to be called when FLR is initiated. This emulator will report that FLR is supported if flr_handler = Some(_)
89    pub fn new(typ: pci_express::DevicePortType, flr_handler: Option<Arc<dyn FlrHandler>>) -> Self {
90        Self {
91            pcie_capabilities: pci_express::PciExpressCapabilities::new()
92                .with_capability_version(2)
93                .with_device_port_type(typ),
94            device_capabilities: pci_express::DeviceCapabilities::new()
95                .with_function_level_reset(flr_handler.is_some()),
96            link_capabilities: pci_express::LinkCapabilities::new()
97                .with_max_link_speed(LinkSpeed::Speed32_0GtS.into_bits()) // PCIe 32.0 GT/s speed
98                .with_max_link_width(LinkWidth::X16.into_bits()), // x16 link width
99            slot_capabilities: pci_express::SlotCapabilities::new(),
100            root_capabilities: pci_express::RootCapabilities::new(),
101            device_capabilities_2: pci_express::DeviceCapabilities2::new(),
102            link_capabilities_2: pci_express::LinkCapabilities2::new()
103                .with_supported_link_speeds_vector(SupportedLinkSpeedsVector::UpToGen5.into_bits()), // Support speeds up to PCIe Gen 5 (32.0 GT/s)
104            slot_capabilities_2: pci_express::SlotCapabilities2::new(),
105            state: Arc::new(Mutex::new(PciExpressState::new())),
106            flr_handler,
107        }
108    }
109
110    fn handle_device_control_status_write(&mut self, val: u32) {
111        // Device Control (2 bytes) + Device Status (2 bytes)
112        let new_control = pci_express::DeviceControl::from_bits(val as u16);
113        let mut state = self.state.lock();
114
115        // Check if FLR was initiated
116        let old_flr = state.device_control.initiate_function_level_reset();
117        let new_flr = new_control.initiate_function_level_reset();
118
119        // DEVNOTE: It is "safe" to drop a new FLR request if there is still a previous
120        // FLR request in progress. The PCIe spec indicates that such behavior is undefined,
121        // so we choose to ignore the new FLR request.
122        if new_flr && !old_flr {
123            if let Some(handler) = &self.flr_handler {
124                handler.initiate_flr();
125            }
126        }
127
128        // Update the control register but clear the FLR bit as it's self-clearing
129        state.device_control = new_control.with_initiate_function_level_reset(false);
130
131        // Handle Device Status - most bits are write-1-to-clear
132        let new_status = pci_express::DeviceStatus::from_bits((val >> 16) as u16);
133        let mut current_status = state.device_status;
134
135        // Clear bits that were written as 1 (write-1-to-clear semantics)
136        if new_status.correctable_error_detected() {
137            current_status.set_correctable_error_detected(false);
138        }
139        if new_status.non_fatal_error_detected() {
140            current_status.set_non_fatal_error_detected(false);
141        }
142        if new_status.fatal_error_detected() {
143            current_status.set_fatal_error_detected(false);
144        }
145        if new_status.unsupported_request_detected() {
146            current_status.set_unsupported_request_detected(false);
147        }
148
149        state.device_status = current_status;
150    }
151
152    fn handle_slot_control_status_write(&mut self, val: u32) {
153        // Slot Control (2 bytes) + Slot Status (2 bytes)
154        let new_slot_control = pci_express::SlotControl::from_bits(val as u16);
155        let mut state = self.state.lock();
156
157        // Mask slot control bits based on slot capabilities
158        // Only allow writes to bits that correspond to capabilities that are present
159        let mut masked_control = new_slot_control;
160
161        // If attention button is not present, attention button enable should be read-only (hardwired to 0)
162        if !self.slot_capabilities.attention_button_present() {
163            masked_control.set_attention_button_pressed_enable(false);
164        }
165
166        // If power controller is not present, power controller control should be read-only (hardwired to 0)
167        if !self.slot_capabilities.power_controller_present() {
168            masked_control.set_power_controller_control(false);
169        }
170
171        // If MRL sensor is not present, MRL sensor changed enable should be read-only (hardwired to 0)
172        if !self.slot_capabilities.mrl_sensor_present() {
173            masked_control.set_mrl_sensor_changed_enable(false);
174        }
175
176        // If attention indicator is not present, attention indicator control should be read-only (hardwired to 00b)
177        if !self.slot_capabilities.attention_indicator_present() {
178            masked_control.set_attention_indicator_control(0);
179        }
180
181        // If power indicator is not present, power indicator control should be read-only (hardwired to 00b)
182        if !self.slot_capabilities.power_indicator_present() {
183            masked_control.set_power_indicator_control(0);
184        }
185
186        // If hotplug is not capable, hotplug interrupt enable should be read-only (hardwired to 0)
187        if !self.slot_capabilities.hot_plug_capable() {
188            masked_control.set_hot_plug_interrupt_enable(false);
189        }
190
191        // If electromechanical interlock is not present, interlock control should be read-only (hardwired to 0)
192        if !self.slot_capabilities.electromechanical_interlock_present() {
193            masked_control.set_electromechanical_interlock_control(false);
194        }
195
196        // If no command completed support, command completed interrupt enable should be read-only (hardwired to 0)
197        if self.slot_capabilities.no_command_completed_support() {
198            masked_control.set_command_completed_interrupt_enable(false);
199        }
200
201        state.slot_control = masked_control;
202
203        // Slot Status upper 16 bits - handle RW1C and RO bits properly
204        let new_slot_status = pci_express::SlotStatus::from_bits((val >> 16) as u16);
205        let mut current_slot_status = state.slot_status;
206
207        // RW1C bits: writing 1 clears the bit, writing 0 leaves it unchanged
208        // Clear bits where a 1 was written (RW1C behavior)
209        if new_slot_status.attention_button_pressed() {
210            current_slot_status.set_attention_button_pressed(false);
211        }
212        if new_slot_status.power_fault_detected() {
213            current_slot_status.set_power_fault_detected(false);
214        }
215        if new_slot_status.mrl_sensor_changed() {
216            current_slot_status.set_mrl_sensor_changed(false);
217        }
218        if new_slot_status.presence_detect_changed() {
219            current_slot_status.set_presence_detect_changed(false);
220        }
221        if new_slot_status.command_completed() {
222            current_slot_status.set_command_completed(false);
223        }
224        if new_slot_status.data_link_layer_state_changed() {
225            current_slot_status.set_data_link_layer_state_changed(false);
226        }
227
228        // RO bits (mrl_sensor_state, presence_detect_state, electromechanical_interlock_status)
229        // are not modified - they remain as they were
230
231        state.slot_status = current_slot_status;
232    }
233
234    fn handle_link_control_status_write(&mut self, val: u32) {
235        // Link Control (2 bytes) + Link Status (2 bytes)
236        let new_link_control = pci_express::LinkControl::from_bits(val as u16);
237        let mut state = self.state.lock();
238
239        // Apply the new link control but ensure retrain_link always reads as 0
240        let mut masked_control = new_link_control;
241        masked_control.set_retrain_link(false); // retrain_link always reads as 0
242
243        state.link_control = masked_control;
244        // Link Status upper 16 bits - read-only, ignore any writes
245    }
246
247    fn handle_link_control_2_write(&mut self, val: u32) {
248        // Link Control 2 (2 bytes) + Link Status 2 (2 bytes)
249        let new_link_control_2 = pci_express::LinkControl2::from_bits(val as u16);
250        let mut state = self.state.lock();
251
252        // Validate that target_link_speed doesn't exceed max_link_speed from Link Capabilities
253        let max_speed = self.link_capabilities.max_link_speed();
254        let requested_speed = new_link_control_2.target_link_speed();
255
256        // Clamp the target link speed to not exceed the maximum supported speed
257        let actual_speed = if requested_speed > max_speed as u16 {
258            max_speed as u16
259        } else {
260            requested_speed
261        };
262
263        // Update Link Control 2 with the validated speed
264        state.link_control_2 = new_link_control_2.with_target_link_speed(actual_speed);
265
266        // Update Link Status to reflect the target link speed as current link speed
267        // This simulates the link retraining and speed negotiation completing immediately
268        state.link_status = state.link_status.with_current_link_speed(actual_speed);
269
270        // Link Status 2 upper 16 bits - mostly read-only, so we don't modify it
271    }
272
273    /// Enable hotplug support for this PCIe capability.
274    /// This configures the appropriate registers to support hotpluggable devices.
275    /// Panics if called on device types other than RootPort or DownstreamSwitchPort.
276    ///
277    /// # Arguments
278    /// * `slot_number` - The physical slot number to assign to this hotplug-capable port
279    pub fn with_hotplug_support(mut self, slot_number: u32) -> Self {
280        use pci_express::DevicePortType;
281
282        // Validate that hotplug is only enabled for appropriate port types
283        let port_type = self.pcie_capabilities.device_port_type();
284        match port_type {
285            DevicePortType::RootPort | DevicePortType::DownstreamSwitchPort => {
286                // Valid port types for hotplug support
287            }
288            DevicePortType::Endpoint | DevicePortType::UpstreamSwitchPort => {
289                panic!(
290                    "Hotplug support is not valid for device port type {:?}. \
291                     Only RootPort and DownstreamSwitchPort support hotplug.",
292                    port_type
293                );
294            }
295        }
296
297        // Enable slot implemented in PCIe capabilities when hotplug is enabled
298        self.pcie_capabilities = self.pcie_capabilities.with_slot_implemented(true);
299
300        // Enable hotplug capabilities in slot capabilities register.
301        //
302        // We advertise no_command_completed_support because our emulation
303        // applies Slot Control changes instantly (no hardware delay). This
304        // tells the guest's pciehp driver to skip waiting for command_completed
305        // after writing Slot Control (PCIe spec ยง7.5.3.9).
306        //
307        // Without this, a naive command_completed implementation that sets
308        // the bit on every Slot Control write creates an interrupt storm:
309        // the guest clears command_completed via RW1C (which is itself a
310        // Slot Control write), re-triggering command_completed in a loop.
311        // A correct implementation for ports with real delay would need to
312        // diff old vs new Slot Control values and only signal completion
313        // when control bits actually change, not on RW1C status clears.
314        self.slot_capabilities = self
315            .slot_capabilities
316            .with_hot_plug_surprise(true)
317            .with_hot_plug_capable(true)
318            .with_no_command_completed_support(true)
319            .with_physical_slot_number(slot_number);
320
321        // Enable Data Link Layer Link Active Reporting when hotplug is enabled
322        self.link_capabilities = self
323            .link_capabilities
324            .with_data_link_layer_link_active_reporting(true);
325
326        self
327    }
328
329    /// Set the presence detect state for the slot.
330    /// This method only has effect if the slot is implemented (slot_implemented = true).
331    /// If slot is not implemented, the call is silently ignored, as the spec says
332    /// "If this register is implemented but the Slot Implemented bit is Clear,
333    /// the field behavior of this entire register with the exception of the DLLSC bit is undefined."
334    ///
335    /// # Arguments
336    /// * `present` - true if a device is present in the slot, false if the slot is empty
337    pub fn set_presence_detect_state(&self, present: bool) {
338        if !self.pcie_capabilities.slot_implemented() {
339            // Silently ignore if slot is not implemented
340            return;
341        }
342
343        let mut state = self.state.lock();
344        state.slot_status =
345            state
346                .slot_status
347                .with_presence_detect_state(if present { 1 } else { 0 });
348
349        // Update Data Link Layer Link Active in Link Status to match presence.
350        // The pciehp driver checks this (via DLLLA) when LLActRep is advertised.
351        state.link_status = state.link_status.with_data_link_layer_link_active(present);
352    }
353
354    /// Set the RW1C changed bits in Slot Status to signal a hotplug event.
355    /// Call this only for runtime hotplug events, not build-time device attachment.
356    pub fn set_hotplug_changed_bits(&self) {
357        let mut state = self.state.lock();
358        state.slot_status.set_presence_detect_changed(true);
359        state.slot_status.set_data_link_layer_state_changed(true);
360    }
361
362    /// Atomically update presence detect state, link active state, and
363    /// changed bits for a hotplug event.
364    pub fn set_hotplug_state(&self, present: bool) {
365        if !self.pcie_capabilities.slot_implemented() {
366            return;
367        }
368
369        let mut state = self.state.lock();
370        state.slot_status =
371            state
372                .slot_status
373                .with_presence_detect_state(if present { 1 } else { 0 });
374        state.link_status = state.link_status.with_data_link_layer_link_active(present);
375
376        // Update link speed/width to reflect link state. When a device is
377        // removed, the link goes down and these fields reset to 0. When a
378        // device is added, the link trains and reports its negotiated speed.
379        if present {
380            state.link_status = state
381                .link_status
382                .with_current_link_speed(LinkSpeed::Speed32_0GtS.into_bits() as u16)
383                .with_negotiated_link_width(LinkWidth::X16.into_bits() as u16);
384        } else {
385            state.link_status = state
386                .link_status
387                .with_current_link_speed(0)
388                .with_negotiated_link_width(0);
389        }
390
391        state.slot_status.set_presence_detect_changed(true);
392        state.slot_status.set_data_link_layer_state_changed(true);
393    }
394
395    /// Returns whether the hot plug interrupt is enabled in Slot Control.
396    pub fn hot_plug_interrupt_enabled(&self) -> bool {
397        self.state.lock().slot_control.hot_plug_interrupt_enable()
398    }
399
400    /// Returns a reference to the slot capabilities register.
401    pub fn slot_capabilities(&self) -> &pci_express::SlotCapabilities {
402        &self.slot_capabilities
403    }
404}
405
406impl PciCapability for PciExpressCapability {
407    fn label(&self) -> &str {
408        "pci-express"
409    }
410
411    fn capability_id(&self) -> CapabilityId {
412        CapabilityId::PCI_EXPRESS
413    }
414
415    fn len(&self) -> usize {
416        // Implement the full PCI Express Capability structure (PCI Spec, Section 7.5.3):
417        // 0x00: PCIe Capabilities (2 bytes) + Next Pointer (1 byte) + Capability ID (1 byte)
418        // 0x04: Device Capabilities (4 bytes)
419        // 0x08: Device Control (2 bytes) + Device Status (2 bytes)
420        // 0x0C: Link Capabilities (4 bytes)
421        // 0x10: Link Control (2 bytes) + Link Status (2 bytes)
422        // 0x14: Slot Capabilities (4 bytes)
423        // 0x18: Slot Control (2 bytes) + Slot Status (2 bytes)
424        // 0x1C: Root Control (2 bytes) + Root Capabilities (2 bytes)
425        // 0x20: Root Status (4 bytes)
426        // 0x24: Device Capabilities 2 (4 bytes)
427        // 0x28: Device Control 2 (2 bytes) + Device Status 2 (2 bytes)
428        // 0x2C: Link Capabilities 2 (4 bytes)
429        // 0x30: Link Control 2 (2 bytes) + Link Status 2 (2 bytes)
430        // 0x34: Slot Capabilities 2 (4 bytes)
431        // 0x38: Slot Control 2 (2 bytes) + Slot Status 2 (2 bytes)
432        // Total: 60 bytes (0x3C)
433        0x3C
434    }
435
436    fn read_u32(&self, offset: u16) -> u32 {
437        let label = self.label();
438        match PciExpressCapabilityHeader(offset) {
439            PciExpressCapabilityHeader::PCIE_CAPS => {
440                // PCIe Capabilities Register (16 bits) + Next Pointer (8 bits) + Capability ID (8 bits)
441                (self.pcie_capabilities.into_bits() as u32) << 16
442                    | CapabilityId::PCI_EXPRESS.0 as u32
443            }
444            PciExpressCapabilityHeader::DEVICE_CAPS => self.device_capabilities.into_bits(),
445            PciExpressCapabilityHeader::DEVICE_CTL_STS => {
446                let state = self.state.lock();
447                let device_control = state.device_control.into_bits() as u32;
448                let device_status = state.device_status.into_bits() as u32;
449                device_control | (device_status << 16)
450            }
451            PciExpressCapabilityHeader::LINK_CAPS => self.link_capabilities.into_bits(),
452            PciExpressCapabilityHeader::LINK_CTL_STS => {
453                // Link Control (2 bytes) + Link Status (2 bytes)
454                let state = self.state.lock();
455                state.link_control.into_bits() as u32
456                    | ((state.link_status.into_bits() as u32) << 16)
457            }
458            PciExpressCapabilityHeader::SLOT_CAPS => self.slot_capabilities.into_bits(),
459            PciExpressCapabilityHeader::SLOT_CTL_STS => {
460                // Slot Control (2 bytes) + Slot Status (2 bytes)
461                let state = self.state.lock();
462                state.slot_control.into_bits() as u32
463                    | ((state.slot_status.into_bits() as u32) << 16)
464            }
465            PciExpressCapabilityHeader::ROOT_CTL_CAPS => {
466                // Root Control (2 bytes) + Root Capabilities (2 bytes)
467                let state = self.state.lock();
468                state.root_control.into_bits() as u32
469                    | ((self.root_capabilities.into_bits() as u32) << 16)
470            }
471            PciExpressCapabilityHeader::ROOT_STS => {
472                // Root Status (4 bytes)
473                let state = self.state.lock();
474                state.root_status.into_bits()
475            }
476            PciExpressCapabilityHeader::DEVICE_CAPS_2 => self.device_capabilities_2.into_bits(),
477            PciExpressCapabilityHeader::DEVICE_CTL_STS_2 => {
478                // Device Control 2 (2 bytes) + Device Status 2 (2 bytes)
479                let state = self.state.lock();
480                state.device_control_2.into_bits() as u32
481                    | ((state.device_status_2.into_bits() as u32) << 16)
482            }
483            PciExpressCapabilityHeader::LINK_CAPS_2 => self.link_capabilities_2.into_bits(),
484            PciExpressCapabilityHeader::LINK_CTL_STS_2 => {
485                // Link Control 2 (2 bytes) + Link Status 2 (2 bytes)
486                let state = self.state.lock();
487                state.link_control_2.into_bits() as u32
488                    | ((state.link_status_2.into_bits() as u32) << 16)
489            }
490            PciExpressCapabilityHeader::SLOT_CAPS_2 => self.slot_capabilities_2.into_bits(),
491            PciExpressCapabilityHeader::SLOT_CTL_STS_2 => {
492                // Slot Control 2 (2 bytes) + Slot Status 2 (2 bytes)
493                let state = self.state.lock();
494                state.slot_control_2.into_bits() as u32
495                    | ((state.slot_status_2.into_bits() as u32) << 16)
496            }
497            _ => {
498                tracelimit::warn_ratelimited!(
499                    ?label,
500                    offset,
501                    "unhandled pci express capability read"
502                );
503                0
504            }
505        }
506    }
507
508    fn write_u32(&mut self, offset: u16, val: u32) {
509        let label = self.label();
510        match PciExpressCapabilityHeader(offset) {
511            PciExpressCapabilityHeader::PCIE_CAPS => {
512                // PCIe Capabilities register is read-only
513                tracelimit::warn_ratelimited!(
514                    ?label,
515                    offset,
516                    val,
517                    "write to read-only pcie capabilities"
518                );
519            }
520            PciExpressCapabilityHeader::DEVICE_CAPS => {
521                // Device Capabilities register is read-only
522                tracelimit::warn_ratelimited!(
523                    ?label,
524                    offset,
525                    val,
526                    "write to read-only device capabilities"
527                );
528            }
529            PciExpressCapabilityHeader::DEVICE_CTL_STS => {
530                self.handle_device_control_status_write(val);
531            }
532            PciExpressCapabilityHeader::LINK_CAPS => {
533                // Link Capabilities register is read-only
534                tracelimit::warn_ratelimited!(
535                    ?label,
536                    offset,
537                    val,
538                    "write to read-only link capabilities"
539                );
540            }
541            PciExpressCapabilityHeader::LINK_CTL_STS => {
542                self.handle_link_control_status_write(val);
543            }
544            PciExpressCapabilityHeader::SLOT_CAPS => {
545                // Slot Capabilities register is read-only
546                tracelimit::warn_ratelimited!(
547                    ?label,
548                    offset,
549                    val,
550                    "write to read-only slot capabilities"
551                );
552            }
553            PciExpressCapabilityHeader::SLOT_CTL_STS => {
554                self.handle_slot_control_status_write(val);
555            }
556            PciExpressCapabilityHeader::ROOT_CTL_CAPS => {
557                // Root Control (2 bytes) + Root Capabilities (2 bytes)
558                let mut state = self.state.lock();
559                state.root_control = pci_express::RootControl::from_bits(val as u16);
560                // Root Capabilities upper 16 bits are read-only
561            }
562            PciExpressCapabilityHeader::ROOT_STS => {
563                // Root Status (4 bytes) - many bits are write-1-to-clear
564                let mut state = self.state.lock();
565                // For simplicity, we'll allow basic writes for now
566                state.root_status = pci_express::RootStatus::from_bits(val);
567            }
568            PciExpressCapabilityHeader::DEVICE_CAPS_2 => {
569                // Device Capabilities 2 register is read-only
570                tracelimit::warn_ratelimited!(
571                    ?label,
572                    offset,
573                    val,
574                    "write to read-only device capabilities 2"
575                );
576            }
577            PciExpressCapabilityHeader::DEVICE_CTL_STS_2 => {
578                // Device Control 2 (2 bytes) + Device Status 2 (2 bytes)
579                let mut state = self.state.lock();
580                state.device_control_2 = pci_express::DeviceControl2::from_bits(val as u16);
581                // Device Status 2 upper 16 bits - mostly read-only or write-1-to-clear
582                state.device_status_2 = pci_express::DeviceStatus2::from_bits((val >> 16) as u16);
583            }
584            PciExpressCapabilityHeader::LINK_CAPS_2 => {
585                // Link Capabilities 2 register is read-only
586                tracelimit::warn_ratelimited!(
587                    ?label,
588                    offset,
589                    val,
590                    "write to read-only link capabilities 2"
591                );
592            }
593            PciExpressCapabilityHeader::LINK_CTL_STS_2 => {
594                self.handle_link_control_2_write(val);
595            }
596            PciExpressCapabilityHeader::SLOT_CAPS_2 => {
597                // Slot Capabilities 2 register is read-only
598                tracelimit::warn_ratelimited!(
599                    ?label,
600                    offset,
601                    val,
602                    "write to read-only slot capabilities 2"
603                );
604            }
605            PciExpressCapabilityHeader::SLOT_CTL_STS_2 => {
606                // Slot Control 2 (2 bytes) + Slot Status 2 (2 bytes)
607                let mut state = self.state.lock();
608                state.slot_control_2 = pci_express::SlotControl2::from_bits(val as u16);
609                // Slot Status 2 upper 16 bits - mostly read-only or write-1-to-clear
610                state.slot_status_2 = pci_express::SlotStatus2::from_bits((val >> 16) as u16);
611            }
612            _ => {
613                tracelimit::warn_ratelimited!(
614                    ?label,
615                    offset,
616                    val,
617                    "unhandled pci express capability write"
618                );
619            }
620        }
621    }
622
623    fn reset(&mut self) {
624        let mut state = self.state.lock();
625        *state = PciExpressState::new();
626    }
627
628    fn as_pci_express(&self) -> Option<&PciExpressCapability> {
629        Some(self)
630    }
631
632    fn as_pci_express_mut(&mut self) -> Option<&mut PciExpressCapability> {
633        Some(self)
634    }
635}
636
637mod save_restore {
638    use super::*;
639    use vmcore::save_restore::RestoreError;
640    use vmcore::save_restore::SaveError;
641    use vmcore::save_restore::SaveRestore;
642
643    mod state {
644        use mesh::payload::Protobuf;
645        use vmcore::save_restore::SavedStateRoot;
646
647        #[derive(Protobuf, SavedStateRoot)]
648        #[mesh(package = "pci.capabilities.pci_express")]
649        pub struct SavedState {
650            #[mesh(1)]
651            pub device_control: u16,
652            #[mesh(2)]
653            pub device_status: u16,
654            #[mesh(3)]
655            pub flr_handler: u16,
656        }
657    }
658
659    impl SaveRestore for PciExpressCapability {
660        type SavedState = state::SavedState;
661
662        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
663            Err(SaveError::NotSupported)
664        }
665
666        fn restore(&mut self, _: Self::SavedState) -> Result<(), RestoreError> {
667            Err(RestoreError::SavedStateNotSupported)
668        }
669    }
670}
671
672#[cfg(test)]
673mod tests {
674    use super::*;
675    use crate::spec::caps::pci_express::DevicePortType;
676    use std::sync::atomic::{AtomicBool, Ordering};
677
678    #[derive(Debug)]
679    struct TestFlrHandler {
680        flr_initiated: AtomicBool,
681    }
682
683    impl TestFlrHandler {
684        fn new() -> Arc<Self> {
685            Arc::new(Self {
686                flr_initiated: AtomicBool::new(false),
687            })
688        }
689
690        fn was_flr_initiated(&self) -> bool {
691            self.flr_initiated.load(Ordering::Acquire)
692        }
693
694        fn reset(&self) {
695            self.flr_initiated.store(false, Ordering::Release);
696        }
697    }
698
699    impl FlrHandler for TestFlrHandler {
700        fn initiate_flr(&self) {
701            self.flr_initiated.store(true, Ordering::Release);
702        }
703    }
704
705    impl Inspect for TestFlrHandler {
706        fn inspect(&self, req: inspect::Request<'_>) {
707            req.respond()
708                .field("flr_initiated", self.flr_initiated.load(Ordering::Acquire));
709        }
710    }
711
712    #[test]
713    fn test_pci_express_capability_read_u32_endpoint() {
714        let flr_handler = TestFlrHandler::new();
715        let cap = PciExpressCapability::new(DevicePortType::Endpoint, Some(flr_handler));
716
717        // Test PCIe Capabilities Register (offset 0x00)
718        let caps_val = cap.read_u32(0x00);
719        assert_eq!(caps_val & 0xFF, 0x10); // Capability ID = 0x10
720        assert_eq!((caps_val >> 8) & 0xFF, 0x00); // Next Pointer = 0x00
721        assert_eq!((caps_val >> 16) & 0xFFFF, 0x0002); // PCIe Caps: Version 2, Device/Port Type 0
722
723        // Test Device Capabilities Register (offset 0x04)
724        let device_caps_val = cap.read_u32(0x04);
725        assert_eq!(
726            device_caps_val & PCI_EXPRESS_DEVICE_CAPS_FLR_BIT_MASK,
727            PCI_EXPRESS_DEVICE_CAPS_FLR_BIT_MASK
728        ); // FLR bit should be set
729
730        // Test Device Control/Status Register (offset 0x08) - should be zero initially
731        let device_ctl_sts_val = cap.read_u32(0x08);
732        assert_eq!(device_ctl_sts_val, 0); // Both control and status should be 0
733
734        // Test Link Control/Status Register (offset 0x10) - should have link status initialized
735        let link_ctl_sts_val = cap.read_u32(0x10);
736        let expected_link_status = (LinkSpeed::Speed32_0GtS.into_bits() as u16)
737            | ((LinkWidth::X16.into_bits() as u16) << 4); // current_link_speed + negotiated_link_width
738        assert_eq!(link_ctl_sts_val, (expected_link_status as u32) << 16); // Link status is in upper 16 bits
739    }
740
741    #[test]
742    fn test_pci_express_capability_read_u32_root_port() {
743        let cap = PciExpressCapability::new(DevicePortType::RootPort, None);
744
745        // Test PCIe Capabilities Register (offset 0x00)
746        let caps_val = cap.read_u32(0x00);
747        assert_eq!(caps_val & 0xFF, 0x10); // Capability ID = 0x10
748        assert_eq!((caps_val >> 8) & 0xFF, 0x00); // Next Pointer = 0x00
749        assert_eq!((caps_val >> 16) & 0xFFFF, 0x0042); // PCIe Caps: Version 2, Device/Port Type 4
750    }
751
752    #[test]
753    fn test_pci_express_capability_read_u32_no_flr() {
754        let cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
755
756        // Test Device Capabilities Register (offset 0x04) - FLR should not be set
757        let device_caps_val = cap.read_u32(0x04);
758        assert_eq!(device_caps_val & PCI_EXPRESS_DEVICE_CAPS_FLR_BIT_MASK, 0);
759    }
760
761    #[test]
762    fn test_pci_express_capability_write_u32_readonly_registers() {
763        let mut cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
764
765        // Try to write to read-only PCIe Capabilities Register (offset 0x00)
766        let original_caps = cap.read_u32(0x00);
767        cap.write_u32(0x00, 0xFFFFFFFF);
768        assert_eq!(cap.read_u32(0x00), original_caps); // Should be unchanged
769
770        // Try to write to read-only Device Capabilities Register (offset 0x04)
771        let original_device_caps = cap.read_u32(0x04);
772        cap.write_u32(0x04, 0xFFFFFFFF);
773        assert_eq!(cap.read_u32(0x04), original_device_caps); // Should be unchanged
774    }
775
776    #[test]
777    fn test_pci_express_capability_write_u32_device_control() {
778        let flr_handler = TestFlrHandler::new();
779        let mut cap =
780            PciExpressCapability::new(DevicePortType::Endpoint, Some(flr_handler.clone()));
781
782        // Initial state should have FLR bit clear
783        let initial_ctl_sts = cap.read_u32(0x08);
784        assert_eq!(initial_ctl_sts & 0xFFFF, 0); // Device Control should be 0
785
786        // Test writing to Device Control Register (lower 16 bits of offset 0x08)
787        // Set some control bits but not FLR initially
788        cap.write_u32(0x08, 0x0001); // Enable correctable error reporting (bit 0)
789        let device_ctl_sts = cap.read_u32(0x08);
790        assert_eq!(device_ctl_sts & 0xFFFF, 0x0001); // Device Control should be set
791        assert!(!flr_handler.was_flr_initiated()); // FLR should not be triggered
792
793        // Test FLR initiation (bit 15 of Device Control)
794        flr_handler.reset();
795        cap.write_u32(0x08, 0x8001); // Set FLR bit (bit 15) and other control bits
796        let device_ctl_sts_after_flr = cap.read_u32(0x08);
797        assert_eq!(device_ctl_sts_after_flr & 0xFFFF, 0x0001); // FLR bit should be cleared, others remain
798        assert!(flr_handler.was_flr_initiated()); // FLR should be triggered
799
800        // Test that writing FLR bit when it's already been triggered behaves correctly
801        flr_handler.reset();
802        // After the previous FLR, device_control should have bit 0 set but FLR clear
803        // So writing 0x8000 (only FLR bit) should trigger FLR again
804        cap.write_u32(0x08, 0x8000); // Set FLR bit only
805        let device_ctl_sts_final = cap.read_u32(0x08);
806        assert_eq!(device_ctl_sts_final & 0xFFFF, 0x0000); // All bits should be cleared (FLR self-clears, bit 0 was overwritten)
807        assert!(flr_handler.was_flr_initiated()); // Should trigger because FLR transitioned from 0 to 1
808    }
809
810    #[test]
811    fn test_pci_express_capability_write_u32_device_status() {
812        let mut cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
813
814        // Manually set some status bits to test write-1-to-clear behavior
815        {
816            let mut state = cap.state.lock();
817            state.device_status.set_correctable_error_detected(true);
818            state.device_status.set_non_fatal_error_detected(true);
819            state.device_status.set_fatal_error_detected(true);
820            state.device_status.set_unsupported_request_detected(true);
821        }
822
823        // Check that status bits are set
824        let device_ctl_sts = cap.read_u32(0x08);
825        let status_bits = (device_ctl_sts >> 16) & 0xFFFF;
826        assert_ne!(status_bits & 0x0F, 0); // Some status bits should be set
827
828        // Write 1 to clear correctable error bit (bit 0 of status)
829        cap.write_u32(0x08, 0x00010000); // Write 1 to bit 16 (correctable error in upper 16 bits)
830        let device_ctl_sts_after = cap.read_u32(0x08);
831        let status_bits_after = (device_ctl_sts_after >> 16) & 0xFFFF;
832        assert_eq!(status_bits_after & 0x01, 0); // Correctable error bit should be cleared
833        assert_ne!(status_bits_after & 0x0E, 0); // Other error bits should still be set
834
835        // Clear all remaining error bits
836        cap.write_u32(0x08, 0x000E0000); // Write 1 to bits 17-19 (other error bits)
837        let final_status = (cap.read_u32(0x08) >> 16) & 0xFFFF;
838        assert_eq!(final_status & 0x0F, 0); // All error bits should be cleared
839    }
840
841    #[test]
842    fn test_pci_express_capability_write_u32_unhandled_offset() {
843        let mut cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
844
845        // Writing to unhandled offset should not panic
846        cap.write_u32(0x10, 0xFFFFFFFF);
847        // Should not crash and should not affect other registers
848        assert_eq!(cap.read_u32(0x08), 0); // Device Control/Status should still be 0
849    }
850
851    #[test]
852    fn test_pci_express_capability_reset() {
853        let flr_handler = TestFlrHandler::new();
854        let mut cap =
855            PciExpressCapability::new(DevicePortType::Endpoint, Some(flr_handler.clone()));
856
857        // Set some state
858        cap.write_u32(0x08, 0x0001); // Set some device control bits
859
860        // Manually set some status bits
861        {
862            let mut state = cap.state.lock();
863            state.device_status.set_correctable_error_detected(true);
864        }
865
866        // Verify state is set
867        let device_ctl_sts = cap.read_u32(0x08);
868        assert_ne!(device_ctl_sts, 0);
869
870        // Reset the capability
871        cap.reset();
872
873        // Verify state is cleared
874        let device_ctl_sts_after_reset = cap.read_u32(0x08);
875        assert_eq!(device_ctl_sts_after_reset, 0);
876    }
877
878    #[test]
879    fn test_pci_express_capability_extended_registers() {
880        let cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
881
882        // Test that extended registers return proper default values and don't crash
883        // Link Capabilities should have default speed (Speed32_0GtS) and width (X16)
884        let expected_link_caps =
885            LinkSpeed::Speed32_0GtS.into_bits() | (LinkWidth::X16.into_bits() << 4); // speed + (width << 4) = 5 + (16 << 4) = 5 + 256 = 261
886        assert_eq!(cap.read_u32(0x0C), expected_link_caps); // Link Capabilities
887        // Link Control/Status should have Link Status with current_link_speed=5 and negotiated_link_width=16
888        let expected_link_ctl_sts = (LinkSpeed::Speed32_0GtS.into_bits() as u16)
889            | ((LinkWidth::X16.into_bits() as u16) << 4); // current_link_speed (bits 0-3) + negotiated_link_width (bits 4-9) = 5 + (16 << 4) = 5 + 256 = 261
890        assert_eq!(cap.read_u32(0x10), (expected_link_ctl_sts as u32) << 16); // Link Control/Status (status in upper 16 bits)
891        assert_eq!(cap.read_u32(0x14), 0); // Slot Capabilities
892        assert_eq!(cap.read_u32(0x18), 0); // Slot Control/Status
893        assert_eq!(cap.read_u32(0x1C), 0); // Root Control/Capabilities
894        assert_eq!(cap.read_u32(0x20), 0); // Root Status
895        assert_eq!(cap.read_u32(0x24), 0); // Device Capabilities 2
896        assert_eq!(cap.read_u32(0x28), 0); // Device Control/Status 2
897        // Link Capabilities 2 has supported_link_speeds_vector set to UpToGen5
898        let expected_link_caps_2 = SupportedLinkSpeedsVector::UpToGen5.into_bits() << 1; // supported_link_speeds_vector at bits 1-7 = 31 << 1 = 62
899        assert_eq!(cap.read_u32(0x2C), expected_link_caps_2); // Link Capabilities 2
900        // Link Control/Status 2 - Link Control 2 should have target_link_speed set to Speed32_0GtS (5)
901        let expected_link_ctl_sts_2 = LinkSpeed::Speed32_0GtS.into_bits() as u16; // target_link_speed in lower 4 bits = 5
902        assert_eq!(cap.read_u32(0x30), expected_link_ctl_sts_2 as u32); // Link Control/Status 2
903        assert_eq!(cap.read_u32(0x34), 0); // Slot Capabilities 2
904        assert_eq!(cap.read_u32(0x38), 0); // Slot Control/Status 2
905    }
906
907    #[test]
908    fn test_pci_express_capability_length() {
909        let cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
910        assert_eq!(cap.len(), 0x3C); // Should be 60 bytes (0x3C)
911    }
912
913    #[test]
914    fn test_pci_express_capability_label() {
915        let cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
916        assert_eq!(cap.label(), "pci-express");
917    }
918
919    #[test]
920    fn test_pci_express_capability_with_hotplug_support() {
921        // Test with RootPort (should work)
922        let cap = PciExpressCapability::new(DevicePortType::RootPort, None);
923        let cap_with_hotplug = cap.with_hotplug_support(1);
924
925        // Verify that the method doesn't crash and returns the capability
926        assert_eq!(cap_with_hotplug.label(), "pci-express");
927        assert_eq!(cap_with_hotplug.len(), 0x3C);
928
929        // Verify hotplug capabilities are set
930        assert!(cap_with_hotplug.slot_capabilities.hot_plug_surprise());
931        assert!(cap_with_hotplug.slot_capabilities.hot_plug_capable());
932        assert_eq!(cap_with_hotplug.slot_capabilities.physical_slot_number(), 1);
933
934        // Verify that slot_implemented is set in PCIe capabilities
935        assert!(
936            cap_with_hotplug.pcie_capabilities.slot_implemented(),
937            "slot_implemented should be true when hotplug is enabled"
938        );
939
940        // Test with DownstreamSwitchPort (should work)
941        let cap2 = PciExpressCapability::new(DevicePortType::DownstreamSwitchPort, None);
942        let cap2_with_hotplug = cap2.with_hotplug_support(2);
943
944        assert!(cap2_with_hotplug.slot_capabilities.hot_plug_surprise());
945        assert!(cap2_with_hotplug.slot_capabilities.hot_plug_capable());
946        assert_eq!(
947            cap2_with_hotplug.slot_capabilities.physical_slot_number(),
948            2
949        );
950
951        // Verify that slot_implemented is set for downstream switch port too
952        assert!(
953            cap2_with_hotplug.pcie_capabilities.slot_implemented(),
954            "slot_implemented should be true when hotplug is enabled"
955        );
956
957        // Test that non-hotplug capability doesn't have slot_implemented set
958        let cap_no_hotplug = PciExpressCapability::new(DevicePortType::RootPort, None);
959        assert!(
960            !cap_no_hotplug.pcie_capabilities.slot_implemented(),
961            "slot_implemented should be false when hotplug is not enabled"
962        );
963    }
964
965    #[test]
966    #[should_panic(expected = "Hotplug support is not valid for device port type Endpoint")]
967    fn test_pci_express_capability_with_hotplug_support_endpoint_panics() {
968        let cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
969        cap.with_hotplug_support(1);
970    }
971
972    #[test]
973    #[should_panic(
974        expected = "Hotplug support is not valid for device port type UpstreamSwitchPort"
975    )]
976    fn test_pci_express_capability_with_hotplug_support_upstream_panics() {
977        let cap = PciExpressCapability::new(DevicePortType::UpstreamSwitchPort, None);
978        cap.with_hotplug_support(1);
979    }
980
981    #[test]
982    fn test_slot_control_write_protection() {
983        // Create a root port capability with hotplug support but limited slot capabilities
984        let mut cap = PciExpressCapability::new(DevicePortType::RootPort, None);
985        cap = cap.with_hotplug_support(1);
986
987        // Modify slot capabilities to disable some features for testing
988        cap.slot_capabilities.set_attention_button_present(false);
989        cap.slot_capabilities.set_power_controller_present(false);
990        cap.slot_capabilities.set_mrl_sensor_present(false);
991        cap.slot_capabilities.set_attention_indicator_present(false);
992        cap.slot_capabilities.set_power_indicator_present(false);
993        cap.slot_capabilities
994            .set_electromechanical_interlock_present(false);
995        cap.slot_capabilities.set_no_command_completed_support(true);
996
997        // Try to write to slot control register with all bits set
998        let slot_ctl_sts_offset = 0x18; // SLOT_CTL_STS offset
999        let val_to_write = 0xFFFFFFFF; // All bits set in both control and status
1000
1001        cap.write_u32(slot_ctl_sts_offset, val_to_write);
1002
1003        // Read back the slot control register (lower 16 bits)
1004        let read_back = cap.read_u32(slot_ctl_sts_offset);
1005        let slot_control_value = read_back as u16;
1006        let slot_control = pci_express::SlotControl::from_bits(slot_control_value);
1007
1008        // Verify that features not present in capabilities were not set in control register
1009        assert!(
1010            !slot_control.attention_button_pressed_enable(),
1011            "Attention button enable should be 0 when capability not present"
1012        );
1013        assert!(
1014            !slot_control.power_controller_control(),
1015            "Power controller control should be 0 when capability not present"
1016        );
1017        assert!(
1018            !slot_control.mrl_sensor_changed_enable(),
1019            "MRL sensor changed enable should be 0 when capability not present"
1020        );
1021        assert_eq!(
1022            slot_control.attention_indicator_control(),
1023            0,
1024            "Attention indicator control should be 0 when capability not present"
1025        );
1026        assert_eq!(
1027            slot_control.power_indicator_control(),
1028            0,
1029            "Power indicator control should be 0 when capability not present"
1030        );
1031        assert!(
1032            !slot_control.electromechanical_interlock_control(),
1033            "Electromechanical interlock control should be 0 when capability not present"
1034        );
1035        assert!(
1036            !slot_control.command_completed_interrupt_enable(),
1037            "Command completed interrupt enable should be 0 when no command completed support"
1038        );
1039
1040        // However, hotplug interrupt enable should be settable since hotplug is capable
1041        assert!(
1042            slot_control.hot_plug_interrupt_enable(),
1043            "Hotplug interrupt enable should be settable when hotplug capable"
1044        );
1045    }
1046
1047    #[test]
1048    fn test_link_control_retrain_link_behavior() {
1049        // Test that retrain_link always reads as 0 regardless of what is written
1050        let mut cap = PciExpressCapability::new(DevicePortType::RootPort, None);
1051
1052        let link_ctl_sts_offset = 0x10; // LINK_CTL_STS offset
1053
1054        // Write a value with retrain_link bit set (bit 5)
1055        let write_val = 0x0020; // retrain_link bit (bit 5) = 1
1056        cap.write_u32(link_ctl_sts_offset, write_val);
1057
1058        // Read back and verify retrain_link is always 0
1059        let read_back = cap.read_u32(link_ctl_sts_offset);
1060        let link_control = pci_express::LinkControl::from_bits(read_back as u16);
1061
1062        assert!(
1063            !link_control.retrain_link(),
1064            "retrain_link should always read as 0"
1065        );
1066
1067        // Verify other bits can still be set (except retrain_link)
1068        let write_val_2 = 0x0001; // aspm_control bit 0 = 1
1069        cap.write_u32(link_ctl_sts_offset, write_val_2);
1070
1071        let read_back_2 = cap.read_u32(link_ctl_sts_offset);
1072        let link_control_2 = pci_express::LinkControl::from_bits(read_back_2 as u16);
1073
1074        assert_eq!(
1075            link_control_2.aspm_control(),
1076            1,
1077            "Other control bits should be settable"
1078        );
1079        assert!(
1080            !link_control_2.retrain_link(),
1081            "retrain_link should still read as 0"
1082        );
1083    }
1084
1085    #[test]
1086    fn test_hotplug_link_capabilities() {
1087        // Test that Data Link Layer Link Active Reporting is enabled with hotplug
1088        let cap = PciExpressCapability::new(DevicePortType::RootPort, None);
1089        let cap_with_hotplug = cap.with_hotplug_support(1);
1090
1091        let link_caps_offset = 0x0C; // LINK_CAPS offset
1092        let link_caps = cap_with_hotplug.read_u32(link_caps_offset);
1093        let link_capabilities = pci_express::LinkCapabilities::from_bits(link_caps);
1094
1095        // Verify that Data Link Layer Link Active Reporting is enabled
1096        assert!(
1097            link_capabilities.data_link_layer_link_active_reporting(),
1098            "Data Link Layer Link Active Reporting should be enabled for hotplug"
1099        );
1100
1101        // Verify default speed and width are still correct
1102        assert_eq!(
1103            link_capabilities.max_link_speed(),
1104            LinkSpeed::Speed32_0GtS.into_bits(),
1105            "Max link speed should be Speed32_0GtS (PCIe 32.0 GT/s)"
1106        );
1107        assert_eq!(
1108            link_capabilities.max_link_width(),
1109            LinkWidth::X16.into_bits(),
1110            "Max link width should be X16 (x16)"
1111        );
1112
1113        // Test that non-hotplug capability doesn't have Data Link Layer Link Active Reporting
1114        let cap_no_hotplug = PciExpressCapability::new(DevicePortType::RootPort, None);
1115        let link_caps_no_hotplug = cap_no_hotplug.read_u32(link_caps_offset);
1116        let link_capabilities_no_hotplug =
1117            pci_express::LinkCapabilities::from_bits(link_caps_no_hotplug);
1118
1119        assert!(
1120            !link_capabilities_no_hotplug.data_link_layer_link_active_reporting(),
1121            "Data Link Layer Link Active Reporting should be disabled without hotplug"
1122        );
1123    }
1124
1125    #[test]
1126    fn test_link_status_read_only() {
1127        // Test that Link Status register is read-only and cannot be modified by writes
1128        let mut cap = PciExpressCapability::new(DevicePortType::RootPort, None);
1129
1130        let link_ctl_sts_offset = 0x10; // LINK_CTL_STS offset
1131
1132        // Set some initial link status values (this would normally be done by hardware)
1133        {
1134            let mut state = cap.state.lock();
1135            state.link_status.set_current_link_speed(0b0001); // Set initial speed
1136            state.link_status.set_negotiated_link_width(0b000001); // Set initial width
1137            state.link_status.set_link_training(true); // Set link training active
1138            state.link_status.set_data_link_layer_link_active(true); // Set DLL active
1139        }
1140
1141        // Read initial values
1142        let initial_read = cap.read_u32(link_ctl_sts_offset);
1143        let initial_link_status = pci_express::LinkStatus::from_bits((initial_read >> 16) as u16);
1144
1145        // Verify initial values are set
1146        assert_eq!(
1147            initial_link_status.current_link_speed(),
1148            0b0001,
1149            "Initial link speed should be set"
1150        );
1151        assert_eq!(
1152            initial_link_status.negotiated_link_width(),
1153            0b000001,
1154            "Initial link width should be set"
1155        );
1156        assert!(
1157            initial_link_status.link_training(),
1158            "Initial link training should be active"
1159        );
1160        assert!(
1161            initial_link_status.data_link_layer_link_active(),
1162            "Initial DLL should be active"
1163        );
1164
1165        // Try to write different values to Link Status (upper 16 bits) while also writing to Link Control
1166        let write_val = 0xFFFF0001; // Upper 16 bits all 1s (Link Status), lower 16 bits = 1 (Link Control)
1167        cap.write_u32(link_ctl_sts_offset, write_val);
1168
1169        // Read back and verify Link Status hasn't changed
1170        let after_write = cap.read_u32(link_ctl_sts_offset);
1171        let final_link_status = pci_express::LinkStatus::from_bits((after_write >> 16) as u16);
1172        let final_link_control = pci_express::LinkControl::from_bits(after_write as u16);
1173
1174        // Link Status should remain unchanged (read-only)
1175        assert_eq!(
1176            final_link_status.current_link_speed(),
1177            initial_link_status.current_link_speed(),
1178            "Link Status current_link_speed should be read-only"
1179        );
1180        assert_eq!(
1181            final_link_status.negotiated_link_width(),
1182            initial_link_status.negotiated_link_width(),
1183            "Link Status negotiated_link_width should be read-only"
1184        );
1185        assert_eq!(
1186            final_link_status.link_training(),
1187            initial_link_status.link_training(),
1188            "Link Status link_training should be read-only"
1189        );
1190        assert_eq!(
1191            final_link_status.data_link_layer_link_active(),
1192            initial_link_status.data_link_layer_link_active(),
1193            "Link Status data_link_layer_link_active should be read-only"
1194        );
1195
1196        // But Link Control should be modifiable
1197        assert_eq!(
1198            final_link_control.aspm_control(),
1199            1,
1200            "Link Control should be writable"
1201        );
1202    }
1203
1204    #[test]
1205    fn test_slot_status_rw1c_behavior() {
1206        // Create a root port capability with hotplug support
1207        let mut cap = PciExpressCapability::new(DevicePortType::RootPort, None);
1208        cap = cap.with_hotplug_support(1);
1209
1210        let slot_ctl_sts_offset = 0x18; // SLOT_CTL_STS offset
1211
1212        // First, simulate setting some status bits (this would normally be done by hardware)
1213        {
1214            let mut state = cap.state.lock();
1215            state.slot_status.set_attention_button_pressed(true);
1216            state.slot_status.set_power_fault_detected(true);
1217            state.slot_status.set_mrl_sensor_changed(true);
1218            state.slot_status.set_presence_detect_changed(true);
1219            state.slot_status.set_command_completed(true);
1220            state.slot_status.set_data_link_layer_state_changed(true);
1221            // Set some RO bits too
1222            state.slot_status.set_mrl_sensor_state(1);
1223            state.slot_status.set_presence_detect_state(1);
1224            state.slot_status.set_electromechanical_interlock_status(1);
1225        }
1226
1227        // Read the initial status to verify all bits are set
1228        let initial_read = cap.read_u32(slot_ctl_sts_offset);
1229        let initial_status = pci_express::SlotStatus::from_bits((initial_read >> 16) as u16);
1230        assert!(
1231            initial_status.attention_button_pressed(),
1232            "Initial attention button pressed should be set"
1233        );
1234        assert!(
1235            initial_status.power_fault_detected(),
1236            "Initial power fault detected should be set"
1237        );
1238        assert!(
1239            initial_status.mrl_sensor_changed(),
1240            "Initial MRL sensor changed should be set"
1241        );
1242        assert!(
1243            initial_status.presence_detect_changed(),
1244            "Initial presence detect changed should be set"
1245        );
1246        assert!(
1247            initial_status.command_completed(),
1248            "Initial command completed should be set"
1249        );
1250        assert!(
1251            initial_status.data_link_layer_state_changed(),
1252            "Initial data link layer state changed should be set"
1253        );
1254        assert_eq!(
1255            initial_status.mrl_sensor_state(),
1256            1,
1257            "Initial MRL sensor state should be set"
1258        );
1259        assert_eq!(
1260            initial_status.presence_detect_state(),
1261            1,
1262            "Initial presence detect state should be set"
1263        );
1264        assert_eq!(
1265            initial_status.electromechanical_interlock_status(),
1266            1,
1267            "Initial electromechanical interlock status should be set"
1268        );
1269
1270        // Write 1 to clear specific RW1C bits (upper 16 bits contain status)
1271        // Write 1s only to some RW1C bits to test selective clearing
1272        // Bit positions: attention_button_pressed(0), command_completed(4), data_link_layer_state_changed(8)
1273        let write_val = (0b0000_0001_0001_0001_u16 as u32) << 16; // Clear bits 0, 4, and 8
1274        cap.write_u32(slot_ctl_sts_offset, write_val);
1275
1276        // Read back and verify RW1C behavior
1277        let after_write = cap.read_u32(slot_ctl_sts_offset);
1278        let final_status = pci_express::SlotStatus::from_bits((after_write >> 16) as u16);
1279
1280        // RW1C bits that were written with 1 should be cleared
1281        assert!(
1282            !final_status.attention_button_pressed(),
1283            "Attention button pressed should be cleared after write-1"
1284        );
1285        assert!(
1286            !final_status.command_completed(),
1287            "Command completed should be cleared after write-1"
1288        );
1289        assert!(
1290            !final_status.data_link_layer_state_changed(),
1291            "Data link layer state changed should be cleared after write-1"
1292        );
1293
1294        // RW1C bits that were written with 0 should remain unchanged
1295        assert!(
1296            final_status.power_fault_detected(),
1297            "Power fault detected should remain set (write-0)"
1298        );
1299        assert!(
1300            final_status.mrl_sensor_changed(),
1301            "MRL sensor changed should remain set (write-0)"
1302        );
1303        assert!(
1304            final_status.presence_detect_changed(),
1305            "Presence detect changed should remain set (write-0)"
1306        );
1307
1308        // RO bits should remain unchanged regardless of what was written
1309        assert_eq!(
1310            final_status.mrl_sensor_state(),
1311            1,
1312            "MRL sensor state should remain unchanged (RO)"
1313        );
1314        assert_eq!(
1315            final_status.presence_detect_state(),
1316            1,
1317            "Presence detect state should remain unchanged (RO)"
1318        );
1319        assert_eq!(
1320            final_status.electromechanical_interlock_status(),
1321            1,
1322            "Electromechanical interlock status should remain unchanged (RO)"
1323        );
1324    }
1325
1326    #[test]
1327    fn test_link_control_2_target_speed_validation() {
1328        // Test that target link speed is validated against max link speed and reflected in link status
1329        let mut cap = PciExpressCapability::new(DevicePortType::RootPort, None);
1330
1331        let link_ctl_sts_2_offset = 0x30; // LINK_CTL_STS_2 offset
1332
1333        // Initially, target link speed should be Speed32_0GtS (5) and current link speed should match
1334        let initial_read = cap.read_u32(link_ctl_sts_2_offset);
1335        let initial_link_control_2 = pci_express::LinkControl2::from_bits(initial_read as u16);
1336        assert_eq!(
1337            initial_link_control_2.target_link_speed(),
1338            LinkSpeed::Speed32_0GtS.into_bits() as u16,
1339            "Initial target link speed should be Speed32_0GtS"
1340        );
1341
1342        // Check that link status reflects this speed
1343        let link_ctl_sts_offset = 0x10; // LINK_CTL_STS offset
1344        let link_ctl_sts = cap.read_u32(link_ctl_sts_offset);
1345        let link_status = pci_express::LinkStatus::from_bits((link_ctl_sts >> 16) as u16);
1346        assert_eq!(
1347            link_status.current_link_speed(),
1348            LinkSpeed::Speed32_0GtS.into_bits() as u16,
1349            "Initial current link speed should match target speed"
1350        );
1351        assert_eq!(
1352            link_status.negotiated_link_width(),
1353            LinkWidth::X16.into_bits() as u16,
1354            "Initial negotiated link width should be X16"
1355        );
1356
1357        // Test writing a valid speed (Speed16_0GtS = 4) that's less than max speed (Speed32_0GtS = 5)
1358        let valid_speed = LinkSpeed::Speed16_0GtS.into_bits() as u16; // 4
1359        cap.write_u32(link_ctl_sts_2_offset, valid_speed as u32);
1360
1361        // Verify target link speed was set correctly
1362        let after_valid_write = cap.read_u32(link_ctl_sts_2_offset);
1363        let link_control_2_after_valid =
1364            pci_express::LinkControl2::from_bits(after_valid_write as u16);
1365        assert_eq!(
1366            link_control_2_after_valid.target_link_speed(),
1367            valid_speed,
1368            "Target link speed should be set to requested valid speed"
1369        );
1370
1371        // Verify current link speed was updated in link status
1372        let link_ctl_sts_after_valid = cap.read_u32(link_ctl_sts_offset);
1373        let link_status_after_valid =
1374            pci_express::LinkStatus::from_bits((link_ctl_sts_after_valid >> 16) as u16);
1375        assert_eq!(
1376            link_status_after_valid.current_link_speed(),
1377            valid_speed,
1378            "Current link speed should be updated to match target speed"
1379        );
1380
1381        // Test writing an invalid speed (Speed64_0GtS = 6) that exceeds max speed (Speed32_0GtS = 5)
1382        let invalid_speed = LinkSpeed::Speed64_0GtS.into_bits() as u16; // 6
1383        cap.write_u32(link_ctl_sts_2_offset, invalid_speed as u32);
1384
1385        // Verify target link speed was clamped to max speed
1386        let after_invalid_write = cap.read_u32(link_ctl_sts_2_offset);
1387        let link_control_2_after_invalid =
1388            pci_express::LinkControl2::from_bits(after_invalid_write as u16);
1389        let max_speed = LinkSpeed::Speed32_0GtS.into_bits() as u16; // 5
1390        assert_eq!(
1391            link_control_2_after_invalid.target_link_speed(),
1392            max_speed,
1393            "Target link speed should be clamped to max supported speed"
1394        );
1395
1396        // Verify current link speed was updated to the clamped value
1397        let link_ctl_sts_after_invalid = cap.read_u32(link_ctl_sts_offset);
1398        let link_status_after_invalid =
1399            pci_express::LinkStatus::from_bits((link_ctl_sts_after_invalid >> 16) as u16);
1400        assert_eq!(
1401            link_status_after_invalid.current_link_speed(),
1402            max_speed,
1403            "Current link speed should be updated to clamped max speed"
1404        );
1405
1406        // Verify that link width remains unchanged throughout
1407        assert_eq!(
1408            link_status_after_valid.negotiated_link_width(),
1409            LinkWidth::X16.into_bits() as u16,
1410            "Negotiated link width should remain unchanged"
1411        );
1412        assert_eq!(
1413            link_status_after_invalid.negotiated_link_width(),
1414            LinkWidth::X16.into_bits() as u16,
1415            "Negotiated link width should remain unchanged"
1416        );
1417    }
1418
1419    #[test]
1420    fn test_with_hotplug_support_slot_number() {
1421        // Test that slot numbers are properly set when enabling hotplug support
1422
1423        // Test with slot number 5
1424        let cap1 = PciExpressCapability::new(DevicePortType::RootPort, None);
1425        let cap1_with_hotplug = cap1.with_hotplug_support(5);
1426
1427        assert!(cap1_with_hotplug.slot_capabilities.hot_plug_capable());
1428        assert_eq!(
1429            cap1_with_hotplug.slot_capabilities.physical_slot_number(),
1430            5
1431        );
1432
1433        // Test with slot number 0
1434        let cap2 = PciExpressCapability::new(DevicePortType::DownstreamSwitchPort, None);
1435        let cap2_with_hotplug = cap2.with_hotplug_support(0);
1436
1437        assert!(cap2_with_hotplug.slot_capabilities.hot_plug_capable());
1438        assert_eq!(
1439            cap2_with_hotplug.slot_capabilities.physical_slot_number(),
1440            0
1441        );
1442
1443        // Test with a larger slot number
1444        let cap3 = PciExpressCapability::new(DevicePortType::RootPort, None);
1445        let cap3_with_hotplug = cap3.with_hotplug_support(255);
1446
1447        assert!(cap3_with_hotplug.slot_capabilities.hot_plug_capable());
1448        assert_eq!(
1449            cap3_with_hotplug.slot_capabilities.physical_slot_number(),
1450            255
1451        );
1452    }
1453
1454    #[test]
1455    fn test_slot_implemented_flag_in_pcie_capabilities_register() {
1456        // Test that slot_implemented bit is correctly set in the PCIe Capabilities register
1457        // when hotplug support is enabled
1458
1459        // Test without hotplug - slot_implemented should be false
1460        let cap_no_hotplug = PciExpressCapability::new(DevicePortType::RootPort, None);
1461        let caps_val_no_hotplug = cap_no_hotplug.read_u32(0x00);
1462        let pcie_caps_no_hotplug = (caps_val_no_hotplug >> 16) as u16;
1463        let slot_implemented_bit = (pcie_caps_no_hotplug >> 8) & 0x1; // slot_implemented is bit 8 of PCIe capabilities
1464        assert_eq!(
1465            slot_implemented_bit, 0,
1466            "slot_implemented should be 0 when hotplug is not enabled"
1467        );
1468
1469        // Test with hotplug - slot_implemented should be true
1470        let cap_with_hotplug = cap_no_hotplug.with_hotplug_support(1);
1471        let caps_val_with_hotplug = cap_with_hotplug.read_u32(0x00);
1472        let pcie_caps_with_hotplug = (caps_val_with_hotplug >> 16) as u16;
1473        let slot_implemented_bit_hotplug = (pcie_caps_with_hotplug >> 8) & 0x1; // slot_implemented is bit 8 of PCIe capabilities
1474        assert_eq!(
1475            slot_implemented_bit_hotplug, 1,
1476            "slot_implemented should be 1 when hotplug is enabled"
1477        );
1478    }
1479
1480    #[test]
1481    fn test_set_presence_detect_state() {
1482        // Test setting presence detect state on a hotplug-capable port
1483        let cap = PciExpressCapability::new(DevicePortType::RootPort, None).with_hotplug_support(1);
1484
1485        // Initially, presence detect state should be 0 (no device present)
1486        let initial_slot_status = cap.read_u32(0x18); // Slot Control + Slot Status
1487        let initial_presence_detect = (initial_slot_status >> 22) & 0x1; // presence_detect_state is bit 6 of slot status (upper 16 bits)
1488        assert_eq!(
1489            initial_presence_detect, 0,
1490            "Initial presence detect state should be 0"
1491        );
1492
1493        // Set device as present
1494        cap.set_presence_detect_state(true);
1495        let present_slot_status = cap.read_u32(0x18);
1496        let present_presence_detect = (present_slot_status >> 22) & 0x1;
1497        assert_eq!(
1498            present_presence_detect, 1,
1499            "Presence detect state should be 1 when device is present"
1500        );
1501
1502        // Set device as not present
1503        cap.set_presence_detect_state(false);
1504        let absent_slot_status = cap.read_u32(0x18);
1505        let absent_presence_detect = (absent_slot_status >> 22) & 0x1;
1506        assert_eq!(
1507            absent_presence_detect, 0,
1508            "Presence detect state should be 0 when device is not present"
1509        );
1510    }
1511
1512    #[test]
1513    fn test_set_presence_detect_state_without_slot_implemented() {
1514        // Test that setting presence detect state is silently ignored when slot is not implemented
1515        let cap = PciExpressCapability::new(DevicePortType::RootPort, None);
1516
1517        // Should not panic and should be silently ignored
1518        cap.set_presence_detect_state(true);
1519        cap.set_presence_detect_state(false);
1520    }
1521}