linux/drivers/mmc/core/sdio_irq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * linux/drivers/mmc/core/sdio_irq.c
   4 *
   5 * Author:      Nicolas Pitre
   6 * Created:     June 18, 2007
   7 * Copyright:   MontaVista Software Inc.
   8 *
   9 * Copyright 2008 Pierre Ossman
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/sched.h>
  14#include <uapi/linux/sched/types.h>
  15#include <linux/kthread.h>
  16#include <linux/export.h>
  17#include <linux/wait.h>
  18#include <linux/delay.h>
  19
  20#include <linux/mmc/core.h>
  21#include <linux/mmc/host.h>
  22#include <linux/mmc/card.h>
  23#include <linux/mmc/sdio.h>
  24#include <linux/mmc/sdio_func.h>
  25
  26#include "sdio_ops.h"
  27#include "core.h"
  28#include "card.h"
  29
  30static int sdio_get_pending_irqs(struct mmc_host *host, u8 *pending)
  31{
  32        struct mmc_card *card = host->card;
  33        int ret;
  34
  35        WARN_ON(!host->claimed);
  36
  37        ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, pending);
  38        if (ret) {
  39                pr_debug("%s: error %d reading SDIO_CCCR_INTx\n",
  40                       mmc_card_id(card), ret);
  41                return ret;
  42        }
  43
  44        if (*pending && mmc_card_broken_irq_polling(card) &&
  45            !(host->caps & MMC_CAP_SDIO_IRQ)) {
  46                unsigned char dummy;
  47
  48                /* A fake interrupt could be created when we poll SDIO_CCCR_INTx
  49                 * register with a Marvell SD8797 card. A dummy CMD52 read to
  50                 * function 0 register 0xff can avoid this.
  51                 */
  52                mmc_io_rw_direct(card, 0, 0, 0xff, 0, &dummy);
  53        }
  54
  55        return 0;
  56}
  57
  58static int process_sdio_pending_irqs(struct mmc_host *host)
  59{
  60        struct mmc_card *card = host->card;
  61        int i, ret, count;
  62        bool sdio_irq_pending = host->sdio_irq_pending;
  63        unsigned char pending;
  64        struct sdio_func *func;
  65
  66        /* Don't process SDIO IRQs if the card is suspended. */
  67        if (mmc_card_suspended(card))
  68                return 0;
  69
  70        /* Clear the flag to indicate that we have processed the IRQ. */
  71        host->sdio_irq_pending = false;
  72
  73        /*
  74         * Optimization, if there is only 1 function interrupt registered
  75         * and we know an IRQ was signaled then call irq handler directly.
  76         * Otherwise do the full probe.
  77         */
  78        func = card->sdio_single_irq;
  79        if (func && sdio_irq_pending) {
  80                func->irq_handler(func);
  81                return 1;
  82        }
  83
  84        ret = sdio_get_pending_irqs(host, &pending);
  85        if (ret)
  86                return ret;
  87
  88        count = 0;
  89        for (i = 1; i <= 7; i++) {
  90                if (pending & (1 << i)) {
  91                        func = card->sdio_func[i - 1];
  92                        if (!func) {
  93                                pr_warn("%s: pending IRQ for non-existent function\n",
  94                                        mmc_card_id(card));
  95                                ret = -EINVAL;
  96                        } else if (func->irq_handler) {
  97                                func->irq_handler(func);
  98                                count++;
  99                        } else {
 100                                pr_warn("%s: pending IRQ with no handler\n",
 101                                        sdio_func_id(func));
 102                                ret = -EINVAL;
 103                        }
 104                }
 105        }
 106
 107        if (count)
 108                return count;
 109
 110        return ret;
 111}
 112
 113static void sdio_run_irqs(struct mmc_host *host)
 114{
 115        mmc_claim_host(host);
 116        if (host->sdio_irqs) {
 117                process_sdio_pending_irqs(host);
 118                if (!host->sdio_irq_pending)
 119                        host->ops->ack_sdio_irq(host);
 120        }
 121        mmc_release_host(host);
 122}
 123
 124void sdio_irq_work(struct work_struct *work)
 125{
 126        struct mmc_host *host =
 127                container_of(work, struct mmc_host, sdio_irq_work.work);
 128
 129        sdio_run_irqs(host);
 130}
 131
 132void sdio_signal_irq(struct mmc_host *host)
 133{
 134        host->sdio_irq_pending = true;
 135        queue_delayed_work(system_wq, &host->sdio_irq_work, 0);
 136}
 137EXPORT_SYMBOL_GPL(sdio_signal_irq);
 138
 139static int sdio_irq_thread(void *_host)
 140{
 141        struct mmc_host *host = _host;
 142        unsigned long period, idle_period;
 143        int ret;
 144
 145        sched_set_fifo_low(current);
 146
 147        /*
 148         * We want to allow for SDIO cards to work even on non SDIO
 149         * aware hosts.  One thing that non SDIO host cannot do is
 150         * asynchronous notification of pending SDIO card interrupts
 151         * hence we poll for them in that case.
 152         */
 153        idle_period = msecs_to_jiffies(10);
 154        period = (host->caps & MMC_CAP_SDIO_IRQ) ?
 155                MAX_SCHEDULE_TIMEOUT : idle_period;
 156
 157        pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n",
 158                 mmc_hostname(host), period);
 159
 160        do {
 161                /*
 162                 * We claim the host here on drivers behalf for a couple
 163                 * reasons:
 164                 *
 165                 * 1) it is already needed to retrieve the CCCR_INTx;
 166                 * 2) we want the driver(s) to clear the IRQ condition ASAP;
 167                 * 3) we need to control the abort condition locally.
 168                 *
 169                 * Just like traditional hard IRQ handlers, we expect SDIO
 170                 * IRQ handlers to be quick and to the point, so that the
 171                 * holding of the host lock does not cover too much work
 172                 * that doesn't require that lock to be held.
 173                 */
 174                ret = __mmc_claim_host(host, NULL,
 175                                       &host->sdio_irq_thread_abort);
 176                if (ret)
 177                        break;
 178                ret = process_sdio_pending_irqs(host);
 179                mmc_release_host(host);
 180
 181                /*
 182                 * Give other threads a chance to run in the presence of
 183                 * errors.
 184                 */
 185                if (ret < 0) {
 186                        set_current_state(TASK_INTERRUPTIBLE);
 187                        if (!kthread_should_stop())
 188                                schedule_timeout(HZ);
 189                        set_current_state(TASK_RUNNING);
 190                }
 191
 192                /*
 193                 * Adaptive polling frequency based on the assumption
 194                 * that an interrupt will be closely followed by more.
 195                 * This has a substantial benefit for network devices.
 196                 */
 197                if (!(host->caps & MMC_CAP_SDIO_IRQ)) {
 198                        if (ret > 0)
 199                                period /= 2;
 200                        else {
 201                                period++;
 202                                if (period > idle_period)
 203                                        period = idle_period;
 204                        }
 205                }
 206
 207                set_current_state(TASK_INTERRUPTIBLE);
 208                if (host->caps & MMC_CAP_SDIO_IRQ)
 209                        host->ops->enable_sdio_irq(host, 1);
 210                if (!kthread_should_stop())
 211                        schedule_timeout(period);
 212                set_current_state(TASK_RUNNING);
 213        } while (!kthread_should_stop());
 214
 215        if (host->caps & MMC_CAP_SDIO_IRQ)
 216                host->ops->enable_sdio_irq(host, 0);
 217
 218        pr_debug("%s: IRQ thread exiting with code %d\n",
 219                 mmc_hostname(host), ret);
 220
 221        return ret;
 222}
 223
 224static int sdio_card_irq_get(struct mmc_card *card)
 225{
 226        struct mmc_host *host = card->host;
 227
 228        WARN_ON(!host->claimed);
 229
 230        if (!host->sdio_irqs++) {
 231                if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
 232                        atomic_set(&host->sdio_irq_thread_abort, 0);
 233                        host->sdio_irq_thread =
 234                                kthread_run(sdio_irq_thread, host,
 235                                            "ksdioirqd/%s", mmc_hostname(host));
 236                        if (IS_ERR(host->sdio_irq_thread)) {
 237                                int err = PTR_ERR(host->sdio_irq_thread);
 238                                host->sdio_irqs--;
 239                                return err;
 240                        }
 241                } else if (host->caps & MMC_CAP_SDIO_IRQ) {
 242                        host->ops->enable_sdio_irq(host, 1);
 243                }
 244        }
 245
 246        return 0;
 247}
 248
 249static int sdio_card_irq_put(struct mmc_card *card)
 250{
 251        struct mmc_host *host = card->host;
 252
 253        WARN_ON(!host->claimed);
 254
 255        if (host->sdio_irqs < 1)
 256                return -EINVAL;
 257
 258        if (!--host->sdio_irqs) {
 259                if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
 260                        atomic_set(&host->sdio_irq_thread_abort, 1);
 261                        kthread_stop(host->sdio_irq_thread);
 262                } else if (host->caps & MMC_CAP_SDIO_IRQ) {
 263                        host->ops->enable_sdio_irq(host, 0);
 264                }
 265        }
 266
 267        return 0;
 268}
 269
 270/* If there is only 1 function registered set sdio_single_irq */
 271static void sdio_single_irq_set(struct mmc_card *card)
 272{
 273        struct sdio_func *func;
 274        int i;
 275
 276        card->sdio_single_irq = NULL;
 277        if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
 278            card->host->sdio_irqs == 1) {
 279                for (i = 0; i < card->sdio_funcs; i++) {
 280                        func = card->sdio_func[i];
 281                        if (func && func->irq_handler) {
 282                                card->sdio_single_irq = func;
 283                                break;
 284                        }
 285                }
 286        }
 287}
 288
 289/**
 290 *      sdio_claim_irq - claim the IRQ for a SDIO function
 291 *      @func: SDIO function
 292 *      @handler: IRQ handler callback
 293 *
 294 *      Claim and activate the IRQ for the given SDIO function. The provided
 295 *      handler will be called when that IRQ is asserted.  The host is always
 296 *      claimed already when the handler is called so the handler should not
 297 *      call sdio_claim_host() or sdio_release_host().
 298 */
 299int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
 300{
 301        int ret;
 302        unsigned char reg;
 303
 304        if (!func)
 305                return -EINVAL;
 306
 307        pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));
 308
 309        if (func->irq_handler) {
 310                pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func));
 311                return -EBUSY;
 312        }
 313
 314        ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
 315        if (ret)
 316                return ret;
 317
 318        reg |= 1 << func->num;
 319
 320        reg |= 1; /* Master interrupt enable */
 321
 322        ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
 323        if (ret)
 324                return ret;
 325
 326        func->irq_handler = handler;
 327        ret = sdio_card_irq_get(func->card);
 328        if (ret)
 329                func->irq_handler = NULL;
 330        sdio_single_irq_set(func->card);
 331
 332        return ret;
 333}
 334EXPORT_SYMBOL_GPL(sdio_claim_irq);
 335
 336/**
 337 *      sdio_release_irq - release the IRQ for a SDIO function
 338 *      @func: SDIO function
 339 *
 340 *      Disable and release the IRQ for the given SDIO function.
 341 */
 342int sdio_release_irq(struct sdio_func *func)
 343{
 344        int ret;
 345        unsigned char reg;
 346
 347        if (!func)
 348                return -EINVAL;
 349
 350        pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func));
 351
 352        if (func->irq_handler) {
 353                func->irq_handler = NULL;
 354                sdio_card_irq_put(func->card);
 355                sdio_single_irq_set(func->card);
 356        }
 357
 358        ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
 359        if (ret)
 360                return ret;
 361
 362        reg &= ~(1 << func->num);
 363
 364        /* Disable master interrupt with the last function interrupt */
 365        if (!(reg & 0xFE))
 366                reg = 0;
 367
 368        ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
 369        if (ret)
 370                return ret;
 371
 372        return 0;
 373}
 374EXPORT_SYMBOL_GPL(sdio_release_irq);
 375
 376