feat: generic pcie host dummy
This commit is contained in:
@@ -29,7 +29,8 @@ QEMU_OPTS+=-kernel $(O)/kernel.bin \
|
||||
-M virt,virtualization=off \
|
||||
-cpu cortex-a72 \
|
||||
-m 512 \
|
||||
-serial chardev:serial0
|
||||
-serial chardev:serial0 \
|
||||
-device virtio-serial-pci
|
||||
endif
|
||||
ifeq ($(MACH),rpi3b)
|
||||
QEMU_OPTS+=-kernel $(O)/kernel.bin \
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::arch::aarch64::{
|
||||
use crate::dev::timer::TimestampSource;
|
||||
use crate::dev::{
|
||||
irq::{IntController, IntSource},
|
||||
pci::{PciHostDevice, pcie::gpex::GenericPcieHost},
|
||||
rtc::pl031::Pl031,
|
||||
serial::{pl011::Pl011, SerialDevice},
|
||||
Device,
|
||||
@@ -19,6 +20,8 @@ const UART0_BASE: usize = 0x09000000;
|
||||
const RTC_BASE: usize = 0x09010000;
|
||||
const GICD_BASE: usize = 0x08000000;
|
||||
const GICC_BASE: usize = 0x08010000;
|
||||
// TODO extract this from device tree
|
||||
const ECAM_BASE: usize = 0x4010000000;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn init_board() -> Result<(), Errno> {
|
||||
@@ -30,6 +33,9 @@ pub fn init_board() -> Result<(), Errno> {
|
||||
|
||||
RTC.enable()?;
|
||||
RTC.init_irqs()?;
|
||||
|
||||
PCIE.enable()?;
|
||||
PCIE.map()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -55,4 +61,5 @@ pub fn intc() -> &'static impl IntController<IrqNumber = IrqNumber> {
|
||||
static UART0: Pl011 = unsafe { Pl011::new(UART0_BASE, IrqNumber::new(33)) };
|
||||
static RTC: Pl031 = unsafe { Pl031::new(RTC_BASE, IrqNumber::new(34)) };
|
||||
static GIC: Gic = unsafe { Gic::new(GICD_BASE, GICC_BASE) };
|
||||
static PCIE: GenericPcieHost = unsafe { GenericPcieHost::new(ECAM_BASE, 8) };
|
||||
static LOCAL_TIMER: GenericTimer = GenericTimer {};
|
||||
|
||||
@@ -5,6 +5,7 @@ use error::Errno;
|
||||
// Device classes
|
||||
pub mod gpio;
|
||||
pub mod irq;
|
||||
pub mod pci;
|
||||
pub mod rtc;
|
||||
pub mod serial;
|
||||
pub mod timer;
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::dev::Device;
|
||||
use core::fmt;
|
||||
use error::Errno;
|
||||
|
||||
pub mod pcie;
|
||||
|
||||
macro_rules! ecam_field {
|
||||
($getter:ident, $off:expr, u16) => {
|
||||
#[inline(always)]
|
||||
fn $getter(&self) -> u16 {
|
||||
self.readw($off)
|
||||
}
|
||||
};
|
||||
($getter:ident, $off:expr, u8) => {
|
||||
#[inline(always)]
|
||||
fn $getter(&self) -> u8 {
|
||||
self.readb($off)
|
||||
}
|
||||
};
|
||||
($getter:ident, $setter:ident, $off:expr, u16) => {
|
||||
#[inline(always)]
|
||||
unsafe fn $setter(&self, v: u16) {
|
||||
self.writew($off, v)
|
||||
}
|
||||
|
||||
ecam_field! { $getter, $off, u16 }
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct PciAddress {
|
||||
value: u32,
|
||||
}
|
||||
|
||||
pub trait PciCfgSpace {
|
||||
fn readl(&self, off: usize) -> u32;
|
||||
unsafe fn writel(&self, off: usize, val: u32);
|
||||
|
||||
#[inline(always)]
|
||||
fn readw(&self, off: usize) -> u16 {
|
||||
assert!(off & 0x1 == 0);
|
||||
(self.readl(off & !0x3) >> ((off & 0x3) * 8)) as u16
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn readb(&self, off: usize) -> u8 {
|
||||
(self.readl(off & !0x3) >> ((off & 0x3) * 8)) as u8
|
||||
}
|
||||
|
||||
ecam_field! { vendor_id, 0x00, u16 }
|
||||
ecam_field! { device_id, 0x02, u16 }
|
||||
ecam_field! { header_type, 0x0E, u8 }
|
||||
|
||||
#[inline(always)]
|
||||
fn is_valid(&self) -> bool {
|
||||
self.readl(0) != 0xFFFFFFFF
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PciHostDevice: Device {
|
||||
fn map(&self) -> Result<(), Errno>;
|
||||
}
|
||||
|
||||
impl PciAddress {
|
||||
#[inline(always)]
|
||||
pub const fn new(bus: u8, dev: u8, func: u8) -> Self {
|
||||
Self {
|
||||
value: ((bus as u32) << 8) | ((dev as u32) << 3) | (func as u32),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn bus(self) -> u8 {
|
||||
(self.value >> 8) as u8
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn dev(self) -> u8 {
|
||||
((self.value >> 3) as u8) & 0x1F
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn func(self) -> u8 {
|
||||
(self.value as u8) & 0x7
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn with_func(self, func: u8) -> Self {
|
||||
Self::new(self.bus(), self.dev(), func)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PciAddress {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{:02x}:{:02x}:{:02x}",
|
||||
self.bus(),
|
||||
self.dev(),
|
||||
self.func()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
use crate::dev::{
|
||||
pci::{pcie::EcamCfgSpace, PciCfgSpace, PciAddress, PciHostDevice},
|
||||
Device,
|
||||
};
|
||||
use error::Errno;
|
||||
|
||||
pub struct GenericPcieHost {
|
||||
ecam_base: usize,
|
||||
// TODO
|
||||
#[allow(dead_code)]
|
||||
bus_count: u8,
|
||||
}
|
||||
|
||||
impl Device for GenericPcieHost {
|
||||
fn name(&self) -> &'static str {
|
||||
"Generic PCIe Host Controller"
|
||||
}
|
||||
|
||||
unsafe fn enable(&self) -> Result<(), Errno> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl PciHostDevice for GenericPcieHost {
|
||||
fn map(&self) -> Result<(), Errno> {
|
||||
let bus0 = unsafe { EcamCfgSpace::new(self.ecam_base, PciAddress::new(0, 0, 0)) };
|
||||
|
||||
if bus0.header_type() & 0x80 == 0 {
|
||||
self.map_bus(0)?;
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericPcieHost {
|
||||
fn map_device(&self, addr: PciAddress) -> Result<(), Errno> {
|
||||
let fn0 = unsafe { EcamCfgSpace::new(self.ecam_base, addr) };
|
||||
if !fn0.is_valid() {
|
||||
return Ok(());
|
||||
}
|
||||
let ty = fn0.header_type();
|
||||
|
||||
//self.map_function(addr, fn0)?;
|
||||
|
||||
// Check if device is a multi-function one
|
||||
if ty & 0x80 != 0 {
|
||||
for func in 1..8 {
|
||||
let addr = addr.with_func(func);
|
||||
let f = unsafe { EcamCfgSpace::new(self.ecam_base, addr) };
|
||||
if f.is_valid() {
|
||||
//self.map_function(addr, f)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn map_bus(&self, bus: u8) -> Result<(), Errno> {
|
||||
for dev in 0u8..=255 {
|
||||
self.map_device(PciAddress::new(bus, dev, 0))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub const unsafe fn new(ecam_base: usize, bus_count: u8) -> Self {
|
||||
Self {
|
||||
ecam_base,
|
||||
bus_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
use crate::dev::pci::{PciAddress, PciCfgSpace};
|
||||
|
||||
pub mod gpex;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct EcamCfgSpace {
|
||||
base: usize,
|
||||
}
|
||||
|
||||
impl EcamCfgSpace {
|
||||
pub const unsafe fn new(ecam_base: usize, addr: PciAddress) -> Self {
|
||||
Self {
|
||||
base: ecam_base + (addr.value as usize) * 4096
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PciCfgSpace for EcamCfgSpace {
|
||||
#[inline(always)]
|
||||
fn readl(&self, off: usize) -> u32 {
|
||||
assert!(off & 0x3 == 0);
|
||||
unsafe {
|
||||
core::ptr::read_volatile((self.base + off) as *const u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn writel(&self, off: usize, val: u32) {
|
||||
assert!(off & 0x3 == 0);
|
||||
core::ptr::write_volatile((self.base + off) as *mut u32, val);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user