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