media: cec-adap.c: fix is_configuring state
authorHans Verkuil <hverkuil-cisco@xs4all.nl>
Fri, 6 May 2022 07:43:25 +0000 (09:43 +0200)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Fri, 13 May 2022 09:28:54 +0000 (11:28 +0200)
If an adapter is trying to claim a free logical address then it is
in the 'is_configuring' state. If during that process the cable is
disconnected (HPD goes low, which in turn invalidates the physical
address), then cec_adap_unconfigure() is called, and that set the
is_configuring boolean to false, even though the thread that's
trying to claim an LA is still running.

Don't touch the is_configuring bool in cec_adap_unconfigure(), it
will eventually be cleared by the thread. By making that change
the cec_config_log_addr() function also had to change: it was
aborting if is_configuring became false (since that is what
cec_adap_unconfigure() did), but that no longer works. Instead
check if the physical address is invalid. That is a much
more appropriate check anyway.

This fixes a bug where the the adapter could be disabled even
though the device was still configuring. This could cause POLL
transmits to time out.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
drivers/media/cec/core/cec-adap.c

index 004121e..6c23550 100644 (file)
@@ -1275,7 +1275,7 @@ static int cec_config_log_addr(struct cec_adapter *adap,
                 * While trying to poll the physical address was reset
                 * and the adapter was unconfigured, so bail out.
                 */
-               if (!adap->is_configuring)
+               if (adap->phys_addr == CEC_PHYS_ADDR_INVALID)
                        return -EINTR;
 
                if (err)
@@ -1332,7 +1332,6 @@ static void cec_adap_unconfigure(struct cec_adapter *adap)
        if (!adap->needs_hpd || adap->phys_addr != CEC_PHYS_ADDR_INVALID)
                WARN_ON(call_op(adap, adap_log_addr, CEC_LOG_ADDR_INVALID));
        adap->log_addrs.log_addr_mask = 0;
-       adap->is_configuring = false;
        adap->is_configured = false;
        cec_flush(adap);
        wake_up_interruptible(&adap->kthread_waitq);
@@ -1526,9 +1525,10 @@ unconfigure:
        for (i = 0; i < las->num_log_addrs; i++)
                las->log_addr[i] = CEC_LOG_ADDR_INVALID;
        cec_adap_unconfigure(adap);
+       adap->is_configuring = false;
        adap->kthread_config = NULL;
-       mutex_unlock(&adap->lock);
        complete(&adap->config_completion);
+       mutex_unlock(&adap->lock);
        return 0;
 }