Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/pci/pcie/pcie_port.rs
5394 views
1
// Copyright 2022 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::str::FromStr;
6
use std::sync::Arc;
7
8
use base::error;
9
use base::warn;
10
use base::Event;
11
use resources::SystemAllocator;
12
use sync::Mutex;
13
14
use crate::pci::pci_configuration::PciCapConfig;
15
use crate::pci::pci_configuration::PciCapConfigWriteResult;
16
use crate::pci::pci_configuration::PciCapMapping;
17
use crate::pci::pci_configuration::PciCapability;
18
use crate::pci::pcie::pci_bridge::PciBridgeBusRange;
19
use crate::pci::pcie::pcie_device::PcieCap;
20
use crate::pci::pcie::pcie_device::PcieDevice;
21
use crate::pci::pcie::pcie_host::PcieHostPort;
22
use crate::pci::pcie::*;
23
use crate::pci::pm::PciDevicePower;
24
use crate::pci::pm::PciPmCap;
25
use crate::pci::pm::PmConfig;
26
use crate::pci::pm::PmStatusChange;
27
use crate::pci::MsiConfig;
28
use crate::pci::PciAddress;
29
use crate::pci::PciDeviceError;
30
31
// reserve 8MB memory window
32
const PCIE_BR_MEM_SIZE: u64 = 0x80_0000;
33
// reserve 64MB prefetch window
34
const PCIE_BR_PREF_MEM_SIZE: u64 = 0x400_0000;
35
36
fn trigger_interrupt(msi: &Option<Arc<Mutex<MsiConfig>>>) {
37
if let Some(msi_config) = msi {
38
let msi_config = msi_config.lock();
39
if msi_config.is_msi_enabled() {
40
msi_config.trigger()
41
}
42
}
43
}
44
45
struct PcieRootCap {
46
secondary_bus_num: u8,
47
subordinate_bus_num: u8,
48
49
control: u16,
50
status: u32,
51
pme_pending_requester_id: Option<u16>,
52
53
msi_config: Option<Arc<Mutex<MsiConfig>>>,
54
}
55
56
impl PcieRootCap {
57
fn new(secondary_bus_num: u8, subordinate_bus_num: u8) -> Self {
58
PcieRootCap {
59
secondary_bus_num,
60
subordinate_bus_num,
61
control: 0,
62
status: 0,
63
pme_pending_requester_id: None,
64
msi_config: None,
65
}
66
}
67
68
fn clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>) {
69
self.msi_config = Some(msi_config);
70
}
71
72
fn trigger_pme_interrupt(&self) {
73
if (self.control & PCIE_ROOTCTL_PME_ENABLE) != 0
74
&& (self.status & PCIE_ROOTSTA_PME_STATUS) != 0
75
{
76
trigger_interrupt(&self.msi_config)
77
}
78
}
79
}
80
81
static PCIE_ROOTS_CAP: Mutex<Vec<Arc<Mutex<PcieRootCap>>>> = Mutex::new(Vec::new());
82
83
fn push_pcie_root_cap(root_cap: Arc<Mutex<PcieRootCap>>) {
84
PCIE_ROOTS_CAP.lock().push(root_cap);
85
}
86
87
fn get_pcie_root_cap(bus_num: u8) -> Option<Arc<Mutex<PcieRootCap>>> {
88
for root_cap in PCIE_ROOTS_CAP.lock().iter() {
89
let root_cap_lock = root_cap.lock();
90
if root_cap_lock.secondary_bus_num <= bus_num
91
&& root_cap_lock.subordinate_bus_num >= bus_num
92
{
93
return Some(root_cap.clone());
94
}
95
}
96
97
None
98
}
99
100
pub struct PciePort {
101
device_id: u16,
102
debug_label: String,
103
preferred_address: Option<PciAddress>,
104
pci_address: Option<PciAddress>,
105
bus_range: PciBridgeBusRange,
106
pcie_host: Option<PcieHostPort>,
107
pcie_config: Arc<Mutex<PcieConfig>>,
108
pm_config: Arc<Mutex<PmConfig>>,
109
110
msi_config: Option<Arc<Mutex<MsiConfig>>>,
111
112
// For PcieRootPort, root_cap point to itself
113
// For PcieDownstreamPort or PciDownstreamPort, root_cap point to PcieRootPort its behind.
114
root_cap: Arc<Mutex<PcieRootCap>>,
115
port_type: PcieDevicePortType,
116
117
prepare_hotplug: bool,
118
}
119
120
impl PciePort {
121
/// Constructs a new PCIE port
122
pub fn new(
123
device_id: u16,
124
debug_label: String,
125
primary_bus_num: u8,
126
secondary_bus_num: u8,
127
slot_implemented: bool,
128
port_type: PcieDevicePortType,
129
) -> Self {
130
let bus_range = PciBridgeBusRange {
131
primary: primary_bus_num,
132
secondary: secondary_bus_num,
133
subordinate: secondary_bus_num,
134
};
135
136
let root_cap = if port_type == PcieDevicePortType::RootPort {
137
let cap = Arc::new(Mutex::new(PcieRootCap::new(
138
secondary_bus_num,
139
secondary_bus_num,
140
)));
141
push_pcie_root_cap(cap.clone());
142
cap
143
} else {
144
get_pcie_root_cap(primary_bus_num).expect("Pcie root port should be created at first")
145
};
146
147
PciePort {
148
device_id,
149
debug_label,
150
preferred_address: None,
151
pci_address: None,
152
bus_range,
153
pcie_host: None,
154
msi_config: None,
155
pcie_config: Arc::new(Mutex::new(PcieConfig::new(
156
root_cap.clone(),
157
slot_implemented,
158
port_type,
159
))),
160
pm_config: Arc::new(Mutex::new(PmConfig::new(false))),
161
162
root_cap,
163
port_type,
164
165
prepare_hotplug: false,
166
}
167
}
168
169
pub fn new_from_host(
170
pcie_host: PcieHostPort,
171
slot_implemented: bool,
172
port_type: PcieDevicePortType,
173
) -> std::result::Result<Self, PciDeviceError> {
174
let bus_range = pcie_host.get_bus_range();
175
let host_address = PciAddress::from_str(&pcie_host.host_name())
176
.map_err(|e| PciDeviceError::PciAddressParseFailure(pcie_host.host_name(), e))?;
177
let root_cap = if port_type == PcieDevicePortType::RootPort {
178
let cap = Arc::new(Mutex::new(PcieRootCap::new(
179
bus_range.secondary,
180
bus_range.subordinate,
181
)));
182
push_pcie_root_cap(cap.clone());
183
cap
184
} else {
185
get_pcie_root_cap(bus_range.primary).expect("Pcie root port should be created at first")
186
};
187
188
Ok(PciePort {
189
device_id: pcie_host.read_device_id(),
190
debug_label: pcie_host.host_name(),
191
preferred_address: Some(host_address),
192
pci_address: None,
193
bus_range,
194
pcie_host: Some(pcie_host),
195
msi_config: None,
196
pcie_config: Arc::new(Mutex::new(PcieConfig::new(
197
root_cap.clone(),
198
slot_implemented,
199
port_type,
200
))),
201
pm_config: Arc::new(Mutex::new(PmConfig::new(false))),
202
203
root_cap,
204
port_type,
205
206
prepare_hotplug: false,
207
})
208
}
209
210
pub fn get_device_id(&self) -> u16 {
211
self.device_id
212
}
213
214
pub fn get_address(&self) -> Option<PciAddress> {
215
self.pci_address
216
}
217
218
pub fn debug_label(&self) -> String {
219
self.debug_label.clone()
220
}
221
222
pub fn preferred_address(&self) -> Option<PciAddress> {
223
self.preferred_address
224
}
225
226
pub fn allocate_address(
227
&mut self,
228
resources: &mut SystemAllocator,
229
) -> std::result::Result<PciAddress, PciDeviceError> {
230
if self.pci_address.is_none() {
231
if let Some(address) = self.preferred_address {
232
if resources.reserve_pci(address, self.debug_label()) {
233
self.pci_address = Some(address);
234
} else {
235
self.pci_address = None;
236
}
237
} else {
238
self.pci_address =
239
resources.allocate_pci(self.bus_range.primary, self.debug_label());
240
}
241
}
242
self.pci_address.ok_or(PciDeviceError::PciAllocationFailed)
243
}
244
245
pub fn read_config(&self, reg_idx: usize, data: &mut u32) {
246
if let Some(host) = &self.pcie_host {
247
host.read_config(reg_idx, data);
248
}
249
}
250
251
pub fn write_config(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
252
if let Some(host) = self.pcie_host.as_mut() {
253
host.write_config(reg_idx, offset, data);
254
}
255
}
256
257
pub fn handle_cap_write_result(&mut self, res: Box<dyn PciCapConfigWriteResult>) {
258
if let Some(status) = res.downcast_ref::<PmStatusChange>() {
259
if status.from == PciDevicePower::D3
260
&& status.to == PciDevicePower::D0
261
&& self.prepare_hotplug
262
{
263
if let Some(host) = self.pcie_host.as_mut() {
264
host.hotplug_probe();
265
self.prepare_hotplug = false;
266
}
267
}
268
}
269
}
270
271
pub fn get_caps(&self) -> Vec<(Box<dyn PciCapability>, Option<Box<dyn PciCapConfig>>)> {
272
vec![
273
(
274
Box::new(PcieCap::new(self.port_type, self.hotplug_implemented(), 0)),
275
Some(Box::new(self.pcie_config.clone())),
276
),
277
(
278
Box::new(PciPmCap::new()),
279
Some(Box::new(self.pm_config.clone())),
280
),
281
]
282
}
283
284
pub fn get_bus_range(&self) -> Option<PciBridgeBusRange> {
285
Some(self.bus_range)
286
}
287
288
pub fn get_bridge_window_size(&self) -> (u64, u64) {
289
if let Some(host) = &self.pcie_host {
290
host.get_bridge_window_size()
291
} else {
292
(PCIE_BR_MEM_SIZE, PCIE_BR_PREF_MEM_SIZE)
293
}
294
}
295
296
pub fn get_slot_control(&self) -> u16 {
297
self.pcie_config.lock().get_slot_control()
298
}
299
300
pub fn clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>) {
301
if self.port_type == PcieDevicePortType::RootPort {
302
self.root_cap.lock().clone_interrupt(msi_config.clone());
303
}
304
self.pcie_config.lock().msi_config = Some(msi_config.clone());
305
self.msi_config = Some(msi_config);
306
}
307
308
pub fn hotplug_implemented(&self) -> bool {
309
self.pcie_config.lock().slot_control.is_some()
310
}
311
312
pub fn inject_pme(&mut self, requester_id: u16) {
313
let mut r = self.root_cap.lock();
314
if (r.status & PCIE_ROOTSTA_PME_STATUS) != 0 {
315
r.status |= PCIE_ROOTSTA_PME_PENDING;
316
r.pme_pending_requester_id = Some(requester_id);
317
} else {
318
r.status &= !PCIE_ROOTSTA_PME_REQ_ID_MASK;
319
r.status |= requester_id as u32;
320
r.pme_pending_requester_id = None;
321
r.status |= PCIE_ROOTSTA_PME_STATUS;
322
r.trigger_pme_interrupt();
323
}
324
}
325
326
/// Has command completion pending.
327
pub fn is_hpc_pending(&self) -> bool {
328
self.pcie_config.lock().hpc_sender.is_some()
329
}
330
331
/// Sets a sender for hot plug or unplug complete.
332
pub fn set_hpc_sender(&mut self, event: Event) {
333
self.pcie_config
334
.lock()
335
.hpc_sender
336
.replace(HotPlugCompleteSender::new(event));
337
}
338
339
pub fn trigger_hp_or_pme_interrupt(&mut self) {
340
if self.pm_config.lock().should_trigger_pme() {
341
self.pcie_config.lock().hp_interrupt_pending = true;
342
self.inject_pme(self.pci_address.unwrap().pme_requester_id());
343
} else {
344
self.pcie_config.lock().trigger_hp_interrupt();
345
}
346
}
347
348
pub fn is_host(&self) -> bool {
349
self.pcie_host.is_some()
350
}
351
352
/// Checks if the slot is enabled by guest and ready for hotplug events.
353
pub fn is_hotplug_ready(&self) -> bool {
354
self.pcie_config.lock().is_hotplug_ready()
355
}
356
357
/// Gets a notification when the port is ready for hotplug. If the port is already ready, then
358
/// the notification event is triggerred immediately.
359
pub fn get_ready_notification(&mut self) -> std::result::Result<Event, PciDeviceError> {
360
self.pcie_config.lock().get_ready_notification()
361
}
362
363
pub fn hot_unplug(&mut self) {
364
if let Some(host) = self.pcie_host.as_mut() {
365
host.hot_unplug()
366
}
367
}
368
369
pub fn is_match(&self, host_addr: PciAddress) -> Option<u8> {
370
if host_addr.bus == self.bus_range.secondary || self.pcie_host.is_none() {
371
Some(self.bus_range.secondary)
372
} else {
373
None
374
}
375
}
376
377
pub fn removed_downstream_valid(&self) -> bool {
378
self.pcie_config.lock().removed_downstream_valid
379
}
380
381
pub fn mask_slot_status(&mut self, mask: u16) {
382
self.pcie_config.lock().mask_slot_status(mask);
383
}
384
385
pub fn set_slot_status(&mut self, flag: u16) {
386
self.pcie_config.lock().set_slot_status(flag);
387
}
388
389
pub fn should_trigger_pme(&mut self) -> bool {
390
self.pm_config.lock().should_trigger_pme()
391
}
392
393
pub fn prepare_hotplug(&mut self) {
394
self.prepare_hotplug = true;
395
}
396
}
397
398
struct HotPlugCompleteSender {
399
sender: Event,
400
armed: bool,
401
}
402
403
impl HotPlugCompleteSender {
404
fn new(sender: Event) -> Self {
405
Self {
406
sender,
407
armed: false,
408
}
409
}
410
411
fn arm(&mut self) {
412
self.armed = true;
413
}
414
415
fn armed(&self) -> bool {
416
self.armed
417
}
418
419
fn signal(&self) -> base::Result<()> {
420
self.sender.signal()
421
}
422
}
423
424
pub struct PcieConfig {
425
msi_config: Option<Arc<Mutex<MsiConfig>>>,
426
427
slot_control: Option<u16>,
428
slot_status: u16,
429
430
// For PcieRootPort, root_cap point to itself
431
// For PcieDownstreamPort or PciDownstreamPort, root_cap point to PcieRootPort its behind.
432
root_cap: Arc<Mutex<PcieRootCap>>,
433
port_type: PcieDevicePortType,
434
435
hpc_sender: Option<HotPlugCompleteSender>,
436
hp_interrupt_pending: bool,
437
removed_downstream_valid: bool,
438
439
enabled: bool,
440
hot_plug_ready_notifications: Vec<Event>,
441
cap_mapping: Option<PciCapMapping>,
442
}
443
444
impl PcieConfig {
445
fn new(
446
root_cap: Arc<Mutex<PcieRootCap>>,
447
slot_implemented: bool,
448
port_type: PcieDevicePortType,
449
) -> Self {
450
PcieConfig {
451
msi_config: None,
452
453
slot_control: if slot_implemented {
454
Some(PCIE_SLTCTL_PIC_OFF | PCIE_SLTCTL_AIC_OFF)
455
} else {
456
None
457
},
458
slot_status: 0,
459
460
root_cap,
461
port_type,
462
463
hpc_sender: None,
464
hp_interrupt_pending: false,
465
removed_downstream_valid: false,
466
467
enabled: false,
468
hot_plug_ready_notifications: Vec::new(),
469
cap_mapping: None,
470
}
471
}
472
473
fn read_pcie_cap(&self, offset: usize, data: &mut u32) {
474
if offset == PCIE_SLTCTL_OFFSET {
475
*data = ((self.slot_status as u32) << 16) | (self.get_slot_control() as u32);
476
} else if offset == PCIE_ROOTCTL_OFFSET {
477
*data = match self.port_type {
478
PcieDevicePortType::RootPort => self.root_cap.lock().control as u32,
479
_ => 0,
480
};
481
} else if offset == PCIE_ROOTSTA_OFFSET {
482
*data = match self.port_type {
483
PcieDevicePortType::RootPort => self.root_cap.lock().status,
484
_ => 0,
485
};
486
}
487
}
488
489
// Checks if the slot is enabled by guest and ready for hotplug events.
490
fn is_hotplug_ready(&self) -> bool {
491
// The hotplug capability flags are set when the guest enables the device. Checks all flags
492
// required by the hotplug mechanism.
493
let slot_control = self.get_slot_control();
494
(slot_control & (PCIE_SLTCTL_PDCE | PCIE_SLTCTL_ABPE)) != 0
495
&& (slot_control & PCIE_SLTCTL_CCIE) != 0
496
&& (slot_control & PCIE_SLTCTL_HPIE) != 0
497
}
498
499
/// Gets a notification when the port is ready for hotplug. If the port is already ready, then
500
/// the notification event is triggerred immediately.
501
fn get_ready_notification(&mut self) -> std::result::Result<Event, PciDeviceError> {
502
let event = Event::new().map_err(|e| PciDeviceError::EventCreationFailed(e.errno()))?;
503
if self.is_hotplug_ready() {
504
event
505
.signal()
506
.map_err(|e| PciDeviceError::EventSignalFailed(e.errno()))?;
507
} else {
508
self.hot_plug_ready_notifications.push(
509
event
510
.try_clone()
511
.map_err(|e| PciDeviceError::EventCloneFailed(e.errno()))?,
512
);
513
}
514
Ok(event)
515
}
516
517
fn write_pcie_cap(&mut self, offset: usize, data: &[u8]) {
518
self.removed_downstream_valid = false;
519
match offset {
520
PCIE_SLTCTL_OFFSET => {
521
let Ok(value) = data.try_into().map(u16::from_le_bytes) else {
522
warn!("write SLTCTL isn't word, len: {}", data.len());
523
return;
524
};
525
if !self.enabled
526
&& (value & (PCIE_SLTCTL_PDCE | PCIE_SLTCTL_ABPE)) != 0
527
&& (value & PCIE_SLTCTL_CCIE) != 0
528
&& (value & PCIE_SLTCTL_HPIE) != 0
529
{
530
// Device is getting enabled by the guest.
531
for notf_event in self.hot_plug_ready_notifications.drain(..) {
532
if let Err(e) = notf_event.signal() {
533
error!("Failed to signal hot plug ready: {}", e);
534
}
535
}
536
self.enabled = true;
537
}
538
539
// if slot is populated, power indicator is off,
540
// it will detach devices
541
let old_control = self.get_slot_control();
542
match self.slot_control.as_mut() {
543
Some(v) => *v = value,
544
None => return,
545
}
546
if (self.slot_status & PCIE_SLTSTA_PDS != 0)
547
&& (value & PCIE_SLTCTL_PIC == PCIE_SLTCTL_PIC_OFF)
548
&& (old_control & PCIE_SLTCTL_PIC != PCIE_SLTCTL_PIC_OFF)
549
{
550
self.removed_downstream_valid = true;
551
self.slot_status &= !PCIE_SLTSTA_PDS;
552
self.trigger_hp_interrupt();
553
}
554
555
// Guest enable hotplug interrupt and has hotplug interrupt
556
// pending, inject it right row.
557
if (old_control & PCIE_SLTCTL_HPIE == 0)
558
&& (value & PCIE_SLTCTL_HPIE == PCIE_SLTCTL_HPIE)
559
&& self.hp_interrupt_pending
560
{
561
self.hp_interrupt_pending = false;
562
self.trigger_hp_interrupt();
563
}
564
565
if old_control != value {
566
let old_pic_state = old_control & PCIE_SLTCTL_PIC;
567
let pic_state = value & PCIE_SLTCTL_PIC;
568
if old_pic_state == PCIE_SLTCTL_PIC_BLINK && old_pic_state != pic_state {
569
// The power indicator (PIC) is controled by the guest to indicate the power
570
// state of the slot.
571
// For successful hotplug: OFF => BLINK => (board enabled) => ON
572
// For failed hotplug: OFF => BLINK => (board enable failed) => OFF
573
// For hot unplug: ON => BLINK => (board disabled) => OFF
574
// hot (un)plug is completed at next slot status write after it changed to
575
// ON or OFF state.
576
577
if let Some(sender) = self.hpc_sender.as_mut() {
578
sender.arm();
579
}
580
}
581
self.slot_status |= PCIE_SLTSTA_CC;
582
self.trigger_cc_interrupt();
583
}
584
}
585
PCIE_SLTSTA_OFFSET => {
586
if self.slot_control.is_none() {
587
return;
588
}
589
if let Some(hpc_sender) = self.hpc_sender.as_mut() {
590
if hpc_sender.armed() {
591
if let Err(e) = hpc_sender.signal() {
592
error!("Failed to send hot un/plug complete signal: {}", e);
593
}
594
self.hpc_sender = None;
595
}
596
}
597
let Ok(value) = data.try_into().map(u16::from_le_bytes) else {
598
warn!("write SLTSTA isn't word, len: {}", data.len());
599
return;
600
};
601
if value & PCIE_SLTSTA_ABP != 0 {
602
self.slot_status &= !PCIE_SLTSTA_ABP;
603
}
604
if value & PCIE_SLTSTA_PFD != 0 {
605
self.slot_status &= !PCIE_SLTSTA_PFD;
606
}
607
if value & PCIE_SLTSTA_PDC != 0 {
608
self.slot_status &= !PCIE_SLTSTA_PDC;
609
}
610
if value & PCIE_SLTSTA_CC != 0 {
611
self.slot_status &= !PCIE_SLTSTA_CC;
612
}
613
if value & PCIE_SLTSTA_DLLSC != 0 {
614
self.slot_status &= !PCIE_SLTSTA_DLLSC;
615
}
616
}
617
PCIE_ROOTCTL_OFFSET => {
618
let Ok(v) = data.try_into().map(u16::from_le_bytes) else {
619
warn!("write root control isn't word, len: {}", data.len());
620
return;
621
};
622
if self.port_type == PcieDevicePortType::RootPort {
623
self.root_cap.lock().control = v;
624
} else {
625
warn!("write root control register while device isn't root port");
626
}
627
}
628
PCIE_ROOTSTA_OFFSET => {
629
let Ok(v) = data.try_into().map(u32::from_le_bytes) else {
630
warn!("write root status isn't dword, len: {}", data.len());
631
return;
632
};
633
if self.port_type == PcieDevicePortType::RootPort {
634
if v & PCIE_ROOTSTA_PME_STATUS != 0 {
635
let mut r = self.root_cap.lock();
636
if let Some(requester_id) = r.pme_pending_requester_id {
637
r.status &= !PCIE_ROOTSTA_PME_PENDING;
638
r.status &= !PCIE_ROOTSTA_PME_REQ_ID_MASK;
639
r.status |= requester_id as u32;
640
r.status |= PCIE_ROOTSTA_PME_STATUS;
641
r.pme_pending_requester_id = None;
642
r.trigger_pme_interrupt();
643
} else {
644
r.status &= !PCIE_ROOTSTA_PME_STATUS;
645
}
646
}
647
} else {
648
warn!("write root status register while device isn't root port");
649
}
650
}
651
_ => (),
652
}
653
}
654
655
fn get_slot_control(&self) -> u16 {
656
if let Some(slot_control) = self.slot_control {
657
return slot_control;
658
}
659
0
660
}
661
662
fn trigger_cc_interrupt(&self) {
663
if (self.get_slot_control() & PCIE_SLTCTL_CCIE) != 0
664
&& (self.slot_status & PCIE_SLTSTA_CC) != 0
665
{
666
trigger_interrupt(&self.msi_config)
667
}
668
}
669
670
fn trigger_hp_interrupt(&mut self) {
671
let slot_control = self.get_slot_control();
672
if (slot_control & PCIE_SLTCTL_HPIE) != 0 {
673
self.set_slot_status(PCIE_SLTSTA_PDC);
674
if (self.slot_status & slot_control & (PCIE_SLTCTL_ABPE | PCIE_SLTCTL_PDCE)) != 0 {
675
trigger_interrupt(&self.msi_config)
676
}
677
}
678
}
679
680
fn mask_slot_status(&mut self, mask: u16) {
681
self.slot_status &= mask;
682
if let Some(mapping) = self.cap_mapping.as_mut() {
683
mapping.set_reg(
684
PCIE_SLTCTL_OFFSET / 4,
685
(self.slot_status as u32) << 16,
686
0xffff0000,
687
);
688
}
689
}
690
691
fn set_slot_status(&mut self, flag: u16) {
692
self.slot_status |= flag;
693
if let Some(mapping) = self.cap_mapping.as_mut() {
694
mapping.set_reg(
695
PCIE_SLTCTL_OFFSET / 4,
696
(self.slot_status as u32) << 16,
697
0xffff0000,
698
);
699
}
700
}
701
}
702
703
const PCIE_CONFIG_READ_MASK: [u32; PCIE_CAP_LEN / 4] = {
704
let mut arr: [u32; PCIE_CAP_LEN / 4] = [0; PCIE_CAP_LEN / 4];
705
arr[PCIE_SLTCTL_OFFSET / 4] = 0xffffffff;
706
arr[PCIE_ROOTCTL_OFFSET / 4] = 0xffffffff;
707
arr[PCIE_ROOTSTA_OFFSET / 4] = 0xffffffff;
708
arr
709
};
710
711
impl PciCapConfig for PcieConfig {
712
fn read_mask(&self) -> &'static [u32] {
713
&PCIE_CONFIG_READ_MASK
714
}
715
716
fn read_reg(&self, reg_idx: usize) -> u32 {
717
let mut data = 0;
718
self.read_pcie_cap(reg_idx * 4, &mut data);
719
data
720
}
721
722
fn write_reg(
723
&mut self,
724
reg_idx: usize,
725
offset: u64,
726
data: &[u8],
727
) -> Option<Box<dyn PciCapConfigWriteResult>> {
728
self.write_pcie_cap(reg_idx * 4 + offset as usize, data);
729
None
730
}
731
732
fn set_cap_mapping(&mut self, mapping: PciCapMapping) {
733
self.cap_mapping = Some(mapping);
734
}
735
}
736
737
/// Helper trait for implementing PcieDevice where most functions
738
/// are proxied directly to a PciePort instance.
739
pub trait PciePortVariant: Send {
740
fn get_pcie_port(&self) -> &PciePort;
741
fn get_pcie_port_mut(&mut self) -> &mut PciePort;
742
743
/// Called via PcieDevice.get_removed_devices
744
fn get_removed_devices_impl(&self) -> Vec<PciAddress>;
745
746
/// Called via PcieDevice.hotplug_implemented
747
fn hotplug_implemented_impl(&self) -> bool;
748
749
/// Called via PcieDevice.hotplug
750
fn hotplugged_impl(&self) -> bool;
751
}
752
753
impl<T: PciePortVariant> PcieDevice for T {
754
fn get_device_id(&self) -> u16 {
755
self.get_pcie_port().get_device_id()
756
}
757
758
fn debug_label(&self) -> String {
759
self.get_pcie_port().debug_label()
760
}
761
762
fn preferred_address(&self) -> Option<PciAddress> {
763
self.get_pcie_port().preferred_address()
764
}
765
766
fn allocate_address(
767
&mut self,
768
resources: &mut SystemAllocator,
769
) -> std::result::Result<PciAddress, PciDeviceError> {
770
self.get_pcie_port_mut().allocate_address(resources)
771
}
772
773
fn clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>) {
774
self.get_pcie_port_mut().clone_interrupt(msi_config);
775
}
776
777
fn read_config(&self, reg_idx: usize, data: &mut u32) {
778
self.get_pcie_port().read_config(reg_idx, data);
779
}
780
781
fn write_config(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
782
self.get_pcie_port_mut().write_config(reg_idx, offset, data);
783
}
784
785
fn get_caps(&self) -> Vec<(Box<dyn PciCapability>, Option<Box<dyn PciCapConfig>>)> {
786
self.get_pcie_port().get_caps()
787
}
788
789
fn handle_cap_write_result(&mut self, res: Box<dyn PciCapConfigWriteResult>) {
790
self.get_pcie_port_mut().handle_cap_write_result(res)
791
}
792
793
fn get_bus_range(&self) -> Option<PciBridgeBusRange> {
794
self.get_pcie_port().get_bus_range()
795
}
796
797
fn get_removed_devices(&self) -> Vec<PciAddress> {
798
self.get_removed_devices_impl()
799
}
800
801
fn hotplug_implemented(&self) -> bool {
802
self.hotplug_implemented_impl()
803
}
804
805
fn hotplugged(&self) -> bool {
806
self.hotplugged_impl()
807
}
808
809
fn get_bridge_window_size(&self) -> (u64, u64) {
810
self.get_pcie_port().get_bridge_window_size()
811
}
812
}
813
814