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