refactor PCI mod using pci crate

master
WangRunji 6 years ago
parent d9bdaf9875
commit 11c5609171

10
kernel/Cargo.lock generated

@ -247,6 +247,14 @@ name = "pc-keyboard"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pci"
version = "0.0.1"
source = "git+https://github.com/rcore-os/pci-rs#30f2e83aa51dd313957f3fd6c3b233d3c905a4d0"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pulldown-cmark"
version = "0.0.3"
@ -311,6 +319,7 @@ dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)",
"raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)",
"rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)",
@ -611,6 +620,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73"
"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a"
"checksum pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48392db76c4e9a69e0b3be356c5f97ebb7b14413c5e4fd0af4755dbf86e2fce"
"checksum pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)" = "<none>"
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"

@ -44,6 +44,7 @@ volatile = "0.2"
heapless = "0.4"
console-traits = "0.3"
buddy_system_allocator = "0.1"
pci = { git = "https://github.com/rcore-os/pci-rs" }
device_tree = { git = "https://github.com/rcore-os/device_tree-rs" }
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" }
lazy_static = { version = "1.3", features = ["spin_no_std"] }

@ -1,318 +1,142 @@
use crate::drivers::net::*;
use crate::drivers::block::*;
use crate::drivers::net::*;
use crate::drivers::{Driver, DRIVERS, NET_DRIVERS};
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::sync::Arc;
use core::cmp::Ordering;
use pci::*;
use spin::Mutex;
use x86_64::instructions::port::Port;
const PCI_VENDOR: u32 = 0x00;
const PCI_DEVICE: u32 = 0x02;
const PCI_COMMAND: u32 = 0x04;
const PCI_STATUS: u32 = 0x06;
const PCI_SUBCLASS: u32 = 0x0a;
const PCI_CLASS: u32 = 0x0b;
const PCI_HEADER: u32 = 0x0e;
const PCI_BAR0: u32 = 0x10; // first
const PCI_BAR5: u32 = 0x24; // last
const PCI_CAP_PTR: u32 = 0x34;
const PCI_INTERRUPT_LINE: u32 = 0x3c;
const PCI_INTERRUPT_PIN: u32 = 0x3d;
const PCI_MSI_CTRL_CAP: u32 = 0x00;
const PCI_MSI_ADDR: u32 = 0x04;
const PCI_MSI_UPPER_ADDR: u32 = 0x08;
const PCI_MSI_DATA: u32 = 0x0C;
const PCI_CAP_ID_MSI: u32 = 0x05;
const PCI_ADDR_PORT: u16 = 0xcf8;
const PCI_DATA_PORT: u16 = 0xcfc;
const PCI_BASE_ADDRESS_SPACE: u32 = 0x01;
const PCI_BASE_ADDRESS_SPACE_IO: u32 = 0x01;
const PCI_BASE_ADDRESS_SPACE_MEMORY: u32 = 0x00;
const PCI_BASE_ADDRESS_MEM_TYPE_MASK: u32 = 0x06;
const PCI_BASE_ADDRESS_MEM_TYPE_32: u32 = 0x00;
const PCI_BASE_ADDRESS_MEM_TYPE_1M: u32 = 0x02;
const PCI_BASE_ADDRESS_MEM_TYPE_64: u32 = 0x04;
const PCI_BASE_ADDRESS_MEM_PREFETCH: u32 = 0x08;
const PCI_BASE_ADDRESS_MEM_MASK: u32 = 0xfffffff0;
#[derive(Copy, Clone)]
pub struct PciTag(u32);
impl Ord for PciTag {
fn cmp(&self, other: &PciTag) -> Ordering {
self.0.cmp(&other.0)
}
}
impl PartialOrd for PciTag {
fn partial_cmp(&self, other: &PciTag) -> Option<Ordering> {
Some(self.cmp(other))
}
}
const PCI_COMMAND: u16 = 0x04;
const PCI_CAP_PTR: u16 = 0x34;
const PCI_INTERRUPT_LINE: u16 = 0x3c;
const PCI_INTERRUPT_PIN: u16 = 0x3d;
impl Eq for PciTag {}
const PCI_MSI_CTRL_CAP: u16 = 0x00;
const PCI_MSI_ADDR: u16 = 0x04;
const PCI_MSI_UPPER_ADDR: u16 = 0x08;
const PCI_MSI_DATA: u16 = 0x0C;
impl PartialEq for PciTag {
fn eq(&self, other: &PciTag) -> bool {
self.0 == other.0
}
}
impl PciTag {
pub fn new(bus: u32, dev: u32, func: u32) -> PciTag {
assert!(bus < 256);
assert!(dev < 32);
assert!(func < 8);
PciTag(bus << 16 | dev << 11 | func << 8)
}
const PCI_CAP_ID_MSI: u8 = 0x05;
pub fn bus(&self) -> u32 {
(self.0 >> 16) & 0xFF
}
struct PortOpsImpl;
pub fn dev(&self) -> u32 {
(self.0 >> 11) & 0x1F
impl PortOps for PortOpsImpl {
unsafe fn read8(&self, port: u16) -> u8 {
Port::new(port).read()
}
pub fn func(&self) -> u32 {
(self.0 >> 8) & 0x7
unsafe fn read16(&self, port: u16) -> u16 {
Port::new(port).read()
}
// biscuit/src/pci/pci.go Pci_read
pub unsafe fn read(&self, reg: u32, width: u32) -> u32 {
// spans in one reg
assert_eq!(reg / 4, (reg + width - 1) / 4);
let enable = 1 << 31;
let rsh = reg % 4;
let r = reg - rsh;
let t = enable | self.0 | r;
let mut pci_addr: Port<u32> = Port::new(PCI_ADDR_PORT);
let mut pci_data: Port<u32> = Port::new(PCI_DATA_PORT);
pci_addr.write(t);
let d = pci_data.read();
pci_addr.write(0);
let ret = d >> (rsh * 8);
let m = if width < 4 {
(1 << (8 * width)) - 1
} else {
0xffffffff
};
return ret & m;
unsafe fn read32(&self, port: u16) -> u32 {
Port::new(port).read()
}
pub unsafe fn write(&self, reg: u32, val: u32) {
assert_eq!(reg & 3, 0);
let enable = 1 << 31;
let t = enable | self.0 | reg;
let mut pci_addr: Port<u32> = Port::new(PCI_ADDR_PORT);
let mut pci_data: Port<u32> = Port::new(PCI_DATA_PORT);
pci_addr.write(t);
pci_data.write(val);
pci_addr.write(0);
unsafe fn write8(&self, port: u16, val: u8) {
Port::new(port).write(val);
}
// biscuit/src/pci/pci.go Pci_bar_mem
// linux/drivers/pci/probe.c pci_read_bases
// return (addr, len)
pub unsafe fn get_bar_mem(&self, bar_number: u32) -> Option<(usize, usize)> {
assert!(bar_number <= 6);
let bar = PCI_BAR0 + 4 * bar_number;
let mut base_lo = self.read(bar, 4);
self.write(bar, 0xffffffff);
let mut max_base_lo = self.read(bar, 4);
self.write(bar, base_lo);
let mut base;
let mut max_base;
let mut address_mark;
// memory instead of io
assert!(base_lo & PCI_BASE_ADDRESS_SPACE == PCI_BASE_ADDRESS_SPACE_MEMORY);
match base_lo & PCI_BASE_ADDRESS_MEM_TYPE_MASK {
PCI_BASE_ADDRESS_MEM_TYPE_32 => {
base = (base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize;
max_base = (max_base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize;
address_mark = PCI_BASE_ADDRESS_MEM_MASK as usize;
}
PCI_BASE_ADDRESS_MEM_TYPE_64 => {
base = (base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize;
max_base = (max_base_lo & PCI_BASE_ADDRESS_MEM_MASK) as usize;
let base_hi = self.read(bar + 4, 4);
self.write(bar + 4, 0xffffffff);
let max_base_hi = self.read(bar + 4, 4);
self.write(bar + 4, base_hi);
base |= (base_hi as usize) << 32;
max_base |= (max_base_hi as usize) << 32;
address_mark = !0;
}
_ => unimplemented!("pci bar mem type"),
}
if max_base == 0 {
return None;
}
// linux/drivers/pci/probe.c pci_size
let mut size = max_base & address_mark;
if size == 0 {
return None;
}
size = (size & !(size - 1)) - 1;
debug!(
"device memory address from {:#X} to {:#X}",
base,
base + size
);
return Some((base as usize, size as usize));
unsafe fn write16(&self, port: u16, val: u16) {
Port::new(port).write(val);
}
// returns a tuple of (vid, did, next)
pub fn probe(&self) -> Option<(u32, u32, bool)> {
unsafe {
// To lookup vendor and device, please see https://pci-ids.ucw.cz/read/PC/
let v = self.read(PCI_VENDOR, 2);
if v == 0xffff {
return None;
}
let d = self.read(PCI_DEVICE, 2);
let mf = self.read(PCI_HEADER, 1);
// To lookup class and subclass, please see https://pci-ids.ucw.cz/read/PD/
let cl = self.read(PCI_CLASS, 1);
let scl = self.read(PCI_SUBCLASS, 1);
let line = self.read(PCI_INTERRUPT_LINE, 1);
let pin = self.read(PCI_INTERRUPT_PIN, 1);
info!(
"{:02x}:{:02x}.{}: {:#x} {:#x} ({} {}) irq {}:{}",
self.bus(),
self.dev(),
self.func(),
v,
d,
cl,
scl,
line,
pin
);
return Some((v, d, mf & 0x80 != 0));
}
unsafe fn write32(&self, port: u16, val: u32) {
Port::new(port).write(val);
}
}
/// Enable the pci tag and its interrupt
/// Return assigned MSI interrupt number when applicable
pub unsafe fn enable(&self) -> Option<u32> {
// 23 and lower are used
static mut MSI_IRQ: u32 = 23;
let orig = self.read(PCI_COMMAND, 2);
// IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable
self.write(PCI_COMMAND, orig | 0x40f);
// find MSI cap
let mut msi_found = false;
let mut cap_ptr = self.read(PCI_CAP_PTR, 1);
let mut assigned_irq = None;
while cap_ptr > 0 {
let cap_id = self.read(cap_ptr, 1);
if cap_id == PCI_CAP_ID_MSI {
// The manual Volume 3 Chapter 10.11 Message Signalled Interrupts
// 0 is (usually) the apic id of the bsp.
self.write(cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12));
MSI_IRQ += 1;
let irq = MSI_IRQ;
assigned_irq = Some(irq);
// we offset all our irq numbers by 32
self.write(cap_ptr + PCI_MSI_DATA, irq + 32);
// enable MSI interrupt, assuming 64bit for now
let orig_ctrl = self.read(cap_ptr + PCI_MSI_CTRL_CAP, 4);
self.write(cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000);
debug!(
"MSI control {:#b}, enabling MSI interrupts",
orig_ctrl >> 16
);
msi_found = true;
break;
}
debug!(
"PCI device has cap id {} at {:#X}",
self.read(cap_ptr, 1),
cap_ptr
);
cap_ptr = self.read(cap_ptr + 1, 1);
}
if !msi_found {
// Use PCI legacy interrupt instead
// IO Space | MEM Space | Bus Mastering | Special Cycles
self.write(PCI_COMMAND, orig | 0xf);
let line = self.read(PCI_INTERRUPT_LINE, 1);
let pin = self.read(PCI_INTERRUPT_PIN, 1);
/// Enable the pci device and its interrupt
/// Return assigned MSI interrupt number when applicable
unsafe fn enable(loc: Location) -> Option<u32> {
let ops = &PortOpsImpl;
let am = CSpaceAccessMethod::IO;
// 23 and lower are used
static mut MSI_IRQ: u32 = 23;
let orig = am.read16(ops, loc, PCI_COMMAND);
// IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable
am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32);
// find MSI cap
let mut msi_found = false;
let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16;
let mut assigned_irq = None;
while cap_ptr > 0 {
let cap_id = am.read8(ops, loc, cap_ptr);
if cap_id == PCI_CAP_ID_MSI {
// The manual Volume 3 Chapter 10.11 Message Signalled Interrupts
// 0 is (usually) the apic id of the bsp.
am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12));
MSI_IRQ += 1;
let irq = MSI_IRQ;
assigned_irq = Some(irq);
// we offset all our irq numbers by 32
am.write32(ops, loc, cap_ptr + PCI_MSI_DATA, irq + 32);
// enable MSI interrupt, assuming 64bit for now
let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP);
am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000);
debug!(
"MSI not found, using PCI interrupt line {} pin {}",
line, pin
"MSI control {:#b}, enabling MSI interrupts",
orig_ctrl >> 16
);
msi_found = true;
break;
}
debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr);
cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16;
}
assigned_irq
if !msi_found {
// Use PCI legacy interrupt instead
// IO Space | MEM Space | Bus Mastering | Special Cycles
am.write32(ops, loc, PCI_COMMAND, (orig | 0xf) as u32);
debug!("MSI not found, using PCI interrupt");
}
assigned_irq
}
pub fn init_driver(name: String, vid: u32, did: u32, tag: PciTag) {
if vid == 0x8086 {
if did == 0x100e || did == 0x100f || did == 0x10d3 {
pub fn init_driver(dev: &PCIDevice) {
match (dev.id.vendor_id, dev.id.device_id) {
(0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => {
// 0x100e
// 82540EM Gigabit Ethernet Controller
// 0x100f
// 82545EM Gigabit Ethernet Controller (Copper)
// 0x10d3
// 82574L Gigabit Network Connection
if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } {
unsafe {
tag.enable();
}
e1000::e1000_init(addr, len);
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
let _ = unsafe { enable(dev.loc) };
e1000::e1000_init(addr as usize, len as usize);
}
} else if did == 0x10fb {
}
(0x8086, 0x10fb) => {
// 82599ES 10-Gigabit SFI/SFP+ Network Connection
if let Some((addr, len)) = unsafe { tag.get_bar_mem(0) } {
let irq = unsafe { tag.enable() };
PCI_DRIVERS
.lock()
.insert(tag, ixgbe::ixgbe_init(name, irq, addr, len));
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function);
let irq = unsafe { enable(dev.loc) };
PCI_DRIVERS.lock().insert(
dev.loc,
ixgbe::ixgbe_init(name, irq, addr as usize, len as usize),
);
}
} else if did == 0x2922 {
}
(0x8086, 0x2922) => {
// 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode]
if let Some((addr, len)) = unsafe { tag.get_bar_mem(5) } {
let irq = unsafe { tag.enable() };
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] {
let irq = unsafe { enable(dev.loc) };
PCI_DRIVERS
.lock()
.insert(tag, ahci::ahci_init(irq, addr, len));
.insert(dev.loc, ahci::ahci_init(irq, addr as usize, len as usize));
}
}
_ => {}
}
}
pub fn detach_driver(tag: &PciTag) -> bool {
match PCI_DRIVERS.lock().remove(tag) {
pub fn detach_driver(loc: &Location) -> bool {
match PCI_DRIVERS.lock().remove(loc) {
Some(driver) => {
DRIVERS
.write()
@ -327,51 +151,44 @@ pub fn detach_driver(tag: &PciTag) -> bool {
}
pub fn init() {
for bus in 0..256 {
for dev in 0..32 {
let tag = PciTag::new(bus, dev, 0);
if let Some((vid, did, next)) = tag.probe() {
let name = format!("enp{}s{}f0", bus, dev);
init_driver(name, vid, did, tag);
if next {
for func in 1..8 {
let tag = PciTag::new(bus, dev, func);
if let Some((vid, did, _)) = tag.probe() {
let name = format!("enp{}s{}f{}", bus, dev, func);
init_driver(name, vid, did, tag);
}
}
}
}
}
let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) };
for dev in pci_iter {
info!(
"pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) 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.pic_interrupt_line,
dev.interrupt_pin,
);
init_driver(&dev);
}
}
pub fn find_device(vendor: u32, product: u32) -> Option<PciTag> {
for bus in 0..256 {
for dev in 0..32 {
let tag = PciTag::new(bus, dev, 0);
if let Some((vid, did, next)) = tag.probe() {
if vid == vendor && did == product {
return Some(tag);
}
if next {
for func in 1..8 {
let tag = PciTag::new(bus, dev, func);
if let Some((vid, did, _)) = tag.probe() {
if vid == vendor && did == product {
return Some(tag);
}
}
}
}
}
pub fn find_device(vendor: u16, product: u16) -> Option<Location> {
let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) };
for dev in pci_iter {
if dev.id.vendor_id == vendor && dev.id.device_id == product {
return Some(dev.loc);
}
}
None
}
pub fn get_bar0_mem(loc: Location) -> Option<(usize, usize)> {
unsafe { probe_function(&PortOpsImpl, loc, CSpaceAccessMethod::IO) }
.and_then(|dev| dev.bars[0])
.map(|bar| match bar {
BAR::Memory(addr, len, _, _) => (addr as usize, len as usize),
_ => unimplemented!(),
})
}
lazy_static! {
pub static ref PCI_DRIVERS: Arc<Mutex<BTreeMap<PciTag, Arc<Driver>>>> =
Arc::new(Mutex::new(BTreeMap::new()));
pub static ref PCI_DRIVERS: Mutex<BTreeMap<Location, Arc<Driver>>> =
Mutex::new(BTreeMap::new());
}

@ -13,13 +13,13 @@ pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult {
vendor, product
);
let tag = pci::find_device(vendor as u32, product as u32).ok_or(SysError::ENOENT)?;
let tag = pci::find_device(vendor as u16, product as u16).ok_or(SysError::ENOENT)?;
if pci::detach_driver(&tag) {
info!("Kernel driver detached");
}
// Get BAR0 memory
let (base, len) = unsafe { tag.get_bar_mem(0) }.ok_or(SysError::ENOENT)?;
let (base, len) = pci::get_bar0_mem(tag).ok_or(SysError::ENOENT)?;
let mut proc = process();
let virt_addr = proc.vm.find_free_area(0, len);

Loading…
Cancel
Save