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, &reg);
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, &reg);
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