diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-12-23 20:45:51 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-12-23 20:45:51 +0100 |
| commit | cd9a65ba3969460cd7ecb9200f12a828c26205aa (patch) | |
| tree | 4a81809854a9c87d7bc0baaf87d10193b8e6098d | |
| parent | 40ef66cdfb03ceef9671bd95c7dbe46a5155df73 (diff) | |
stm32/usb: use separate irq flags.
- Fixes race condition that could cause losing irqs (because `if flags != 0` was clearing all)
- Doesn't need CAS, which is nice for thumbv6.
| -rw-r--r-- | embassy-stm32/src/usb/usb.rs | 66 |
1 files changed, 33 insertions, 33 deletions
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 460abfe28..cba4915c1 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -2,10 +2,9 @@ | |||
| 2 | 2 | ||
| 3 | use core::future::poll_fn; | 3 | use core::future::poll_fn; |
| 4 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 5 | use core::sync::atomic::Ordering; | 5 | use core::sync::atomic::{AtomicBool, Ordering}; |
| 6 | use core::task::Poll; | 6 | use core::task::Poll; |
| 7 | 7 | ||
| 8 | use atomic_polyfill::{AtomicBool, AtomicU8}; | ||
| 9 | use embassy_hal_common::into_ref; | 8 | use embassy_hal_common::into_ref; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 11 | use embassy_time::{block_for, Duration}; | 10 | use embassy_time::{block_for, Duration}; |
| @@ -35,10 +34,9 @@ static BUS_WAKER: AtomicWaker = NEW_AW; | |||
| 35 | static EP0_SETUP: AtomicBool = AtomicBool::new(false); | 34 | static EP0_SETUP: AtomicBool = AtomicBool::new(false); |
| 36 | static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; | 35 | static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; |
| 37 | static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; | 36 | static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; |
| 38 | static IRQ_FLAGS: AtomicU8 = AtomicU8::new(0); | 37 | static IRQ_RESET: AtomicBool = AtomicBool::new(false); |
| 39 | const IRQ_FLAG_RESET: u8 = 0x01; | 38 | static IRQ_SUSPEND: AtomicBool = AtomicBool::new(false); |
| 40 | const IRQ_FLAG_SUSPEND: u8 = 0x02; | 39 | static IRQ_RESUME: AtomicBool = AtomicBool::new(false); |
| 41 | const IRQ_FLAG_RESUME: u8 = 0x04; | ||
| 42 | 40 | ||
| 43 | fn convert_type(t: EndpointType) -> EpType { | 41 | fn convert_type(t: EndpointType) -> EpType { |
| 44 | match t { | 42 | match t { |
| @@ -184,47 +182,51 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 184 | 182 | ||
| 185 | let istr = regs.istr().read(); | 183 | let istr = regs.istr().read(); |
| 186 | 184 | ||
| 187 | let mut flags: u8 = 0; | ||
| 188 | |||
| 189 | if istr.susp() { | 185 | if istr.susp() { |
| 190 | //trace!("USB IRQ: susp"); | 186 | //trace!("USB IRQ: susp"); |
| 191 | flags |= IRQ_FLAG_SUSPEND; | 187 | IRQ_SUSPEND.store(true, Ordering::Relaxed); |
| 192 | regs.cntr().modify(|w| { | 188 | regs.cntr().modify(|w| { |
| 193 | w.set_fsusp(true); | 189 | w.set_fsusp(true); |
| 194 | w.set_lpmode(true); | 190 | w.set_lpmode(true); |
| 195 | }) | 191 | }); |
| 192 | |||
| 193 | // Write 0 to clear. | ||
| 194 | let mut clear = regs::Istr(!0); | ||
| 195 | clear.set_susp(false); | ||
| 196 | regs.istr().write_value(clear); | ||
| 197 | |||
| 198 | // Wake main thread. | ||
| 199 | BUS_WAKER.wake(); | ||
| 196 | } | 200 | } |
| 197 | 201 | ||
| 198 | if istr.wkup() { | 202 | if istr.wkup() { |
| 199 | //trace!("USB IRQ: wkup"); | 203 | //trace!("USB IRQ: wkup"); |
| 200 | flags |= IRQ_FLAG_RESUME; | 204 | IRQ_RESUME.store(true, Ordering::Relaxed); |
| 201 | regs.cntr().modify(|w| { | 205 | regs.cntr().modify(|w| { |
| 202 | w.set_fsusp(false); | 206 | w.set_fsusp(false); |
| 203 | w.set_lpmode(false); | 207 | w.set_lpmode(false); |
| 204 | }) | 208 | }); |
| 209 | |||
| 210 | // Write 0 to clear. | ||
| 211 | let mut clear = regs::Istr(!0); | ||
| 212 | clear.set_wkup(false); | ||
| 213 | regs.istr().write_value(clear); | ||
| 214 | |||
| 215 | // Wake main thread. | ||
| 216 | BUS_WAKER.wake(); | ||
| 205 | } | 217 | } |
| 206 | 218 | ||
| 207 | if istr.reset() { | 219 | if istr.reset() { |
| 208 | //trace!("USB IRQ: reset"); | 220 | //trace!("USB IRQ: reset"); |
| 209 | flags |= IRQ_FLAG_RESET; | 221 | IRQ_RESET.store(true, Ordering::Relaxed); |
| 210 | 222 | ||
| 211 | // Write 0 to clear. | 223 | // Write 0 to clear. |
| 212 | let mut clear = regs::Istr(!0); | 224 | let mut clear = regs::Istr(!0); |
| 213 | clear.set_reset(false); | 225 | clear.set_reset(false); |
| 214 | regs.istr().write_value(clear); | 226 | regs.istr().write_value(clear); |
| 215 | } | ||
| 216 | 227 | ||
| 217 | if flags != 0 { | 228 | // Wake main thread. |
| 218 | // Send irqs to main thread. | ||
| 219 | IRQ_FLAGS.fetch_or(flags, Ordering::AcqRel); | ||
| 220 | BUS_WAKER.wake(); | 229 | BUS_WAKER.wake(); |
| 221 | |||
| 222 | // Clear them | ||
| 223 | let mut mask = regs::Istr(0); | ||
| 224 | mask.set_wkup(true); | ||
| 225 | mask.set_susp(true); | ||
| 226 | mask.set_reset(true); | ||
| 227 | regs.istr().write_value(regs::Istr(!(istr.0 & mask.0))); | ||
| 228 | } | 230 | } |
| 229 | 231 | ||
| 230 | if istr.ctr() { | 232 | if istr.ctr() { |
| @@ -436,17 +438,15 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 436 | if self.inited { | 438 | if self.inited { |
| 437 | let regs = T::regs(); | 439 | let regs = T::regs(); |
| 438 | 440 | ||
| 439 | let flags = IRQ_FLAGS.load(Ordering::Acquire); | 441 | if IRQ_RESUME.load(Ordering::Acquire) { |
| 440 | 442 | IRQ_RESUME.store(false, Ordering::Relaxed); | |
| 441 | if flags & IRQ_FLAG_RESUME != 0 { | ||
| 442 | IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESUME, Ordering::AcqRel); | ||
| 443 | return Poll::Ready(Event::Resume); | 443 | return Poll::Ready(Event::Resume); |
| 444 | } | 444 | } |
| 445 | 445 | ||
| 446 | if flags & IRQ_FLAG_RESET != 0 { | 446 | if IRQ_RESET.load(Ordering::Acquire) { |
| 447 | IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESET, Ordering::AcqRel); | 447 | IRQ_RESET.store(false, Ordering::Relaxed); |
| 448 | 448 | ||
| 449 | trace!("RESET REGS WRITINGINGING"); | 449 | trace!("RESET"); |
| 450 | regs.daddr().write(|w| { | 450 | regs.daddr().write(|w| { |
| 451 | w.set_ef(true); | 451 | w.set_ef(true); |
| 452 | w.set_add(0); | 452 | w.set_add(0); |
| @@ -475,8 +475,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 475 | return Poll::Ready(Event::Reset); | 475 | return Poll::Ready(Event::Reset); |
| 476 | } | 476 | } |
| 477 | 477 | ||
| 478 | if flags & IRQ_FLAG_SUSPEND != 0 { | 478 | if IRQ_SUSPEND.load(Ordering::Acquire) { |
| 479 | IRQ_FLAGS.fetch_and(!IRQ_FLAG_SUSPEND, Ordering::AcqRel); | 479 | IRQ_SUSPEND.store(false, Ordering::Relaxed); |
| 480 | return Poll::Ready(Event::Suspend); | 480 | return Poll::Ready(Event::Suspend); |
| 481 | } | 481 | } |
| 482 | 482 | ||
