summaryrefslogtreecommitdiffstats
path: root/drivers/media/cec/core/cec-adap.c
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2022-05-10 10:53:05 +0200
committerMauro Carvalho Chehab <mchehab@kernel.org>2022-05-13 11:29:39 +0200
commitf9222f8ca18bcb1d55dd749b493b29fd8092fb82 (patch)
tree5daa3437ae5b8a76fe4a678d8c0fd8a1ae59466a /drivers/media/cec/core/cec-adap.c
parente3891b36364e85914fcb7a535656695a67e876a7 (diff)
downloadlinux-f9222f8ca18bcb1d55dd749b493b29fd8092fb82.tar.bz2
media: cec-adap.c: drop activate_cnt, use state info instead
Using an activation counter to decide when the enable or disable the cec adapter is not the best approach and can lead to race conditions. Change this to determining the current status of the adapter, and enable or disable the adapter accordingly. It now only needs to be called whenever there is a chance that the state changes, and it can handle enabling/disabling monitoring as well if needed. This simplifies the code and it should be a more robust approach as well. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Diffstat (limited to 'drivers/media/cec/core/cec-adap.c')
-rw-r--r--drivers/media/cec/core/cec-adap.c152
1 files changed, 59 insertions, 93 deletions
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c
index 38c43a37133d..8bf91b5a7d0e 100644
--- a/drivers/media/cec/core/cec-adap.c
+++ b/drivers/media/cec/core/cec-adap.c
@@ -1574,47 +1574,59 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block)
}
/*
- * Helper functions to enable/disable the CEC adapter.
+ * Helper function to enable/disable the CEC adapter.
*
- * These functions are called with adap->lock held.
+ * This function is called with adap->lock held.
*/
-static int cec_activate_cnt_inc(struct cec_adapter *adap)
+static int cec_adap_enable(struct cec_adapter *adap)
{
- int ret;
+ bool enable;
+ int ret = 0;
+
+ enable = adap->monitor_all_cnt || adap->monitor_pin_cnt ||
+ adap->log_addrs.num_log_addrs;
+ if (adap->needs_hpd)
+ enable = enable && adap->phys_addr != CEC_PHYS_ADDR_INVALID;
- if (adap->activate_cnt++)
+ if (enable == adap->is_enabled)
return 0;
/* serialize adap_enable */
mutex_lock(&adap->devnode.lock);
- adap->last_initiator = 0xff;
- adap->transmit_in_progress = false;
- ret = call_op(adap, adap_enable, true);
- if (ret)
- adap->activate_cnt--;
+ if (enable) {
+ adap->last_initiator = 0xff;
+ adap->transmit_in_progress = false;
+ ret = adap->ops->adap_enable(adap, true);
+ if (!ret) {
+ /*
+ * Enable monitor-all/pin modes if needed. We warn, but
+ * continue if this fails as this is not a critical error.
+ */
+ if (adap->monitor_all_cnt)
+ WARN_ON(call_op(adap, adap_monitor_all_enable, true));
+ if (adap->monitor_pin_cnt)
+ WARN_ON(call_op(adap, adap_monitor_pin_enable, true));
+ }
+ } else {
+ /* Disable monitor-all/pin modes if needed (needs_hpd == 1) */
+ if (adap->monitor_all_cnt)
+ WARN_ON(call_op(adap, adap_monitor_all_enable, false));
+ if (adap->monitor_pin_cnt)
+ WARN_ON(call_op(adap, adap_monitor_pin_enable, false));
+ WARN_ON(adap->ops->adap_enable(adap, false));
+ adap->last_initiator = 0xff;
+ adap->transmit_in_progress = false;
+ adap->transmit_in_progress_aborted = false;
+ if (adap->transmitting)
+ cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED, 0);
+ }
+ if (!ret)
+ adap->is_enabled = enable;
+ wake_up_interruptible(&adap->kthread_waitq);
mutex_unlock(&adap->devnode.lock);
return ret;
}
-static void cec_activate_cnt_dec(struct cec_adapter *adap)
-{
- if (WARN_ON(!adap->activate_cnt))
- return;
-
- if (--adap->activate_cnt)
- return;
-
- /* serialize adap_enable */
- mutex_lock(&adap->devnode.lock);
- WARN_ON(call_op(adap, adap_enable, false));
- adap->last_initiator = 0xff;
- adap->transmit_in_progress = false;
- adap->transmit_in_progress_aborted = false;
- if (adap->transmitting)
- cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED, 0);
- mutex_unlock(&adap->devnode.lock);
-}
-
/* Set a new physical address and send an event notifying userspace of this.
*
* This function is called with adap->lock held.
@@ -1635,33 +1647,16 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
adap->phys_addr = CEC_PHYS_ADDR_INVALID;
cec_post_state_event(adap);
cec_adap_unconfigure(adap);
- if (becomes_invalid && adap->needs_hpd) {
- /* Disable monitor-all/pin modes if needed */
- if (adap->monitor_all_cnt)
- WARN_ON(call_op(adap, adap_monitor_all_enable, false));
- if (adap->monitor_pin_cnt)
- WARN_ON(call_op(adap, adap_monitor_pin_enable, false));
- cec_activate_cnt_dec(adap);
- wake_up_interruptible(&adap->kthread_waitq);
- }
- if (becomes_invalid)
+ if (becomes_invalid) {
+ cec_adap_enable(adap);
return;
- }
-
- if (is_invalid && adap->needs_hpd) {
- if (cec_activate_cnt_inc(adap))
- return;
- /*
- * Re-enable monitor-all/pin modes if needed. We warn, but
- * continue if this fails as this is not a critical error.
- */
- if (adap->monitor_all_cnt)
- WARN_ON(call_op(adap, adap_monitor_all_enable, true));
- if (adap->monitor_pin_cnt)
- WARN_ON(call_op(adap, adap_monitor_pin_enable, true));
+ }
}
adap->phys_addr = phys_addr;
+ if (is_invalid)
+ cec_adap_enable(adap);
+
cec_post_state_event(adap);
if (!adap->log_addrs.num_log_addrs)
return;
@@ -1722,6 +1717,7 @@ int __cec_s_log_addrs(struct cec_adapter *adap,
struct cec_log_addrs *log_addrs, bool block)
{
u16 type_mask = 0;
+ int err;
int i;
if (adap->devnode.unregistered)
@@ -1738,8 +1734,7 @@ int __cec_s_log_addrs(struct cec_adapter *adap,
adap->log_addrs.osd_name[0] = '\0';
adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE;
adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0;
- if (!adap->needs_hpd)
- cec_activate_cnt_dec(adap);
+ cec_adap_enable(adap);
return 0;
}
@@ -1873,17 +1868,12 @@ int __cec_s_log_addrs(struct cec_adapter *adap,
sizeof(log_addrs->features[i]));
}
- if (!adap->needs_hpd && !adap->is_configuring && !adap->is_configured) {
- int ret = cec_activate_cnt_inc(adap);
-
- if (ret)
- return ret;
- }
log_addrs->log_addr_mask = adap->log_addrs.log_addr_mask;
adap->log_addrs = *log_addrs;
- if (adap->phys_addr != CEC_PHYS_ADDR_INVALID)
+ err = cec_adap_enable(adap);
+ if (!err && adap->phys_addr != CEC_PHYS_ADDR_INVALID)
cec_claim_log_addrs(adap, block);
- return 0;
+ return err;
}
int cec_s_log_addrs(struct cec_adapter *adap,
@@ -2186,20 +2176,9 @@ int cec_monitor_all_cnt_inc(struct cec_adapter *adap)
if (adap->monitor_all_cnt++)
return 0;
- if (!adap->needs_hpd) {
- ret = cec_activate_cnt_inc(adap);
- if (ret) {
- adap->monitor_all_cnt--;
- return ret;
- }
- }
-
- ret = call_op(adap, adap_monitor_all_enable, true);
- if (ret) {
+ ret = cec_adap_enable(adap);
+ if (ret)
adap->monitor_all_cnt--;
- if (!adap->needs_hpd)
- cec_activate_cnt_dec(adap);
- }
return ret;
}
@@ -2210,8 +2189,7 @@ void cec_monitor_all_cnt_dec(struct cec_adapter *adap)
if (--adap->monitor_all_cnt)
return;
WARN_ON(call_op(adap, adap_monitor_all_enable, false));
- if (!adap->needs_hpd)
- cec_activate_cnt_dec(adap);
+ cec_adap_enable(adap);
}
/*
@@ -2226,20 +2204,9 @@ int cec_monitor_pin_cnt_inc(struct cec_adapter *adap)
if (adap->monitor_pin_cnt++)
return 0;
- if (!adap->needs_hpd) {
- ret = cec_activate_cnt_inc(adap);
- if (ret) {
- adap->monitor_pin_cnt--;
- return ret;
- }
- }
-
- ret = call_op(adap, adap_monitor_pin_enable, true);
- if (ret) {
+ ret = cec_adap_enable(adap);
+ if (ret)
adap->monitor_pin_cnt--;
- if (!adap->needs_hpd)
- cec_activate_cnt_dec(adap);
- }
return ret;
}
@@ -2250,8 +2217,7 @@ void cec_monitor_pin_cnt_dec(struct cec_adapter *adap)
if (--adap->monitor_pin_cnt)
return;
WARN_ON(call_op(adap, adap_monitor_pin_enable, false));
- if (!adap->needs_hpd)
- cec_activate_cnt_dec(adap);
+ cec_adap_enable(adap);
}
#ifdef CONFIG_DEBUG_FS
@@ -2265,7 +2231,7 @@ int cec_adap_status(struct seq_file *file, void *priv)
struct cec_data *data;
mutex_lock(&adap->lock);
- seq_printf(file, "activation count: %u\n", adap->activate_cnt);
+ seq_printf(file, "enabled: %d\n", adap->is_enabled);
seq_printf(file, "configured: %d\n", adap->is_configured);
seq_printf(file, "configuring: %d\n", adap->is_configuring);
seq_printf(file, "phys_addr: %x.%x.%x.%x\n",