Replace Location with PciDeviceLocation

This commit is contained in:
Yuke Peng
2023-07-05 06:39:27 -07:00
committed by Tate, Hongliang Tian
parent a47b98b160
commit 9bce8b879b
12 changed files with 68 additions and 139 deletions

View File

@ -1,4 +1,5 @@
use crate::util::{CSpaceAccessMethod, Location}; use crate::util::CSpaceAccessMethod;
use jinux_frame::bus::pci::PciDeviceLocation;
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct CapabilityEXPData { pub struct CapabilityEXPData {
@ -9,7 +10,7 @@ pub struct CapabilityEXPData {
} }
impl CapabilityEXPData { impl CapabilityEXPData {
pub(crate) fn new(loc: Location, cap_ptr: u16) -> Self { pub(crate) fn new(loc: PciDeviceLocation, cap_ptr: u16) -> Self {
let am = CSpaceAccessMethod::IO; let am = CSpaceAccessMethod::IO;
let cap = am.read16(loc, cap_ptr + 0x2); let cap = am.read16(loc, cap_ptr + 0x2);
Self { Self {

View File

@ -1,6 +1,7 @@
//! This mod is used in frame to do device initialization //! This mod is used in frame to do device initialization
use crate::util::*; use crate::util::CSpaceAccessMethod;
use alloc::vec::Vec; use alloc::vec::Vec;
use jinux_frame::bus::pci::PciDeviceLocation;
use self::{ use self::{
exp::CapabilityEXPData, msi::CapabilityMSIData, msix::CapabilityMSIXData, pm::CapabilityPMData, exp::CapabilityEXPData, msi::CapabilityMSIData, msix::CapabilityMSIXData, pm::CapabilityPMData,
@ -70,7 +71,7 @@ pub struct Capability {
impl Capability { impl Capability {
/// get the capabilities of one device /// get the capabilities of one device
pub fn device_capabilities(loc: Location) -> Vec<Self> { pub fn device_capabilities(loc: PciDeviceLocation) -> Vec<Self> {
let mut capabilities = Vec::new(); let mut capabilities = Vec::new();
let am = CSpaceAccessMethod::IO; let am = CSpaceAccessMethod::IO;
let mut cap_ptr = am.read8(loc, PCI_CAP_PTR) as u16; let mut cap_ptr = am.read8(loc, PCI_CAP_PTR) as u16;

View File

@ -1,5 +1,6 @@
use crate::util::{CSpaceAccessMethod, Location}; use crate::util::CSpaceAccessMethod;
use bitflags::bitflags; use bitflags::bitflags;
use jinux_frame::bus::pci::PciDeviceLocation;
bitflags! { bitflags! {
pub struct CapabilityMSIMessageControl: u16 { pub struct CapabilityMSIMessageControl: u16 {
const ADDR64_CAPABLE = 1 << 7; const ADDR64_CAPABLE = 1 << 7;
@ -25,7 +26,7 @@ pub struct CapabilityMSIData {
} }
impl CapabilityMSIData { impl CapabilityMSIData {
pub(crate) fn new(loc: Location, cap_ptr: u16) -> Self { pub(crate) fn new(loc: PciDeviceLocation, cap_ptr: u16) -> Self {
let am = CSpaceAccessMethod::IO; let am = CSpaceAccessMethod::IO;
let message_control = let message_control =
CapabilityMSIMessageControl::from_bits_truncate(am.read16(loc, cap_ptr + 0x02)); CapabilityMSIMessageControl::from_bits_truncate(am.read16(loc, cap_ptr + 0x02));

View File

@ -1,4 +1,5 @@
use crate::util::*; use crate::util::CSpaceAccessMethod;
use jinux_frame::bus::pci::PciDeviceLocation;
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(C)] #[repr(C)]
@ -9,7 +10,7 @@ pub struct CapabilityMSIXData {
} }
impl CapabilityMSIXData { impl CapabilityMSIXData {
pub fn new(loc: Location, cap_ptr: u16) -> Self { pub fn new(loc: PciDeviceLocation, cap_ptr: u16) -> Self {
let am = CSpaceAccessMethod::IO; let am = CSpaceAccessMethod::IO;
Self { Self {
message_control: am.read16(loc, cap_ptr + 2), message_control: am.read16(loc, cap_ptr + 2),

View File

@ -1,4 +1,5 @@
use crate::util::{CSpaceAccessMethod, Location}; use crate::util::CSpaceAccessMethod;
use jinux_frame::bus::pci::PciDeviceLocation;
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct CapabilityPMData { pub struct CapabilityPMData {
@ -12,7 +13,7 @@ pub struct CapabilityPMData {
} }
impl CapabilityPMData { impl CapabilityPMData {
pub(crate) fn new(loc: Location, cap_ptr: u16) -> Self { pub(crate) fn new(loc: PciDeviceLocation, cap_ptr: u16) -> Self {
let am = CSpaceAccessMethod::IO; let am = CSpaceAccessMethod::IO;
let cap = am.read32(loc, cap_ptr + 0x4); let cap = am.read32(loc, cap_ptr + 0x4);
Self { Self {

View File

@ -1,4 +1,5 @@
use crate::util::{CSpaceAccessMethod, Location}; use crate::util::CSpaceAccessMethod;
use jinux_frame::bus::pci::PciDeviceLocation;
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct CapabilitySATAData { pub struct CapabilitySATAData {
@ -9,7 +10,7 @@ pub struct CapabilitySATAData {
} }
impl CapabilitySATAData { impl CapabilitySATAData {
pub(crate) fn new(loc: Location, cap_ptr: u16) -> Self { pub(crate) fn new(loc: PciDeviceLocation, cap_ptr: u16) -> Self {
let am = CSpaceAccessMethod::IO; let am = CSpaceAccessMethod::IO;
let sata_cr0 = am.read32(loc, cap_ptr); let sata_cr0 = am.read32(loc, cap_ptr);
let sata_cr1 = am.read32(loc, cap_ptr + 0x4); let sata_cr1 = am.read32(loc, cap_ptr + 0x4);

View File

@ -2,7 +2,8 @@ pub mod virtio;
use virtio::CapabilityVirtioData; use virtio::CapabilityVirtioData;
use crate::util::{CSpaceAccessMethod, Location}; use crate::util::CSpaceAccessMethod;
use jinux_frame::bus::pci::PciDeviceLocation;
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CapabilityVNDRData { pub enum CapabilityVNDRData {
@ -11,7 +12,7 @@ pub enum CapabilityVNDRData {
} }
impl CapabilityVNDRData { impl CapabilityVNDRData {
pub(crate) fn new(loc: Location, cap_ptr: u16) -> Self { pub(crate) fn new(loc: PciDeviceLocation, cap_ptr: u16) -> Self {
let am = CSpaceAccessMethod::IO; let am = CSpaceAccessMethod::IO;
let vid = am.read16(loc, 0); let vid = am.read16(loc, 0);
match vid { match vid {

View File

@ -1,4 +1,5 @@
use crate::util::*; use crate::util::CSpaceAccessMethod;
use jinux_frame::bus::pci::PciDeviceLocation;
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct CapabilityVirtioData { pub struct CapabilityVirtioData {
@ -10,7 +11,7 @@ pub struct CapabilityVirtioData {
} }
impl CapabilityVirtioData { impl CapabilityVirtioData {
pub(crate) fn new(loc: Location, cap_ptr: u16) -> Self { pub(crate) fn new(loc: PciDeviceLocation, cap_ptr: u16) -> Self {
let am = CSpaceAccessMethod::IO; let am = CSpaceAccessMethod::IO;
let cap_len = am.read8(loc, cap_ptr + 2); let cap_len = am.read8(loc, cap_ptr + 2);
let option = if cap_len > 0x10 { let option = if cap_len > 0x10 {

View File

@ -11,10 +11,11 @@ use component::init_component;
use component::ComponentInitError; use component::ComponentInitError;
use alloc::{sync::Arc, vec::Vec}; use alloc::{sync::Arc, vec::Vec};
use jinux_frame::bus::pci::PciDeviceLocation;
use spin::{mutex::Mutex, Once}; use spin::{mutex::Mutex, Once};
use util::CSpaceAccessMethod; use util::CSpaceAccessMethod;
pub use crate::util::PCIDevice; pub use crate::util::PciDevice;
pub const PCI_COMMAND: u16 = 0x04; pub const PCI_COMMAND: u16 = 0x04;
pub const PCI_BAR: u16 = 0x10; pub const PCI_BAR: u16 = 0x10;
@ -37,28 +38,31 @@ fn pci_component_init() -> Result<(), ComponentInitError> {
Ok(()) Ok(())
} }
pub struct PCIComponent { pub struct PCIComponent {
pci_device: Mutex<Vec<Arc<PCIDevice>>>, pci_device: Mutex<Vec<Arc<PciDevice>>>,
} }
impl PCIComponent { impl PCIComponent {
pub fn init() -> Result<Self, ComponentInitError> { pub fn init() -> Result<Self, ComponentInitError> {
let mut devices = Vec::new(); let mut devices = Vec::new();
for dev in util::scan_bus(CSpaceAccessMethod::IO) { for location in PciDeviceLocation::all() {
let Some(device) = util::find_device(location,CSpaceAccessMethod::IO) else{
continue;
};
log::info!( log::info!(
"pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) command: {:?} status: {:?} irq: {}:{:?}", "pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) command: {:?} status: {:?} irq: {}:{:?}",
dev.loc.bus, device.loc.bus,
dev.loc.device, device.loc.device,
dev.loc.function, device.loc.function,
dev.id.vendor_id, device.id.vendor_id,
dev.id.device_id, device.id.device_id,
dev.id.class, device.id.class,
dev.id.subclass, device.id.subclass,
dev.command, device.command,
dev.status, device.status,
dev.pic_interrupt_line, device.pic_interrupt_line,
dev.interrupt_pin device.interrupt_pin
); );
devices.push(Arc::new(dev)); devices.push(Arc::new(device));
} }
Ok(Self { Ok(Self {
pci_device: Mutex::new(devices), pci_device: Mutex::new(devices),
@ -75,7 +79,7 @@ impl PCIComponent {
} }
impl PCIComponent { impl PCIComponent {
pub fn get_pci_devices(self: &Self, index: usize) -> Option<Arc<PCIDevice>> { pub fn get_pci_devices(self: &Self, index: usize) -> Option<Arc<PciDevice>> {
self.pci_device.lock().get(index).cloned() self.pci_device.lock().get(index).cloned()
} }

View File

@ -2,11 +2,11 @@ use alloc::vec::Vec;
use log::debug; use log::debug;
use pod::Pod; use pod::Pod;
use crate::util::{CSpaceAccessMethod, Location, BAR}; use crate::util::{CSpaceAccessMethod, BAR};
use super::capability::msix::CapabilityMSIXData; use super::capability::msix::CapabilityMSIXData;
use jinux_frame::{offset_of, trap::IrqAllocateHandle}; use jinux_frame::{bus::pci::PciDeviceLocation, offset_of, trap::IrqAllocateHandle};
use jinux_util::frame_ptr::InFramePtr; use jinux_util::frame_ptr::InFramePtr;
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -37,7 +37,7 @@ impl MSIX {
pub fn new( pub fn new(
cap: &CapabilityMSIXData, cap: &CapabilityMSIXData,
bars: [Option<BAR>; 6], bars: [Option<BAR>; 6],
loc: Location, loc: PciDeviceLocation,
cap_ptr: u16, cap_ptr: u16,
) -> Self { ) -> Self {
let table_info = cap.table_info; let table_info = cap.table_info;

View File

@ -2,6 +2,7 @@ extern crate jinux_frame;
use crate::capability::Capability; use crate::capability::Capability;
use alloc::vec::Vec; use alloc::vec::Vec;
use bitflags::bitflags; use bitflags::bitflags;
use jinux_frame::bus::pci::PciDeviceLocation;
pub enum PCIDeviceCommonCfgOffset { pub enum PCIDeviceCommonCfgOffset {
VendorId = 0x00, VendorId = 0x00,
@ -46,19 +47,19 @@ pub enum CSpaceAccessMethod {
// All IO-bus ops are 32-bit, we mask and shift to get the values we want. // All IO-bus ops are 32-bit, we mask and shift to get the values we want.
impl CSpaceAccessMethod { impl CSpaceAccessMethod {
pub fn read8(self, loc: Location, offset: u16) -> u8 { pub fn read8(self, loc: PciDeviceLocation, offset: u16) -> u8 {
let val = self.read32(loc, offset & 0b11111100); let val = self.read32(loc, offset & 0b11111100);
((val >> ((offset as usize & 0b11) << 3)) & 0xFF) as u8 ((val >> ((offset as usize & 0b11) << 3)) & 0xFF) as u8
} }
/// Returns a value in native endian. /// Returns a value in native endian.
pub fn read16(self, loc: Location, offset: u16) -> u16 { pub fn read16(self, loc: PciDeviceLocation, offset: u16) -> u16 {
let val = self.read32(loc, offset & 0b11111100); let val = self.read32(loc, offset & 0b11111100);
((val >> ((offset as usize & 0b10) << 3)) & 0xFFFF) as u16 ((val >> ((offset as usize & 0b10) << 3)) & 0xFFFF) as u16
} }
/// Returns a value in native endian. /// Returns a value in native endian.
pub fn read32(self, loc: Location, offset: u16) -> u32 { pub fn read32(self, loc: PciDeviceLocation, offset: u16) -> u32 {
debug_assert!( debug_assert!(
(offset & 0b11) == 0, (offset & 0b11) == 0,
"misaligned PCI configuration dword u32 read" "misaligned PCI configuration dword u32 read"
@ -66,7 +67,7 @@ impl CSpaceAccessMethod {
match self { match self {
CSpaceAccessMethod::IO => { CSpaceAccessMethod::IO => {
jinux_frame::arch::x86::device::pci::PCI_ADDRESS_PORT jinux_frame::arch::x86::device::pci::PCI_ADDRESS_PORT
.write(loc.encode() | ((offset as u32) & 0b11111100)); .write(loc.encode_as_x86_address_value() | ((offset as u32) & 0b11111100));
jinux_frame::arch::x86::device::pci::PCI_DATA_PORT jinux_frame::arch::x86::device::pci::PCI_DATA_PORT
.read() .read()
.to_le() .to_le()
@ -77,7 +78,7 @@ impl CSpaceAccessMethod {
} }
} }
pub fn write8(self, loc: Location, offset: u16, val: u8) { pub fn write8(self, loc: PciDeviceLocation, offset: u16, val: u8) {
let old = self.read32(loc, offset & (0xFFFC)); let old = self.read32(loc, offset & (0xFFFC));
let dest = offset as usize & 0b11 << 3; let dest = offset as usize & 0b11 << 3;
let mask = (0xFF << dest) as u32; let mask = (0xFF << dest) as u32;
@ -89,7 +90,7 @@ impl CSpaceAccessMethod {
} }
/// Converts val to little endian before writing. /// Converts val to little endian before writing.
pub fn write16(self, loc: Location, offset: u16, val: u16) { pub fn write16(self, loc: PciDeviceLocation, offset: u16, val: u16) {
let old = self.read32(loc, offset & (0xFFFC)); let old = self.read32(loc, offset & (0xFFFC));
let dest = offset as usize & 0b10 << 3; let dest = offset as usize & 0b10 << 3;
let mask = (0xFFFF << dest) as u32; let mask = (0xFFFF << dest) as u32;
@ -102,7 +103,7 @@ impl CSpaceAccessMethod {
/// Takes a value in native endian, converts it to little-endian, and writes it to the PCI /// Takes a value in native endian, converts it to little-endian, and writes it to the PCI
/// device configuration space at register `offset`. /// device configuration space at register `offset`.
pub fn write32(self, loc: Location, offset: u16, val: u32) { pub fn write32(self, loc: PciDeviceLocation, offset: u16, val: u32) {
debug_assert!( debug_assert!(
(offset & 0b11) == 0, (offset & 0b11) == 0,
"misaligned PCI configuration dword u32 read" "misaligned PCI configuration dword u32 read"
@ -110,7 +111,7 @@ impl CSpaceAccessMethod {
match self { match self {
CSpaceAccessMethod::IO => { CSpaceAccessMethod::IO => {
jinux_frame::arch::x86::device::pci::PCI_ADDRESS_PORT jinux_frame::arch::x86::device::pci::PCI_ADDRESS_PORT
.write(loc.encode() | (offset as u32 & 0b11111100)); .write(loc.encode_as_x86_address_value() | (offset as u32 & 0b11111100));
jinux_frame::arch::x86::device::pci::PCI_DATA_PORT.write(val.to_le()) jinux_frame::arch::x86::device::pci::PCI_DATA_PORT.write(val.to_le())
} //MemoryMapped(ptr) => { } //MemoryMapped(ptr) => {
// // FIXME: Clarify whether the rules for GEP/GEPi forbid using regular .offset() here. // // FIXME: Clarify whether the rules for GEP/GEPi forbid using regular .offset() here.
@ -120,24 +121,6 @@ impl CSpaceAccessMethod {
} }
} }
/// Physical location of a device on the bus
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Location {
pub bus: u8,
pub device: u8,
pub function: u8,
}
impl Location {
#[inline(always)]
fn encode(self) -> u32 {
(1 << 31)
| ((self.bus as u32) << 16)
| (((self.device as u32) & 0b11111) << 11)
| (((self.function as u32) & 0b111) << 8)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Identifier { pub struct Identifier {
pub vendor_id: u16, pub vendor_id: u16,
@ -215,8 +198,8 @@ bitflags! {
/// ///
/// Although accessing configuration space may be expensive, it is not cached. /// Although accessing configuration space may be expensive, it is not cached.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct PCIDevice { pub struct PciDevice {
pub loc: Location, pub loc: PciDeviceLocation,
pub id: Identifier, pub id: Identifier,
pub command: Command, pub command: Command,
pub status: Status, pub status: Status,
@ -232,7 +215,7 @@ pub struct PCIDevice {
pub capabilities: Vec<Capability>, pub capabilities: Vec<Capability>,
} }
impl PCIDevice { impl PciDevice {
/// set the status bits /// set the status bits
pub fn set_status_bits(&self, status: Status) { pub fn set_status_bits(&self, status: Status) {
let am = CSpaceAccessMethod::IO; let am = CSpaceAccessMethod::IO;
@ -328,7 +311,11 @@ pub enum BAR {
} }
impl BAR { impl BAR {
pub fn decode(loc: Location, am: CSpaceAccessMethod, idx: u16) -> (Option<BAR>, usize) { pub fn decode(
loc: PciDeviceLocation,
am: CSpaceAccessMethod,
idx: u16,
) -> (Option<BAR>, usize) {
let raw = am.read32(loc, 16 + (idx << 2)); let raw = am.read32(loc, 16 + (idx << 2));
am.write32(loc, 16 + (idx << 2), !0); am.write32(loc, 16 + (idx << 2), !0);
let len_encoded = am.read32(loc, 16 + (idx << 2)); let len_encoded = am.read32(loc, 16 + (idx << 2));
@ -370,66 +357,7 @@ impl BAR {
} }
} }
pub(crate) struct BusScan { pub(crate) fn find_device(loc: PciDeviceLocation, am: CSpaceAccessMethod) -> Option<PciDevice> {
loc: Location,
am: CSpaceAccessMethod,
}
impl BusScan {
fn done(&self) -> bool {
if self.loc.bus == 255 && self.loc.device == 31 && self.loc.function == 7 {
true
} else {
false
}
}
fn increment(&mut self) {
// TODO: Decide whether this is actually nicer than taking a u16 and incrementing until it
// wraps.
if self.loc.function < 7 {
self.loc.function += 1;
return;
} else {
self.loc.function = 0;
if self.loc.device < 31 {
self.loc.device += 1;
return;
} else {
self.loc.device = 0;
if self.loc.bus == 255 {
self.loc.device = 31;
self.loc.device = 7;
} else {
self.loc.bus += 1;
return;
}
}
}
}
}
impl ::core::iter::Iterator for BusScan {
type Item = PCIDevice;
#[inline]
fn next(&mut self) -> Option<PCIDevice> {
// FIXME: very naive atm, could be smarter and waste much less time by only scanning used
// busses.
let mut ret = None;
loop {
if self.done() {
return ret;
}
ret = probe_function(self.loc, self.am);
self.increment();
if ret.is_some() {
return ret;
}
}
}
}
fn probe_function(loc: Location, am: CSpaceAccessMethod) -> Option<PCIDevice> {
// FIXME: it'd be more efficient to use read32 and decode separately. // FIXME: it'd be more efficient to use read32 and decode separately.
let vid = am.read16(loc, 0); let vid = am.read16(loc, 0);
if vid == 0xFFFF { if vid == 0xFFFF {
@ -551,7 +479,7 @@ fn probe_function(loc: Location, am: CSpaceAccessMethod) -> Option<PCIDevice> {
i = next; i = next;
} }
Some(PCIDevice { Some(PciDevice {
loc: loc, loc: loc,
id: id, id: id,
command: command, command: command,
@ -568,14 +496,3 @@ fn probe_function(loc: Location, am: CSpaceAccessMethod) -> Option<PCIDevice> {
capabilities: capabilities, capabilities: capabilities,
}) })
} }
pub(crate) fn scan_bus(am: CSpaceAccessMethod) -> BusScan {
BusScan {
loc: Location {
bus: 0,
device: 0,
function: 0,
},
am: am,
}
}

View File

@ -13,7 +13,7 @@ use bitflags::bitflags;
use component::ComponentInitError; use component::ComponentInitError;
use device::VirtioDevice; use device::VirtioDevice;
use jinux_frame::{offset_of, trap::TrapFrame}; use jinux_frame::{offset_of, trap::TrapFrame};
use jinux_pci::util::{PCIDevice, BAR}; use jinux_pci::{util::BAR, PciDevice};
use jinux_util::frame_ptr::InFramePtr; use jinux_util::frame_ptr::InFramePtr;
use log::{debug, info}; use log::{debug, info};
use pod::Pod; use pod::Pod;
@ -226,7 +226,7 @@ pub struct PCIVirtioDevice {
impl PCIVirtioDevice { impl PCIVirtioDevice {
/// create a new PCI Virtio Device, note that this function will stop with device status features ok /// create a new PCI Virtio Device, note that this function will stop with device status features ok
pub fn new(dev: Arc<PCIDevice>) -> Self { pub fn new(dev: Arc<PciDevice>) -> Self {
assert_eq!(dev.id.vendor_id, 0x1af4); assert_eq!(dev.id.vendor_id, 0x1af4);
let device_type = match dev.id.device_id { let device_type = match dev.id.device_id {
0x1000 | 0x1041 => VirtioDeviceType::Network, 0x1000 | 0x1041 => VirtioDeviceType::Network,