serial: adi_uart4: avoid double increment of icount.tx in DMA TX path#3228
serial: adi_uart4: avoid double increment of icount.tx in DMA TX path#3228qasim-ijaz merged 6 commits intoadsp-6.12.0-yfrom
Conversation
|
Looks like you may have committed with your GMail: If you have a work directory and personal directory on our machine you can do something like:
|
https://github.com/analogdevicesinc/linux/actions/runs/23827385771/job/69453339504?pr=3228#step:9:23 |
|
It is important to also explain the impact of the bug. From Claude:
How did you test this change? |
|
This made me curious about the non-DMA path (from Claude):
|
31d9cc3 to
9901041
Compare
Hi @pamolloy, thanks for the extensive review! I’ve updated the commit message to better explain the impact. This does not affect actual data transmission, but it does make I tested this change on both the ADSP-SC594 and ADSP-SC598 and verified Link: https://elixir.bootlin.com/linux/v6.12/source/include/linux/serial_core.h#L826 |
Should be fixed now but seems like the file isn't being compiled during checks for some reason? |
|
Does this driver really technically depends on a specific architecture Or all those conditionals are being used to say "HEY! This is only works with my SOC!"? Ideally simplify the conditionals to represent the technical dependency, not "what this driver support at the moment". Also, at |
Thanks!
Can you also explain what the "Kernel serial diagnostics" are and what userspace tools use them? Enough so someone else can reproduce it relatively easily. I assume this would be useful if we were using the UART to transmit generic data and not using it as a console. When used as a console these statistics certainly aren't necessary. |
Sure, so an example would be something like /proc/tty/driver/adi-uart4 this directly shows you various pieces of info such as the rx and tx counts the driver has completed: To easily reproduce and view changes to the tx and rx you can boot up Linux on a ADSP-SC589 or ADSP-SC594 (or whatever). Then in a separate terminal ssh into the board. Then in the ssh session view the above. Then in the serial console type a single character, move back to the ssh session and view the data again, it should have increased now. I did this exact experiment, so this is the count beforehand: ...Then type a character in the serial console (i pressed 'a' once) and view the counters again in the ssh session: As you can see the TX counter has gone to 19596 (should be 19595) which illustrates the double increment |
Thank for your review. I will look into this. |
| module_exit(adi_uart4_serial_exit); | ||
|
|
||
| MODULE_DESCRIPTION("ADI UART4 serial driver"); | ||
| MODULE_LICENSE("GPL"); |
There was a problem hiding this comment.
Should be at the end of the file
There was a problem hiding this comment.
Would be good to address the coccicheck warning as well:
coccicheck: 3-8 No need to set .owner here. The core will do it.
There was a problem hiding this comment.
Good idea, I have fixed this.
@pamolloy maybe i should add this info to the commit message? could be a good addition |
Definitely, in this case where we're committing into our own tree and this commit will get squashed before mainlining. If this patch were submitted mainline some of the above information would be nice to include in a cover letter (to show you've tested it), although most of the context isn't required for a mainline review since it'll get reviewed by subsystem maintainers. Of course within ADI we can't specialize in all subsystems so it is really helpful to include in the PR description in that case. 😄 We also have the System Level doctools documentation, which is a good place to document things, especially if it is applicable to our customers. |
095f7ff to
cb28d13
Compare
In adi_uart4_serial_dma_tx(), the driver updates uart->port.icount.tx manually and then calls uart_xmit_advance(&uart->port, uart->tx_count). However, uart_xmit_advance() already advances the xmit_fifo TX queue and accounts transmitted bytes into icount.tx, so the function counts each completed DMA transfer twice. This does not affect data transmission, but it makes TX accounting incorrect. Kernel serial diagnostics that report icount.tx will show inflated TX byte counts, which could make it harder to debug UART related bugs/issues in the future. An example of this is /proc/tty/driver/adi-uart4 which directly shows you various pieces of information such as the TX and RX counts associated with the driver: root@adsp-sc598-som-ezkit:~# cat /proc/tty/driver/adi-uart4 serinfo:1.0 driver revision: 0: uart:ADI-UART4 irq:0 tx:19594 rx:25 To reproduce and view changes to the TX and RX counts you can boot up Linux on an ADSP-SC589 or ADSP-SC594. Then in a separate terminal SSH into the board. Then in the SSH session view the above. Then in the serial console type a single character, move back to the SSH session and view the data again, it should have increased now. I did this exact experiment, so this is the count beforehand: root@adsp-sc598-som-ezkit:~# cat /proc/tty/driver/adi-uart4 serinfo:1.0 driver revision: 0: uart:ADI-UART4 irq:0 tx:19594 rx:25 Then type a character in the serial console (i pressed 'a' once) and view the counters again in the SSH session: root@adsp-sc598-som-ezkit:~# cat /proc/tty/driver/adi-uart4 serinfo:1.0 driver revision: 0: uart:ADI-UART4 irq:0 tx:19596 rx:26 As you can see the TX counter has gone to 19596 (should be 19595) which illustrates the double increment once from "uart->port.icount.tx += uart->tx_count;" and another time from the uart_xmit_advance() call. Fix this by dropping the explicit icount.tx update and relying on uart_xmit_advance() for TX accounting. Fixes: eab94da ("serial: Add UART driver for SC5xx SoCs") Signed-off-by: Qasim Ijaz <qasim.ijaz@analog.com>
adi_uart4_serial_remove() frees "uart" before checking and releasing the DMA channels stored in the same structure. Move the DMA channel release before "kfree(uart)" so the remove path does not dereference freed memory. Fixes: eab94da ("serial: Add UART driver for SC5xx SoCs") Signed-off-by: Qasim Ijaz <qasim.ijaz@analog.com>
Add COMPILE_TEST to SERIAL_ADI_UART4 so CI build jobs can build the driver. Signed-off-by: Qasim Ijaz <qasim.ijaz@analog.com>
Add the missing MODULE_LICENSE() declaration so CI jobs can build the driver. Signed-off-by: Qasim Ijaz <qasim.ijaz@analog.com>
Remove the explicit .owner assignment from adi_uart4_serial_driver to address the coccicheck warning: "No need to set .owner here. The core will do it." Signed-off-by: Qasim Ijaz <qasim.ijaz@analog.com>
a56d53b to
054247a
Compare
…llback
During the DMA TX completion callback adi_uart4_serial_dma_tx(), the
driver checks whether to call uart_write_wakeup() before advancing the
xmit_fifo TX queue with uart_xmit_advance().
uart_write_wakeup() notifies the tty layer that the driver can accept
more output and wakes tasks blocked in the tty write path. For ttySC0,
that allows a blocked writer to resume and eventually queue more bytes
into the TX buffer (xmit_fifo).
Because this check is done before xmit_fifo is advanced, the wakeup
decision uses stale xmit_fifo state. This becomes problematic when a
completed DMA transfer reduces the pending TX queue below
WAKEUP_CHARS, because blocked writers can miss their wakeup and remain
stalled. This includes the case where the DMA completion drains the
queue completely.
Missing this wakeup can stop further output from being queued and make
the serial console appear to hang or freeze.
I was able to reproduce the issue on both the ADSP-SC594 and ADSP-SC598
by running 'top' on the serial console and repeatedly refreshing the
display. When the issue triggers, the userspace writer ('top') ends up
blocked in the tty write path, for example:
wait_woken
n_tty_write
file_tty_write
tty_write
vfs_write
ksys_write
To fix this issue, the driver should first advance xmit_fifo via
uart_xmit_advance() and only then evaluate whether uart_write_wakeup()
is needed based on the post completion FIFO state. Furthermore
drop the "if (!kfifo_is_empty(&tport->xmit_fifo)" check, since an empty
xmit_fifo after uart_xmit_advance() means the pending TX queue
has dropped to 0, which is still below WAKEUP_CHARS and is a
valid case for uart_write_wakeup().
Tested-by: Arturs Artamonovs <arturs.artamonovs@analog.com>
Fixes: eab94da ("serial: Add UART driver for SC5xx SoCs")
Signed-off-by: Qasim Ijaz <qasim.ijaz@analog.com>
In adi_uart4_serial_dma_tx(), the driver updates uart->port.icount.tx
manually and then calls uart_xmit_advance(&uart->port, uart->tx_count).
However, uart_xmit_advance() already advances the xmit_fifo TX queue and
accounts transmitted bytes into icount.tx, so the function counts each
completed DMA transfer twice.
Fix this by dropping the explicit icount.tx update and rely on uart_xmit_advance()
for TX accounting.
Fixes: eab94da ("serial: Add UART driver for SC5xx SoCs")
Signed-off-by: Qasim Ijaz qasim.ijaz@analog.com
PR Type
PR Checklist