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 <skunkolee@gmail.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
Mika Westerberg 2026-09-18 09:19:29 +03:00
parent 5ef3b5a4ea
commit a93a8e3200

View File

@ -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);