pcid: AER + pciehp event producers (P2-1)
New events module: a 500ms poller thread scans every enumerated device and produces two read-only event streams: - /scheme/pci/aer — uncorrectable (NonFatal) and correctable AER status from the PCIe AER extended capability, emitted as 'severity=<level> device=<bdf> raw=...' lines and W1C-cleared - /scheme/pci/pciehp — Slot Status events from hot-plug-capable ports (presence detect, DLL state, attention button, MRL sensor, power fault), emitted as 'kind=<event> device=<bdf>' lines and W1C-cleared Events accumulate in capped in-memory logs (64 lines) served by the scheme; device strings use the scheme dir-name format (0000--00--1f.2) so driver-manager's route_to_driver matches bound paths. The Pcie handle is now Arc-shared with the poller. Extended capabilities need ECAM; on PCI 3.0 fallback machines the scanners gracefully produce nothing. This wires driver-manager's previously inert unified event listener to real producers.
This commit is contained in:
@@ -0,0 +1,217 @@
|
|||||||
|
//! AER and PCIe-native-hotplug event producers.
|
||||||
|
//!
|
||||||
|
//! A poller thread scans every enumerated device every 500 ms:
|
||||||
|
//! - AER: reads the PCIe AER extended capability's uncorrectable and
|
||||||
|
//! correctable error status registers, emits one line per event, and
|
||||||
|
//! write-1-to-clears the bits (the registers are W1C by spec).
|
||||||
|
//! - pciehp: reads the Slot Status register of hot-plug-capable ports and
|
||||||
|
//! emits one line per event bit (presence detect, DLL state, attention
|
||||||
|
//! button, MRL sensor, power fault), then W1C-clears them.
|
||||||
|
//!
|
||||||
|
//! Events accumulate in capped in-memory logs served read-only as
|
||||||
|
//! `/scheme/pci/aer` and `/scheme/pci/pciehp`. Consumers (driver-manager's
|
||||||
|
//! unified listener) hash lines to deduplicate across polls, matching the
|
||||||
|
//! polling-fallback model in the migration plan. Proper MSI-based delivery
|
||||||
|
//! is the follow-up once pcid grows an IRQ path for AER/hotplug.
|
||||||
|
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use log::{debug, info};
|
||||||
|
use pci_types::{ConfigRegionAccess, PciAddress};
|
||||||
|
|
||||||
|
use crate::cfg_access::Pcie;
|
||||||
|
|
||||||
|
const MAX_EVENTS: usize = 64;
|
||||||
|
const POLL_INTERVAL_MS: u64 = 500;
|
||||||
|
|
||||||
|
const AER_CAP_ID: u16 = 0x0001;
|
||||||
|
const AER_UNCORRECTABLE_STATUS: u16 = 0x04;
|
||||||
|
const AER_CORRECTABLE_STATUS: u16 = 0x10;
|
||||||
|
|
||||||
|
const PCIE_CAP_ID: u8 = 0x10;
|
||||||
|
const SLOT_CAPABILITIES: u16 = 0x0C;
|
||||||
|
const SLOT_CONTROL_STATUS: u16 = 0x18;
|
||||||
|
const SLOT_CAP_HOT_PLUG_CAPABLE: u32 = 1 << 6;
|
||||||
|
|
||||||
|
const SLTSTA_ATTENTION_BUTTON: u32 = 1 << 0;
|
||||||
|
const SLTSTA_POWER_FAULT: u32 = 1 << 1;
|
||||||
|
const SLTSTA_MRL_SENSOR: u32 = 1 << 2;
|
||||||
|
const SLTSTA_PRESENCE_DETECT: u32 = 1 << 3;
|
||||||
|
const SLTSTA_DLL_STATE: u32 = 1 << 5;
|
||||||
|
|
||||||
|
|
||||||
|
fn scheme_name(addr: &PciAddress) -> String {
|
||||||
|
format!("{}", addr).replace(':', "--")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventLog {
|
||||||
|
aer: Mutex<VecDeque<String>>,
|
||||||
|
pciehp: Mutex<VecDeque<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventLog {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
aer: Mutex::new(VecDeque::new()),
|
||||||
|
pciehp: Mutex::new(VecDeque::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(log: &Mutex<VecDeque<String>>, line: String) {
|
||||||
|
let mut queue = log.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
|
if queue.len() >= MAX_EVENTS {
|
||||||
|
queue.pop_front();
|
||||||
|
}
|
||||||
|
queue.push_back(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snapshot(log: &Mutex<VecDeque<String>>) -> String {
|
||||||
|
let queue = log.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
|
queue.iter().cloned().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_aer(&self, line: String) {
|
||||||
|
Self::push(&self.aer, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_pciehp(&self, line: String) {
|
||||||
|
Self::push(&self.pciehp, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn aer_snapshot(&self) -> String {
|
||||||
|
Self::snapshot(&self.aer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pciehp_snapshot(&self) -> String {
|
||||||
|
Self::snapshot(&self.pciehp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_event_poller(
|
||||||
|
pcie: Arc<Pcie>,
|
||||||
|
devices: Vec<PciAddress>,
|
||||||
|
log: Arc<EventLog>,
|
||||||
|
) -> thread::JoinHandle<()> {
|
||||||
|
thread::Builder::new()
|
||||||
|
.name("pcid-events".to_string())
|
||||||
|
.spawn(move || {
|
||||||
|
info!(
|
||||||
|
"pcid-events: AER/pciehp poller started ({} devices, {} ms poll)",
|
||||||
|
devices.len(),
|
||||||
|
POLL_INTERVAL_MS
|
||||||
|
);
|
||||||
|
loop {
|
||||||
|
poll_aer(&pcie, &devices, &log);
|
||||||
|
poll_pciehp(&pcie, &devices, &log);
|
||||||
|
thread::sleep(Duration::from_millis(POLL_INTERVAL_MS));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.expect("spawn pcid event poller")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_aer(pcie: &Pcie, devices: &[PciAddress], log: &EventLog) {
|
||||||
|
for addr in devices {
|
||||||
|
let Some(cap_off) = find_extended_capability(pcie, *addr, AER_CAP_ID) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let uncorrectable = unsafe { pcie.read(*addr, cap_off + AER_UNCORRECTABLE_STATUS) };
|
||||||
|
if uncorrectable != 0 && uncorrectable != u32::MAX {
|
||||||
|
debug!("AER: uncorrectable error on {addr}: 0x{uncorrectable:08x}");
|
||||||
|
log.push_aer(format!(
|
||||||
|
"severity=NonFatal device={} raw=uncorrectable_status=0x{uncorrectable:08x}\n", scheme_name(addr)
|
||||||
|
));
|
||||||
|
unsafe { pcie.write(*addr, cap_off + AER_UNCORRECTABLE_STATUS, uncorrectable) };
|
||||||
|
}
|
||||||
|
|
||||||
|
let correctable = unsafe { pcie.read(*addr, cap_off + AER_CORRECTABLE_STATUS) };
|
||||||
|
if correctable != 0 && correctable != u32::MAX {
|
||||||
|
debug!("AER: correctable error on {addr}: 0x{correctable:08x}");
|
||||||
|
log.push_aer(format!(
|
||||||
|
"severity=Correctable device={} raw=correctable_status=0x{correctable:08x}\n", scheme_name(addr)
|
||||||
|
));
|
||||||
|
unsafe { pcie.write(*addr, cap_off + AER_CORRECTABLE_STATUS, correctable) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_pciehp(pcie: &Pcie, devices: &[PciAddress], log: &EventLog) {
|
||||||
|
for addr in devices {
|
||||||
|
let Some(cap_off) = find_standard_capability(pcie, *addr, PCIE_CAP_ID) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let slot_capabilities = unsafe { pcie.read(*addr, cap_off + SLOT_CAPABILITIES) };
|
||||||
|
if slot_capabilities == u32::MAX || slot_capabilities & SLOT_CAP_HOT_PLUG_CAPABLE == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let status = unsafe { pcie.read(*addr, cap_off + SLOT_CONTROL_STATUS) } >> 16;
|
||||||
|
if status == 0 || status == 0xFFFF {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if status & SLTSTA_ATTENTION_BUTTON != 0 {
|
||||||
|
log.push_pciehp(format!("kind=attention_button device={}\n", scheme_name(addr)));
|
||||||
|
}
|
||||||
|
if status & SLTSTA_POWER_FAULT != 0 {
|
||||||
|
log.push_pciehp(format!("kind=power_fault device={}\n", scheme_name(addr)));
|
||||||
|
}
|
||||||
|
if status & SLTSTA_MRL_SENSOR != 0 {
|
||||||
|
log.push_pciehp(format!("kind=mrl_sensor device={}\n", scheme_name(addr)));
|
||||||
|
}
|
||||||
|
if status & SLTSTA_PRESENCE_DETECT != 0 {
|
||||||
|
log.push_pciehp(format!("kind=presence_detect device={}\n", scheme_name(addr)));
|
||||||
|
}
|
||||||
|
if status & SLTSTA_DLL_STATE != 0 {
|
||||||
|
log.push_pciehp(format!("kind=dll_state device={}\n", scheme_name(addr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write-1-to-clear the event bits in Slot Status (upper word of the
|
||||||
|
// Slot Control/Status dword), preserving the current Slot Control
|
||||||
|
// value in the lower word.
|
||||||
|
let control_status = unsafe { pcie.read(*addr, cap_off + SLOT_CONTROL_STATUS) };
|
||||||
|
let clear_value = (control_status & 0x0000_FFFF) | (status << 16);
|
||||||
|
unsafe { pcie.write(*addr, cap_off + SLOT_CONTROL_STATUS, clear_value) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_extended_capability(pcie: &Pcie, addr: PciAddress, cap_id: u16) -> Option<u16> {
|
||||||
|
let mut offset = 0x100u16;
|
||||||
|
for _ in 0..48 {
|
||||||
|
if offset == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let header = unsafe { pcie.read(addr, offset) };
|
||||||
|
if header == u32::MAX || header == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if (header & 0xFFFF) as u16 == cap_id {
|
||||||
|
return Some(offset);
|
||||||
|
}
|
||||||
|
offset = ((header >> 20) & 0xFFF) as u16;
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_standard_capability(pcie: &Pcie, addr: PciAddress, cap_id: u8) -> Option<u16> {
|
||||||
|
let command_status = unsafe { pcie.read(addr, 0x04) };
|
||||||
|
if (command_status >> 16) & 0x10 == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut ptr = (unsafe { pcie.read(addr, 0x34) } & 0xFC) as u16;
|
||||||
|
for _ in 0..48 {
|
||||||
|
if ptr == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let entry = unsafe { pcie.read(addr, ptr) };
|
||||||
|
if (entry & 0xFF) as u8 == cap_id {
|
||||||
|
return Some(ptr);
|
||||||
|
}
|
||||||
|
ptr = ((entry >> 8) & 0xFC) as u16;
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#![feature(non_exhaustive_omitted_patterns_lint)]
|
#![feature(non_exhaustive_omitted_patterns_lint)]
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use log::{debug, info, trace, warn};
|
use log::{debug, info, trace, warn};
|
||||||
use pci_types::capability::PciCapability;
|
use pci_types::capability::PciCapability;
|
||||||
@@ -18,6 +19,7 @@ use pcid_interface::{FullDeviceId, LegacyInterruptLine, PciBar, PciFunction, Pci
|
|||||||
|
|
||||||
mod cfg_access;
|
mod cfg_access;
|
||||||
mod driver_handler;
|
mod driver_handler;
|
||||||
|
mod events;
|
||||||
mod scheme;
|
mod scheme;
|
||||||
|
|
||||||
pub struct Func {
|
pub struct Func {
|
||||||
@@ -284,11 +286,11 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
|||||||
common::file_level(),
|
common::file_level(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let pcie = Pcie::new();
|
let pcie = Arc::new(Pcie::new());
|
||||||
|
|
||||||
info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV");
|
info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV");
|
||||||
|
|
||||||
let mut scheme = scheme::PciScheme::new(pcie);
|
let mut scheme = scheme::PciScheme::new(Arc::clone(&pcie));
|
||||||
let socket = redox_scheme::Socket::create().expect("failed to open pci scheme socket");
|
let socket = redox_scheme::Socket::create().expect("failed to open pci scheme socket");
|
||||||
let handler = Blocking::new(&socket, 16);
|
let handler = Blocking::new(&socket, 16);
|
||||||
|
|
||||||
@@ -342,6 +344,11 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
|||||||
}
|
}
|
||||||
debug!("Enumeration complete, now starting pci scheme");
|
debug!("Enumeration complete, now starting pci scheme");
|
||||||
|
|
||||||
|
let event_log = Arc::new(events::EventLog::new());
|
||||||
|
let devices: Vec<PciAddress> = scheme.tree.keys().copied().collect();
|
||||||
|
scheme.set_event_log(Arc::clone(&event_log));
|
||||||
|
let _events_thread = events::spawn_event_poller(Arc::clone(&pcie), devices, event_log);
|
||||||
|
|
||||||
register_sync_scheme(&socket, "pci", &mut scheme)
|
register_sync_scheme(&socket, "pci", &mut scheme)
|
||||||
.expect("failed to register pci scheme to namespace");
|
.expect("failed to register pci scheme to namespace");
|
||||||
|
|
||||||
|
|||||||
+58
-13
@@ -6,7 +6,7 @@ use redox_scheme::{CallerCtx, OpenResult};
|
|||||||
use scheme_utils::HandleMap;
|
use scheme_utils::HandleMap;
|
||||||
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
|
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
|
||||||
use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR};
|
use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR};
|
||||||
use syscall::flag::{MODE_CHR, MODE_DIR, O_DIRECTORY, O_STAT};
|
use syscall::flag::{MODE_CHR, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT};
|
||||||
use syscall::schemev2::NewFdFlags;
|
use syscall::schemev2::NewFdFlags;
|
||||||
use syscall::ENOLCK;
|
use syscall::ENOLCK;
|
||||||
|
|
||||||
@@ -14,8 +14,9 @@ use crate::cfg_access::Pcie;
|
|||||||
|
|
||||||
pub struct PciScheme {
|
pub struct PciScheme {
|
||||||
handles: HandleMap<HandleWrapper>,
|
handles: HandleMap<HandleWrapper>,
|
||||||
pub pcie: Pcie,
|
pub pcie: std::sync::Arc<Pcie>,
|
||||||
pub tree: BTreeMap<PciAddress, crate::Func>,
|
pub tree: BTreeMap<PciAddress, crate::Func>,
|
||||||
|
events: std::sync::Arc<crate::events::EventLog>,
|
||||||
}
|
}
|
||||||
enum Handle {
|
enum Handle {
|
||||||
TopLevel { entries: Vec<String> },
|
TopLevel { entries: Vec<String> },
|
||||||
@@ -23,6 +24,8 @@ enum Handle {
|
|||||||
Device,
|
Device,
|
||||||
Config { addr: PciAddress },
|
Config { addr: PciAddress },
|
||||||
Channel { addr: PciAddress, st: ChannelState },
|
Channel { addr: PciAddress, st: ChannelState },
|
||||||
|
Aer,
|
||||||
|
Pciehp,
|
||||||
SchemeRoot,
|
SchemeRoot,
|
||||||
}
|
}
|
||||||
struct HandleWrapper {
|
struct HandleWrapper {
|
||||||
@@ -33,7 +36,11 @@ impl Handle {
|
|||||||
fn is_file(&self) -> bool {
|
fn is_file(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
Self::Access | Self::Config { .. } | Self::Channel { .. }
|
Self::Access
|
||||||
|
| Self::Config { .. }
|
||||||
|
| Self::Channel { .. }
|
||||||
|
| Self::Aer
|
||||||
|
| Self::Pciehp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn is_dir(&self) -> bool {
|
fn is_dir(&self) -> bool {
|
||||||
@@ -95,16 +102,21 @@ impl SchemeSync for PciScheme {
|
|||||||
let path = path.trim_matches('/');
|
let path = path.trim_matches('/');
|
||||||
|
|
||||||
let handle = if path.is_empty() {
|
let handle = if path.is_empty() {
|
||||||
Handle::TopLevel {
|
let mut entries: Vec<String> = self
|
||||||
entries: self
|
.tree
|
||||||
.tree
|
.iter()
|
||||||
.iter()
|
// FIXME remove replacement of : once the old scheme format is no longer supported.
|
||||||
// FIXME remove replacement of : once the old scheme format is no longer supported.
|
.map(|(addr, _)| format!("{}", addr).replace(':', "--"))
|
||||||
.map(|(addr, _)| format!("{}", addr).replace(':', "--"))
|
.collect::<Vec<_>>();
|
||||||
.collect::<Vec<_>>(),
|
entries.push("aer".to_string());
|
||||||
}
|
entries.push("pciehp".to_string());
|
||||||
|
Handle::TopLevel { entries }
|
||||||
} else if path == "access" {
|
} else if path == "access" {
|
||||||
Handle::Access
|
Handle::Access
|
||||||
|
} else if path == "aer" {
|
||||||
|
Handle::Aer
|
||||||
|
} else if path == "pciehp" {
|
||||||
|
Handle::Pciehp
|
||||||
} else {
|
} else {
|
||||||
let idx = path.find('/').unwrap_or(path.len());
|
let idx = path.find('/').unwrap_or(path.len());
|
||||||
let (addr_str, after) = path.split_at(idx);
|
let (addr_str, after) = path.split_at(idx);
|
||||||
@@ -142,6 +154,8 @@ impl SchemeSync for PciScheme {
|
|||||||
Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755),
|
Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755),
|
||||||
Handle::Config { .. } => (config_size, MODE_CHR | 0o600),
|
Handle::Config { .. } => (config_size, MODE_CHR | 0o600),
|
||||||
Handle::Access | Handle::Channel { .. } => (0, MODE_CHR | 0o600),
|
Handle::Access | Handle::Channel { .. } => (0, MODE_CHR | 0o600),
|
||||||
|
Handle::Aer => (self.events.aer_snapshot().len(), MODE_FILE | 0o444),
|
||||||
|
Handle::Pciehp => (self.events.pciehp_snapshot().len(), MODE_FILE | 0o444),
|
||||||
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||||
};
|
};
|
||||||
stat.st_size = len as u64;
|
stat.st_size = len as u64;
|
||||||
@@ -186,6 +200,28 @@ impl SchemeSync for PciScheme {
|
|||||||
addr: _,
|
addr: _,
|
||||||
ref mut st,
|
ref mut st,
|
||||||
} => Self::read_channel(st, buf),
|
} => Self::read_channel(st, buf),
|
||||||
|
Handle::Aer => {
|
||||||
|
let data = self.events.aer_snapshot();
|
||||||
|
let bytes = data.as_bytes();
|
||||||
|
let offset = usize::try_from(_offset).map_err(|_| Error::new(EINVAL))?;
|
||||||
|
if offset >= bytes.len() {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
let count = (bytes.len() - offset).min(buf.len());
|
||||||
|
buf[..count].copy_from_slice(&bytes[offset..offset + count]);
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
Handle::Pciehp => {
|
||||||
|
let data = self.events.pciehp_snapshot();
|
||||||
|
let bytes = data.as_bytes();
|
||||||
|
let offset = usize::try_from(_offset).map_err(|_| Error::new(EINVAL))?;
|
||||||
|
if offset >= bytes.len() {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
let count = (bytes.len() - offset).min(buf.len());
|
||||||
|
buf[..count].copy_from_slice(&bytes[offset..offset + count]);
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
||||||
_ => Err(Error::new(EBADF)),
|
_ => Err(Error::new(EBADF)),
|
||||||
}
|
}
|
||||||
@@ -219,7 +255,11 @@ impl SchemeSync for PciScheme {
|
|||||||
return Ok(buf);
|
return Ok(buf);
|
||||||
}
|
}
|
||||||
Handle::Device => DEVICE_CONTENTS,
|
Handle::Device => DEVICE_CONTENTS,
|
||||||
Handle::Access | Handle::Config { .. } | Handle::Channel { .. } => {
|
Handle::Access
|
||||||
|
| Handle::Config { .. }
|
||||||
|
| Handle::Channel { .. }
|
||||||
|
| Handle::Aer
|
||||||
|
| Handle::Pciehp => {
|
||||||
return Err(Error::new(ENOTDIR));
|
return Err(Error::new(ENOTDIR));
|
||||||
}
|
}
|
||||||
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||||
@@ -383,11 +423,16 @@ impl PciScheme {
|
|||||||
if self.pcie.has_ecam() { 4096 } else { 256 }
|
if self.pcie.has_ecam() { 4096 } else { 256 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(pcie: Pcie) -> Self {
|
pub fn set_event_log(&mut self, events: std::sync::Arc<crate::events::EventLog>) {
|
||||||
|
self.events = events;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(pcie: std::sync::Arc<Pcie>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
handles: HandleMap::new(),
|
handles: HandleMap::new(),
|
||||||
pcie,
|
pcie,
|
||||||
tree: BTreeMap::new(),
|
tree: BTreeMap::new(),
|
||||||
|
events: std::sync::Arc::new(crate::events::EventLog::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn parse_after_pci_addr(&mut self, addr: PciAddress, after: &str) -> Result<Handle> {
|
fn parse_after_pci_addr(&mut self, addr: PciAddress, after: &str) -> Result<Handle> {
|
||||||
|
|||||||
Reference in New Issue
Block a user