2008-05-05 02:37:25     How to send data through SPI in interrupt?

Document created by Aaronwu Employee on Aug 6, 2013
Version 1Show Document
  • View in full screen mode

2008-05-05 02:37:25     How to send data through SPI in interrupt?

Zhi Qiang Zhang (CHINA)

Message: 55470   

 

Hi,

 

I make a char driver that sends data through SPI to a CPLD that has a SPI slave IP implementation in it, when the CPLD want data it will pull up or pull donw the intr line, the ISR in the driver will send data through SPI.

 

irqreturn_t cdg_irq_handler(int irq, void *dev_id)

{

        unsigned long flags;

        unsigned short val = 0x8181;

        struct spi_cdg_t *p_spi_cdg = dev_id;

        u8 *buffer;

 

        struct spi_transfer     t = {

                        .len            = 2,

                        .speed_hz       = p_spi_cdg->hz,

                };

        struct spi_message      m;

 

        spin_lock_irqsave(&spicdg_lock, flags);

 

        printk(KERN_INFO "hz = %d, handle = %x\r\n", p_spi_cdg->hz, p_spi_cdg->dma_handle);

 

        buffer = dma_alloc_coherent(NULL, 2, &p_spi_cdg->dma_handle, GFP_KERNEL);

 

        spi_message_init(&m);

        spi_message_add_tail(&t, &m);

        t.tx_buf = buffer;

        spi_sync(p_spi_cdg->spidev, &m);

 

        dma_free_coherent(NULL, 2, buffer, p_spi_cdg->dma_handle);

 

        spin_unlock_irqrestore(&spicdg_lock, flags);

 

 

        return IRQ_HANDLED;

}

 

 

when the interrupt comes, the system crashed. If mark that line "spi_sync(p_spi_cdg->spidev, &m);", nothing happend. Here is some of the crash info,

 

root:/> hz = 0, handle = 0

BUG: scheduling while atomic: swapper/0/0x00010003

 

SEQUENCER STATUS:               Not tainted

SEQSTAT: 00002000  IPEND: 0002  SYSCFG: 0006

  HWERRCAUSE: 0x0

  EXCAUSE   : 0x0

RETE: <0x00000000> /* Maybe null pointer? */

RETN: <0x0048c000> /* unknown address */

RETX: <0x0040492e> [ init + 0x492e ]

RETS: <0xffa082c4> { _cpu_idle + 0x20 }

PC  : <0xffa08314> { _default_idle + 0x28 }

 

PROCESSOR STATE:

R0 : 0000ffff    R1 : 00000002    R2 : 0000001f    R3 : 00000000

R4 : 00000000    R5 : 00000000    R6 : 00000000    R7 : 00195a44

P0 : ffa08a14    P1 : 001c4000    P2 : 001b4d9c    P3 : 001962e0

P4 : 001c4000    P5 : ffa082ec    FP : 001b4d9c    SP : 001c5ed8

LB0: ffa0971c    LT0: ffa0971a    LC0: 00000000

LB1: 00000001    LT1: 00000000    LC1: 00000000

B0 : 00000000    L0 : 00000000    M0 : 00000000    I0 : 5aa91e00

B1 : 00000000    L1 : 00000000    M1 : 00000000    I1 : 00000000

B2 : 00000000    L2 : 00000000    M2 : 00000000    I2 : 00000000

B3 : 00000000    L3 : 00000000    M3 : 00000000    I3 : 00000000

A0.w: 10623b90   A0.x: 00000000   A1.w: 00005c54   A1.x: 00000000

USP : 001c6000  ASTAT: 00002020

 

bad: scheduling from the idle thread!

Hardware Trace:

   0 Target : <0x000045b8> { _dump_stack + 0x0 }

     Source : <0x0000aa3a> { _dequeue_task_idle + 0x32 }

   1 Target : <0x0000aa3a> { _dequeue_task_idle + 0x32 }

     Source : <0x0000e4e2> { _printk + 0x16 }

   2 Target : <0x0000e4de> { _printk + 0x12 }

     Source : <0x0000e36e> { _vprintk + 0x1fa }

   3 Target : <0x0000e34e> { _vprintk + 0x1da }

     Source : <0xffa08cf0> { __common_int_entry + 0xd8 }

   4 Target : <0xffa08c8e> { __common_int_entry + 0x76 }

     Source : <0xffa08adc> { _return_from_int + 0x58 }

   5 Target : <0xffa08adc> { _return_from_int + 0x58 }

     Source : <0xffa08ab2> { _return_from_int + 0x2e }

   6 Target : <0xffa08a84> { _return_from_int + 0x0 }

     Source : <0xffa08c8a> { __common_int_entry + 0x72 }

   7 Target : <0xffa08c88> { __common_int_entry + 0x70 }

     Source : <0xffa083e2> { _asm_do_IRQ + 0x6e }

   8 Target : <0xffa083da> { _asm_do_IRQ + 0x66 }

     Source : <0x00012f18> { _irq_exit + 0x44 }

   9 Target : <0x00012f06> { _irq_exit + 0x32 }

     Source : <0x00012ef6> { _irq_exit + 0x22 }

  10 Target : <0x00012ed4> { _irq_exit + 0x0 }

     Source : <0xffa083d6> { _asm_do_IRQ + 0x62 }

  11 Target : <0xffa083d6> { _asm_do_IRQ + 0x62 }

     Source : <0xffa083d0> { _asm_do_IRQ + 0x5c }

  12 Target : <0xffa083aa> { _asm_do_IRQ + 0x36 }

     Source : <0x0002eba0> { _handle_simple_irq + 0xa4 }

  13 Target : <0x0002eb78> { _handle_simple_irq + 0x7c }

     Source : <0x0002ebaa> { _handle_simple_irq + 0xae }

  14 Target : <0x0002ebaa> { _handle_simple_irq + 0xae }

     Source : <0x0002e222> { _note_interrupt + 0x14e }

  15 Target : <0x0002e20a> { _note_interrupt + 0x136 }

     Source : <0x0002e0f4> { _note_interrupt + 0x20 }

Stack from 001c5c8c:

        00000000 0000aa3e 001c4000 7fffffff e974c300 001b2954 00000001 001c5cc0

        000090ee 001b2954 00000000 001c5ccc 00009850 001c5cd8 0000914e 00197144

        001c5d04 ffa09316 001b2a94 001c5d04 ffa0947a 001b2a94 001b2954 001c5ed8

        00000000 00000000 001c4000 001c4000 001306d8 001c4000 001c5d7c 001306d8

        001c4000 001c4000 001c5dac 7fffffff 00000002 001c4000 001b4d9c 001c5db0

        01cd8e48 7fffffff 00000002 001c4000 001b4d9c 001c5d7c 0013055a 001c4000

 

Call Trace:

[<001304aa>] _wait_for_common+0x82/0x13c

[<0000ffff>] _release_task+0x317/0x3c0

[<0000b29c>] _default_wake_function+0x0/0x10

[<000e330e>] _spi_sync+0x3e/0x4c

[<0000ffff>] _release_task+0x317/0x3c0

[<000a61da>] _cdg_irq_handler+0xa6/0xe4

[<000e331c>] _spi_complete+0x0/0x4

[<0002d6e0>] _handle_IRQ_event+0x34/0x5c

[<0002ee36>] _handle_edge_irq+0xa2/0x128

[<00008806>] _bfin_demux_gpio_irq+0x9e/0xb8

[<00008002>] _l1_inst_sram_free+0x6/0x54

[<00002000>] _get_sclk+0x4/0x5c

[<00002020>] _get_sclk+0x24/0x5c

[<00005c54>] _peripheral_free+0x18/0x84

[<001c6000>] __edata+0x0/0x16c

[<0000ffff>] _release_task+0x317/0x3c0

[<0000ffff>] _release_task+0x317/0x3c0

[<001c6a70>] _start_kernel+0x228/0x27c

[<001c62d4>] _unknown_bootoption+0x0/0x220

[<001c6000>] __edata+0x0/0x16c

[<001c61bc>] _real_start+0x50/0x94

 

Jump to address 0 - 0x0fff

Kernel OOPS in progress

Deferred Exception context

CURRENT PROCESS:

COMM=ksoftirqd/0 PID=3

invalid mm

return address: [0x00000000]; contents of:

 

SEQUENCER STATUS:               Not tainted

SEQSTAT: 0006202d  IPEND: 9030  SYSCFG: 0006

  HWERRCAUSE: 0x18

  EXCAUSE   : 0x2d

  physical IVG12 asserted : <0xffa08e38> { _evt_evt12 + 0x0 }

  physical IVG15 asserted : <0xffa08e50> { _evt_system_call + 0x0 }

  logical irq   6 mapped  : <0xffa08418> { _timer_interrupt + 0x0 }

  logical irq  16 mapped  : <0x00112d48> { _AudioRxIsr + 0x0 }

  logical irq  17 mapped  : <0x001130c4> { _AudioTxIsr + 0x0 }

  logical irq  18 mapped  : <0x00113f94> { _sport1_AudioRxIsr + 0x0 }

  logical irq  19 mapped  : <0x00114310> { _sport1_AudioTxIsr + 0x0 }

  logical irq  21 mapped  : <0x000ab060> { _bfin_serial_dma_rx_int + 0x0 }

  logical irq  22 mapped  : <0x000aafbc> { _bfin_serial_dma_tx_int + 0x0 }

  logical irq  38 mapped  : <0x000a6134> { _cdg_irq_handler + 0x0 }

  logical irq  44 mapped  : <0x000e8d80> { _usb_hcd_irq + 0x0 }

 

 

 

 

 

What is the problem? Thank you.

 

 

 

 

 

Regards,

 

ZhangZQ

QuoteReplyEditDelete

 

 

2008-05-05 02:45:53     Re: How to send data through SPI in interrupt?

Mike Frysinger (UNITED STATES)

Message: 55471   

 

it already told you what the problem is:

BUG: scheduling while atomic: swapper/0/0x00010003

 

you cannot call functions that sleep from interrupt context ... since spi_sync() can sleep, you cannot use it

QuoteReplyEditDelete

 

 

2008-05-05 02:49:34     Re: How to send data through SPI in interrupt?

Vitja Makarov (RUSSIAN FEDERATION)

Message: 55472   

 

That means you cannot use spi_sync, when interrupts are disabled. You may:

 

1. try spi_async(don't forget to disable your interrupt until transfer is complete)

 

2. serve interrupts in tasklet/workqueue

 

3. write spi registers directly, you don't need dma here as interrupts are disabled.

QuoteReplyEditDelete

 

 

2008-05-05 03:21:22     Re: How to send data through SPI in interrupt?

Zhi Qiang Zhang (CHINA)

Message: 55473   

 

I prefer that '2. serve interrupts in tasklet/workqueue', is there an existing driver that works in this way for reference? Is that mean creat a thread in the driver waitting for an event, and in the ISR will fire the event, right ? Thank you!

 

 

 

Regards,

 

ZhangZQ

 

 

QuoteReplyEditDelete

 

 

2008-05-05 03:43:54     Re: How to send data through SPI in interrupt?

Vitja Makarov (RUSSIAN FEDERATION)

Message: 55476   

 

You should disable your IRQ, then schedule_work/tasklet_schedule, when your tasklet is done reenable irq, and replace spin_lock_irqsave with spin_lock.

 

Better do allocs/frees at device constructor/destructor, if it's possible.

QuoteReplyEditDelete

 

 

2008-05-05 05:03:32     Re: How to send data through SPI in interrupt?

Zhi Qiang Zhang (CHINA)

Message: 55484   

 

I add

 

disable_irq(IRQ_PF5); enable_irq(IRQ_PF5);

 

but the system still crash.

 

What does schedule_work/tasklet_schedule mean?

 

 

 

Regards,

 

ZhangZQ

QuoteReplyEditDelete

 

 

2008-05-05 05:08:05     Re: How to send data through SPI in interrupt?

Zhi Qiang Zhang (CHINA)

Message: 55485   

 

Mike,

 

Can you tell me how to solve this problem?

 

 

 

Regards,

 

ZhangZQ

QuoteReplyEditDelete

 

 

2008-05-05 05:22:03     Re: How to send data through SPI in interrupt?

Vitja Makarov (RUSSIAN FEDERATION)

Message: 55487   

 

That means you have to create tasklet that will serve your interrupt, interrupt handler will just schedule its execution. See spi_bf5xx driver for example on tasklets/workqueue usage.

 

But I think spi_async is better here, you have to provide callback function and when it's done it will notify you. Don't forget this way  spi_transfer and spi_message couldn't be allocated on stack.

 

 

 

vitja.

QuoteReplyEditDelete

 

 

2008-05-05 07:53:42     Re: How to send data through SPI in interrupt?

Zhi Qiang Zhang (CHINA)

Message: 55498   

 

Vitja,

 

Thank you. I found queue_work, INIT_WORK in spi_bf5xx.c, are they the tasklets/workqueue? I never used them before.

 

 

 

Regards,

 

ZhangZQ

QuoteReplyEditDelete

 

 

2008-05-05 09:06:18     Re: How to send data through SPI in interrupt?

Mike Frysinger (UNITED STATES)

Message: 55504   

 

Vitja has already given you much better pointers than I ... if you dont know how to use the common kernel mechanisms he refers to, download a Linux kernel books for free and read it

 

we provide references to a few free books you can get online in our wiki:

http://docs.blackfin.uclinux.org/doku.php?id=references_and_pointers

QuoteReplyEditDelete

 

 

2008-05-05 10:45:15     Re: How to send data through SPI in interrupt?

Zhi Qiang Zhang (CHINA)

Message: 55513   

 

Mike, Thanks.

Attachments

    Outcomes