From 46d64ee0126bf6976426bfd65c50dd4fa98c3dad Mon Sep 17 00:00:00 2001 From: Amit Aryeh Levy Date: Fri, 13 Sep 2024 11:04:07 -0700 Subject: [PATCH] sam4l: spi: adapt SPI implementation to leasable buffers --- boards/imix/src/test/spi_dummy.rs | 15 +++--- boards/imix/src/test/spi_loopback.rs | 27 +++++----- chips/sam4l/src/spi.rs | 81 +++++++++++++++++----------- chips/sam4l/src/usart.rs | 30 +++++++---- 4 files changed, 90 insertions(+), 63 deletions(-) diff --git a/boards/imix/src/test/spi_dummy.rs b/boards/imix/src/test/spi_dummy.rs index 3d1ce362f0..3bc9c20eae 100644 --- a/boards/imix/src/test/spi_dummy.rs +++ b/boards/imix/src/test/spi_dummy.rs @@ -8,6 +8,7 @@ use core::ptr::addr_of_mut; use kernel::hil::gpio::Configure; use kernel::hil::spi::{self, SpiMaster}; +use kernel::utilities::leasable_buffer::SubSliceMut; use kernel::ErrorCode; #[allow(unused_variables, dead_code)] @@ -31,17 +32,16 @@ impl spi::SpiMasterClient for DummyCB { #[allow(unused_variables, dead_code)] fn read_write_done( &self, - write: &'static mut [u8], - read: Option<&'static mut [u8]>, - len: usize, - _status: Result<(), ErrorCode>, + write: SubSliceMut<'static, u8>, + read: Option>, + status: Result, ) { unsafe { // do actual stuff // TODO verify SPI return value let _ = self .spi - .read_write_bytes(&mut *addr_of_mut!(A5), None, A5.len()); + .read_write_bytes((&mut *addr_of_mut!(A5) as &mut [u8]).into(), None); // FLOP = !FLOP; // let len: usize = BUF1.len(); @@ -89,9 +89,8 @@ pub unsafe fn spi_dummy_test(spi: &'static sam4l::spi::SpiHw<'static>) { let len = BUF2.len(); if spi.read_write_bytes( - &mut *addr_of_mut!(BUF2), - Some(&mut *addr_of_mut!(BUF1)), - len, + (&mut *addr_of_mut!(BUF2) as &mut [u8]).into(), + Some((&mut *addr_of_mut!(BUF1) as &mut [u8]).into()), ) != Ok(()) { loop { diff --git a/boards/imix/src/test/spi_loopback.rs b/boards/imix/src/test/spi_loopback.rs index 73f5147a85..d081f8e299 100644 --- a/boards/imix/src/test/spi_loopback.rs +++ b/boards/imix/src/test/spi_loopback.rs @@ -21,6 +21,7 @@ use core::ptr::addr_of_mut; use kernel::component::Component; use kernel::debug; use kernel::hil::spi::{self, SpiMasterDevice}; +use kernel::utilities::leasable_buffer::SubSliceMut; use kernel::ErrorCode; #[allow(unused_variables, dead_code)] @@ -49,14 +50,13 @@ impl spi::SpiMasterClient for SpiLoopback { #[allow(unused_variables, dead_code)] fn read_write_done( &self, - write: &'static mut [u8], - read: Option<&'static mut [u8]>, - len: usize, - status: Result<(), ErrorCode>, + mut write: SubSliceMut<'static, u8>, + read: Option>, + status: Result, ) { let mut good = true; let read = read.unwrap(); - for (c, v) in write.iter().enumerate() { + for (c, v) in write[..].iter().enumerate() { if read[c] != *v { debug!( "SPI test error at index {}: wrote {} but read {}", @@ -75,7 +75,7 @@ impl spi::SpiMasterClient for SpiLoopback { write[i] = counter.wrapping_add(i as u8); } - if let Err((e, _, _)) = self.spi.read_write_bytes(write, Some(read), len) { + if let Err((e, _, _)) = self.spi.read_write_bytes(write, Some(read)) { panic!( "Could not continue SPI test, error on read_write_bytes is {:?}", e @@ -98,9 +98,8 @@ pub unsafe fn spi_loopback_test( let len = WBUF.len(); if let Err((e, _, _)) = spi.read_write_bytes( - &mut *addr_of_mut!(WBUF), - Some(&mut *addr_of_mut!(RBUF)), - len, + (&mut *addr_of_mut!(WBUF) as &mut [u8]).into(), + Some((&mut *addr_of_mut!(RBUF) as &mut [u8]).into()), ) { panic!( "Could not start SPI test, error on read_write_bytes is {:?}", @@ -130,9 +129,8 @@ pub unsafe fn spi_two_loopback_test(mux: &'static MuxSpiMaster<'static, sam4l::s let len = WBUF.len(); if let Err((e, _, _)) = spi_fast.read_write_bytes( - &mut *addr_of_mut!(WBUF), - Some(&mut *addr_of_mut!(RBUF)), - len, + (&mut *addr_of_mut!(WBUF) as &mut [u8]).into(), + Some((&mut *addr_of_mut!(RBUF) as &mut [u8]).into()), ) { panic!( "Could not start SPI test, error on read_write_bytes is {:?}", @@ -142,9 +140,8 @@ pub unsafe fn spi_two_loopback_test(mux: &'static MuxSpiMaster<'static, sam4l::s let len = WBUF2.len(); if let Err((e, _, _)) = spi_slow.read_write_bytes( - &mut *addr_of_mut!(WBUF2), - Some(&mut *addr_of_mut!(RBUF2)), - len, + (&mut *addr_of_mut!(WBUF2) as &mut [u8]).into(), + Some((&mut *addr_of_mut!(RBUF2) as &mut [u8]).into()), ) { panic!( "Could not start SPI test, error on read_write_bytes is {:?}", diff --git a/chips/sam4l/src/spi.rs b/chips/sam4l/src/spi.rs index eedc471a4e..30842c878e 100644 --- a/chips/sam4l/src/spi.rs +++ b/chips/sam4l/src/spi.rs @@ -23,6 +23,7 @@ use kernel::hil::spi::SpiMasterClient; use kernel::hil::spi::SpiSlaveClient; use kernel::platform::chip::ClockInterface; use kernel::utilities::cells::OptionalCell; +use kernel::utilities::leasable_buffer::SubSliceMut; use kernel::utilities::peripheral_management::{PeripheralManagement, PeripheralManager}; use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable}; use kernel::utilities::registers::{self, register_bitfields, ReadOnly, ReadWrite, WriteOnly}; @@ -443,35 +444,26 @@ impl<'a> SpiHw<'a> { // the caller, and the caller may want to be able write into it. fn read_write_bytes( &self, - write_buffer: Option<&'static mut [u8]>, - read_buffer: Option<&'static mut [u8]>, - len: usize, + write_buffer: Option>, + read_buffer: Option>, ) -> Result< (), ( ErrorCode, - Option<&'static mut [u8]>, - Option<&'static mut [u8]>, + Option>, + Option>, ), > { - if write_buffer.is_none() && read_buffer.is_none() { - return Err((ErrorCode::INVAL, write_buffer, read_buffer)); - } + let count = match (&write_buffer, &read_buffer) { + (Some(ref wb), Some(ref rb)) => cmp::min(wb.len(), rb.len()), + (Some(ref wb), None) => wb.len(), + (None, Some(ref rb)) => rb.len(), + (None, None) => return Err((ErrorCode::INVAL, write_buffer, read_buffer)), + }; // Start by enabling the SPI driver. self.enable(); - // Determine how many bytes to move based on the shortest of the - // write_buffer length, the read_buffer length, and the user requested - // len. - let mut count: usize = len; - write_buffer - .as_ref() - .map(|buf| count = cmp::min(count, buf.len())); - read_buffer - .as_ref() - .map(|buf| count = cmp::min(count, buf.len())); - // Configure DMA to transfer that many bytes. self.dma_length.set(count); @@ -491,19 +483,19 @@ impl<'a> SpiHw<'a> { .set(self.transfers_in_progress.get() + 1); self.dma_read.map(move |read| { read.enable(); - read.do_transfer(DMAPeripheral::SPI_RX, rbuf, count); + read.do_transfer(DMAPeripheral::SPI_RX, rbuf.take(), count); }); }); // The ordering of these operations matters. // For transfers 4 bytes or longer, this will work as expected. // For shorter transfers, the first byte will be missing. - write_buffer.map(|wbuf| { + write_buffer.map(|buf| { self.transfers_in_progress .set(self.transfers_in_progress.get() + 1); self.dma_write.map(move |write| { write.enable(); - write.do_transfer(DMAPeripheral::SPI_TX, wbuf, count); + write.do_transfer(DMAPeripheral::SPI_TX, buf.take(), count); }); }); @@ -571,19 +563,29 @@ impl<'a> spi::SpiMaster<'a> for SpiHw<'a> { // the caller, and the caller may want to be able write into it. fn read_write_bytes( &self, - write_buffer: &'static mut [u8], - read_buffer: Option<&'static mut [u8]>, - len: usize, - ) -> Result<(), (ErrorCode, &'static mut [u8], Option<&'static mut [u8]>)> { + write_buffer: SubSliceMut<'static, u8>, + read_buffer: Option>, + ) -> Result< + (), + ( + ErrorCode, + SubSliceMut<'static, u8>, + Option>, + ), + > { // If busy, don't start. if self.is_busy() { return Err((ErrorCode::BUSY, write_buffer, read_buffer)); } if let Err((err, write_buffer, read_buffer)) = - self.read_write_bytes(Some(write_buffer), read_buffer, len) + self.read_write_bytes(Some(write_buffer), read_buffer) { - Err((err, write_buffer.unwrap(), read_buffer)) + Err(( + err, + write_buffer.unwrap_or((&mut [] as &mut [u8]).into()), + read_buffer, + )) } else { Ok(()) } @@ -686,7 +688,26 @@ impl<'a> spi::SpiSlave<'a> for SpiHw<'a> { Option<&'static mut [u8]>, ), > { - self.read_write_bytes(write_buffer, read_buffer, len) + let write_buffer = write_buffer.map(|b| { + let mut buf: SubSliceMut = b.into(); + if buf.len() > len { + buf.slice(..len); + } + buf + }); + let read_buffer = read_buffer.map(|b| { + let mut buf: SubSliceMut = b.into(); + if buf.len() > len { + buf.slice(..len); + } + buf + }); + + if let Err((e, mwb, mrb)) = self.read_write_bytes(write_buffer, read_buffer) { + Err((e, mwb.map(|b| b.take()), mrb.map(|b| b.take()))) + } else { + Ok(()) + } } fn set_polarity(&self, polarity: ClockPolarity) -> Result<(), ErrorCode> { @@ -740,7 +761,7 @@ impl DMAClient for SpiHw<'_> { SpiRole::SpiMaster => { self.client.map(|cb| { txbuf.map(|txbuf| { - cb.read_write_done(txbuf, rxbuf, len, Ok(())); + cb.read_write_done(txbuf.into(), rxbuf.map(|b| b.into()), Ok(len)); }); }); } diff --git a/chips/sam4l/src/usart.rs b/chips/sam4l/src/usart.rs index 8081401152..dda647ed5a 100644 --- a/chips/sam4l/src/usart.rs +++ b/chips/sam4l/src/usart.rs @@ -14,6 +14,7 @@ use kernel::hil::spi; use kernel::hil::spi::cs::ChipSelectPolar; use kernel::hil::uart; use kernel::utilities::cells::OptionalCell; +use kernel::utilities::leasable_buffer::SubSliceMut; use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable}; use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite, WriteOnly}; use kernel::utilities::StaticRef; @@ -702,7 +703,11 @@ impl<'a> USART<'a> { // state. let len = self.tx_len.get(); self.tx_len.set(0); - client.read_write_done(txbuffer.unwrap(), rxbuf, len, Ok(())); + client.read_write_done( + txbuffer.unwrap().into(), + rxbuf.map(|b| b.into()), + Ok(len), + ); } } }); @@ -1086,20 +1091,25 @@ impl<'a> spi::SpiMaster<'a> for USART<'a> { fn read_write_bytes( &self, - write_buffer: &'static mut [u8], - read_buffer: Option<&'static mut [u8]>, - len: usize, - ) -> Result<(), (ErrorCode, &'static mut [u8], Option<&'static mut [u8]>)> { + write_buffer: SubSliceMut<'static, u8>, + read_buffer: Option>, + ) -> Result< + (), + ( + ErrorCode, + SubSliceMut<'static, u8>, + Option>, + ), + > { let usart = &USARTRegManager::new(self); self.enable_tx(usart); self.enable_rx(usart); // Calculate the correct length for the transmission - let buflen = read_buffer.as_ref().map_or(write_buffer.len(), |rbuf| { + let count = read_buffer.as_ref().map_or(write_buffer.len(), |rbuf| { cmp::min(rbuf.len(), write_buffer.len()) }); - let count = cmp::min(buflen, len); self.tx_len.set(count); @@ -1128,12 +1138,12 @@ impl<'a> spi::SpiMaster<'a> for USART<'a> { self.usart_tx_state.set(USARTStateTX::DMA_Transmitting); self.usart_rx_state.set(USARTStateRX::Idle); dma.enable(); - dma.do_transfer(self.tx_dma_peripheral, write_buffer, count); + dma.do_transfer(self.tx_dma_peripheral, write_buffer.take(), count); // Start the read transaction. self.usart_rx_state.set(USARTStateRX::DMA_Receiving); read.enable(); - read.do_transfer(self.rx_dma_peripheral, rbuf, count); + read.do_transfer(self.rx_dma_peripheral, rbuf.take(), count); }); }); }); @@ -1143,7 +1153,7 @@ impl<'a> spi::SpiMaster<'a> for USART<'a> { self.usart_tx_state.set(USARTStateTX::DMA_Transmitting); self.usart_rx_state.set(USARTStateRX::Idle); dma.enable(); - dma.do_transfer(self.tx_dma_peripheral, write_buffer, count); + dma.do_transfer(self.tx_dma_peripheral, write_buffer.take(), count); }); }