Move the IO port based fallback for PCI out of the pci module

The pci module is included in the pcid_interface library, which never
needs it.
This commit is contained in:
bjorn3
2024-01-20 14:00:51 +01:00
parent 4f20b90fc3
commit 3cbfbf6442
4 changed files with 120 additions and 112 deletions
+4 -14
View File
@@ -10,7 +10,7 @@ use log::{debug, error, info, warn, trace};
use redox_log::{OutputBuilder, RedoxLogger};
use crate::config::Config;
use crate::pci::{CfgAccess, Pci, PciAddress, PciBar, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType};
use crate::pci::{CfgAccess, PciAddress, PciBar, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType};
use crate::pci::cap::Capability as PciCapability;
use crate::pci::func::{ConfigReader, ConfigWriter};
use crate::pcie::Pcie;
@@ -206,12 +206,11 @@ impl DriverHandler {
pub struct State {
threads: Mutex<Vec<thread::JoinHandle<()>>>,
pci: Arc<Pci>,
pcie: Option<Pcie>,
pcie: Pcie,
}
impl State {
fn preferred_cfg_access(&self) -> &dyn CfgAccess {
self.pcie.as_ref().map(|pcie| pcie as &dyn CfgAccess).unwrap_or(&*self.pci as &dyn CfgAccess)
&self.pcie
}
}
@@ -565,17 +564,8 @@ fn main(args: Args) {
let _logger_ref = setup_logging(args.verbose);
let pci = Arc::new(Pci::new());
let state = Arc::new(State {
pci: Arc::clone(&pci),
pcie: match Pcie::new(Arc::clone(&pci)) {
Ok(pcie) => Some(pcie),
Err(error) => {
info!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error);
None
}
},
pcie: Pcie::new(),
threads: Mutex::new(Vec::new()),
});
-88
View File
@@ -1,19 +1,13 @@
use std::convert::TryFrom;
use std::fmt;
use std::sync::{Mutex, Once};
use bit_field::BitField;
use serde::{Deserialize, Serialize};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use syscall::io::{Io as _, Pio};
pub use self::bar::PciBar;
pub use self::class::PciClass;
pub use self::func::PciFunc;
pub use self::header::{PciHeader, PciHeaderError, PciHeaderType};
use log::info;
mod bar;
pub mod cap;
mod class;
@@ -86,85 +80,3 @@ impl fmt::Debug for PciAddress {
write!(f, "{}", self)
}
}
pub struct Pci {
lock: Mutex<()>,
iopl_once: Once,
}
impl Pci {
pub fn new() -> Self {
Self {
lock: Mutex::new(()),
iopl_once: Once::new(),
}
}
fn set_iopl() {
// make sure that pcid is not granted io port permission unless pcie memory-mapped
// configuration space is not available.
info!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports");
unsafe {
syscall::iopl(3).expect("pcid: failed to set iopl to 3");
}
}
fn address(address: PciAddress, offset: u8) -> u32 {
// TODO: Find the part of pcid that uses an unaligned offset!
//
// assert_eq!(offset & 0xFC, offset, "pci offset is not aligned");
//
let offset = offset & 0xFC;
assert_eq!(
address.segment(),
0,
"usage of multiple segments requires PCIe extended configuration"
);
0x80000000
| (u32::from(address.bus()) << 16)
| (u32::from(address.device()) << 11)
| (u32::from(address.function()) << 8)
| u32::from(offset)
}
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl CfgAccess for Pci {
unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 {
let _guard = self.lock.lock().unwrap();
self.iopl_once.call_once(Self::set_iopl);
let offset =
u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space");
let address = Self::address(address, offset);
Pio::<u32>::new(0xCF8).write(address);
Pio::<u32>::new(0xCFC).read()
}
unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) {
let _guard = self.lock.lock().unwrap();
self.iopl_once.call_once(Self::set_iopl);
let offset =
u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space");
let address = Self::address(address, offset);
Pio::<u32>::new(0xCF8).write(address);
Pio::<u32>::new(0xCFC).write(value);
}
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
impl CfgAccess for Pci {
unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 {
let _guard = self.lock.lock().unwrap();
todo!("Pci::CfgAccess::read on this architecture")
}
unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32) {
let _guard = self.lock.lock().unwrap();
todo!("Pci::CfgAccess::write on this architecture")
}
}
+91
View File
@@ -0,0 +1,91 @@
use std::convert::TryFrom;
use std::sync::{Mutex, Once};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use syscall::io::{Io as _, Pio};
use log::info;
use crate::pci::{CfgAccess, PciAddress};
pub(crate) struct Pci {
lock: Mutex<()>,
iopl_once: Once,
}
impl Pci {
pub(crate) fn new() -> Self {
Self {
lock: Mutex::new(()),
iopl_once: Once::new(),
}
}
fn set_iopl() {
// make sure that pcid is not granted io port permission unless pcie memory-mapped
// configuration space is not available.
info!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports");
unsafe {
syscall::iopl(3).expect("pcid: failed to set iopl to 3");
}
}
fn address(address: PciAddress, offset: u8) -> u32 {
// TODO: Find the part of pcid that uses an unaligned offset!
//
// assert_eq!(offset & 0xFC, offset, "pci offset is not aligned");
//
let offset = offset & 0xFC;
assert_eq!(
address.segment(),
0,
"usage of multiple segments requires PCIe extended configuration"
);
0x80000000
| (u32::from(address.bus()) << 16)
| (u32::from(address.device()) << 11)
| (u32::from(address.function()) << 8)
| u32::from(offset)
}
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl CfgAccess for Pci {
unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 {
let _guard = self.lock.lock().unwrap();
self.iopl_once.call_once(Self::set_iopl);
let offset =
u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space");
let address = Self::address(address, offset);
Pio::<u32>::new(0xCF8).write(address);
Pio::<u32>::new(0xCFC).read()
}
unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) {
let _guard = self.lock.lock().unwrap();
self.iopl_once.call_once(Self::set_iopl);
let offset =
u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space");
let address = Self::address(address, offset);
Pio::<u32>::new(0xCF8).write(address);
Pio::<u32>::new(0xCFC).write(value);
}
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
impl CfgAccess for Pci {
unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 {
let _guard = self.lock.lock().unwrap();
todo!("Pci::CfgAccess::read on this architecture")
}
unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32) {
let _guard = self.lock.lock().unwrap();
todo!("Pci::CfgAccess::write on this architecture")
}
}
+25 -10
View File
@@ -1,7 +1,12 @@
use std::sync::{Arc, Mutex};
use std::sync::Mutex;
use std::{fmt, fs, io, mem, ptr, slice};
use crate::pci::{CfgAccess, Pci, PciAddress};
use log::info;
use crate::pci::{CfgAccess, PciAddress};
use fallback::Pci;
mod fallback;
pub const MCFG_NAME: [u8; 4] = *b"MCFG";
@@ -120,14 +125,14 @@ impl fmt::Debug for Mcfg {
pub struct Pcie {
lock: Mutex<()>,
bus_maps: Vec<Option<(*mut u32, usize)>>,
fallback: Arc<Pci>,
fallback: Pci,
}
unsafe impl Send for Pcie {}
unsafe impl Sync for Pcie {}
impl Pcie {
pub fn new(fallback: Arc<Pci>) -> io::Result<Self> {
Mcfg::with(|mcfg| {
pub fn new() -> Self {
match Mcfg::with(|mcfg| {
let alloc_maps = (0..=255)
.map(|bus| {
if let Some(alloc) = mcfg.at_bus(bus) {
@@ -141,9 +146,19 @@ impl Pcie {
Ok(Self {
lock: Mutex::new(()),
bus_maps: alloc_maps,
fallback,
fallback: Pci::new(),
})
})
}) {
Ok(pcie) => pcie,
Err(error) => {
info!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error);
Self {
lock: Mutex::new(()),
bus_maps: vec![],
fallback: Pci::new(),
}
}
}
}
unsafe fn physmap_pcie_bus(alloc: &PcieAlloc, bus: u8) -> (*mut u32, usize) {
@@ -190,9 +205,9 @@ impl Pcie {
"multiple segments not yet implemented"
);
let bus_addr = match self.bus_maps[address.bus() as usize] {
Some(bus_addr) => bus_addr,
None => return f(None),
let bus_addr = match self.bus_maps.get(address.bus() as usize) {
Some(Some(bus_addr)) => bus_addr,
Some(None) | None => return f(None),
};
let virt_pointer = unsafe {
// FIXME use byte_add once stable