Merge branch 'pci_cleanup2' into 'master'
Couple more pci cleanups See merge request redox-os/drivers!134
This commit is contained in:
+3
-4
@@ -86,17 +86,16 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
|
||||
info!("IDE PCI CONFIG: {:?}", pci_config);
|
||||
|
||||
let pci_header = pcid_handle.fetch_header().expect("ided: failed to fetch PCI header");
|
||||
let busmaster_base = match pci_header.get_bar(4) {
|
||||
let busmaster_base = match pci_config.func.bars[4] {
|
||||
PciBar::Port(port) => port,
|
||||
other => panic!("TODO: IDE busmaster BAR {:#x?}", other),
|
||||
};
|
||||
let (primary, primary_irq) = if pci_header.interface() & 1 != 0 {
|
||||
let (primary, primary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 {
|
||||
panic!("TODO: IDE primary channel is PCI native");
|
||||
} else {
|
||||
(Channel::primary_compat(busmaster_base).unwrap(), 14)
|
||||
};
|
||||
let (secondary, secondary_irq) = if pci_header.interface() & 1 != 0 {
|
||||
let (secondary, secondary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 {
|
||||
panic!("TODO: IDE secondary channel is PCI native");
|
||||
} else {
|
||||
(Channel::secondary_compat(busmaster_base + 8).unwrap(), 15)
|
||||
|
||||
+2
-1
@@ -185,7 +185,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
let mut irq_file = get_int_method(&mut pcid_handle).expect("ihdad: no interrupt file");
|
||||
|
||||
{
|
||||
let vend_prod:u32 = ((pci_config.func.venid as u32) << 16) | (pci_config.func.devid as u32);
|
||||
let vend_prod: u32 = ((pci_config.func.full_device_id.vendor_id as u32) << 16)
|
||||
| (pci_config.func.full_device_id.device_id as u32);
|
||||
|
||||
let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") }));
|
||||
let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ihdad: failed to create hda scheme");
|
||||
|
||||
@@ -3,6 +3,8 @@ use std::ops::Range;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::pci::FullDeviceId;
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
pub struct Config {
|
||||
pub drivers: Vec<DriverConfig>,
|
||||
@@ -20,3 +22,67 @@ pub struct DriverConfig {
|
||||
pub device_id_range: Option<Range<u16>>,
|
||||
pub command: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl DriverConfig {
|
||||
pub fn match_function(&self, id: &FullDeviceId) -> bool {
|
||||
if let Some(class) = self.class {
|
||||
if class != id.class {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(subclass) = self.subclass {
|
||||
if subclass != id.subclass {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(interface) = self.interface {
|
||||
if interface != id.interface {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref ids) = self.ids {
|
||||
let mut device_found = false;
|
||||
for (vendor, devices) in ids {
|
||||
let vendor_without_prefix = vendor.trim_start_matches("0x");
|
||||
let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16;
|
||||
|
||||
if vendor != id.vendor_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
for device in devices {
|
||||
if *device == id.device_id {
|
||||
device_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !device_found {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if let Some(vendor) = self.vendor {
|
||||
if vendor != id.vendor_id {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(device) = self.device {
|
||||
if device != id.device_id {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref device_id_range) = self.device_id_range {
|
||||
if id.device_id < device_id_range.start || device_id_range.end <= id.device_id {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use thiserror::Error;
|
||||
|
||||
pub use crate::pci::cap::Capability;
|
||||
pub use crate::pci::msi;
|
||||
pub use crate::pci::{PciAddress, PciBar, PciHeader};
|
||||
pub use crate::pci::{FullDeviceId, PciAddress, PciBar};
|
||||
|
||||
pub mod irq_helpers;
|
||||
|
||||
@@ -45,10 +45,8 @@ pub struct PciFunction {
|
||||
/// Legacy interrupt pin (INTx#), none if INTx# interrupts aren't supported at all.
|
||||
pub legacy_interrupt_pin: Option<LegacyInterruptPin>,
|
||||
|
||||
/// Vendor ID
|
||||
pub venid: u16,
|
||||
/// Device ID
|
||||
pub devid: u16,
|
||||
/// All identifying information of the PCI function.
|
||||
pub full_device_id: FullDeviceId,
|
||||
}
|
||||
impl PciFunction {
|
||||
pub fn name(&self) -> String {
|
||||
@@ -87,11 +85,11 @@ pub enum PciFeature {
|
||||
MsiX,
|
||||
}
|
||||
impl PciFeature {
|
||||
pub fn is_msi(&self) -> bool {
|
||||
if let &Self::Msi = self { true } else { false }
|
||||
pub fn is_msi(self) -> bool {
|
||||
if let Self::Msi = self { true } else { false }
|
||||
}
|
||||
pub fn is_msix(&self) -> bool {
|
||||
if let &Self::MsiX = self { true } else { false }
|
||||
pub fn is_msix(self) -> bool {
|
||||
if let Self::MsiX = self { true } else { false }
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@@ -165,7 +163,6 @@ pub enum SetFeatureInfo {
|
||||
#[non_exhaustive]
|
||||
pub enum PcidClientRequest {
|
||||
RequestConfig,
|
||||
RequestHeader,
|
||||
RequestFeatures,
|
||||
RequestCapabilities,
|
||||
EnableFeature(PciFeature),
|
||||
@@ -188,7 +185,6 @@ pub enum PcidServerResponseError {
|
||||
pub enum PcidClientResponse {
|
||||
Capabilities(Vec<Capability>),
|
||||
Config(SubdriverArguments),
|
||||
Header(PciHeader),
|
||||
AllFeatures(Vec<(PciFeature, FeatureStatus)>),
|
||||
FeatureEnabled(PciFeature),
|
||||
FeatureStatus(PciFeature, FeatureStatus),
|
||||
@@ -266,13 +262,6 @@ impl PcidServerHandle {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch_header(&mut self) -> Result<PciHeader> {
|
||||
self.send(&PcidClientRequest::RequestHeader)?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::Header(a) => Ok(a),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn fetch_all_features(&mut self) -> Result<Vec<(PciFeature, FeatureStatus)>> {
|
||||
self.send(&PcidClientRequest::RequestFeatures)?;
|
||||
match self.recv()? {
|
||||
|
||||
+161
-204
@@ -2,8 +2,8 @@ use std::fs::{File, metadata, read_dir};
|
||||
use std::io::prelude::*;
|
||||
use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use std::process::Command;
|
||||
use std::thread;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{i64, thread};
|
||||
|
||||
use structopt::StructOpt;
|
||||
use log::{debug, error, info, warn, trace};
|
||||
@@ -33,9 +33,7 @@ struct Args {
|
||||
}
|
||||
|
||||
pub struct DriverHandler {
|
||||
config: config::DriverConfig,
|
||||
addr: PciAddress,
|
||||
header: PciHeader,
|
||||
capabilities: Vec<(u8, PciCapability)>,
|
||||
|
||||
state: Arc<State>,
|
||||
@@ -59,9 +57,6 @@ impl DriverHandler {
|
||||
PcidClientRequest::RequestConfig => {
|
||||
PcidClientResponse::Config(args.clone())
|
||||
}
|
||||
PcidClientRequest::RequestHeader => {
|
||||
PcidClientResponse::Header(self.header.clone())
|
||||
}
|
||||
PcidClientRequest::RequestFeatures => {
|
||||
PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability {
|
||||
PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))),
|
||||
@@ -195,9 +190,9 @@ impl DriverHandler {
|
||||
let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_write as RawFd) };
|
||||
let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_read as RawFd) };
|
||||
|
||||
while let Ok(msg) = recv(&mut pcid_from_client) {
|
||||
let response = self.respond(msg, &args);
|
||||
send(&mut pcid_to_client, &response).unwrap();
|
||||
while let Ok(msg) = recv(&mut pcid_from_client) {
|
||||
let response = self.respond(msg, &args);
|
||||
send(&mut pcid_to_client, &response).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,204 +260,164 @@ fn handle_parsed_header(state: Arc<State>, config: &Config, addr: PciAddress, he
|
||||
info!("{}", string);
|
||||
|
||||
for driver in config.drivers.iter() {
|
||||
if let Some(class) = driver.class {
|
||||
if class != raw_class { continue; }
|
||||
if !driver.match_function(header.full_device_id()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(subclass) = driver.subclass {
|
||||
if subclass != header.subclass() { continue; }
|
||||
let Some(ref args) = driver.command else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Enable bus mastering, memory space, and I/O space
|
||||
unsafe {
|
||||
let mut data = pci.read(addr, 0x04);
|
||||
data |= 7;
|
||||
pci.write(addr, 0x04, data);
|
||||
}
|
||||
|
||||
if let Some(interface) = driver.interface {
|
||||
if interface != header.interface() { continue; }
|
||||
}
|
||||
// Set IRQ line to 9 if not set
|
||||
let mut irq;
|
||||
let interrupt_pin;
|
||||
|
||||
if let Some(ref ids) = driver.ids {
|
||||
let mut device_found = false;
|
||||
for (vendor, devices) in ids {
|
||||
let vendor_without_prefix = vendor.trim_start_matches("0x");
|
||||
let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16;
|
||||
|
||||
if vendor != header.vendor_id() { continue; }
|
||||
|
||||
for device in devices {
|
||||
if *device == header.device_id() {
|
||||
device_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
let mut data = pci.read(addr, 0x3C);
|
||||
irq = (data & 0xFF) as u8;
|
||||
interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8;
|
||||
if irq == 0xFF {
|
||||
irq = 9;
|
||||
}
|
||||
if !device_found { continue; }
|
||||
data = (data & 0xFFFFFF00) | irq as u32;
|
||||
pci.write(addr, 0x3C, data);
|
||||
};
|
||||
|
||||
// Find BAR sizes
|
||||
//TODO: support 64-bit BAR sizes?
|
||||
let mut bars = [PciBar::None; 6];
|
||||
let mut bar_sizes = [0; 6];
|
||||
unsafe {
|
||||
let count = match header.header_type() {
|
||||
PciHeaderType::GENERAL => 6,
|
||||
PciHeaderType::PCITOPCI => 2,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
for i in 0..count {
|
||||
bars[i] = header.get_bar(i);
|
||||
|
||||
let offset = 0x10 + (i as u8) * 4;
|
||||
|
||||
let original = pci.read(addr, offset.into());
|
||||
pci.write(addr, offset.into(), 0xFFFFFFFF);
|
||||
|
||||
let new = pci.read(addr, offset.into());
|
||||
pci.write(addr, offset.into(), original);
|
||||
|
||||
let masked = if new & 1 == 1 {
|
||||
new & 0xFFFFFFFC
|
||||
} else {
|
||||
new & 0xFFFFFFF0
|
||||
};
|
||||
|
||||
let size = (!masked).wrapping_add(1);
|
||||
bar_sizes[i] = if size <= 1 {
|
||||
0
|
||||
} else {
|
||||
size
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let capabilities = if header.status() & (1 << 4) != 0 {
|
||||
let func = PciFunc {
|
||||
pci: state.preferred_cfg_access(),
|
||||
addr
|
||||
};
|
||||
crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::<Vec<_>>()
|
||||
} else {
|
||||
if let Some(vendor) = driver.vendor {
|
||||
if vendor != header.vendor_id() { continue; }
|
||||
Vec::new()
|
||||
};
|
||||
debug!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities);
|
||||
|
||||
use driver_interface::LegacyInterruptPin;
|
||||
|
||||
let legacy_interrupt_pin = match interrupt_pin {
|
||||
0 => None,
|
||||
1 => Some(LegacyInterruptPin::IntA),
|
||||
2 => Some(LegacyInterruptPin::IntB),
|
||||
3 => Some(LegacyInterruptPin::IntC),
|
||||
4 => Some(LegacyInterruptPin::IntD),
|
||||
|
||||
other => {
|
||||
warn!("pcid: invalid interrupt pin: {}", other);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(device) = driver.device {
|
||||
if device != header.device_id() { continue; }
|
||||
}
|
||||
}
|
||||
let func = driver_interface::PciFunction {
|
||||
bars,
|
||||
bar_sizes,
|
||||
addr,
|
||||
legacy_interrupt_line: irq,
|
||||
legacy_interrupt_pin,
|
||||
full_device_id: header.full_device_id().clone(),
|
||||
};
|
||||
|
||||
if let Some(ref device_id_range) = driver.device_id_range {
|
||||
if header.device_id() < device_id_range.start ||
|
||||
device_id_range.end <= header.device_id() { continue; }
|
||||
}
|
||||
let subdriver_args = driver_interface::SubdriverArguments {
|
||||
func,
|
||||
};
|
||||
|
||||
if let Some(ref args) = driver.command {
|
||||
// Enable bus mastering, memory space, and I/O space
|
||||
unsafe {
|
||||
let mut data = pci.read(addr, 0x04);
|
||||
data |= 7;
|
||||
pci.write(addr, 0x04, data);
|
||||
}
|
||||
|
||||
// Set IRQ line to 9 if not set
|
||||
let mut irq;
|
||||
let interrupt_pin;
|
||||
|
||||
unsafe {
|
||||
let mut data = pci.read(addr, 0x3C);
|
||||
irq = (data & 0xFF) as u8;
|
||||
interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8;
|
||||
if irq == 0xFF {
|
||||
irq = 9;
|
||||
let mut args = args.iter();
|
||||
if let Some(program) = args.next() {
|
||||
let mut command = Command::new(program);
|
||||
for arg in args {
|
||||
if arg.starts_with("$") {
|
||||
panic!("support for $VARIABLE has been removed. use pcid_interface instead");
|
||||
}
|
||||
data = (data & 0xFFFFFF00) | irq as u32;
|
||||
pci.write(addr, 0x3C, data);
|
||||
command.arg(arg);
|
||||
}
|
||||
|
||||
info!("PCID SPAWN {:?}", command);
|
||||
|
||||
// TODO: libc wrapper?
|
||||
let [fds1, fds2] = unsafe {
|
||||
let mut fds1 = [0 as libc::c_int; 2];
|
||||
let mut fds2 = [0 as libc::c_int; 2];
|
||||
|
||||
assert_eq!(libc::pipe(fds1.as_mut_ptr()), 0, "pcid: failed to create pcid->client pipe");
|
||||
assert_eq!(libc::pipe(fds2.as_mut_ptr()), 0, "pcid: failed to create client->pcid pipe");
|
||||
|
||||
[
|
||||
fds1.map(|c| c as usize),
|
||||
fds2.map(|c| c as usize),
|
||||
]
|
||||
};
|
||||
|
||||
// Find BAR sizes
|
||||
//TODO: support 64-bit BAR sizes?
|
||||
let mut bars = [PciBar::None; 6];
|
||||
let mut bar_sizes = [0; 6];
|
||||
unsafe {
|
||||
let count = match header.header_type() {
|
||||
PciHeaderType::GENERAL => 6,
|
||||
PciHeaderType::PCITOPCI => 2,
|
||||
_ => 0,
|
||||
};
|
||||
let [pcid_to_client_read, pcid_to_client_write] = fds1;
|
||||
let [pcid_from_client_read, pcid_from_client_write] = fds2;
|
||||
|
||||
for i in 0..count {
|
||||
bars[i] = header.get_bar(i);
|
||||
let envs = vec![
|
||||
("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)),
|
||||
("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)),
|
||||
];
|
||||
|
||||
let offset = 0x10 + (i as u8) * 4;
|
||||
|
||||
let original = pci.read(addr, offset.into());
|
||||
pci.write(addr, offset.into(), 0xFFFFFFFF);
|
||||
|
||||
let new = pci.read(addr, offset.into());
|
||||
pci.write(addr, offset.into(), original);
|
||||
|
||||
let masked = if new & 1 == 1 {
|
||||
new & 0xFFFFFFFC
|
||||
} else {
|
||||
new & 0xFFFFFFF0
|
||||
match command.envs(envs).spawn() {
|
||||
Ok(mut child) => {
|
||||
let driver_handler = DriverHandler {
|
||||
addr,
|
||||
state: Arc::clone(&state),
|
||||
capabilities,
|
||||
};
|
||||
|
||||
let size = (!masked).wrapping_add(1);
|
||||
bar_sizes[i] = if size <= 1 {
|
||||
0
|
||||
} else {
|
||||
size
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let capabilities = if header.status() & (1 << 4) != 0 {
|
||||
let func = PciFunc {
|
||||
pci: state.preferred_cfg_access(),
|
||||
addr
|
||||
};
|
||||
crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::<Vec<_>>()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
debug!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities);
|
||||
|
||||
use driver_interface::LegacyInterruptPin;
|
||||
|
||||
let legacy_interrupt_pin = match interrupt_pin {
|
||||
0 => None,
|
||||
1 => Some(LegacyInterruptPin::IntA),
|
||||
2 => Some(LegacyInterruptPin::IntB),
|
||||
3 => Some(LegacyInterruptPin::IntC),
|
||||
4 => Some(LegacyInterruptPin::IntD),
|
||||
|
||||
other => {
|
||||
warn!("pcid: invalid interrupt pin: {}", other);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let func = driver_interface::PciFunction {
|
||||
bars,
|
||||
bar_sizes,
|
||||
addr,
|
||||
devid: header.device_id(),
|
||||
legacy_interrupt_line: irq,
|
||||
legacy_interrupt_pin,
|
||||
venid: header.vendor_id(),
|
||||
};
|
||||
|
||||
let subdriver_args = driver_interface::SubdriverArguments {
|
||||
func,
|
||||
};
|
||||
|
||||
let mut args = args.iter();
|
||||
if let Some(program) = args.next() {
|
||||
let mut command = Command::new(program);
|
||||
for arg in args {
|
||||
if arg.starts_with("$") {
|
||||
panic!("support for $VARIABLE has been removed. use pcid_interface instead");
|
||||
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),
|
||||
}
|
||||
command.arg(arg);
|
||||
}
|
||||
|
||||
info!("PCID SPAWN {:?}", command);
|
||||
|
||||
// TODO: libc wrapper?
|
||||
let [fds1, fds2] = unsafe {
|
||||
let mut fds1 = [0 as libc::c_int; 2];
|
||||
let mut fds2 = [0 as libc::c_int; 2];
|
||||
|
||||
assert_eq!(libc::pipe(fds1.as_mut_ptr()), 0, "pcid: failed to create pcid->client pipe");
|
||||
assert_eq!(libc::pipe(fds2.as_mut_ptr()), 0, "pcid: failed to create client->pcid pipe");
|
||||
|
||||
[
|
||||
fds1.map(|c| c as usize),
|
||||
fds2.map(|c| c as usize),
|
||||
]
|
||||
};
|
||||
|
||||
let [pcid_to_client_read, pcid_to_client_write] = fds1;
|
||||
let [pcid_from_client_read, pcid_from_client_write] = fds2;
|
||||
|
||||
let envs = vec![
|
||||
("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)),
|
||||
("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)),
|
||||
];
|
||||
|
||||
match command.envs(envs).spawn() {
|
||||
Ok(mut child) => {
|
||||
let driver_handler = DriverHandler {
|
||||
addr,
|
||||
config: driver.clone(),
|
||||
header,
|
||||
state: Arc::clone(&state),
|
||||
capabilities,
|
||||
};
|
||||
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),
|
||||
}
|
||||
}
|
||||
Err(err) => error!("pcid: failed to execute {:?}: {}", command, err)
|
||||
}
|
||||
Err(err) => error!("pcid: failed to execute {:?}: {}", command, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,22 +438,24 @@ fn setup_logging(verbosity: u8) -> Option<&'static RedoxLogger> {
|
||||
.build()
|
||||
);
|
||||
|
||||
match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.log") {
|
||||
Ok(b) => logger = logger.with_output(
|
||||
b.with_filter(log::LevelFilter::Trace)
|
||||
.flush_on_newline(true)
|
||||
.build()
|
||||
),
|
||||
Err(error) => eprintln!("pcid: failed to open pcid.log"),
|
||||
}
|
||||
match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.ansi.log") {
|
||||
Ok(b) => logger = logger.with_output(
|
||||
b.with_filter(log::LevelFilter::Trace)
|
||||
.with_ansi_escape_codes()
|
||||
.flush_on_newline(true)
|
||||
.build()
|
||||
),
|
||||
Err(error) => eprintln!("pcid: failed to open pcid.ansi.log"),
|
||||
#[cfg(target_os = "redox")] {
|
||||
match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.log") {
|
||||
Ok(b) => logger = logger.with_output(
|
||||
b.with_filter(log::LevelFilter::Trace)
|
||||
.flush_on_newline(true)
|
||||
.build()
|
||||
),
|
||||
Err(error) => eprintln!("pcid: failed to open pcid.log"),
|
||||
}
|
||||
match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.ansi.log") {
|
||||
Ok(b) => logger = logger.with_output(
|
||||
b.with_filter(log::LevelFilter::Trace)
|
||||
.with_ansi_escape_codes()
|
||||
.flush_on_newline(true)
|
||||
.build()
|
||||
),
|
||||
Err(error) => eprintln!("pcid: failed to open pcid.ansi.log"),
|
||||
}
|
||||
}
|
||||
|
||||
match logger.enable() {
|
||||
|
||||
+42
-142
@@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
use super::bar::PciBar;
|
||||
use super::class::PciClass;
|
||||
use super::func::ConfigReader;
|
||||
use super::id::FullDeviceId;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum PciHeaderError {
|
||||
@@ -31,18 +32,10 @@ bitflags! {
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SharedPciHeader {
|
||||
vendor_id: u16,
|
||||
device_id: u16,
|
||||
command: u16,
|
||||
status: u16,
|
||||
revision: u8,
|
||||
interface: u8,
|
||||
subclass: u8,
|
||||
class: PciClass,
|
||||
cache_line_size: u8,
|
||||
latency_timer: u8,
|
||||
header_type: PciHeaderType,
|
||||
bist: u8,
|
||||
full_device_id: FullDeviceId,
|
||||
command: u16,
|
||||
status: u16,
|
||||
header_type: PciHeaderType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@@ -50,36 +43,17 @@ pub enum PciHeader {
|
||||
General {
|
||||
shared: SharedPciHeader,
|
||||
bars: [PciBar; 6],
|
||||
cardbus_cis_ptr: u32,
|
||||
subsystem_vendor_id: u16,
|
||||
subsystem_id: u16,
|
||||
expansion_rom_bar: u32,
|
||||
cap_pointer: u8,
|
||||
interrupt_line: u8,
|
||||
interrupt_pin: u8,
|
||||
min_grant: u8,
|
||||
max_latency: u8,
|
||||
},
|
||||
PciToPci {
|
||||
shared: SharedPciHeader,
|
||||
bars: [PciBar; 2],
|
||||
primary_bus_num: u8,
|
||||
secondary_bus_num: u8,
|
||||
subordinate_bus_num: u8,
|
||||
secondary_latency_timer: u8,
|
||||
io_base: u8,
|
||||
io_limit: u8,
|
||||
secondary_status: u16,
|
||||
mem_base: u16,
|
||||
mem_limit: u16,
|
||||
prefetch_base: u16,
|
||||
prefetch_limit: u16,
|
||||
prefetch_base_upper: u32,
|
||||
prefetch_limit_upper: u32,
|
||||
io_base_upper: u16,
|
||||
io_limit_upper: u16,
|
||||
cap_pointer: u8,
|
||||
expansion_rom: u32,
|
||||
interrupt_line: u8,
|
||||
interrupt_pin: u8,
|
||||
bridge_control: u16,
|
||||
@@ -127,24 +101,20 @@ impl PciHeader {
|
||||
let revision = bytes[8];
|
||||
let interface = bytes[9];
|
||||
let subclass = bytes[10];
|
||||
let class = PciClass::from(bytes[11]);
|
||||
let cache_line_size = bytes[12];
|
||||
let latency_timer = bytes[13];
|
||||
let class = bytes[11];
|
||||
let header_type = PciHeaderType::from_bits_truncate(bytes[14]);
|
||||
let bist = bytes[15];
|
||||
let shared = SharedPciHeader {
|
||||
vendor_id,
|
||||
device_id,
|
||||
full_device_id: FullDeviceId {
|
||||
vendor_id,
|
||||
device_id,
|
||||
class,
|
||||
subclass,
|
||||
interface,
|
||||
revision,
|
||||
},
|
||||
command,
|
||||
status,
|
||||
revision,
|
||||
interface,
|
||||
subclass,
|
||||
class,
|
||||
cache_line_size,
|
||||
latency_timer,
|
||||
header_type,
|
||||
bist,
|
||||
};
|
||||
|
||||
match header_type & PciHeaderType::HEADER_TYPE {
|
||||
@@ -152,73 +122,35 @@ impl PciHeader {
|
||||
let bytes = unsafe { reader.read_range(16, 48) };
|
||||
let mut bars = [PciBar::None; 6];
|
||||
Self::get_bars(&bytes, &mut bars);
|
||||
let cardbus_cis_ptr = LittleEndian::read_u32(&bytes[24..28]);
|
||||
let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]);
|
||||
let subsystem_id = LittleEndian::read_u16(&bytes[30..32]);
|
||||
let expansion_rom_bar = LittleEndian::read_u32(&bytes[32..36]);
|
||||
let cap_pointer = bytes[36];
|
||||
let interrupt_line = bytes[44];
|
||||
let interrupt_pin = bytes[45];
|
||||
let min_grant = bytes[46];
|
||||
let max_latency = bytes[47];
|
||||
Ok(PciHeader::General {
|
||||
shared,
|
||||
bars,
|
||||
cardbus_cis_ptr,
|
||||
subsystem_vendor_id,
|
||||
subsystem_id,
|
||||
expansion_rom_bar,
|
||||
cap_pointer,
|
||||
interrupt_line,
|
||||
interrupt_pin,
|
||||
min_grant,
|
||||
max_latency,
|
||||
})
|
||||
}
|
||||
PciHeaderType::PCITOPCI => {
|
||||
let bytes = unsafe { reader.read_range(16, 48) };
|
||||
let mut bars = [PciBar::None; 2];
|
||||
Self::get_bars(&bytes, &mut bars);
|
||||
let primary_bus_num = bytes[8];
|
||||
let secondary_bus_num = bytes[9];
|
||||
let subordinate_bus_num = bytes[10];
|
||||
let secondary_latency_timer = bytes[11];
|
||||
let io_base = bytes[12];
|
||||
let io_limit = bytes[13];
|
||||
let secondary_status = LittleEndian::read_u16(&bytes[14..16]);
|
||||
let mem_base = LittleEndian::read_u16(&bytes[16..18]);
|
||||
let mem_limit = LittleEndian::read_u16(&bytes[18..20]);
|
||||
let prefetch_base = LittleEndian::read_u16(&bytes[20..22]);
|
||||
let prefetch_limit = LittleEndian::read_u16(&bytes[22..24]);
|
||||
let prefetch_base_upper = LittleEndian::read_u32(&bytes[24..28]);
|
||||
let prefetch_limit_upper = LittleEndian::read_u32(&bytes[28..32]);
|
||||
let io_base_upper = LittleEndian::read_u16(&bytes[32..34]);
|
||||
let io_limit_upper = LittleEndian::read_u16(&bytes[34..36]);
|
||||
let cap_pointer = bytes[36];
|
||||
let expansion_rom = LittleEndian::read_u32(&bytes[40..44]);
|
||||
let interrupt_line = bytes[44];
|
||||
let interrupt_pin = bytes[45];
|
||||
let bridge_control = LittleEndian::read_u16(&bytes[46..48]);
|
||||
Ok(PciHeader::PciToPci {
|
||||
shared,
|
||||
bars,
|
||||
primary_bus_num,
|
||||
secondary_bus_num,
|
||||
subordinate_bus_num,
|
||||
secondary_latency_timer,
|
||||
io_base,
|
||||
io_limit,
|
||||
secondary_status,
|
||||
mem_base,
|
||||
mem_limit,
|
||||
prefetch_base,
|
||||
prefetch_limit,
|
||||
prefetch_base_upper,
|
||||
prefetch_limit_upper,
|
||||
io_base_upper,
|
||||
io_limit_upper,
|
||||
cap_pointer,
|
||||
expansion_rom,
|
||||
interrupt_line,
|
||||
interrupt_pin,
|
||||
bridge_control,
|
||||
@@ -245,88 +177,56 @@ impl PciHeader {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the Vendor ID field.
|
||||
pub fn vendor_id(&self) -> u16 {
|
||||
/// Return all identifying information of the PCI function.
|
||||
pub fn full_device_id(&self) -> &FullDeviceId {
|
||||
match self {
|
||||
&PciHeader::General {
|
||||
shared: SharedPciHeader { vendor_id, .. },
|
||||
PciHeader::General {
|
||||
shared:
|
||||
SharedPciHeader {
|
||||
full_device_id: device_id,
|
||||
..
|
||||
},
|
||||
..
|
||||
}
|
||||
| &PciHeader::PciToPci {
|
||||
shared: SharedPciHeader { vendor_id, .. },
|
||||
..
|
||||
} => vendor_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the Device ID field.
|
||||
pub fn device_id(&self) -> u16 {
|
||||
match self {
|
||||
&PciHeader::General {
|
||||
shared: SharedPciHeader { device_id, .. },
|
||||
..
|
||||
}
|
||||
| &PciHeader::PciToPci {
|
||||
shared: SharedPciHeader { device_id, .. },
|
||||
| PciHeader::PciToPci {
|
||||
shared:
|
||||
SharedPciHeader {
|
||||
full_device_id: device_id,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => device_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the Vendor ID field.
|
||||
pub fn vendor_id(&self) -> u16 {
|
||||
self.full_device_id().vendor_id
|
||||
}
|
||||
|
||||
/// Return the Device ID field.
|
||||
pub fn device_id(&self) -> u16 {
|
||||
self.full_device_id().device_id
|
||||
}
|
||||
|
||||
/// Return the Revision field.
|
||||
pub fn revision(&self) -> u8 {
|
||||
match self {
|
||||
&PciHeader::General {
|
||||
shared: SharedPciHeader { revision, .. },
|
||||
..
|
||||
}
|
||||
| &PciHeader::PciToPci {
|
||||
shared: SharedPciHeader { revision, .. },
|
||||
..
|
||||
} => revision,
|
||||
}
|
||||
self.full_device_id().revision
|
||||
}
|
||||
|
||||
/// Return the Interface field.
|
||||
pub fn interface(&self) -> u8 {
|
||||
match self {
|
||||
&PciHeader::General {
|
||||
shared: SharedPciHeader { interface, .. },
|
||||
..
|
||||
}
|
||||
| &PciHeader::PciToPci {
|
||||
shared: SharedPciHeader { interface, .. },
|
||||
..
|
||||
} => interface,
|
||||
}
|
||||
self.full_device_id().interface
|
||||
}
|
||||
|
||||
/// Return the Subclass field.
|
||||
pub fn subclass(&self) -> u8 {
|
||||
match self {
|
||||
&PciHeader::General {
|
||||
shared: SharedPciHeader { subclass, .. },
|
||||
..
|
||||
}
|
||||
| &PciHeader::PciToPci {
|
||||
shared: SharedPciHeader { subclass, .. },
|
||||
..
|
||||
} => subclass,
|
||||
}
|
||||
self.full_device_id().subclass
|
||||
}
|
||||
|
||||
/// Return the Class field.
|
||||
pub fn class(&self) -> PciClass {
|
||||
match self {
|
||||
&PciHeader::General {
|
||||
shared: SharedPciHeader { class, .. },
|
||||
..
|
||||
}
|
||||
| &PciHeader::PciToPci {
|
||||
shared: SharedPciHeader { class, .. },
|
||||
..
|
||||
} => class,
|
||||
}
|
||||
PciClass::from(self.full_device_id().class)
|
||||
}
|
||||
|
||||
/// Return the Headers BARs.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// All identifying information of a PCI function.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct FullDeviceId {
|
||||
pub vendor_id: u16,
|
||||
pub device_id: u16,
|
||||
pub class: u8,
|
||||
pub subclass: u8,
|
||||
pub interface: u8,
|
||||
pub revision: u8,
|
||||
}
|
||||
@@ -7,12 +7,14 @@ pub use self::bar::PciBar;
|
||||
pub use self::class::PciClass;
|
||||
pub use self::func::PciFunc;
|
||||
pub use self::header::{PciHeader, PciHeaderError, PciHeaderType};
|
||||
pub use self::id::FullDeviceId;
|
||||
|
||||
mod bar;
|
||||
pub mod cap;
|
||||
mod class;
|
||||
pub mod func;
|
||||
pub mod header;
|
||||
mod id;
|
||||
pub mod msi;
|
||||
|
||||
pub trait CfgAccess {
|
||||
|
||||
@@ -116,7 +116,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
// 0x1001 - virtio-blk
|
||||
let pci_config = pcid_handle.fetch_config()?;
|
||||
|
||||
assert_eq!(pci_config.func.devid, 0x1001);
|
||||
assert_eq!(pci_config.func.full_device_id.device_id, 0x1001);
|
||||
log::info!("virtio-blk: initiating startup sequence :^)");
|
||||
|
||||
let device = virtio_core::probe_device(&mut pcid_handle)?;
|
||||
|
||||
@@ -96,10 +96,10 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result<File, Error> {
|
||||
}
|
||||
|
||||
pub fn probe_legacy_port_transport(
|
||||
pci_header: &PciHeader,
|
||||
pci_config: &SubdriverArguments,
|
||||
pcid_handle: &mut PcidServerHandle,
|
||||
) -> Result<Device, Error> {
|
||||
if let PciBar::Port(port) = pci_header.get_bar(0) {
|
||||
if let PciBar::Port(port) = pci_config.func.bars[0] {
|
||||
unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") };
|
||||
log::warn!("virtio: using legacy transport");
|
||||
|
||||
|
||||
@@ -61,10 +61,9 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result<File, Error> {
|
||||
/// This function panics if the device is not a virtio device.
|
||||
pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result<Device, Error> {
|
||||
let pci_config = pcid_handle.fetch_config()?;
|
||||
let pci_header = pcid_handle.fetch_header()?;
|
||||
|
||||
assert_eq!(
|
||||
pci_config.func.venid, 6900,
|
||||
pci_config.func.full_device_id.vendor_id, 6900,
|
||||
"virtio_core::probe_device: not a virtio device"
|
||||
);
|
||||
|
||||
@@ -91,7 +90,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result<Device, Error>
|
||||
_ => continue,
|
||||
}
|
||||
|
||||
let bar = pci_header.get_bar(capability.bar as usize);
|
||||
let bar = pci_config.func.bars[capability.bar as usize];
|
||||
let addr = match bar {
|
||||
PciBar::Memory32(addr) => addr as usize,
|
||||
PciBar::Memory64(addr) => addr as usize,
|
||||
@@ -189,7 +188,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result<Device, Error>
|
||||
|
||||
Ok(device)
|
||||
} else {
|
||||
crate::arch::probe_legacy_port_transport(&pci_header, pcid_handle)
|
||||
crate::arch::probe_legacy_port_transport(&pci_config, pcid_handle)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -416,7 +416,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
// 0x1050 - virtio-gpu
|
||||
let pci_config = pcid_handle.fetch_config()?;
|
||||
|
||||
assert_eq!(pci_config.func.devid, 0x1050);
|
||||
assert_eq!(pci_config.func.full_device_id.device_id, 0x1050);
|
||||
log::info!("virtio-gpu: initiating startup sequence :^)");
|
||||
|
||||
let device = DEVICE.try_call_once(|| virtio_core::probe_device(&mut pcid_handle))?;
|
||||
|
||||
@@ -38,7 +38,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> {
|
||||
// 0x1000 - virtio-net
|
||||
let pci_config = pcid_handle.fetch_config()?;
|
||||
|
||||
assert_eq!(pci_config.func.devid, 0x1000);
|
||||
assert_eq!(pci_config.func.full_device_id.device_id, 0x1000);
|
||||
log::info!("virtio-net: initiating startup sequence :^)");
|
||||
|
||||
let device = virtio_core::probe_device(&mut pcid_handle)?;
|
||||
|
||||
Reference in New Issue
Block a user