|
|
|
@ -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());
|
|
|
|
|
}
|
|
|
|
|