-
Notifications
You must be signed in to change notification settings - Fork 767
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Preliminary Xtensa support #805
Conversation
cef3762
to
21a5bb8
Compare
embassy/src/executor/arch/xtensa.rs
Outdated
} | ||
// if not, wait for interrupt | ||
else { | ||
// waiti sets the PS.INTLEVEL therefore no critical section is needed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the critical section in riscv was needed to avoid a race if an irq happens between SIGNAL_WORK_THREAD_MODE.load
and waiti
. the load would read false
so the core would be put to sleep, missing the wake.
ARM solves it with the "event register" in SEV/WFE. riscv doesn't have an equivalent and afaict xtensa doesn't either, so maybe the CS is needed here as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point. The issue in Xtensa is that the processor will never wake up if waiti
is executed inside an interrupt-free critical section.
From TRM (emphasis mine):
In some implementations it also powers down the processor’s logic, and waits for an interrupt. After executing the interrupt handler, execution continues with the instruction following the WAITI.
It seems the interrupt can't just be pending, it has to be actually handled which can't happen when interrupts are disabled. Not really sure what to suggest here, any ideas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd maybe verify that experimentally. If it's true a CS doesn't work then there's no way to do this without races, which I'd find very surprising.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in my testing, I've verified that the TRM is indeed correct. However, I also found some more notes on implemented critical sections on Xtensa, they should actually be done by increasing the PS.INTLEVEL
such that PS.INTLEVEL > any possible interrupt level
instead of disabling interrupts via the INTENABLE
register. I need to do a bit more reading to verify that no interrupts can exist at the max (which is 15), the TRM is kinda vague on that. I guess NMI might be at that level, but what can ya do about that :D. By modifying PS.INTLEVEL
, the waiti
instruction can atomically reduce the PS.INTLEVEL
whilst slipping into sleep mode, hence no race conditions :D.
So what this actually means is we need critical_section
impls for Xtensa. It seems the path forward for critical_section
is that every HAL/PAC will have a per chip cs impl that can handle multi core etc, so I've opened esp-rs/esp-hal#87.
I'll make sure all this theory work actually works on hardware and get back to you :).
I've now reverted to using the critical section to avoid the race condition, for reference the CS impl I used looked like this: struct CriticalSection;
critical_section::custom_impl!(CriticalSection);
static mut VPS: u32 = 0;
unsafe impl critical_section::Impl for CriticalSection {
unsafe fn acquire() -> u8 {
core::arch::asm!("rsil {0}, 15", out(reg) VPS);
0
}
unsafe fn release(_token: u8) {
core::arch::asm!("wsr.ps {0}", in(reg) VPS)
}
} With the next release of |
Hmm, if |
I'm not sure there is anything we can do here, |
FYI this file is what I am basing my implementation on, which came straight from Tensilica (now Cadence). Might be worth a quick skim read, just in case I'm missing something obvious 😅. |
- Adds a executor for the Xtensa arch - Light sleep implemented with assembly, so we don't pull in the xtensa_lx crates (yet) - lock behind a nightly feature due to Xtensa asm support not upstream
To the best of my knowledge, I think this is the best we can do for now. I've added a comment to warn that the CS ends early when using I hope this is acceptable as is, I'd be happy to manage any issues relating to Xtensa (or RISCV) if this gets merged :). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool! Let's do this then! We can always change it later if it turns out to be troublesome 🚀
Thank you! :)
bors r+
Build succeeded:
|
Based on the work in #804.
I hope non-upstream target support is acceptable :).