lspci/
bridge.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4use crate::config::{BridgeControlRegister, SecondaryStatusRegister, Type01Config};
5use crate::device::Device;
6use crate::util::format_bytes;
7use std::fmt;
8use zerocopy::Ref;
9
10// A PCI Bridge is a Device with a different (Type 01) configuration layout, but much of the
11// information displayed is similar.
12pub struct Bridge<'a> {
13    device: &'a Device<'a>,
14    cfg: Ref<&'a [u8], Type01Config>,
15}
16
17impl<'a> Bridge<'a> {
18    pub fn new(device: &'a Device<'_>) -> Self {
19        let cfg = Type01Config::new(&device.device.config);
20        Bridge { device, cfg }
21    }
22
23    pub fn decode_bridge_io(&self) -> Option<(u32, u32)> {
24        // Bits 15:4 of both registers reflect the address bits that are writable
25        let mut io_base: u32 = (self.cfg.io_base >> 4).into();
26        let mut io_limit: u32 = (self.cfg.io_limit >> 4).into();
27        let is_32bit: bool = self.cfg.io_base & 0xF == 1;
28        // A valid IO base/limit pair is a [io_base, io_limit] range.
29        if (io_base == 0 && io_limit == 0) || io_base > io_limit {
30            return None;
31        }
32
33        // PCI-to-PCI bridge arch spec 3.2.5.6
34        // Bridges assume the bottom 12 bits of base are 000
35        io_base <<= 12;
36        // Bridges assume the bottom 12 bits of limit are 0xFFF
37        io_limit <<= 12;
38        io_limit |= 0xFFF;
39        if is_32bit {
40            Some((
41                (io_base) | self.cfg.io_base_upper_16 as u32,
42                (io_limit) | self.cfg.io_limit_upper_16 as u32,
43            ))
44        } else {
45            Some((io_base, io_limit))
46        }
47    }
48
49    pub fn decode_bridge_mem(&self) -> Option<(u32, u32)> {
50        // Bits 15:4 of both registers reflect the address bits that are writable
51        let mut mem_base: u32 = (self.cfg.memory_base >> 4).into();
52        let mut mem_limit: u32 = (self.cfg.memory_limit >> 4).into();
53        // A valid base/limit pair is a [mem_base, mem_limit] range.
54        if (mem_base == 0 && mem_limit == 0) || mem_base > mem_limit {
55            return None;
56        }
57
58        // PCI-to-PCI bridge arch spec 3.2.5.8
59        // Bridges assume the bottom 20 bits of base are 00000
60        mem_base <<= 20;
61        // Bridges assume the bottom 20 bits of memory limit are 0xFFFFF
62        mem_limit <<= 20;
63        mem_limit |= 0xFFFFF;
64        Some((mem_base, mem_limit))
65    }
66
67    pub fn decode_bridge_pf(&self) -> Option<(u64, u64)> {
68        // Bits 15:4 of both registers reflect the address bits that are writable
69        let mut pf_base: u64 = (self.cfg.pf_memory_base >> 4).into();
70        let mut pf_limit: u64 = (self.cfg.pf_memory_limit >> 4).into();
71        let is_64bit: bool = self.cfg.pf_memory_base & 0xF == 1;
72        // A valid IO base/limit pair is a [pf_base, pf_limit] range.
73        if (pf_base == 0 && pf_limit == 0) || pf_base > pf_limit {
74            return None;
75        }
76
77        // PCI-to-PCI bridge arch spec 3.2.5.9
78        // Bridges assume the bottom 20 bits of base are 00000
79        pf_base <<= 20;
80        // Bridges assume the bottom 20 bits of limit are 0xFFFFF
81        pf_limit <<= 20;
82        pf_limit |= 0xFFFFF;
83        if is_64bit {
84            Some((
85                (pf_base) | (self.cfg.pf_base_upper_32 as u64) << 32,
86                (pf_limit) | (self.cfg.pf_limit_upper_32 as u64) << 32,
87            ))
88        } else {
89            Some((pf_base, pf_limit))
90        }
91    }
92}
93
94// Add a method to device like is_bridge() -> bool that checks the type header
95impl<'a> fmt::Display for Bridge<'a> {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        self.device.print_common_header(f)?;
98        if self.device.args.verbose {
99            writeln!(
100            f,
101            "\tBus: primary = 0x{:02x}, secondary = 0x{:02x}, subordinate = 0x{:02x}, sec-latency = {}",
102            self.cfg.primary_bus_number,
103            self.cfg.secondary_bus_number,
104            self.cfg.subordinate_bus_number,
105            self.cfg.secondary_latency_timer)?;
106
107            write!(f, "\tI/O behind bridge: ")?;
108            if let Some((base, limit)) = self.decode_bridge_io() {
109                writeln!(
110                    f,
111                    "[0x{:8x}, 0x{:8x}] [size={}]",
112                    base,
113                    limit,
114                    format_bytes((limit - base + 1) as u64)
115                )?;
116            } else {
117                writeln!(f, "[disabled]")?;
118            }
119            write!(f, "\tMemory behind bridge: ")?;
120            if let Some((base, limit)) = self.decode_bridge_mem() {
121                writeln!(
122                    f,
123                    "[0x{:8x}, 0x{:8x}] [size={}]",
124                    base,
125                    limit,
126                    format_bytes((limit - base + 1) as u64)
127                )?;
128            } else {
129                writeln!(f, "[disabled]")?;
130            }
131            write!(f, "\tPrefetchable memory behind bridge: ")?;
132            if let Some((base, limit)) = self.decode_bridge_pf() {
133                writeln!(
134                    f,
135                    "[0x{:16x}, 0x{:16x}] [size={}]",
136                    base,
137                    limit,
138                    format_bytes((limit - base + 1) as u64)
139                )?;
140            } else {
141                writeln!(f, "[disabled]")?;
142            }
143            writeln!(
144                f,
145                "\tSecondary Status: {}",
146                SecondaryStatusRegister(self.cfg.secondary_status)
147            )?;
148            writeln!(f, "\tBridge Control: {}", BridgeControlRegister(self.cfg.bridge_control))?;
149        }
150        self.device.print_common_footer(f)
151    }
152}