[linux-dvb] Kernel panic w/ CVS drivers and Nexus-CA / TT C2300 OT (rev 2.3)

Francois Romieu romieu at fr.zoreil.com
Thu Apr 21 01:24:02 CEST 2005


Mikko Hämäläinen <mikolas at mikolas.net> :
[...]
> scheduling while atomic: czap/0x00000102/4231
> [<c0351083>] schedule+0x503/0x510
> [<c0122583>] __mod_timer+0x123/0x170
> [<c03519e3>] schedule_timeout+0x63/0xc0
> [<c02ff3b7>] qdisc_restart+0x17/0x1d0
> [<c0122fe0>] process_timeout+0x0/0x10
> [<c01233bf>] msleep+0x2f/0x40
> [<e0a34eac>] __av7110_send_fw_cmd+0x7c/0x4e0 [dvb_ttpci]
> [<e0a35358>] av7110_send_fw_cmd+0x48/0xc0 [dvb_ttpci]
> [<e0a35438>] av7110_fw_cmd+0x68/0x90 [dvb_ttpci]
> [<e0a3f437>] ChangePIDs+0x147/0x1f0 [dvb_ttpci]
> [<e0a39c3e>] av7110_set_vidmode+0x8e/0xe0 [dvb_ttpci]
> [<e0a39d29>] get_video_format+0x99/0x110 [dvb_ttpci]
> [<e0a39f1f>] play_video_cb+0x17f/0x2d0 [dvb_ttpci]
> [<c0115bf8>] recalc_task_prio+0x88/0x140
> [<c0115d12>] activate_task+0x62/0x80
> [<c0115e04>] try_to_wake_up+0xa4/0xc0
> [<e0a42b94>] send_ipack+0x94/0x210 [dvb_ttpci]
> [<e0a42d49>] av7110_ipack_flush+0x39/0x50 [dvb_ttpci]
> [<e0a3b20c>] av7110_write_to_decoder+0xcc/0x120 [dvb_ttpci]
> [<e09c40f8>] dvb_dmx_swfilter_packet+0x238/0x280 [dvb_core]

Anything above dvb_dmx_swfilter_packet() is run with a spinlock held.
sleeping/scheduling/down_interruptible is not allowed until the lock
is released. Since __av7110_send_fw_cmd() issues msleep() like crazy, you
bet it is broken :o/

/me looks closer...

The driver does too much (slow) things in its softirq part. A part of it
should probably be posted to a workqueue. Doable but it is not a 5min hack.

Btw, the driver is not really social when something goes wrong:

static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
{
        unsigned long flags; 
        u32 res;

        spin_lock_irqsave(&av7110->debilock, flags);
        res=av7110_debiread(av7110, config, addr, count);
[...]
u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
{
        struct saa7146_dev *dev = av7110->dev;
        u32 result = 0;

        if (count > 32764 || count <= 0) {
                printk("%s: invalid count %d\n", __FUNCTION__, count);
                return 0;
        }
        if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
[...]
int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
{
        unsigned long start;

        /* wait for registers to be programmed */
        start = jiffies;
        while (1) {
                if (saa7146_read(dev, MC2) & 2)
                        break;
                if (time_after(jiffies, start + HZ/20)) {

-> up to 50ms sleep with spinlock held and interruptions disabled.

--
Ueimor




More information about the linux-dvb mailing list