uarte: Be on safe side with potentially racy code

The PS does not specify how many cycles it takes for a STARTXX task to
generate a XXSTARTED event. I think it is instantaneous but let’s be on
the safe side for the following sequence:
1. poll() starttx
2. drop() txstarted not yet set, but future gets dropped
3. txstarted set by hardware, peripheral enabled after it was dropped
This commit is contained in:
Timo Kröger 2021-01-03 12:09:51 +01:00
parent a3b3305b8e
commit 85ec9dd16f

View File

@ -289,27 +289,31 @@ where
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
match T::state().tx_done.poll_wait(cx) { if T::state().tx_done.poll_wait(cx).is_pending() {
Poll::Pending if !uarte.tx_started() => { let ptr = buf.as_ptr();
let uarte = &uarte.instance; let len = buf.len();
let ptr = buf.as_ptr(); assert!(len <= EASY_DMA_SIZE);
let len = buf.len(); // TODO: panic if buffer is not in SRAM
assert!(len <= EASY_DMA_SIZE);
// TODO: panic if buffer is not in SRAM
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
uarte.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); uarte
uarte .instance
.txd .txd
.maxcnt .ptr
.write(|w| unsafe { w.maxcnt().bits(len as _) }); .write(|w| unsafe { w.ptr().bits(ptr as u32) });
uarte
.instance
.txd
.maxcnt
.write(|w| unsafe { w.maxcnt().bits(len as _) });
trace!("starttx"); trace!("starttx");
uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); uarte.instance.tasks_starttx.write(|w| unsafe { w.bits(1) });
Poll::Pending while !uarte.tx_started() {} // Make sure transmission has started
}
Poll::Pending => Poll::Pending, Poll::Pending
Poll::Ready(_) => Poll::Ready(Ok(())), } else {
Poll::Ready(Ok(()))
} }
} }
} }
@ -352,21 +356,26 @@ where
match T::state().rx_done.poll_wait(cx) { match T::state().rx_done.poll_wait(cx) {
Poll::Pending if !uarte.rx_started() => { Poll::Pending if !uarte.rx_started() => {
let uarte = &uarte.instance;
let ptr = buf.as_ptr(); let ptr = buf.as_ptr();
let len = buf.len(); let len = buf.len();
assert!(len <= EASY_DMA_SIZE); assert!(len <= EASY_DMA_SIZE);
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
uarte.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
uarte uarte
.instance
.rxd
.ptr
.write(|w| unsafe { w.ptr().bits(ptr as u32) });
uarte
.instance
.rxd .rxd
.maxcnt .maxcnt
.write(|w| unsafe { w.maxcnt().bits(len as _) }); .write(|w| unsafe { w.maxcnt().bits(len as _) });
trace!("startrx"); trace!("startrx");
uarte.tasks_startrx.write(|w| unsafe { w.bits(1) }); uarte.instance.tasks_startrx.write(|w| unsafe { w.bits(1) });
while !uarte.rx_started() {} // Make sure reception has started
Poll::Pending Poll::Pending
} }
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,