i2c: Answer an unanswered slave read - #470
Open
EvanChuchen731 wants to merge 1 commit into
Open
EvanChuchen731 wants to merge 1 commit into
EvanChuchen731 wants to merge 1 commit into
Conversation
The slave interrupt handler reported a master read as data already sent and staged nothing, so the controller parked the transaction at WAIT_TX_DMA and held SCL low, where it stays until a byte reaches the transmit path. On a bus with the hardware SMBus timeout disabled, nothing on this side ends such a transaction. The handler now stages one filler byte, 0xFF, the value a master reads back from a released SDA line, and re-arms receive in the same command write. Answering in the handler rather than in the application is what closes the window. The i2cs28 enable bits are one-shot and do not survive a transaction, so any intervening transaction leaves the next read unanswered and an application would have to re-arm across an IPC round trip it does not control. A reply slave_write staged is unaffected: the hardware serves it from that call's own arming, so WAIT_TX_DMA never occurs and the filler path never runs. The read-after-write branch skips the receive re-arm, which would reset the length registers the pending drain reads. In buffer mode the transmit FIFO and the receive pool are one 32-byte region, so the filler write replaces byte 0 alone; a whole-DWORD write would zero the received bytes behind it. In DMA mode the two paths are separate, and byte mode has no filler path. Signed-off-by: Evan Chuchen <evan_chuchen@jabil.com>
EvanChuchen731
force-pushed
the
i2c-slave-read-filler
branch
from
September 16, 2026 03:09
59f0043 to
c23e4d1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A master read of the AST1060 slave address stalls the bus when the
application has staged no reply. The controller parks the transaction at
WAIT_TX_DMAand holds SCL low until a byte reaches the transmit path,and the old handler reported the read as
DataSentwhile stagingnothing. On a bus with the hardware SMBus timeout disabled there is no
controller-side backstop.
MCTP over SMBus is write-only in both directions, so no MCTP peer
triggers this. A host that reads us does: an OpenBMC service that probes
by reading, such as
fru-device, or a host expecting a mailbox at ouraddress.
What changes
answer_slave_readstages one filler byte,0xFF, arms transmit,re-arms receive and writes the command register. It runs on the three
WAIT_TX_DMAbranches: a read's first byte, a later byte of the sameread, and a read on a repeated START after a write.
The
0xFFvalue is what a master reads back from a released SDA line.The answer belongs in the handler rather than in the application because
the
i2cs28enable bits are one-shot and do not survive a transaction.Any intervening transaction leaves the next read unanswered, and an
application would have to re-arm across an IPC round trip it does not
control. A reply
slave_writestaged is unaffected: the hardware servesit from that call's own arming, so
WAIT_TX_DMAnever occurs.Scope
This fix keeps the bus from stalling. It is not a read interface: a
reader gets no length and no framing, so a probe reads
0xFFfor as manybytes as it asks for. Whether OpenPRoT wants a real I2C read interface, a
mailbox for a boot stage that runs before MCTP is up, is a separate
question this does not answer.
services/i2c/README.mdrecords the filler behavior.Testing
bazel build --config=k_ast1060_evb //target/ast10x0/...: 405 targets,completed successfully
bazel test --config=k_ast1060_evbof//target/ast10x0/tests/peripherals/i2c/i2c_irq:no_panics_testand:slave_no_panics_test: both pass. These are panic-detector checks onthe binaries and execute no I2C logic
./pw format --checkover the two changed files: no changes needed//target/ast10x0/peripherals/...and//target/ast10x0/backend/i2c/...reports 25 findings, the same 25 ason
mainbefore this change, none of them in a changed fileVerified on hardware
An AST1060 running the MCTP control image, driven by a BMC master in DMA
mode at slave address
0x40:i2ctransfer -y <bus> r1@0x40returnsffi2ctransfer -y <bus> r4@0x40returnsff ff ff ffi2ctransfer -y <bus> w1@0x40 0x00 r1@0x40returnsffSo all three branches answer and the read completes instead of holding
SCL. An MCTP Get Endpoint ID request following those reads is received,
decoded and answered, which confirms the receive path survives the
skipped re-arm on the read-after-write branch.
A register capture at the interrupt entry read
0x00070240right afterthe handler wrote it, with
i2cs24at 0 on that same interrupt, so nopacket completed in between. The next packet's interrupt entry read
0x00070000, with bothTX_BUFF_ENandRX_DMA_ENgone. No code wrotei2cs28between those two reads, so the hardware cleared them. Thearming therefore does not survive a transaction, which is why an
application would have to re-stage after every one.
Known gap
A read the service never asked for still logs
slave_receive failed: theSTOP that ends it wakes the MCTP server, whose latch holds no received
bytes. That log line predates this change.