summary refs log tree commit diff
path: root/devices/src/pci/msix.rs
diff options
context:
space:
mode:
Diffstat (limited to 'devices/src/pci/msix.rs')
-rw-r--r--devices/src/pci/msix.rs69
1 files changed, 69 insertions, 0 deletions
diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs
new file mode 100644
index 0000000..55e71ba
--- /dev/null
+++ b/devices/src/pci/msix.rs
@@ -0,0 +1,69 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::pci::{PciCapability, PciCapabilityID};
+
+use data_model::DataInit;
+
+const MAX_MSIX_VECTORS_PER_DEVICE: u16 = 2048;
+
+// It is safe to implement DataInit; all members are simple numbers and any value is valid.
+unsafe impl DataInit for MsixCap {}
+
+#[allow(dead_code)]
+#[repr(C)]
+#[derive(Clone, Copy, Default)]
+/// MSI-X Capability Structure
+pub struct MsixCap {
+    // To make add_capability() happy
+    _cap_vndr: u8,
+    _cap_next: u8,
+    // Message Control Register
+    //   10-0:  MSI-X Table size
+    //   13-11: Reserved
+    //   14:    Mask. Mask all MSI-X when set.
+    //   15:    Enable. Enable all MSI-X when set.
+    msg_ctl: u16,
+    // Table. Contains the offset and the BAR indicator (BIR)
+    //   2-0:  Table BAR indicator (BIR). Can be 0 to 5.
+    //   31-3: Table offset in the BAR pointed by the BIR.
+    table: u32,
+    // Pending Bit Array. Contains the offset and the BAR indicator (BIR)
+    //   2-0:  PBA BAR indicator (BIR). Can be 0 to 5.
+    //   31-3: PBA offset in the BAR pointed by the BIR.
+    pba: u32,
+}
+
+impl PciCapability for MsixCap {
+    fn bytes(&self) -> &[u8] {
+        self.as_slice()
+    }
+
+    fn id(&self) -> PciCapabilityID {
+        PciCapabilityID::MSIX
+    }
+}
+
+impl MsixCap {
+    pub fn new(
+        table_pci_bar: u8,
+        table_size: u16,
+        table_off: u32,
+        pba_pci_bar: u8,
+        pba_off: u32,
+    ) -> Self {
+        assert!(table_size < MAX_MSIX_VECTORS_PER_DEVICE);
+
+        // Set the table size and enable MSI-X.
+        let msg_ctl: u16 = 0x8000u16 + table_size - 1;
+
+        MsixCap {
+            _cap_vndr: 0,
+            _cap_next: 0,
+            msg_ctl,
+            table: (table_off & 0xffff_fff8u32) | u32::from(table_pci_bar & 0x7u8),
+            pba: (pba_off & 0xffff_fff8u32) | u32::from(pba_pci_bar & 0x7u8),
+        }
+    }
+}