diff --git a/experiments/src/main.rs b/experiments/src/main.rs index 3cb04e5..d9e13f3 100644 --- a/experiments/src/main.rs +++ b/experiments/src/main.rs @@ -30,6 +30,7 @@ use libcortex_a9::{ sync_channel::{Sender, Receiver}, sync_channel, regs::{MPIDR, SP}, + spin_lock_yield, notify_spin_lock, asm }; use libregister::{RegisterR, RegisterW}; @@ -64,7 +65,7 @@ pub unsafe extern "C" fn IRQ() { SP.write(&mut __stack1_start as *mut _ as u32); asm::enable_irq(); CORE1_RESTART.store(false, Ordering::Relaxed); - asm::sev(); + notify_spin_lock(); main_core1(); } } @@ -78,7 +79,7 @@ pub fn restart_core1() { CORE1_RESTART.store(true, Ordering::Relaxed); interrupt_controller.send_sgi(gic::InterruptId(0), gic::CPUCore::Core1.into()); while CORE1_RESTART.load(Ordering::Relaxed) { - asm::wfe(); + spin_lock_yield(); } } diff --git a/libcortex_a9/Cargo.toml b/libcortex_a9/Cargo.toml index 45f628c..90785e3 100644 --- a/libcortex_a9/Cargo.toml +++ b/libcortex_a9/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [features] target_zc706 = [] target_cora_z7_10 = [] +power_saving = [] default = ["target_zc706"] [dependencies] diff --git a/libcortex_a9/src/lib.rs b/libcortex_a9/src/lib.rs index 9df5900..1807b73 100644 --- a/libcortex_a9/src/lib.rs +++ b/libcortex_a9/src/lib.rs @@ -18,3 +18,19 @@ pub use uncached::UncachedSlice; pub use fpu::enable_fpu; global_asm!(include_str!("exceptions.s")); + +#[inline] +pub fn spin_lock_yield() { + #[cfg(feature = "power_saving")] + asm::wfe(); +} + +#[inline] +pub fn notify_spin_lock() { + #[cfg(feature = "power_saving")] + { + asm::dsb(); + asm::sev(); + } +} + diff --git a/libcortex_a9/src/mutex.rs b/libcortex_a9/src/mutex.rs index 4eb8628..1430ac3 100644 --- a/libcortex_a9/src/mutex.rs +++ b/libcortex_a9/src/mutex.rs @@ -1,20 +1,10 @@ use core::ops::{Deref, DerefMut}; use core::sync::atomic::{AtomicU32, Ordering}; use core::cell::UnsafeCell; -use super::asm::*; - -/// [Power-saving features](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html) -#[inline] -fn wait_for_update() { - wfe(); -} - -/// [Power-saving features](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html) -#[inline] -fn signal_update() { - dsb(); - sev(); -} +use super::{ + spin_lock_yield, notify_spin_lock, + asm::{dmb, enter_critical, exit_critical} +}; const LOCKED: u32 = 1; const UNLOCKED: u32 = 0; @@ -45,7 +35,7 @@ impl Mutex { while self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED { unsafe { exit_critical(irq); - wait_for_update(); + spin_lock_yield(); irq = enter_critical(); } } @@ -68,7 +58,7 @@ impl Mutex { dmb(); self.locked.store(UNLOCKED, Ordering::Release); - signal_update(); + notify_spin_lock(); } } diff --git a/libcortex_a9/src/semaphore.rs b/libcortex_a9/src/semaphore.rs index ee0799a..67e6ebb 100644 --- a/libcortex_a9/src/semaphore.rs +++ b/libcortex_a9/src/semaphore.rs @@ -1,10 +1,10 @@ -use super::asm::{sev, wfe}; +use super::{spin_lock_yield, notify_spin_lock}; use core::{ task::{Context, Poll}, pin::Pin, - future::Future + future::Future, + sync::atomic::{AtomicI32, Ordering} }; -use core::sync::atomic::{AtomicI32, Ordering}; pub struct Semaphore { value: AtomicI32, @@ -31,7 +31,7 @@ impl Semaphore { pub fn wait(&self) { while self.try_wait().is_none() { - wfe(); + spin_lock_yield(); } } @@ -59,7 +59,7 @@ impl Semaphore { let value = self.value.load(Ordering::Relaxed); if value < self.max { if self.value.compare_and_swap(value, value + 1, Ordering::SeqCst) == value { - sev(); + notify_spin_lock(); return; } } else { diff --git a/libcortex_a9/src/sync_channel.rs b/libcortex_a9/src/sync_channel.rs index effe4f1..d8ef51f 100644 --- a/libcortex_a9/src/sync_channel.rs +++ b/libcortex_a9/src/sync_channel.rs @@ -6,7 +6,7 @@ use core::{ task::{Context, Poll}, }; use alloc::boxed::Box; -use super::asm::*; +use super::{spin_lock_yield, notify_spin_lock}; pub struct Sender<'a, T> where T: Clone { list: &'a [AtomicPtr], @@ -35,9 +35,7 @@ impl<'a, T> Sender<'a, T> where T: Clone { let prev = entry.swap(ptr, Ordering::Relaxed); // we allow other end get it first self.write.store((write + 1) % self.list.len(), Ordering::Release); - // wake up other core, actually I wonder if the dsb is really needed... - dsb(); - sev(); + notify_spin_lock(); if !prev.is_null() { unsafe { drop_in_place(prev); @@ -51,7 +49,7 @@ impl<'a, T> Sender<'a, T> where T: Clone { let mut content = content; while let Err(back) = self.try_send(content) { content = back; - wfe(); + spin_lock_yield(); } } @@ -116,9 +114,7 @@ impl<'a, T> Receiver<'a, T> where T: Clone { }; let result = data.clone(); self.read.store((read + 1) % self.list.len(), Ordering::Release); - // wake up other core, still idk if the dsb is needed... - dsb(); - sev(); + notify_spin_lock(); Ok(result) } } @@ -128,7 +124,7 @@ impl<'a, T> Receiver<'a, T> where T: Clone { if let Ok(data) = self.try_recv() { return data; } - wfe(); + spin_lock_yield(); } } diff --git a/libsupport_zynq/src/boot.rs b/libsupport_zynq/src/boot.rs index 67e6834..b6a1bbc 100644 --- a/libsupport_zynq/src/boot.rs +++ b/libsupport_zynq/src/boot.rs @@ -4,7 +4,7 @@ use libregister::{ VolatileCell, RegisterR, RegisterW, RegisterRW, }; -use libcortex_a9::{asm, regs::*, cache, mmu}; +use libcortex_a9::{asm, regs::*, cache, mmu, spin_lock_yield, notify_spin_lock}; use libboard_zynq::{slcr, mpcore}; extern "C" { @@ -29,7 +29,7 @@ pub unsafe extern "C" fn Reset() -> ! { } 1 => { while !CORE1_ENABLED.get() { - asm::wfe(); + spin_lock_yield(); } SP.write(&mut __stack1_start as *mut _ as u32); boot_core1(); @@ -144,6 +144,7 @@ impl Core1 { slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(false)); slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_clkstop1(false)); }); + notify_spin_lock(); Core1 {} }