lkml.org 
[lkml]   [2021]   [Sep]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 128/236] soc: qcom: smsm: Fix missed interrupts if state changes while masked
    Date
    From: Stephan Gerhold <stephan@gerhold.net>

    [ Upstream commit e3d4571955050736bbf3eda0a9538a09d9fcfce8 ]

    The SMSM driver detects interrupt edges by tracking the last state
    it has seen (and has triggered the interrupt handler for). This works
    fine, but only if the interrupt does not change state while masked.

    For example, if an interrupt is unmasked while the state is HIGH,
    the stored last_value for that interrupt might still be LOW. Then,
    when the remote processor triggers smsm_intr() we assume that nothing
    has changed, even though the state might have changed from HIGH to LOW.

    Attempt to fix this by checking the current remote state before
    unmasking an IRQ. Use atomic operations to avoid the interrupt handler
    from interfering with the unmask function.

    This fixes modem crashes in some edge cases with the BAM-DMUX driver.
    Specifically, the BAM-DMUX interrupt handler is not called for the
    HIGH -> LOW smsm state transition if the BAM-DMUX driver is loaded
    (and therefore unmasks the interrupt) after the modem was already started:

    qcom-q6v5-mss 4080000.remoteproc: fatal error received: a2_task.c:3188:
    Assert FALSE failed: A2 DL PER deadlock timer expired waiting for Apps ACK

    Fixes: c97c4090ff72 ("soc: qcom: smsm: Add driver for Qualcomm SMSM")
    Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
    Link: https://lore.kernel.org/r/20210712135703.324748-2-stephan@gerhold.net
    Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/soc/qcom/smsm.c | 11 ++++++++---
    1 file changed, 8 insertions(+), 3 deletions(-)

    diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c
    index 70c3c90b997c..c428d0f78816 100644
    --- a/drivers/soc/qcom/smsm.c
    +++ b/drivers/soc/qcom/smsm.c
    @@ -109,7 +109,7 @@ struct smsm_entry {
    DECLARE_BITMAP(irq_enabled, 32);
    DECLARE_BITMAP(irq_rising, 32);
    DECLARE_BITMAP(irq_falling, 32);
    - u32 last_value;
    + unsigned long last_value;

    u32 *remote_state;
    u32 *subscription;
    @@ -204,8 +204,7 @@ static irqreturn_t smsm_intr(int irq, void *data)
    u32 val;

    val = readl(entry->remote_state);
    - changed = val ^ entry->last_value;
    - entry->last_value = val;
    + changed = val ^ xchg(&entry->last_value, val);

    for_each_set_bit(i, entry->irq_enabled, 32) {
    if (!(changed & BIT(i)))
    @@ -266,6 +265,12 @@ static void smsm_unmask_irq(struct irq_data *irqd)
    struct qcom_smsm *smsm = entry->smsm;
    u32 val;

    + /* Make sure our last cached state is up-to-date */
    + if (readl(entry->remote_state) & BIT(irq))
    + set_bit(irq, &entry->last_value);
    + else
    + clear_bit(irq, &entry->last_value);
    +
    set_bit(irq, entry->irq_enabled);

    if (entry->subscription) {
    --
    2.30.2


    \
     
     \ /
      Last update: 2021-09-13 15:43    [W:4.058 / U:0.044 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site