peripherals/i2c: include address byte in slave_read, fix IRQ storm
diff --git a/target/ast10x0/peripherals/i2c/slave.rs b/target/ast10x0/peripherals/i2c/slave.rs index 9888549..360e988 100644 --- a/target/ast10x0/peripherals/i2c/slave.rs +++ b/target/ast10x0/peripherals/i2c/slave.rs
@@ -128,13 +128,13 @@ self.regs().i2cs4c().read().dmarx_actual_len_byte().bits() as usize } else { // Hardware includes the I2C address byte in the buffer count (packet mode, - // I2CC00 bit 20). Subtract 1 to report only the payload byte count. + // I2CC00 bit 20). Report the full count including that byte, consistent + // with what slave_read returns. self.regs() .i2cc0c() .read() .actual_rxd_pool_buffer_size() - .bits() - .saturating_sub(1) as usize + .bits() as usize } } @@ -318,20 +318,20 @@ // Get receive length from buffer length register if self.xfer_mode == I2cXferMode::BufferMode { // AST_I2CC_SLAVE_PKT_SAVE_ADDR (I2CC00 bit 20) deposits the I2C - // address byte at buffer offset 0. Read the raw count once, subtract - // 1 for that byte, then copy only the payload (skipping offset 0). + // address byte at buffer offset 0. Include it in the returned data; + // callers that need the full SMBus frame (e.g. MctpI2cEncap::decode) + // depend on it being present. let raw = self .regs() .i2cc0c() .read() .actual_rxd_pool_buffer_size() .bits() as usize; - let data_len = raw.saturating_sub(1); - let to_read = data_len.min(buffer.len()).min(BUFFER_SIZE - 1); + let to_read = raw.min(buffer.len()).min(BUFFER_SIZE); let mut tmp = [0u8; BUFFER_SIZE]; - self.copy_from_buffer(&mut tmp[..1 + to_read])?; - buffer[..to_read].copy_from_slice(&tmp[1..1 + to_read]); + self.copy_from_buffer(&mut tmp[..to_read])?; + buffer[..to_read].copy_from_slice(&tmp[..to_read]); // Re-enable RX buffer let mut cmd = constants::AST_I2CS_ACTIVE_ALL | constants::AST_I2CS_PKT_MODE_EN; @@ -344,15 +344,13 @@ } else if self.xfer_mode == I2cXferMode::DmaMode { // DMA mode: the hardware has already DMA'd into `self.dma_buf`. // AST_I2CC_SLAVE_PKT_SAVE_ADDR deposits the address byte at dma_buf[0]; - // subtract 1 and skip it, matching the buffer-mode treatment above. + // include it in the returned data (matches buffer-mode treatment above). let hw_len = self.regs().i2cs4c().read().dmarx_actual_len_byte().bits() as usize; - let data_len = hw_len.saturating_sub(1); - let to_read = data_len.min(buffer.len()); + let to_read = hw_len.min(buffer.len()); if let Some(dma_buf) = self.slave_dma_buf.as_deref() { - let src_len = to_read.min(dma_buf.len().saturating_sub(1)); - if let (Some(src), Some(dst)) = - (dma_buf.get(1..1 + src_len), buffer.get_mut(..src_len)) + let src_len = to_read.min(dma_buf.len()); + if let (Some(src), Some(dst)) = (dma_buf.get(..src_len), buffer.get_mut(..src_len)) { dst.copy_from_slice(src); } @@ -464,6 +462,14 @@ let status = self.regs().i2cs24().read().bits(); if status == 0 { + // Master status register i2cm14 retains bits after a master operation + // and keeps the shared IRQ line asserted. Clear it here to stop the storm. + let m14 = self.regs().i2cm14().read().bits(); + if m14 != 0 { + unsafe { + self.regs().i2cm14().write(|w| w.bits(m14)); + } + } return None; }
diff --git a/target/ast10x0/tests/peripherals/i2c/i2c_irq/slave_target.rs b/target/ast10x0/tests/peripherals/i2c/i2c_irq/slave_target.rs index ea0852c..bf3f9a7 100644 --- a/target/ast10x0/tests/peripherals/i2c/i2c_irq/slave_target.rs +++ b/target/ast10x0/tests/peripherals/i2c/i2c_irq/slave_target.rs
@@ -27,7 +27,9 @@ pub struct Target {} const SLAVE_ADDR: u8 = 0x42; -const EXPECTED_WRITE: &[u8] = &[0xAA, 0xBB, 0xCC, 0xDD]; +// SLAVE_PKT_SAVE_ADDR prepends dest address byte (SLAVE_ADDR << 1) at offset 0, +// followed by the master's payload [0xAA, 0xBB, 0xCC, 0xDD]. +const EXPECTED_WRITE: &[u8] = &[SLAVE_ADDR << 1, 0xAA, 0xBB, 0xCC, 0xDD]; const READ_RESPONSE: &[u8] = &[0x55]; fn i2c2_config() -> I2cConfig {
diff --git a/target/ast10x0/tests/peripherals/i2c/i2c_slave_rx/target.rs b/target/ast10x0/tests/peripherals/i2c/i2c_slave_rx/target.rs index 2159999..4d2c934 100644 --- a/target/ast10x0/tests/peripherals/i2c/i2c_slave_rx/target.rs +++ b/target/ast10x0/tests/peripherals/i2c/i2c_slave_rx/target.rs
@@ -18,8 +18,9 @@ /// Slave address the test binary listens on. const SLAVE_ADDR: u8 = 0x42; -/// Payload the master binary sends. -const EXPECTED_PAYLOAD: &[u8] = &[0xDE, 0xAD, 0xBE, 0xEF]; +/// Expected buffer contents: SLAVE_PKT_SAVE_ADDR prepends dest address byte +/// (SLAVE_ADDR << 1) at offset 0, followed by the master's payload [0xDE, 0xAD, 0xBE, 0xEF]. +const EXPECTED_PAYLOAD: &[u8] = &[SLAVE_ADDR << 1, 0xDE, 0xAD, 0xBE, 0xEF]; /// Bus 2 config: standard-speed buffer-mode, no SMBus timeout. const SLAVE_CFG: I2cConfig = I2cConfig { @@ -119,15 +120,17 @@ let received = &rx[..n]; if received != EXPECTED_PAYLOAD { pw_log::error!( - "payload mismatch: got [{:02x} {:02x} {:02x} {:02x}] expected [{:02x} {:02x} {:02x} {:02x}]", + "payload mismatch: got [{:02x} {:02x} {:02x} {:02x} {:02x}] expected [{:02x} {:02x} {:02x} {:02x} {:02x}]", received[0] as u32, received[1] as u32, received[2] as u32, received[3] as u32, + received[4] as u32, EXPECTED_PAYLOAD[0] as u32, EXPECTED_PAYLOAD[1] as u32, EXPECTED_PAYLOAD[2] as u32, EXPECTED_PAYLOAD[3] as u32, + EXPECTED_PAYLOAD[4] as u32, ); return Err("payload content mismatch"); }
diff --git a/target/ast10x0/tests/peripherals/i2c/i2c_slave_rx_ipc/slave_rx_main.rs b/target/ast10x0/tests/peripherals/i2c/i2c_slave_rx_ipc/slave_rx_main.rs index fe775b7..5f48c3c 100644 --- a/target/ast10x0/tests/peripherals/i2c/i2c_slave_rx_ipc/slave_rx_main.rs +++ b/target/ast10x0/tests/peripherals/i2c/i2c_slave_rx_ipc/slave_rx_main.rs
@@ -21,8 +21,9 @@ /// Slave address the test listens on. const SLAVE_ADDR: u8 = 0x42; -/// Payload the master binary sends. -const EXPECTED_PAYLOAD: &[u8] = &[0xDE, 0xAD, 0xBE, 0xEF]; +/// Expected buffer contents: SLAVE_PKT_SAVE_ADDR prepends dest address byte +/// (SLAVE_ADDR << 1) at offset 0, followed by the master's payload [0xDE, 0xAD, 0xBE, 0xEF]. +const EXPECTED_PAYLOAD: &[u8] = &[SLAVE_ADDR << 1, 0xDE, 0xAD, 0xBE, 0xEF]; macro_rules! fail { ($msg:literal) => {{ @@ -80,11 +81,12 @@ if &rx[..event.data_len] != EXPECTED_PAYLOAD { pw_log::error!( - "payload mismatch: got [{:02x} {:02x} {:02x} {:02x}]", + "payload mismatch: got [{:02x} {:02x} {:02x} {:02x} {:02x}]", rx[0] as u32, rx[1] as u32, rx[2] as u32, rx[3] as u32, + rx[4] as u32, ); let _ = syscall::debug_shutdown(Err(pw_status::Error::DataLoss)); loop {}