Merge branch 'pci_cleanup' into 'master'
Couple more pcid cleanups See merge request redox-os/drivers!132
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
use std::cell::Cell;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Mutex;
|
||||
|
||||
#[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<()>,
|
||||
}
|
||||
|
||||
impl Pci {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
lock: Mutex::new(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_iopl() {
|
||||
// The IO privilege level is per-thread, so we need to do the initialization on every thread.
|
||||
thread_local! {
|
||||
static IOPL_ONCE: Cell<bool> = Cell::new(false);
|
||||
}
|
||||
|
||||
IOPL_ONCE.with(|iopl_once| {
|
||||
if !iopl_once.replace(true) {
|
||||
// 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 {
|
||||
assert_eq!(
|
||||
address.segment(),
|
||||
0,
|
||||
"usage of multiple segments requires PCIe extended configuration"
|
||||
);
|
||||
|
||||
assert_eq!(offset & 0xFC, offset, "pci offset is not aligned");
|
||||
|
||||
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::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::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")
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -136,14 +141,24 @@ impl Pcie {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
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,11 @@ 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),
|
||||
assert_eq!(offset & 0xFC, offset, "pci offset is not aligned");
|
||||
|
||||
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
|
||||
+14
-25
@@ -9,16 +9,16 @@ use structopt::StructOpt;
|
||||
use log::{debug, error, info, warn, trace};
|
||||
use redox_log::{OutputBuilder, RedoxLogger};
|
||||
|
||||
use crate::cfg_access::Pcie;
|
||||
use crate::config::Config;
|
||||
use crate::pci::{CfgAccess, Pci, PciAddress, PciBar, PciBus, 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;
|
||||
|
||||
mod cfg_access;
|
||||
mod config;
|
||||
mod driver_interface;
|
||||
mod pci;
|
||||
mod pcie;
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[structopt(about)]
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,12 +470,11 @@ fn handle_parsed_header(state: Arc<State>, config: &Config, addr: PciAddress, he
|
||||
state: Arc::clone(&state),
|
||||
capabilities,
|
||||
};
|
||||
thread::spawn(move || {
|
||||
// RFLAGS are no longer kept in the relibc clone() implementation.
|
||||
unsafe { syscall::iopl(3).expect("pcid: failed to set IOPL"); }
|
||||
|
||||
let _handle = thread::spawn(move || {
|
||||
driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args);
|
||||
});
|
||||
// FIXME this currently deadlocks as pcid doesn't daemonize
|
||||
//state.threads.lock().unwrap().push(handle);
|
||||
match child.wait() {
|
||||
Ok(_status) => (),
|
||||
Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err),
|
||||
@@ -565,17 +563,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()),
|
||||
});
|
||||
|
||||
@@ -592,10 +581,10 @@ fn main(args: Args) {
|
||||
let bus_num = bus_nums[bus_i];
|
||||
bus_i += 1;
|
||||
|
||||
let bus = PciBus { num: bus_num };
|
||||
'dev: for dev in bus.devs() {
|
||||
for func in dev.funcs(pci) {
|
||||
let func_addr = func.addr;
|
||||
'dev: for dev_num in 0..32 {
|
||||
for func_num in 0..8 {
|
||||
let func_addr = PciAddress::new(0, bus_num, dev_num, func_num);
|
||||
let func = PciFunc { pci, addr: func_addr };
|
||||
match PciHeader::from_reader(func) {
|
||||
Ok(header) => {
|
||||
handle_parsed_header(Arc::clone(&state), &config, func_addr, header);
|
||||
@@ -605,7 +594,7 @@ fn main(args: Args) {
|
||||
}
|
||||
Err(PciHeaderError::NoDevice) => {
|
||||
if func_addr.function() == 0 {
|
||||
trace!("PCI {:>02X}/{:>02X}: no dev", bus.num, dev.num);
|
||||
trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num);
|
||||
continue 'dev;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
use super::PciDev;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PciBus {
|
||||
pub num: u8,
|
||||
}
|
||||
|
||||
impl<'pci> PciBus {
|
||||
pub fn devs(self) -> PciBusIter {
|
||||
PciBusIter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PciBusIter {
|
||||
bus: PciBus,
|
||||
num: u8,
|
||||
}
|
||||
|
||||
impl PciBusIter {
|
||||
pub fn new(bus: PciBus) -> Self {
|
||||
PciBusIter { bus, num: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for PciBusIter {
|
||||
type Item = PciDev;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.num {
|
||||
dev_num if dev_num < 32 => {
|
||||
let dev = PciDev {
|
||||
bus: self.bus,
|
||||
num: self.num,
|
||||
};
|
||||
self.num += 1;
|
||||
Some(dev)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,18 +153,6 @@ impl Capability {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn into_msi(self) -> Option<MsiCapability> {
|
||||
match self {
|
||||
Self::Msi(msi) => Some(msi),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn into_msix(self) -> Option<MsixCapability> {
|
||||
match self {
|
||||
Self::MsiX(msix) => Some(msix),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
unsafe fn parse_msi<R: ConfigReader>(reader: &R, offset: u8) -> Self {
|
||||
Self::Msi(MsiCapability::parse(reader, offset))
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
use super::{CfgAccess, PciAddress, PciBus, PciFunc};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PciDev {
|
||||
pub bus: PciBus,
|
||||
pub num: u8,
|
||||
}
|
||||
|
||||
impl<'pci> PciDev {
|
||||
pub fn funcs(self, pci: &'pci dyn CfgAccess) -> PciDevIter<'pci> {
|
||||
PciDevIter::new(self, pci)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PciDevIter<'pci> {
|
||||
pci: &'pci dyn CfgAccess,
|
||||
dev: PciDev,
|
||||
num: u8,
|
||||
}
|
||||
|
||||
impl<'pci> PciDevIter<'pci> {
|
||||
pub fn new(dev: PciDev, pci: &'pci dyn CfgAccess) -> Self {
|
||||
PciDevIter { pci, dev, num: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'pci> Iterator for PciDevIter<'pci> {
|
||||
type Item = PciFunc<'pci>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.num {
|
||||
func_num if func_num < 8 => {
|
||||
let func = PciFunc {
|
||||
pci: self.pci,
|
||||
addr: PciAddress::new(0, self.dev.bus.num, self.dev.num, func_num),
|
||||
};
|
||||
self.num += 1;
|
||||
Some(func)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
use super::{CfgAccess, PciAddress, PciDev};
|
||||
use super::{CfgAccess, PciAddress};
|
||||
|
||||
pub trait ConfigReader {
|
||||
unsafe fn read_range(&self, offset: u16, len: u16) -> Vec<u8> {
|
||||
|
||||
@@ -1,26 +1,16 @@
|
||||
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::bus::{PciBus, PciBusIter};
|
||||
pub use self::class::PciClass;
|
||||
pub use self::dev::{PciDev, PciDevIter};
|
||||
pub use self::func::PciFunc;
|
||||
pub use self::header::{PciHeader, PciHeaderError, PciHeaderType};
|
||||
|
||||
use log::info;
|
||||
|
||||
mod bar;
|
||||
mod bus;
|
||||
pub mod cap;
|
||||
mod class;
|
||||
mod dev;
|
||||
pub mod func;
|
||||
pub mod header;
|
||||
pub mod msi;
|
||||
@@ -90,114 +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(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buses<'pci>(&'pci self) -> PciIter<'pci> {
|
||||
PciIter::new(self)
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PciIter<'pci> {
|
||||
pci: &'pci dyn CfgAccess,
|
||||
num: Option<u8>,
|
||||
}
|
||||
|
||||
impl<'pci> PciIter<'pci> {
|
||||
pub fn new(pci: &'pci dyn CfgAccess) -> Self {
|
||||
PciIter { pci, num: Some(0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'pci> Iterator for PciIter<'pci> {
|
||||
type Item = PciBus;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.num {
|
||||
Some(bus_num) => {
|
||||
let bus = PciBus { num: bus_num };
|
||||
self.num = bus_num.checked_add(1);
|
||||
Some(bus)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user