diff options
Diffstat (limited to 'drivers/media/cec')
-rw-r--r-- | drivers/media/cec/core/cec-adap.c | 46 | ||||
-rw-r--r-- | drivers/media/cec/core/cec-api.c | 8 | ||||
-rw-r--r-- | drivers/media/cec/core/cec-core.c | 3 | ||||
-rw-r--r-- | drivers/media/cec/core/cec-pin-priv.h | 1 | ||||
-rw-r--r-- | drivers/media/cec/core/cec-pin.c | 32 |
5 files changed, 56 insertions, 34 deletions
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index cd9cb354dc2c..2e12331c12a9 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -161,10 +161,10 @@ static void cec_queue_event(struct cec_adapter *adap, u64 ts = ktime_get_ns(); struct cec_fh *fh; - mutex_lock(&adap->devnode.lock); + mutex_lock(&adap->devnode.lock_fhs); list_for_each_entry(fh, &adap->devnode.fhs, list) cec_queue_event_fh(fh, ev, ts); - mutex_unlock(&adap->devnode.lock); + mutex_unlock(&adap->devnode.lock_fhs); } /* Notify userspace that the CEC pin changed state at the given time. */ @@ -178,11 +178,12 @@ void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, }; struct cec_fh *fh; - mutex_lock(&adap->devnode.lock); - list_for_each_entry(fh, &adap->devnode.fhs, list) + mutex_lock(&adap->devnode.lock_fhs); + list_for_each_entry(fh, &adap->devnode.fhs, list) { if (fh->mode_follower == CEC_MODE_MONITOR_PIN) cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); - mutex_unlock(&adap->devnode.lock); + } + mutex_unlock(&adap->devnode.lock_fhs); } EXPORT_SYMBOL_GPL(cec_queue_pin_cec_event); @@ -195,10 +196,10 @@ void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts) }; struct cec_fh *fh; - mutex_lock(&adap->devnode.lock); + mutex_lock(&adap->devnode.lock_fhs); list_for_each_entry(fh, &adap->devnode.fhs, list) cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); - mutex_unlock(&adap->devnode.lock); + mutex_unlock(&adap->devnode.lock_fhs); } EXPORT_SYMBOL_GPL(cec_queue_pin_hpd_event); @@ -211,10 +212,10 @@ void cec_queue_pin_5v_event(struct cec_adapter *adap, bool is_high, ktime_t ts) }; struct cec_fh *fh; - mutex_lock(&adap->devnode.lock); + mutex_lock(&adap->devnode.lock_fhs); list_for_each_entry(fh, &adap->devnode.fhs, list) cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); - mutex_unlock(&adap->devnode.lock); + mutex_unlock(&adap->devnode.lock_fhs); } EXPORT_SYMBOL_GPL(cec_queue_pin_5v_event); @@ -286,12 +287,12 @@ static void cec_queue_msg_monitor(struct cec_adapter *adap, u32 monitor_mode = valid_la ? CEC_MODE_MONITOR : CEC_MODE_MONITOR_ALL; - mutex_lock(&adap->devnode.lock); + mutex_lock(&adap->devnode.lock_fhs); list_for_each_entry(fh, &adap->devnode.fhs, list) { if (fh->mode_follower >= monitor_mode) cec_queue_msg_fh(fh, msg); } - mutex_unlock(&adap->devnode.lock); + mutex_unlock(&adap->devnode.lock_fhs); } /* @@ -302,12 +303,12 @@ static void cec_queue_msg_followers(struct cec_adapter *adap, { struct cec_fh *fh; - mutex_lock(&adap->devnode.lock); + mutex_lock(&adap->devnode.lock_fhs); list_for_each_entry(fh, &adap->devnode.fhs, list) { if (fh->mode_follower == CEC_MODE_FOLLOWER) cec_queue_msg_fh(fh, msg); } - mutex_unlock(&adap->devnode.lock); + mutex_unlock(&adap->devnode.lock_fhs); } /* Notify userspace of an adapter state change. */ @@ -342,7 +343,7 @@ static void cec_data_completed(struct cec_data *data) * Without that we would be referring to a closed filehandle. */ if (data->fh) - list_del(&data->xfer_list); + list_del_init(&data->xfer_list); if (data->blocking) { /* @@ -898,6 +899,8 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, if (fh) list_add_tail(&data->xfer_list, &fh->xfer_list); + else + INIT_LIST_HEAD(&data->xfer_list); list_add_tail(&data->list, &adap->transmit_queue); adap->transmit_queue_sz++; @@ -923,6 +926,10 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, /* The transmit completed (possibly with an error) */ *msg = data->msg; + if (WARN_ON(!list_empty(&data->list))) + list_del(&data->list); + if (WARN_ON(!list_empty(&data->xfer_list))) + list_del(&data->xfer_list); kfree(data); return 0; } @@ -1573,6 +1580,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) /* Disabling monitor all mode should always succeed */ if (adap->monitor_all_cnt) WARN_ON(call_op(adap, adap_monitor_all_enable, false)); + /* serialize adap_enable */ mutex_lock(&adap->devnode.lock); if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) { WARN_ON(adap->ops->adap_enable(adap, false)); @@ -1584,14 +1592,16 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) return; } + /* serialize adap_enable */ mutex_lock(&adap->devnode.lock); adap->last_initiator = 0xff; adap->transmit_in_progress = false; - if ((adap->needs_hpd || list_empty(&adap->devnode.fhs)) && - adap->ops->adap_enable(adap, true)) { - mutex_unlock(&adap->devnode.lock); - return; + if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) { + if (adap->ops->adap_enable(adap, true)) { + mutex_unlock(&adap->devnode.lock); + return; + } } if (adap->monitor_all_cnt && diff --git a/drivers/media/cec/core/cec-api.c b/drivers/media/cec/core/cec-api.c index 769e6b4cddce..d72ad48c9898 100644 --- a/drivers/media/cec/core/cec-api.c +++ b/drivers/media/cec/core/cec-api.c @@ -586,6 +586,7 @@ static int cec_open(struct inode *inode, struct file *filp) return err; } + /* serialize adap_enable */ mutex_lock(&devnode->lock); if (list_empty(&devnode->fhs) && !adap->needs_hpd && @@ -624,7 +625,9 @@ static int cec_open(struct inode *inode, struct file *filp) } #endif + mutex_lock(&devnode->lock_fhs); list_add(&fh->list, &devnode->fhs); + mutex_unlock(&devnode->lock_fhs); mutex_unlock(&devnode->lock); return 0; @@ -653,8 +656,11 @@ static int cec_release(struct inode *inode, struct file *filp) cec_monitor_all_cnt_dec(adap); mutex_unlock(&adap->lock); + /* serialize adap_enable */ mutex_lock(&devnode->lock); + mutex_lock(&devnode->lock_fhs); list_del(&fh->list); + mutex_unlock(&devnode->lock_fhs); if (cec_is_registered(adap) && list_empty(&devnode->fhs) && !adap->needs_hpd && adap->phys_addr == CEC_PHYS_ADDR_INVALID) { WARN_ON(adap->ops->adap_enable(adap, false)); @@ -669,7 +675,7 @@ static int cec_release(struct inode *inode, struct file *filp) data->blocking = false; data->fh = NULL; - list_del(&data->xfer_list); + list_del_init(&data->xfer_list); } mutex_unlock(&adap->lock); while (!list_empty(&fh->msgs)) { diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index 7322e7cd9753..a3ab6a43fb14 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -169,8 +169,10 @@ static void cec_devnode_unregister(struct cec_adapter *adap) devnode->registered = false; devnode->unregistered = true; + mutex_lock(&devnode->lock_fhs); list_for_each_entry(fh, &devnode->fhs, list) wake_up_interruptible(&fh->wait); + mutex_unlock(&devnode->lock_fhs); mutex_unlock(&devnode->lock); @@ -272,6 +274,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, /* adap->devnode initialization */ INIT_LIST_HEAD(&adap->devnode.fhs); + mutex_init(&adap->devnode.lock_fhs); mutex_init(&adap->devnode.lock); adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name); diff --git a/drivers/media/cec/core/cec-pin-priv.h b/drivers/media/cec/core/cec-pin-priv.h index fb101f15865c..7bad5a0b7cb7 100644 --- a/drivers/media/cec/core/cec-pin-priv.h +++ b/drivers/media/cec/core/cec-pin-priv.h @@ -170,7 +170,6 @@ struct cec_pin { ktime_t ts; unsigned int wait_usecs; u16 la_mask; - bool enabled; bool monitor_all; bool rx_eom; bool enable_irq_failed; diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c index a60b6f03a6a1..21f0f749713e 100644 --- a/drivers/media/cec/core/cec-pin.c +++ b/drivers/media/cec/core/cec-pin.c @@ -1033,6 +1033,7 @@ static int cec_pin_thread_func(void *_adap) { struct cec_adapter *adap = _adap; struct cec_pin *pin = adap->pin; + bool irq_enabled = false; for (;;) { wait_event_interruptible(pin->kthread_waitq, @@ -1060,6 +1061,7 @@ static int cec_pin_thread_func(void *_adap) ns_to_ktime(pin->work_rx_msg.rx_ts)); msg->len = 0; } + if (pin->work_tx_status) { unsigned int tx_status = pin->work_tx_status; @@ -1083,27 +1085,39 @@ static int cec_pin_thread_func(void *_adap) switch (atomic_xchg(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED)) { case CEC_PIN_IRQ_DISABLE: - pin->ops->disable_irq(adap); + if (irq_enabled) { + pin->ops->disable_irq(adap); + irq_enabled = false; + } cec_pin_high(pin); cec_pin_to_idle(pin); hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); break; case CEC_PIN_IRQ_ENABLE: + if (irq_enabled) + break; pin->enable_irq_failed = !pin->ops->enable_irq(adap); if (pin->enable_irq_failed) { cec_pin_to_idle(pin); hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); + } else { + irq_enabled = true; } break; default: break; } - if (kthread_should_stop()) break; } + if (pin->ops->disable_irq && irq_enabled) + pin->ops->disable_irq(adap); + hrtimer_cancel(&pin->timer); + cec_pin_read(pin); + cec_pin_to_idle(pin); + pin->state = CEC_ST_OFF; return 0; } @@ -1111,7 +1125,6 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable) { struct cec_pin *pin = adap->pin; - pin->enabled = enable; if (enable) { atomic_set(&pin->work_pin_num_events, 0); pin->work_pin_events_rd = pin->work_pin_events_wr = 0; @@ -1130,13 +1143,7 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable) hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); } else { - if (pin->ops->disable_irq) - pin->ops->disable_irq(adap); - hrtimer_cancel(&pin->timer); kthread_stop(pin->kthread); - cec_pin_read(pin); - cec_pin_to_idle(pin); - pin->state = CEC_ST_OFF; } return 0; } @@ -1157,11 +1164,8 @@ void cec_pin_start_timer(struct cec_pin *pin) if (pin->state != CEC_ST_RX_IRQ) return; - atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED); - pin->ops->disable_irq(pin->adap); - cec_pin_high(pin); - cec_pin_to_idle(pin); - hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); + atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_DISABLE); + wake_up_interruptible(&pin->kthread_waitq); } static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts, |