lkml.org 
[lkml]   [2022]   [Jan]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 029/563] media: cec-pin: fix interrupt en/disable handling
    Date
    From: Hans Verkuil <hverkuil-cisco@xs4all.nl>

    commit 713bdfa10b5957053811470d298def9537d9ff13 upstream.

    The en/disable_irq() functions keep track of the 'depth': i.e. if
    interrupts are disabled twice, then it needs to enable_irq() calls to
    enable them again. The cec-pin framework didn't take this into accound
    and could disable irqs multiple times, and it expected that a single
    enable_irq() would enable them again.

    Move all calls to en/disable_irq() to the kthread where it is easy
    to keep track of the current irq state and ensure that multiple
    en/disable_irq calls never happen.

    If interrupts where disabled twice, then they would never turn on
    again, leaving the CEC adapter in a dead state.

    Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
    Fixes: 865463fc03ed (media: cec-pin: add error injection support)
    Cc: <stable@vger.kernel.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/media/cec/core/cec-pin.c | 31 ++++++++++++++++++-------------
    1 file changed, 18 insertions(+), 13 deletions(-)

    --- 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 *_ad
    {
    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 *_ad
    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 *_ad
    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;
    }

    @@ -1130,13 +1144,7 @@ static int cec_pin_adap_enable(struct ce
    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 +1165,8 @@ void cec_pin_start_timer(struct cec_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,

    \
     
     \ /
      Last update: 2022-01-24 22:09    [W:4.083 / U:0.764 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site