Repository navigation
misc: rp1-pio: two small fixes and support for cyclic output DMA - #7663
hansverkuil wants to merge 7 commits into
Conversation
|
This looks sensible to me. Just in case there are other use cases in future I'd prefer |
|
It makes sense to rename cyclic_tx to tx. I'll wait until #7664 is merged, then I'll rebase and update those issues. checkpatch complains about the Assisted-by tag: do you want me to drop those and just mention it in the commit log? Or not mention the AI use at all? I'm not sure what the guidelines are for AI use in the RPi kernel repo. |
|
I've merged #7664 now. I'm not bothered about the checkpatch complaint - the 7.2 checkpatch is happy with it - it's up to you whether you credit the AI. |
07c3292 to
a7c3ab1
Compare
|
Rebased and renamed cyclic_tx to tx, which was a good change as it made the code a bit easier to understand. |
pelwell
left a comment
There was a problem hiding this comment.
I'm going to paste Claude's review of the second commit verbatim, because I'll miss some nuance if I rewrite it:
- The start of the first period is lost (real bug). For TX, the cyclic descriptor is submitted and started at config time, before anything has
been written. The TX DREQ is asserted whenever the FIFO has space, even with the SM disabled. So the DMAC immediately reads the first
FIFO-depth of words (plus anything it prefetches internally) from period 0, which at that point is still zeros from dma_alloc_coherent. When
the user then fills period 0, the DMA is already past those words. The output therefore starts with about 8 zero words instead of the user's
first words, and no underflow is reported. This contradicts the new comment about filling the whole buffer before enabling the SM. Fix: for
TX, delay dmaengine_submit()/dma_async_issue_pending() until the first write, or until the buffer has been primed. - The writer doesn't catch up properly after an underflow. The callback always calls up(), so if the writer falls behind (head > tail), the
semaphore count rises above buf_count. The writer then writes periods the DMA has already sent. When tail catches up to head, the next write
lands in the period the DMA is currently reading, so the data is torn. It then settles one period short of full lead. It would be better to
have the writer jump tail to head + 1 when it detects an underflow, and replace the counting semaphore with a wait on tail - head < buf_count. - Merged callbacks throw the counts off (affects RX too). dw-axi-dmac reports each finished period through vchan_cyclic_callback(), which just
sets vc->cyclic and schedules a tasklet. If two periods finish before the tasklet runs, the driver gets only one callback. After that,
head_idx and the semaphore are permanently one behind the hardware. For TX, each miss silently reduces how far ahead the writer can get, and
underflow detection works from the wrong head. With small periods under load this is realistic. Using the residue from dmaengine_tx_status()
to find the real position would be more robust. This problem already exists in the RX path, but TX makes it more visible. - The underflow check is best effort. The callback runs in a tasklet, possibly well after the DMA has started the next period. A write that
completes in that gap isn't flagged even though stale data went out. A comment should say so. - The new guard in rp1_pio_sm_xfer_data() is a separate fix. It also protects cyclic RX: before this commit, the kernel API on a cyclic channel
would index bufs[tail % buf_count] when only bufs[0] is allocated. It deserves a mention in the commit message, or its own commit. - Minor points:
- dma_wmb() doesn't order against anything the DMAC can see, since the DMA never reads tail_idx. Its comment ("Pair with the DMAC's reads") is
misleading. It does no harm, but it doesn't achieve anything either. - A zero-byte TX write now blocks and sends a full period of zeros, whereas RX rejects !bytes. Pick one behaviour on purpose.
- Returning -EPIPE even though the data was queued is documented in the uapi header. Still, a caller that retries on error will send that
period twice, so the wording could state that explicitly. - The re-indented dmaengine_prep_dma_cyclic() arguments still aren't aligned with the opening parenthesis (checkpatch --strict).
- dma_wmb() doesn't order against anything the DMAC can see, since the DMA never reads tail_idx. Its comment ("Pair with the DMAC's reads") is
Existing RX issue, not caused by these commits: after -EOVERFLOW, rp1_pio_sm_rx_user() returns without advancing tail_idx. Meanwhile head - tail
keeps growing, so every later read also returns -EOVERFLOW. The stream can't recover without reconfiguring.
| * Cyclic DMA is currently only supported for FROM_SM, and | ||
| * needs at least two real buffers to cycle through. | ||
| */ | ||
| if (dir != RP1_PIO_DIR_FROM_SM || (!buf_size || buf_count < 2)) |
There was a problem hiding this comment.
I think the !buf_size check is effectively covered by the conditions on lines 1050-1051.
There was a problem hiding this comment.
Actually, no: this check also catches the corner case where both buf_size and buf_count are 0, which is a special corner case of the non-cyclic DMA, but for cyclic DMA this makes no sense.
There was a problem hiding this comment.
But that's caught by || buf_count < 2), no?
a7c3ab1 to
12f2a2d
Compare
|
Pushed new code (I let my AI work on the issues your AI found...). Let's see what your AI now thinks of these two patches. Tomorrow I plan to do some actual testing for these corner cases, just to verify what all these AIs have been doing! |
|
Straight from the horse's mouth: 48904ca — fix cyclic RX flow control and overflow recovery
12f2a2d — cyclic DMA for output Improvements: starting the DMA on the first write fixes the zero words at the start. The writer now skips ahead after an underflow instead of
|
12f2a2d to
331dc92
Compare
|
So, another attempt: the first three patches are small, patches 4 and 5 are PIO RX improvements/fixes, and the final patch adds cyclic TX support. It's been fairly extensively tested against all sorts of corner cases, and had one AI code review the other AI (if nothing else, this was educational!). |
|
I could almost merge this as is, but I'll give you a chance to consider making changes. There's quite a bit of overlap between the later commits, with the last commit fixing some deficiencies in the circular buffer handling in the earlier commits. This isn't great for the reviewer, but I'm more interested in the end result. We're definitely into diminishing returns territory with the AI reviews, but the final commit caused quite a bit of feedback from Claude/Opus 5.5, which I'll just paste here verbatim:
|
|
Good comments actually. I'm closing to dropping the whole AI approach to this and do it manually. While AI works really well for pio-la, for this driver it has been quite disappointing. But, as mentioned before, it's been educational... |
|
I agree - it's very much a mixed blessing. |
|
Change of plans: I'll make a new branch to fix rx issues first, then later I'll work on the tx part. I think I'll do this manually rather than relying on AI. |
da2cb4f to
a00d260
Compare
rp1_pio_sm_config_xfer_internal() tested dir == RP1_PIO_DIR_TO_SM in half a dozen places, which is both repetitive and awkward to read where the two arms of the resulting conditionals are not in the natural tx/rx order. Derive a tx bool once and use it throughout, putting the tx arm first consistently. Record it in struct dma_info as well, so that code holding only a dma_info does not have to recover the direction from the index it was looked up by, as rp1_pio_close() had to. No functional change. Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org> Assisted-by: Claude-Code:claude-opus-5
Refuse total buffer sizes of > 512 MB. This also guards against overflows if userspace passes values like ~0. Also allow buf_count values > 4 for cyclic DMA: the limit of 4 is specific to non-cyclic DMA. Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
In the case of cyclic DMA it was possible to accept < 2 buffers or a zero buffer size. Check this and return -EINVAL in that case. Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org> Assisted-by: Claude-Code:claude-opus-5
Set the minimum DMA buf_size to RP1_PIO_CYCLIC_MIN_BUF_SIZE. This ensures that a single period is larger than the FIFO + burst, which avoids some corner cases. Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
In rp1_pio_sm_config_xfer_internal() the buf_size argument was overwritten when calculating the aligned buffer sizes. Use a new variable for that rather than changing the argument. That was rather confusing. Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Cyclic RX DMA support was missing some corner cases: - More than one period might have been DMAed when the callback is called: check the actual DMA status to detect this. If the dma status reports that it is no longer in progress, then return -EIO. - The head/tail indices wrap around at 2^32, but for a buf_count of e.g. 3 it will get out of sync when using % buf_count to get the actual buffer. When head/tail index >= rounddown(INT_MAX, buf_count) wrap it around. - copy_to_user can take a while, during which the buffer that's being copied might be overwritten. Detect such an overflow and report it. Also drop an unnecessary dma_rmb. Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Add support for cyclic TX DMA. Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
a00d260 to
75da9a3
Compare
|
OK, I redid the series, rewriting the last two patches manually. While there are more things that could be done, I think this is in decent shape. One thing that should be considered for this driver is to serialize the ioctls, at least to some extent. It's a bit out of scope of this series. |
|
I'm being shown some concerns about the lack of serialisation, but putting that aside I see three issues which I think are worth considering:
|
The first two patches are small fixes, and the third adds support for cyclic DMA output. Tested and verified with pio-la and spdif encoding/decoding.