feat: generic pcie host dummy

This commit is contained in:
2021-10-08 12:24:31 +03:00
parent cf21dc9b9a
commit 455f6deec3
6 changed files with 225 additions and 1 deletions
+2 -1
View File
@@ -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
View File
@@ -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 {};
+1
View File
@@ -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;
+106
View File
@@ -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()
)
}
}
+76
View File
@@ -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,
}
}
}
+33
View File
@@ -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);
}
}