linux/drivers/net/ipa/ipa_smp2p.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
   4 * Copyright (C) 2019-2020 Linaro Ltd.
   5 */
   6
   7#include <linux/types.h>
   8#include <linux/device.h>
   9#include <linux/interrupt.h>
  10#include <linux/notifier.h>
  11#include <linux/panic_notifier.h>
  12#include <linux/pm_runtime.h>
  13#include <linux/soc/qcom/smem.h>
  14#include <linux/soc/qcom/smem_state.h>
  15
  16#include "ipa_smp2p.h"
  17#include "ipa.h"
  18#include "ipa_uc.h"
  19
  20/**
  21 * DOC: IPA SMP2P communication with the modem
  22 *
  23 * SMP2P is a primitive communication mechanism available between the AP and
  24 * the modem.  The IPA driver uses this for two purposes:  to enable the modem
  25 * to state that the GSI hardware is ready to use; and to communicate the
  26 * state of IPA power in the event of a crash.
  27 *
  28 * GSI needs to have early initialization completed before it can be used.
  29 * This initialization is done either by Trust Zone or by the modem.  In the
  30 * latter case, the modem uses an SMP2P interrupt to tell the AP IPA driver
  31 * when the GSI is ready to use.
  32 *
  33 * The modem is also able to inquire about the current state of IPA
  34 * power by trigging another SMP2P interrupt to the AP.  We communicate
  35 * whether power is enabled using two SMP2P state bits--one to indicate
  36 * the power state (on or off), and a second to indicate the power state
  37 * bit is valid.  The modem will poll the valid bit until it is set, and
  38 * at that time records whether the AP has IPA power enabled.
  39 *
  40 * Finally, if the AP kernel panics, we update the SMP2P state bits even if
  41 * we never receive an interrupt from the modem requesting this.
  42 */
  43
  44/**
  45 * struct ipa_smp2p - IPA SMP2P information
  46 * @ipa:                IPA pointer
  47 * @valid_state:        SMEM state indicating enabled state is valid
  48 * @enabled_state:      SMEM state to indicate power is enabled
  49 * @valid_bit:          Valid bit in 32-bit SMEM state mask
  50 * @enabled_bit:        Enabled bit in 32-bit SMEM state mask
  51 * @enabled_bit:        Enabled bit in 32-bit SMEM state mask
  52 * @clock_query_irq:    IPA interrupt triggered by modem for power query
  53 * @setup_ready_irq:    IPA interrupt triggered by modem to signal GSI ready
  54 * @power_on:           Whether IPA power is on
  55 * @notified:           Whether modem has been notified of power state
  56 * @disabled:           Whether setup ready interrupt handling is disabled
  57 * @mutex:              Mutex protecting ready-interrupt/shutdown interlock
  58 * @panic_notifier:     Panic notifier structure
  59*/
  60struct ipa_smp2p {
  61        struct ipa *ipa;
  62        struct qcom_smem_state *valid_state;
  63        struct qcom_smem_state *enabled_state;
  64        u32 valid_bit;
  65        u32 enabled_bit;
  66        u32 clock_query_irq;
  67        u32 setup_ready_irq;
  68        bool power_on;
  69        bool notified;
  70        bool disabled;
  71        struct mutex mutex;
  72        struct notifier_block panic_notifier;
  73};
  74
  75/**
  76 * ipa_smp2p_notify() - use SMP2P to tell modem about IPA power state
  77 * @smp2p:      SMP2P information
  78 *
  79 * This is called either when the modem has requested it (by triggering
  80 * the modem power query IPA interrupt) or whenever the AP is shutting down
  81 * (via a panic notifier).  It sets the two SMP2P state bits--one saying
  82 * whether the IPA power is on, and the other indicating the first bit
  83 * is valid.
  84 */
  85static void ipa_smp2p_notify(struct ipa_smp2p *smp2p)
  86{
  87        struct device *dev;
  88        u32 value;
  89        u32 mask;
  90
  91        if (smp2p->notified)
  92                return;
  93
  94        dev = &smp2p->ipa->pdev->dev;
  95        smp2p->power_on = pm_runtime_get_if_active(dev, true) > 0;
  96
  97        /* Signal whether the IPA power is enabled */
  98        mask = BIT(smp2p->enabled_bit);
  99        value = smp2p->power_on ? mask : 0;
 100        qcom_smem_state_update_bits(smp2p->enabled_state, mask, value);
 101
 102        /* Now indicate that the enabled flag is valid */
 103        mask = BIT(smp2p->valid_bit);
 104        value = mask;
 105        qcom_smem_state_update_bits(smp2p->valid_state, mask, value);
 106
 107        smp2p->notified = true;
 108}
 109
 110/* Threaded IRQ handler for modem "ipa-clock-query" SMP2P interrupt */
 111static irqreturn_t ipa_smp2p_modem_clk_query_isr(int irq, void *dev_id)
 112{
 113        struct ipa_smp2p *smp2p = dev_id;
 114
 115        ipa_smp2p_notify(smp2p);
 116
 117        return IRQ_HANDLED;
 118}
 119
 120static int ipa_smp2p_panic_notifier(struct notifier_block *nb,
 121                                    unsigned long action, void *data)
 122{
 123        struct ipa_smp2p *smp2p;
 124
 125        smp2p = container_of(nb, struct ipa_smp2p, panic_notifier);
 126
 127        ipa_smp2p_notify(smp2p);
 128
 129        if (smp2p->power_on)
 130                ipa_uc_panic_notifier(smp2p->ipa);
 131
 132        return NOTIFY_DONE;
 133}
 134
 135static int ipa_smp2p_panic_notifier_register(struct ipa_smp2p *smp2p)
 136{
 137        /* IPA panic handler needs to run before modem shuts down */
 138        smp2p->panic_notifier.notifier_call = ipa_smp2p_panic_notifier;
 139        smp2p->panic_notifier.priority = INT_MAX;       /* Do it early */
 140
 141        return atomic_notifier_chain_register(&panic_notifier_list,
 142                                              &smp2p->panic_notifier);
 143}
 144
 145static void ipa_smp2p_panic_notifier_unregister(struct ipa_smp2p *smp2p)
 146{
 147        atomic_notifier_chain_unregister(&panic_notifier_list,
 148                                         &smp2p->panic_notifier);
 149}
 150
 151/* Threaded IRQ handler for modem "ipa-setup-ready" SMP2P interrupt */
 152static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
 153{
 154        struct ipa_smp2p *smp2p = dev_id;
 155        struct device *dev;
 156        int ret;
 157
 158        mutex_lock(&smp2p->mutex);
 159
 160        if (smp2p->disabled)
 161                goto out_mutex_unlock;
 162        smp2p->disabled = true;         /* If any others arrive, ignore them */
 163
 164        /* Power needs to be active for setup */
 165        dev = &smp2p->ipa->pdev->dev;
 166        ret = pm_runtime_get_sync(dev);
 167        if (ret < 0) {
 168                dev_err(dev, "error %d getting power for setup\n", ret);
 169                goto out_power_put;
 170        }
 171
 172        /* An error here won't cause driver shutdown, so warn if one occurs */
 173        ret = ipa_setup(smp2p->ipa);
 174        WARN(ret != 0, "error %d from ipa_setup()\n", ret);
 175
 176out_power_put:
 177        pm_runtime_mark_last_busy(dev);
 178        (void)pm_runtime_put_autosuspend(dev);
 179out_mutex_unlock:
 180        mutex_unlock(&smp2p->mutex);
 181
 182        return IRQ_HANDLED;
 183}
 184
 185/* Initialize SMP2P interrupts */
 186static int ipa_smp2p_irq_init(struct ipa_smp2p *smp2p, const char *name,
 187                              irq_handler_t handler)
 188{
 189        struct device *dev = &smp2p->ipa->pdev->dev;
 190        unsigned int irq;
 191        int ret;
 192
 193        ret = platform_get_irq_byname(smp2p->ipa->pdev, name);
 194        if (ret <= 0)
 195                return ret ? : -EINVAL;
 196        irq = ret;
 197
 198        ret = request_threaded_irq(irq, NULL, handler, 0, name, smp2p);
 199        if (ret) {
 200                dev_err(dev, "error %d requesting \"%s\" IRQ\n", ret, name);
 201                return ret;
 202        }
 203
 204        return irq;
 205}
 206
 207static void ipa_smp2p_irq_exit(struct ipa_smp2p *smp2p, u32 irq)
 208{
 209        free_irq(irq, smp2p);
 210}
 211
 212/* Drop the power reference if it was taken in ipa_smp2p_notify() */
 213static void ipa_smp2p_power_release(struct ipa *ipa)
 214{
 215        struct device *dev = &ipa->pdev->dev;
 216
 217        if (!ipa->smp2p->power_on)
 218                return;
 219
 220        pm_runtime_mark_last_busy(dev);
 221        (void)pm_runtime_put_autosuspend(dev);
 222        ipa->smp2p->power_on = false;
 223}
 224
 225/* Initialize the IPA SMP2P subsystem */
 226int ipa_smp2p_init(struct ipa *ipa, bool modem_init)
 227{
 228        struct qcom_smem_state *enabled_state;
 229        struct device *dev = &ipa->pdev->dev;
 230        struct qcom_smem_state *valid_state;
 231        struct ipa_smp2p *smp2p;
 232        u32 enabled_bit;
 233        u32 valid_bit;
 234        int ret;
 235
 236        valid_state = qcom_smem_state_get(dev, "ipa-clock-enabled-valid",
 237                                          &valid_bit);
 238        if (IS_ERR(valid_state))
 239                return PTR_ERR(valid_state);
 240        if (valid_bit >= 32)            /* BITS_PER_U32 */
 241                return -EINVAL;
 242
 243        enabled_state = qcom_smem_state_get(dev, "ipa-clock-enabled",
 244                                            &enabled_bit);
 245        if (IS_ERR(enabled_state))
 246                return PTR_ERR(enabled_state);
 247        if (enabled_bit >= 32)          /* BITS_PER_U32 */
 248                return -EINVAL;
 249
 250        smp2p = kzalloc(sizeof(*smp2p), GFP_KERNEL);
 251        if (!smp2p)
 252                return -ENOMEM;
 253
 254        smp2p->ipa = ipa;
 255
 256        /* These fields are needed by the power query interrupt
 257         * handler, so initialize them now.
 258         */
 259        mutex_init(&smp2p->mutex);
 260        smp2p->valid_state = valid_state;
 261        smp2p->valid_bit = valid_bit;
 262        smp2p->enabled_state = enabled_state;
 263        smp2p->enabled_bit = enabled_bit;
 264
 265        /* We have enough information saved to handle notifications */
 266        ipa->smp2p = smp2p;
 267
 268        ret = ipa_smp2p_irq_init(smp2p, "ipa-clock-query",
 269                                 ipa_smp2p_modem_clk_query_isr);
 270        if (ret < 0)
 271                goto err_null_smp2p;
 272        smp2p->clock_query_irq = ret;
 273
 274        ret = ipa_smp2p_panic_notifier_register(smp2p);
 275        if (ret)
 276                goto err_irq_exit;
 277
 278        if (modem_init) {
 279                /* Result will be non-zero (negative for error) */
 280                ret = ipa_smp2p_irq_init(smp2p, "ipa-setup-ready",
 281                                         ipa_smp2p_modem_setup_ready_isr);
 282                if (ret < 0)
 283                        goto err_notifier_unregister;
 284                smp2p->setup_ready_irq = ret;
 285        }
 286
 287        return 0;
 288
 289err_notifier_unregister:
 290        ipa_smp2p_panic_notifier_unregister(smp2p);
 291err_irq_exit:
 292        ipa_smp2p_irq_exit(smp2p, smp2p->clock_query_irq);
 293err_null_smp2p:
 294        ipa->smp2p = NULL;
 295        mutex_destroy(&smp2p->mutex);
 296        kfree(smp2p);
 297
 298        return ret;
 299}
 300
 301void ipa_smp2p_exit(struct ipa *ipa)
 302{
 303        struct ipa_smp2p *smp2p = ipa->smp2p;
 304
 305        if (smp2p->setup_ready_irq)
 306                ipa_smp2p_irq_exit(smp2p, smp2p->setup_ready_irq);
 307        ipa_smp2p_panic_notifier_unregister(smp2p);
 308        ipa_smp2p_irq_exit(smp2p, smp2p->clock_query_irq);
 309        /* We won't get notified any more; drop power reference (if any) */
 310        ipa_smp2p_power_release(ipa);
 311        ipa->smp2p = NULL;
 312        mutex_destroy(&smp2p->mutex);
 313        kfree(smp2p);
 314}
 315
 316void ipa_smp2p_disable(struct ipa *ipa)
 317{
 318        struct ipa_smp2p *smp2p = ipa->smp2p;
 319
 320        if (!smp2p->setup_ready_irq)
 321                return;
 322
 323        mutex_lock(&smp2p->mutex);
 324
 325        smp2p->disabled = true;
 326
 327        mutex_unlock(&smp2p->mutex);
 328}
 329
 330/* Reset state tracking whether we have notified the modem */
 331void ipa_smp2p_notify_reset(struct ipa *ipa)
 332{
 333        struct ipa_smp2p *smp2p = ipa->smp2p;
 334        u32 mask;
 335
 336        if (!smp2p->notified)
 337                return;
 338
 339        ipa_smp2p_power_release(ipa);
 340
 341        /* Reset the power enabled valid flag */
 342        mask = BIT(smp2p->valid_bit);
 343        qcom_smem_state_update_bits(smp2p->valid_state, mask, 0);
 344
 345        /* Mark the power disabled for good measure... */
 346        mask = BIT(smp2p->enabled_bit);
 347        qcom_smem_state_update_bits(smp2p->enabled_state, mask, 0);
 348
 349        smp2p->notified = false;
 350}
 351