mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-27 11:23:25 +00:00
Replace Location with PciDeviceLocation
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
a47b98b160
commit
9bce8b879b
@ -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)]
|
||||
pub struct CapabilityEXPData {
|
||||
@ -9,7 +10,7 @@ pub struct 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 cap = am.read16(loc, cap_ptr + 0x2);
|
||||
Self {
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! This mod is used in frame to do device initialization
|
||||
use crate::util::*;
|
||||
use crate::util::CSpaceAccessMethod;
|
||||
use alloc::vec::Vec;
|
||||
use jinux_frame::bus::pci::PciDeviceLocation;
|
||||
|
||||
use self::{
|
||||
exp::CapabilityEXPData, msi::CapabilityMSIData, msix::CapabilityMSIXData, pm::CapabilityPMData,
|
||||
@ -70,7 +71,7 @@ pub struct Capability {
|
||||
|
||||
impl Capability {
|
||||
/// 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 am = CSpaceAccessMethod::IO;
|
||||
let mut cap_ptr = am.read8(loc, PCI_CAP_PTR) as u16;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::util::{CSpaceAccessMethod, Location};
|
||||
use crate::util::CSpaceAccessMethod;
|
||||
use bitflags::bitflags;
|
||||
use jinux_frame::bus::pci::PciDeviceLocation;
|
||||
bitflags! {
|
||||
pub struct CapabilityMSIMessageControl: u16 {
|
||||
const ADDR64_CAPABLE = 1 << 7;
|
||||
@ -25,7 +26,7 @@ pub struct 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 message_control =
|
||||
CapabilityMSIMessageControl::from_bits_truncate(am.read16(loc, cap_ptr + 0x02));
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::util::*;
|
||||
use crate::util::CSpaceAccessMethod;
|
||||
use jinux_frame::bus::pci::PciDeviceLocation;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
@ -9,7 +10,7 @@ pub struct 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;
|
||||
Self {
|
||||
message_control: am.read16(loc, cap_ptr + 2),
|
||||
|
@ -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)]
|
||||
pub struct CapabilityPMData {
|
||||
@ -12,7 +13,7 @@ pub struct 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 cap = am.read32(loc, cap_ptr + 0x4);
|
||||
Self {
|
||||
|
@ -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)]
|
||||
pub struct CapabilitySATAData {
|
||||
@ -9,7 +10,7 @@ pub struct 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 sata_cr0 = am.read32(loc, cap_ptr);
|
||||
let sata_cr1 = am.read32(loc, cap_ptr + 0x4);
|
||||
|
@ -2,7 +2,8 @@ pub mod virtio;
|
||||
|
||||
use virtio::CapabilityVirtioData;
|
||||
|
||||
use crate::util::{CSpaceAccessMethod, Location};
|
||||
use crate::util::CSpaceAccessMethod;
|
||||
use jinux_frame::bus::pci::PciDeviceLocation;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum CapabilityVNDRData {
|
||||
@ -11,7 +12,7 @@ pub enum 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 vid = am.read16(loc, 0);
|
||||
match vid {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::util::*;
|
||||
use crate::util::CSpaceAccessMethod;
|
||||
use jinux_frame::bus::pci::PciDeviceLocation;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct CapabilityVirtioData {
|
||||
@ -10,7 +11,7 @@ pub struct 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 cap_len = am.read8(loc, cap_ptr + 2);
|
||||
let option = if cap_len > 0x10 {
|
||||
|
@ -11,10 +11,11 @@ use component::init_component;
|
||||
use component::ComponentInitError;
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use jinux_frame::bus::pci::PciDeviceLocation;
|
||||
use spin::{mutex::Mutex, Once};
|
||||
use util::CSpaceAccessMethod;
|
||||
|
||||
pub use crate::util::PCIDevice;
|
||||
pub use crate::util::PciDevice;
|
||||
|
||||
pub const PCI_COMMAND: u16 = 0x04;
|
||||
pub const PCI_BAR: u16 = 0x10;
|
||||
@ -37,28 +38,31 @@ fn pci_component_init() -> Result<(), ComponentInitError> {
|
||||
Ok(())
|
||||
}
|
||||
pub struct PCIComponent {
|
||||
pci_device: Mutex<Vec<Arc<PCIDevice>>>,
|
||||
pci_device: Mutex<Vec<Arc<PciDevice>>>,
|
||||
}
|
||||
|
||||
impl PCIComponent {
|
||||
pub fn init() -> Result<Self, ComponentInitError> {
|
||||
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!(
|
||||
"pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) command: {:?} status: {:?} irq: {}:{:?}",
|
||||
dev.loc.bus,
|
||||
dev.loc.device,
|
||||
dev.loc.function,
|
||||
dev.id.vendor_id,
|
||||
dev.id.device_id,
|
||||
dev.id.class,
|
||||
dev.id.subclass,
|
||||
dev.command,
|
||||
dev.status,
|
||||
dev.pic_interrupt_line,
|
||||
dev.interrupt_pin
|
||||
device.loc.bus,
|
||||
device.loc.device,
|
||||
device.loc.function,
|
||||
device.id.vendor_id,
|
||||
device.id.device_id,
|
||||
device.id.class,
|
||||
device.id.subclass,
|
||||
device.command,
|
||||
device.status,
|
||||
device.pic_interrupt_line,
|
||||
device.interrupt_pin
|
||||
);
|
||||
devices.push(Arc::new(dev));
|
||||
devices.push(Arc::new(device));
|
||||
}
|
||||
Ok(Self {
|
||||
pci_device: Mutex::new(devices),
|
||||
@ -75,7 +79,7 @@ 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()
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,11 @@ use alloc::vec::Vec;
|
||||
use log::debug;
|
||||
use pod::Pod;
|
||||
|
||||
use crate::util::{CSpaceAccessMethod, Location, BAR};
|
||||
use crate::util::{CSpaceAccessMethod, BAR};
|
||||
|
||||
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;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@ -37,7 +37,7 @@ impl MSIX {
|
||||
pub fn new(
|
||||
cap: &CapabilityMSIXData,
|
||||
bars: [Option<BAR>; 6],
|
||||
loc: Location,
|
||||
loc: PciDeviceLocation,
|
||||
cap_ptr: u16,
|
||||
) -> Self {
|
||||
let table_info = cap.table_info;
|
||||
|
@ -2,6 +2,7 @@ extern crate jinux_frame;
|
||||
use crate::capability::Capability;
|
||||
use alloc::vec::Vec;
|
||||
use bitflags::bitflags;
|
||||
use jinux_frame::bus::pci::PciDeviceLocation;
|
||||
|
||||
pub enum PCIDeviceCommonCfgOffset {
|
||||
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.
|
||||
|
||||
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);
|
||||
((val >> ((offset as usize & 0b11) << 3)) & 0xFF) as u8
|
||||
}
|
||||
|
||||
/// 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);
|
||||
((val >> ((offset as usize & 0b10) << 3)) & 0xFFFF) as u16
|
||||
}
|
||||
|
||||
/// 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!(
|
||||
(offset & 0b11) == 0,
|
||||
"misaligned PCI configuration dword u32 read"
|
||||
@ -66,7 +67,7 @@ impl CSpaceAccessMethod {
|
||||
match self {
|
||||
CSpaceAccessMethod::IO => {
|
||||
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
|
||||
.read()
|
||||
.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 dest = offset as usize & 0b11 << 3;
|
||||
let mask = (0xFF << dest) as u32;
|
||||
@ -89,7 +90,7 @@ impl CSpaceAccessMethod {
|
||||
}
|
||||
|
||||
/// 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 dest = offset as usize & 0b10 << 3;
|
||||
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
|
||||
/// 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!(
|
||||
(offset & 0b11) == 0,
|
||||
"misaligned PCI configuration dword u32 read"
|
||||
@ -110,7 +111,7 @@ impl CSpaceAccessMethod {
|
||||
match self {
|
||||
CSpaceAccessMethod::IO => {
|
||||
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())
|
||||
} //MemoryMapped(ptr) => {
|
||||
// // 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)]
|
||||
pub struct Identifier {
|
||||
pub vendor_id: u16,
|
||||
@ -215,8 +198,8 @@ bitflags! {
|
||||
///
|
||||
/// Although accessing configuration space may be expensive, it is not cached.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PCIDevice {
|
||||
pub loc: Location,
|
||||
pub struct PciDevice {
|
||||
pub loc: PciDeviceLocation,
|
||||
pub id: Identifier,
|
||||
pub command: Command,
|
||||
pub status: Status,
|
||||
@ -232,7 +215,7 @@ pub struct PCIDevice {
|
||||
pub capabilities: Vec<Capability>,
|
||||
}
|
||||
|
||||
impl PCIDevice {
|
||||
impl PciDevice {
|
||||
/// set the status bits
|
||||
pub fn set_status_bits(&self, status: Status) {
|
||||
let am = CSpaceAccessMethod::IO;
|
||||
@ -328,7 +311,11 @@ pub enum 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));
|
||||
am.write32(loc, 16 + (idx << 2), !0);
|
||||
let len_encoded = am.read32(loc, 16 + (idx << 2));
|
||||
@ -370,66 +357,7 @@ impl BAR {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct BusScan {
|
||||
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> {
|
||||
pub(crate) fn find_device(loc: PciDeviceLocation, am: CSpaceAccessMethod) -> Option<PciDevice> {
|
||||
// FIXME: it'd be more efficient to use read32 and decode separately.
|
||||
let vid = am.read16(loc, 0);
|
||||
if vid == 0xFFFF {
|
||||
@ -551,7 +479,7 @@ fn probe_function(loc: Location, am: CSpaceAccessMethod) -> Option<PCIDevice> {
|
||||
i = next;
|
||||
}
|
||||
|
||||
Some(PCIDevice {
|
||||
Some(PciDevice {
|
||||
loc: loc,
|
||||
id: id,
|
||||
command: command,
|
||||
@ -568,14 +496,3 @@ fn probe_function(loc: Location, am: CSpaceAccessMethod) -> Option<PCIDevice> {
|
||||
capabilities: capabilities,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn scan_bus(am: CSpaceAccessMethod) -> BusScan {
|
||||
BusScan {
|
||||
loc: Location {
|
||||
bus: 0,
|
||||
device: 0,
|
||||
function: 0,
|
||||
},
|
||||
am: am,
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use bitflags::bitflags;
|
||||
use component::ComponentInitError;
|
||||
use device::VirtioDevice;
|
||||
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 log::{debug, info};
|
||||
use pod::Pod;
|
||||
@ -226,7 +226,7 @@ pub struct PCIVirtioDevice {
|
||||
|
||||
impl PCIVirtioDevice {
|
||||
/// 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);
|
||||
let device_type = match dev.id.device_id {
|
||||
0x1000 | 0x1041 => VirtioDeviceType::Network,
|
||||
|
Reference in New Issue
Block a user