Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

media: cec: check 'transmit_in_progress', not 'transmitting'

Currently wait_event_interruptible_timeout is called in cec_thread_func()
when adap->transmitting is set. But if the adapter is unconfigured
while transmitting, then adap->transmitting is set to NULL. But the
hardware is still actually transmitting the message, and that's
indicated by adap->transmit_in_progress and we should wait until that
is finished or times out before transmitting new messages.

As the original commit says: adap->transmitting is the userspace view,
adap->transmit_in_progress reflects the hardware state.

However, if adap->transmitting is NULL and adap->transmit_in_progress
is true, then wait_event_interruptible is called (no timeout), which
can get stuck indefinitely if the CEC driver is flaky and never marks
the transmit-in-progress as 'done'.

So test against transmit_in_progress when deciding whether to use
the timeout variant or not, instead of testing against adap->transmitting.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Fixes: 32804fcb612b ("media: cec: keep track of outstanding transmits")
Cc: <stable@vger.kernel.org> # for v4.19 and up
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
ac479b51 95c29d46

+12 -8
+12 -8
drivers/media/cec/cec-adap.c
··· 465 465 bool timeout = false; 466 466 u8 attempts; 467 467 468 - if (adap->transmitting) { 468 + if (adap->transmit_in_progress) { 469 469 int err; 470 470 471 471 /* ··· 500 500 goto unlock; 501 501 } 502 502 503 - if (adap->transmitting && timeout) { 503 + if (adap->transmit_in_progress && timeout) { 504 504 /* 505 505 * If we timeout, then log that. Normally this does 506 506 * not happen and it is an indication of a faulty CEC ··· 509 509 * so much traffic on the bus that the adapter was 510 510 * unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s). 511 511 */ 512 - pr_warn("cec-%s: message %*ph timed out\n", adap->name, 513 - adap->transmitting->msg.len, 514 - adap->transmitting->msg.msg); 512 + if (adap->transmitting) { 513 + pr_warn("cec-%s: message %*ph timed out\n", adap->name, 514 + adap->transmitting->msg.len, 515 + adap->transmitting->msg.msg); 516 + /* Just give up on this. */ 517 + cec_data_cancel(adap->transmitting, 518 + CEC_TX_STATUS_TIMEOUT); 519 + } else { 520 + pr_warn("cec-%s: transmit timed out\n", adap->name); 521 + } 515 522 adap->transmit_in_progress = false; 516 523 adap->tx_timeouts++; 517 - /* Just give up on this. */ 518 - cec_data_cancel(adap->transmitting, 519 - CEC_TX_STATUS_TIMEOUT); 520 524 goto unlock; 521 525 } 522 526