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.