Branch data Line data Source code
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 : : 30 : 0 : static int sdio_get_pending_irqs(struct mmc_host *host, u8 *pending) 31 : : { 32 : 0 : struct mmc_card *card = host->card; 33 : : int ret; 34 : : 35 : 0 : WARN_ON(!host->claimed); 36 : : 37 : 0 : ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, pending); 38 : 0 : 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 : 0 : if (*pending && mmc_card_broken_irq_polling(card) && 45 : 0 : !(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 : 0 : mmc_io_rw_direct(card, 0, 0, 0xff, 0, &dummy); 53 : : } 54 : : 55 : : return 0; 56 : : } 57 : : 58 : 0 : static int process_sdio_pending_irqs(struct mmc_host *host) 59 : : { 60 : 0 : struct mmc_card *card = host->card; 61 : : int i, ret, count; 62 : 0 : 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 : 0 : if (mmc_card_suspended(card)) 68 : : return 0; 69 : : 70 : : /* Clear the flag to indicate that we have processed the IRQ. */ 71 : 0 : 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 : 0 : func = card->sdio_single_irq; 79 : 0 : if (func && sdio_irq_pending) { 80 : 0 : func->irq_handler(func); 81 : 0 : return 1; 82 : : } 83 : : 84 : 0 : ret = sdio_get_pending_irqs(host, &pending); 85 : 0 : if (ret) 86 : : return ret; 87 : : 88 : : count = 0; 89 : 0 : for (i = 1; i <= 7; i++) { 90 : 0 : if (pending & (1 << i)) { 91 : 0 : func = card->sdio_func[i - 1]; 92 : 0 : if (!func) { 93 : 0 : pr_warn("%s: pending IRQ for non-existent function\n", 94 : : mmc_card_id(card)); 95 : : ret = -EINVAL; 96 : 0 : } else if (func->irq_handler) { 97 : 0 : func->irq_handler(func); 98 : 0 : count++; 99 : : } else { 100 : 0 : pr_warn("%s: pending IRQ with no handler\n", 101 : : sdio_func_id(func)); 102 : : ret = -EINVAL; 103 : : } 104 : : } 105 : : } 106 : : 107 : 0 : if (count) 108 : 0 : return count; 109 : : 110 : 0 : return ret; 111 : : } 112 : : 113 : 0 : static void sdio_run_irqs(struct mmc_host *host) 114 : : { 115 : : mmc_claim_host(host); 116 : 0 : if (host->sdio_irqs) { 117 : 0 : process_sdio_pending_irqs(host); 118 : 0 : if (!host->sdio_irq_pending) 119 : 0 : host->ops->ack_sdio_irq(host); 120 : : } 121 : 0 : mmc_release_host(host); 122 : 0 : } 123 : : 124 : 0 : void sdio_irq_work(struct work_struct *work) 125 : : { 126 : : struct mmc_host *host = 127 : 0 : container_of(work, struct mmc_host, sdio_irq_work.work); 128 : : 129 : 0 : sdio_run_irqs(host); 130 : 0 : } 131 : : 132 : 0 : void sdio_signal_irq(struct mmc_host *host) 133 : : { 134 : 0 : host->sdio_irq_pending = true; 135 : 0 : queue_delayed_work(system_wq, &host->sdio_irq_work, 0); 136 : 0 : } 137 : : EXPORT_SYMBOL_GPL(sdio_signal_irq); 138 : : 139 : 0 : static int sdio_irq_thread(void *_host) 140 : : { 141 : : struct mmc_host *host = _host; 142 : 0 : struct sched_param param = { .sched_priority = 1 }; 143 : : unsigned long period, idle_period; 144 : : int ret; 145 : : 146 : 0 : sched_setscheduler(current, SCHED_FIFO, ¶m); 147 : : 148 : : /* 149 : : * We want to allow for SDIO cards to work even on non SDIO 150 : : * aware hosts. One thing that non SDIO host cannot do is 151 : : * asynchronous notification of pending SDIO card interrupts 152 : : * hence we poll for them in that case. 153 : : */ 154 : : idle_period = msecs_to_jiffies(10); 155 : 0 : period = (host->caps & MMC_CAP_SDIO_IRQ) ? 156 : 0 : MAX_SCHEDULE_TIMEOUT : idle_period; 157 : : 158 : : pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n", 159 : : mmc_hostname(host), period); 160 : : 161 : : do { 162 : : /* 163 : : * We claim the host here on drivers behalf for a couple 164 : : * reasons: 165 : : * 166 : : * 1) it is already needed to retrieve the CCCR_INTx; 167 : : * 2) we want the driver(s) to clear the IRQ condition ASAP; 168 : : * 3) we need to control the abort condition locally. 169 : : * 170 : : * Just like traditional hard IRQ handlers, we expect SDIO 171 : : * IRQ handlers to be quick and to the point, so that the 172 : : * holding of the host lock does not cover too much work 173 : : * that doesn't require that lock to be held. 174 : : */ 175 : 0 : ret = __mmc_claim_host(host, NULL, 176 : : &host->sdio_irq_thread_abort); 177 : 0 : if (ret) 178 : : break; 179 : 0 : ret = process_sdio_pending_irqs(host); 180 : 0 : mmc_release_host(host); 181 : : 182 : : /* 183 : : * Give other threads a chance to run in the presence of 184 : : * errors. 185 : : */ 186 : 0 : if (ret < 0) { 187 : 0 : set_current_state(TASK_INTERRUPTIBLE); 188 : 0 : if (!kthread_should_stop()) 189 : 0 : schedule_timeout(HZ); 190 : 0 : set_current_state(TASK_RUNNING); 191 : : } 192 : : 193 : : /* 194 : : * Adaptive polling frequency based on the assumption 195 : : * that an interrupt will be closely followed by more. 196 : : * This has a substantial benefit for network devices. 197 : : */ 198 : 0 : if (!(host->caps & MMC_CAP_SDIO_IRQ)) { 199 : 0 : if (ret > 0) 200 : 0 : period /= 2; 201 : : else { 202 : 0 : period++; 203 : 0 : if (period > idle_period) 204 : : period = idle_period; 205 : : } 206 : : } 207 : : 208 : 0 : set_current_state(TASK_INTERRUPTIBLE); 209 : 0 : if (host->caps & MMC_CAP_SDIO_IRQ) 210 : 0 : host->ops->enable_sdio_irq(host, 1); 211 : 0 : if (!kthread_should_stop()) 212 : 0 : schedule_timeout(period); 213 : 0 : set_current_state(TASK_RUNNING); 214 : 0 : } while (!kthread_should_stop()); 215 : : 216 : 0 : if (host->caps & MMC_CAP_SDIO_IRQ) 217 : 0 : host->ops->enable_sdio_irq(host, 0); 218 : : 219 : : pr_debug("%s: IRQ thread exiting with code %d\n", 220 : : mmc_hostname(host), ret); 221 : : 222 : 0 : return ret; 223 : : } 224 : : 225 : 0 : static int sdio_card_irq_get(struct mmc_card *card) 226 : : { 227 : 0 : struct mmc_host *host = card->host; 228 : : 229 : 0 : WARN_ON(!host->claimed); 230 : : 231 : 0 : if (!host->sdio_irqs++) { 232 : 0 : if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) { 233 : : atomic_set(&host->sdio_irq_thread_abort, 0); 234 : 0 : host->sdio_irq_thread = 235 : 0 : kthread_run(sdio_irq_thread, host, 236 : : "ksdioirqd/%s", mmc_hostname(host)); 237 : 0 : if (IS_ERR(host->sdio_irq_thread)) { 238 : : int err = PTR_ERR(host->sdio_irq_thread); 239 : 0 : host->sdio_irqs--; 240 : 0 : return err; 241 : : } 242 : 0 : } else if (host->caps & MMC_CAP_SDIO_IRQ) { 243 : 0 : host->ops->enable_sdio_irq(host, 1); 244 : : } 245 : : } 246 : : 247 : : return 0; 248 : : } 249 : : 250 : 0 : static int sdio_card_irq_put(struct mmc_card *card) 251 : : { 252 : 0 : struct mmc_host *host = card->host; 253 : : 254 : 0 : WARN_ON(!host->claimed); 255 : : 256 : 0 : if (host->sdio_irqs < 1) 257 : : return -EINVAL; 258 : : 259 : 0 : if (!--host->sdio_irqs) { 260 : 0 : if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) { 261 : : atomic_set(&host->sdio_irq_thread_abort, 1); 262 : 0 : kthread_stop(host->sdio_irq_thread); 263 : 0 : } else if (host->caps & MMC_CAP_SDIO_IRQ) { 264 : 0 : host->ops->enable_sdio_irq(host, 0); 265 : : } 266 : : } 267 : : 268 : : return 0; 269 : : } 270 : : 271 : : /* If there is only 1 function registered set sdio_single_irq */ 272 : 0 : static void sdio_single_irq_set(struct mmc_card *card) 273 : : { 274 : : struct sdio_func *func; 275 : : int i; 276 : : 277 : 0 : card->sdio_single_irq = NULL; 278 : 0 : if ((card->host->caps & MMC_CAP_SDIO_IRQ) && 279 : 0 : card->host->sdio_irqs == 1) 280 : 0 : for (i = 0; i < card->sdio_funcs; i++) { 281 : 0 : func = card->sdio_func[i]; 282 : 0 : if (func && func->irq_handler) { 283 : 0 : card->sdio_single_irq = func; 284 : 0 : break; 285 : : } 286 : : } 287 : 0 : } 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 : : */ 299 : 0 : int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler) 300 : : { 301 : : int ret; 302 : : unsigned char reg; 303 : : 304 : 0 : if (!func) 305 : : return -EINVAL; 306 : : 307 : : pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func)); 308 : : 309 : 0 : 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 : 0 : ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®); 315 : 0 : if (ret) 316 : : return ret; 317 : : 318 : 0 : reg |= 1 << func->num; 319 : : 320 : 0 : reg |= 1; /* Master interrupt enable */ 321 : : 322 : 0 : ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL); 323 : 0 : if (ret) 324 : : return ret; 325 : : 326 : 0 : func->irq_handler = handler; 327 : 0 : ret = sdio_card_irq_get(func->card); 328 : 0 : if (ret) 329 : 0 : func->irq_handler = NULL; 330 : 0 : sdio_single_irq_set(func->card); 331 : : 332 : 0 : return ret; 333 : : } 334 : : EXPORT_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 : : */ 342 : 0 : int sdio_release_irq(struct sdio_func *func) 343 : : { 344 : : int ret; 345 : : unsigned char reg; 346 : : 347 : 0 : if (!func) 348 : : return -EINVAL; 349 : : 350 : : pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func)); 351 : : 352 : 0 : if (func->irq_handler) { 353 : 0 : func->irq_handler = NULL; 354 : 0 : sdio_card_irq_put(func->card); 355 : 0 : sdio_single_irq_set(func->card); 356 : : } 357 : : 358 : 0 : ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®); 359 : 0 : if (ret) 360 : : return ret; 361 : : 362 : 0 : reg &= ~(1 << func->num); 363 : : 364 : : /* Disable master interrupt with the last function interrupt */ 365 : 0 : if (!(reg & 0xFE)) 366 : 0 : reg = 0; 367 : : 368 : 0 : ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL); 369 : 0 : if (ret) 370 : 0 : return ret; 371 : : 372 : : return 0; 373 : : } 374 : : EXPORT_SYMBOL_GPL(sdio_release_irq); 375 : :