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