In interrupt mode when tb_ring_poll_complete() is called it is possible
that a frame was completed right before the ring interrupt was unmasked
in which case there will be no interrupt and the task starts sleeping.
Avoid this and check if there is anything completed prior putting the
task to sleep. The same can happen with poll() so check the ring there
too before reporting that there is nothing to read.
Assisted-by: LLM
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/stream.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/thunderbolt/stream.c b/drivers/thunderbolt/stream.c
index b4f3b1db9d82..e2b4896dfafb 100644
--- a/drivers/thunderbolt/stream.c
+++ b/drivers/thunderbolt/stream.c
@@ -799,6 +799,7 @@ tbstream_dev_fops_read_iter(struct kiocb *kiocb, struct iov_iter *to)
} else {
ret = wait_event_interruptible(sdev->wait,
READ_ONCE(sdev->rx_pending) ||
+ tb_ring_poll_pending(sdev->rx_ring.ring) ||
tbstream_ring_available(&sdev->rx_ring) ||
tbstream_dev_valid(sdev) != 0 ||
tbstream_dev_closed(sdev) ||@@ -977,10 +978,13 @@ tbstream_dev_fops_poll(struct file *file, struct poll_table_struct *wait)
if (tbstream_ring_available(&sdev->tx_ring))
mask |= EPOLLOUT | EPOLLWRNORM;
- if (tbstream_ring_available(&sdev->rx_ring))
+ if (tbstream_ring_available(&sdev->rx_ring)) {
mask |= EPOLLIN | EPOLLRDNORM;
- else
+ } else {
tbstream_dev_complete_rx(sdev);
+ if (tb_ring_poll_pending(sdev->rx_ring.ring))
+ mask |= EPOLLIN | EPOLLRDNORM;
+ }
return mask;
}--
2.50.1