From a93a8e3200002f0c345fec4c340390e9a60aabc7 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 18 Sep 2026 09:19:29 +0300 Subject: [PATCH] thunderbolt: stream: Make read return framing error to the userspace If any of the frames are corrupted during the receive we currently log a warning and pass them to the userspace without it knowing they were corrupted. Make the driver behave better and return an error (-EIO) to the userspace in that case. For the CLOSE packet, payload does not matter so we handle it the usual way. Reviewed-by: Ivy Lopez Signed-off-by: Mika Westerberg --- drivers/thunderbolt/stream.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/thunderbolt/stream.c b/drivers/thunderbolt/stream.c index 8a1e06148a14..fe88341c4e29 100644 --- a/drivers/thunderbolt/stream.c +++ b/drivers/thunderbolt/stream.c @@ -375,6 +375,7 @@ tbstream_dev_rx_callback(struct tb_ring *ring, struct ring_frame *frame, { struct tbstream_frame *sf = container_of(frame, typeof(*sf), frame); struct tbstream_dev *sdev = sf->sdev; + __poll_t mask; if (canceled) return; @@ -382,19 +383,17 @@ tbstream_dev_rx_callback(struct tb_ring *ring, struct ring_frame *frame, sf->completed = true; sdev->rx_ring.prod++; - if (sf->frame.flags & RING_DESC_CRC_ERROR) { - pr_warn("RX CRC error\n"); - } else if (sf->frame.flags & RING_DESC_BUFFER_OVERRUN) { - pr_warn("RX buffer overrun\n"); - } else { - __poll_t mask = EPOLLIN | EPOLLRDNORM; - - if (sf->frame.eof == TBSTREAM_CLOSE) { - WRITE_ONCE(sdev->close_received, true); - mask |= EPOLLHUP; - } - wake_up_interruptible_poll(&sdev->wait, mask); + mask = EPOLLIN | EPOLLRDNORM; + /* + * The CLOSE packet does not have a payload so the flags do not + * matter. The read_iter() deals with the flags. + */ + if (sf->frame.eof == TBSTREAM_CLOSE) { + WRITE_ONCE(sdev->close_received, true); + mask |= EPOLLHUP; } + + wake_up_interruptible_poll(&sdev->wait, mask); } static struct tbstream_frame * @@ -877,6 +876,19 @@ tbstream_dev_fops_read_iter(struct kiocb *kiocb, struct iov_iter *to) WRITE_ONCE(sdev->closed, true); } break; + } else if (sf->frame.flags & + (RING_DESC_CRC_ERROR | RING_DESC_BUFFER_OVERRUN)) { + /* + * If something was already read return that now + * and next read will report the error. + */ + if (!nbytes) { + pr_warn("corrupted frame received, flags %#x\n", + sf->frame.flags); + tbstream_dev_consume_rx(sdev); + ret = -EIO; + } + break; } sf_size = tb_ring_frame_size(&sf->frame);