devices/pci/pcie/
pcie_rp.rs1use std::collections::BTreeMap;
6
7use anyhow::bail;
8use anyhow::Context;
9use anyhow::Result;
10use base::Event;
11use vm_control::PmeNotify;
12
13use crate::bus::HotPlugBus;
14use crate::bus::HotPlugKey;
15use crate::pci::pcie::pcie_host::PcieHostPort;
16use crate::pci::pcie::pcie_port::PciePort;
17use crate::pci::pcie::pcie_port::PciePortVariant;
18use crate::pci::pcie::*;
19use crate::pci::PciAddress;
20
21const PCIE_RP_DID: u16 = 0x3420;
22pub struct PcieRootPort {
23 pcie_port: PciePort,
24 downstream_devices: BTreeMap<PciAddress, HotPlugKey>,
25 hotplug_out_begin: bool,
26 removed_downstream: Vec<PciAddress>,
27}
28
29impl PcieRootPort {
30 pub fn new(secondary_bus_num: u8, slot_implemented: bool) -> Self {
32 PcieRootPort {
33 pcie_port: PciePort::new(
34 PCIE_RP_DID,
35 "PcieRootPort".to_string(),
36 0,
37 secondary_bus_num,
38 slot_implemented,
39 PcieDevicePortType::RootPort,
40 ),
41 downstream_devices: BTreeMap::new(),
42 hotplug_out_begin: false,
43 removed_downstream: Vec::new(),
44 }
45 }
46
47 pub fn new_from_host(pcie_host: PcieHostPort, slot_implemented: bool) -> Result<Self> {
49 Ok(PcieRootPort {
50 pcie_port: PciePort::new_from_host(
51 pcie_host,
52 slot_implemented,
53 PcieDevicePortType::RootPort,
54 )
55 .context("PciePort::new_from_host failed")?,
56 downstream_devices: BTreeMap::new(),
57 hotplug_out_begin: false,
58 removed_downstream: Vec::new(),
59 })
60 }
61}
62
63impl PciePortVariant for PcieRootPort {
64 fn get_pcie_port(&self) -> &PciePort {
65 &self.pcie_port
66 }
67
68 fn get_pcie_port_mut(&mut self) -> &mut PciePort {
69 &mut self.pcie_port
70 }
71
72 fn get_removed_devices_impl(&self) -> Vec<PciAddress> {
73 if self.pcie_port.removed_downstream_valid() {
74 self.removed_downstream.clone()
75 } else {
76 Vec::new()
77 }
78 }
79
80 fn hotplug_implemented_impl(&self) -> bool {
81 self.pcie_port.hotplug_implemented()
82 }
83
84 fn hotplugged_impl(&self) -> bool {
85 false
86 }
87}
88
89impl HotPlugBus for PcieRootPort {
90 fn hot_plug(&mut self, addr: PciAddress) -> Result<Option<Event>> {
91 if self.pcie_port.is_hpc_pending() {
92 bail!("Hot plug fail: previous slot event is pending.");
93 }
94 if !self.pcie_port.is_hotplug_ready() {
95 bail!("Hot unplug fail: slot is not enabled by the guest yet.");
96 }
97 self.downstream_devices
98 .get(&addr)
99 .context("No downstream devices.")?;
100
101 let hpc_sender = Event::new()?;
102 let hpc_recvr = hpc_sender.try_clone()?;
103 self.pcie_port.set_hpc_sender(hpc_sender);
104 self.pcie_port
105 .set_slot_status(PCIE_SLTSTA_PDS | PCIE_SLTSTA_ABP);
106 self.pcie_port.trigger_hp_or_pme_interrupt();
107 Ok(Some(hpc_recvr))
108 }
109
110 fn hot_unplug(&mut self, addr: PciAddress) -> Result<Option<Event>> {
111 if self.pcie_port.is_hpc_pending() {
112 bail!("Hot unplug fail: previous slot event is pending.");
113 }
114 if !self.pcie_port.is_hotplug_ready() {
115 bail!("Hot unplug fail: slot is not enabled by the guest yet.");
116 }
117 self.downstream_devices
118 .remove(&addr)
119 .context("No downstream devices.")?;
120 if self.hotplug_out_begin {
121 bail!("Hot unplug is pending.")
122 }
123 self.hotplug_out_begin = true;
124
125 self.removed_downstream.clear();
126 self.removed_downstream.push(addr);
127 for (guest_pci_addr, _) in self.downstream_devices.iter() {
129 self.removed_downstream.push(*guest_pci_addr);
130 }
131
132 let hpc_sender = Event::new()?;
133 let hpc_recvr = hpc_sender.try_clone()?;
134 let slot_control = self.pcie_port.get_slot_control();
135 match slot_control & PCIE_SLTCTL_PIC {
136 PCIE_SLTCTL_PIC_ON => {
137 self.pcie_port.set_hpc_sender(hpc_sender);
138 self.pcie_port.set_slot_status(PCIE_SLTSTA_ABP);
139 self.pcie_port.trigger_hp_or_pme_interrupt();
140 }
141 PCIE_SLTCTL_PIC_OFF => {
142 self.pcie_port.mask_slot_status(!PCIE_SLTSTA_PDS);
145 hpc_sender.signal()?;
146 }
147 _ => {
148 bail!("Hot unplug fail: Power indicator is blinking.");
151 }
152 }
153
154 if self.pcie_port.is_host() {
155 self.pcie_port.hot_unplug()
156 }
157 Ok(Some(hpc_recvr))
158 }
159
160 fn get_ready_notification(&mut self) -> anyhow::Result<Event> {
161 Ok(self.pcie_port.get_ready_notification()?)
162 }
163
164 fn get_address(&self) -> Option<PciAddress> {
165 self.pcie_port.get_address()
166 }
167
168 fn get_secondary_bus_number(&self) -> Option<u8> {
169 Some(self.pcie_port.get_bus_range()?.secondary)
170 }
171
172 fn is_match(&self, host_addr: PciAddress) -> Option<u8> {
173 self.pcie_port.is_match(host_addr)
174 }
175
176 fn add_hotplug_device(&mut self, hotplug_key: HotPlugKey, guest_addr: PciAddress) {
177 if !self.pcie_port.hotplug_implemented() {
178 return;
179 }
180
181 if self.hotplug_out_begin {
183 self.hotplug_out_begin = false;
184 self.downstream_devices.clear();
185 self.removed_downstream.clear();
186 }
187
188 self.downstream_devices.insert(guest_addr, hotplug_key);
189 }
190
191 fn get_hotplug_device(&self, hotplug_key: HotPlugKey) -> Option<PciAddress> {
192 for (guest_address, host_info) in self.downstream_devices.iter() {
193 if hotplug_key == *host_info {
194 return Some(*guest_address);
195 }
196 }
197 None
198 }
199
200 fn is_empty(&self) -> bool {
201 self.downstream_devices.is_empty()
202 }
203
204 fn get_hotplug_key(&self) -> Option<HotPlugKey> {
205 None
206 }
207}
208
209impl PmeNotify for PcieRootPort {
210 fn notify(&mut self, requester_id: u16) {
211 self.pcie_port.inject_pme(requester_id);
212 }
213}