This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Why is SDIO driver not interrupt driven?

Other Parts Discussed in Thread: AM3359

It appears to me, that the SDIO driver is not interrupt driven. This gives poor pertormance.

Is there a reason for implementing it this way?

Any plans to fix this?

  • Which is the silicon that you are referring to? Also which is the operating system used and version of the operating system?

  • Running an AM335xEVM, which i  think is using the AM3359, and Linux 3.2.29

    Drivers/mmc/host/omap_hsmmc.c does not export an SDIO interrupt handler,

    (search for NYET and you see it is commented away)

    so the SDIO card is periodically polled in a thread and if an interrupt on the card

    is active, the thread will call the interrupt routine.

    Downloaded the latest linux kernel, and no change.

    The AM335x will do about 11 Mbps on my WiFi SDIO card, and the same card

    on an Atmel ARM9 @ 400 MHz will do 20+ Mbps.

    On. High end laptop, the same card will do 36-40 Mbps.

  • Samuelsson,

    If you are referring to the omap_hsmmc_irq() where its looping there is nothing wrong with the function. This function is the interrupt handler routine and in the while loop its checking for any pending interrupt is active or not. 

    If performance is the constraint then lot of other optimizations can be tried out. 

  • No, I am referring to the reason why this routine is called.

    It is declared as an interrupt routine but the driver does not enable the CIRQ interrupt,

    so there are no interrupts.

    Instead, the SDIO stack will read the CCCR register periodically (at CONFIG_HZ), and if the interrupt

    bit is set, then it will call omap_hsmmc_irq, simulating an interrupt.  

    After each clock tick, a number of transfers are done, but then the bus is idling, losing 75% 

    of the throughput.

  • Ulf,

    I couldn't find the polling logic in the omap_hsmmc.c from the am335x link. Please check the code. Can you share the code where you saw this behavior?

    http://arago-project.org/git/projects/linux-am33x.git?p=projects/linux-am33x.git;a=blob;f=drivers/mmc/host/omap_hsmmc.c;h=35505bd2327cb6a21a7f10367925e72c8cd39fb7;hb=HEAD

  • It is not in the driver, search for NYET, and you will find the place where an SDIO interrupt handler is supposed to be declared.

    It is not.

    The polling logic is in drivers/mmc/core/sdio_irq.c if I remember correctly.

  • You can also try to find where in the driver CIRQ is handled ;-).

    It is not...

  • In drivers/mmc/core/sdio_irq.c you find the "sdio_irq_thread".

        idle_period = msecs_to_jiffies(10);

        period = (host->caps & MMC_CAP_SDIO_IRQ) ?
            MAX_SCHEDULE_TIMEOUT : idle_period;

        do {

            ...

            ret = process_sdio_pending_irqs(host);  // Call the polling loop

            ....

            if error then sleep

       } while (!kthread_should_stop());

    Since the driver does not add MMC_CAP_SDIO_IRQ to host-caps,

    the sdio stack will poll the AM335x driver at least every  "idle_period" which is set to 10 ms above.

    It will process  a burst of transmission during that period, but then idles.

    ---------------------------------------------------------------------------------------------

    important parts of process_sdio_pending_irqs:

    static int process_sdio_pending_irqs(struct mmc_host *host)
    {
        ...

        ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
        ...
        for (i = 1; i <= 7; i++) {
            if (pending & (1 << i)) {
                func = card->sdio_func[i - 1];

                ...
                } else if (func->irq_handler) {
                    func->irq_handler(func);     // Call the AM335x SDIO interrupt routine
                } ...
            }
        }

       ...

    }

  • Sorry for the delayed response.

    Can you try the following?

    1. Enable MMC_CAP_SDIO_IRQ. Not really sure the file to change in arch/arm/mach-omap2/. Need to check the code.

    2. Pass a value like 2ms instead of MAX_SCHEDULE_TIMEOUT and evaluate the performance difference.

  • That won't work.

    There are a lot of other things that needs to be handled for an interrupt scheme to work.

    Increasing the polling rate from 100 Hz to 500-1000 Hz will give much better performance.

  • I have the same problem liked you. Could you tell me where can Increasing the polling rate from 100 Hz to 500-1000 Hz?