[Linux1394-cvslog] rev 787 - branches/linux-2.4
Brought to you by:
aeb,
bencollins
From: SVN U. <dm...@li...> - 2003-02-15 07:33:08
|
Author: dmaas Date: 2003-02-15 02:32:22 -0500 (Sat, 15 Feb 2003) New Revision: 787 Modified: branches/linux-2.4/dv1394-private.h branches/linux-2.4/dv1394.c Log: critical cleanups for dv1394 shutdown and interrupt handling to avoid crashes during shutdown Modified: branches/linux-2.4/dv1394-private.h ============================================================================== --- branches/linux-2.4/dv1394-private.h (original) +++ branches/linux-2.4/dv1394-private.h 2003-02-15 02:32:23.000000000 -0500 @@ -458,6 +458,10 @@ */ spinlock_t spinlock; + /* flag to prevent spurious interrupts (which OHCI seems to + generate a lot :) from accessing the struct */ + int dma_running; + /* 3) the sleeping semaphore 'sem' - this is used from process context only, to serialize various operations on the video_card. Even though only one @@ -571,7 +575,7 @@ static int do_dv1394_init(struct video_card *video, struct dv1394_init *init); static int do_dv1394_init_default(struct video_card *video); -static int do_dv1394_shutdown(struct video_card *video, int free_user_buf); +static void do_dv1394_shutdown(struct video_card *video, int free_user_buf); /* NTSC empty packet rate accurate to within 0.01%, Modified: branches/linux-2.4/dv1394.c ============================================================================== --- branches/linux-2.4/dv1394.c (original) +++ branches/linux-2.4/dv1394.c 2003-02-15 02:32:23.000000000 -0500 @@ -695,7 +695,7 @@ wmb(); #endif - + video->dma_running = 1; /* set the 'run' bit */ reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000); @@ -817,7 +817,9 @@ reg_write(video->ohci, video->ohci_IsoRcvCommandPtr, video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */ wmb(); - + + video->dma_running = 1; + /* run */ reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000); flush_pci_write(video->ohci); @@ -918,16 +920,16 @@ u64 chan_mask; int retval = -EINVAL; - debug_printk( "dv1394: initialising %d\n", video->id ); + debug_printk("dv1394: initialising %d\n", video->id); if(init->api_version != DV1394_API_VERSION) - goto err; + return -EINVAL; /* first sanitize all the parameters */ if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) ) - goto err; + return -EINVAL; if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) ) - goto err; + return -EINVAL; if( (init->syt_offset == 0) || (init->syt_offset > 50) ) /* default SYT offset is 3 cycles */ @@ -948,15 +950,15 @@ if(new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE); /* don't allow the user to allocate the DMA buffer more than once */ - if(video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) - goto err; - + if(video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) { + printk("dv1394: re-sizing the DMA buffer is not allowed\n"); + return -EINVAL; + } + /* shutdown the card if it's currently active */ /* (the card should not be reset if the parameters are screwy) */ - if( video_card_initialized(video) ) - do_dv1394_shutdown(video, 0); - + do_dv1394_shutdown(video, 0); /* try to claim the ISO channel */ spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); @@ -973,7 +975,6 @@ /* initialize misc. fields of video */ video->n_frames = init->n_frames; video->pal_or_ntsc = init->format; - video->cip_accum = 0; video->continuity_counter = 0; @@ -989,7 +990,6 @@ video->current_packet = -1; video->first_frame = 0; - if(video->pal_or_ntsc == DV1394_NTSC) { video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC; video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC; @@ -1002,14 +1002,8 @@ video->syt_offset = init->syt_offset; - /* find and claim DMA contexts on the OHCI card */ - /* XXX this should be the last step of initialization, since the interrupt - handler uses ohci_i*_ctx to indicate whether or not it is safe to touch - frames. I'm not making this change quite yet, since it would be better - to clean up the init/shutdown process first.*/ - if(video->ohci_it_ctx == -1) { ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT, it_tasklet_func, (unsigned long) video); @@ -1017,14 +1011,12 @@ if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) { printk(KERN_ERR "dv1394: could not find an available IT DMA context\n"); retval = -EBUSY; - goto err_ctx; - } - else { - video->ohci_it_ctx = video->it_tasklet.context; - debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); + goto err; } + + video->ohci_it_ctx = video->it_tasklet.context; + debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); } - if(video->ohci_ir_ctx == -1) { ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE, @@ -1033,14 +1025,11 @@ if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) { printk(KERN_ERR "dv1394: could not find an available IR DMA context\n"); retval = -EBUSY; - goto err_ctx; - } - else { - video->ohci_ir_ctx = video->ir_tasklet.context; - debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); + goto err; } + video->ohci_ir_ctx = video->ir_tasklet.context; + debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); } - /* allocate struct frames */ for(i = 0; i < init->n_frames; i++) { @@ -1049,7 +1038,7 @@ if(!video->frames[i]) { printk(KERN_ERR "dv1394: Cannot allocate frame structs\n"); retval = -ENOMEM; - goto err_frames; + goto err; } } @@ -1057,7 +1046,7 @@ /* allocate the ringbuffer */ retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE); if(retval) - goto err_frames; + goto err; video->dv_buf_size = new_buf_size; @@ -1079,7 +1068,7 @@ retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size, video->ohci->dev, PCI_DMA_FROMDEVICE); if(retval) - goto err_dv_buf; + goto err; debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n", video->n_frames*MAX_PACKETS, video->packet_buf.n_pages, @@ -1109,30 +1098,8 @@ return 0; - err_dv_buf: - dma_region_free(&video->dv_buf); - - err_frames: - for(i = 0; i < DV1394_MAX_FRAMES; i++) { - if(video->frames[i]) - frame_delete(video->frames[i]); - } - video->n_frames = 0; - - err_ctx: - if(video->ohci_it_ctx != -1) { - ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet); - video->ohci_it_ctx = -1; - } - if(video->ohci_ir_ctx != -1) { - ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet); - video->ohci_ir_ctx = -1; - } - - spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); - video->ohci->ISO_channel_usage &= ~chan_mask; - spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); - err: +err: + do_dv1394_shutdown(video, 1); return retval; } @@ -1160,10 +1127,15 @@ { unsigned long flags; int i; - + /* no interrupts */ spin_lock_irqsave(&video->spinlock, flags); + video->dma_running = 0; + + if( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) ) + goto out; + /* stop DMA if in progress */ if( (video->active_frame != -1) || (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) || @@ -1203,24 +1175,22 @@ } else debug_printk("dv1394: stop_dma: already stopped.\n"); - + +out: spin_unlock_irqrestore(&video->spinlock, flags); } -static int do_dv1394_shutdown(struct video_card *video, int free_dv_buf) +static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf) { int i; - unsigned long flags; debug_printk("dv1394: shutdown...\n"); /* stop DMA if in progress */ stop_dma(video); - spin_lock_irqsave(&video->spinlock, flags); - /* release the DMA contexts */ if(video->ohci_it_ctx != -1) { video->ohci_IsoXmitContextControlSet = 0; @@ -1251,8 +1221,6 @@ video->ohci_ir_ctx = -1; } - spin_unlock_irqrestore(&video->spinlock, flags); - /* release the ISO channel */ if(video->channel != -1) { u64 chan_mask; @@ -1288,9 +1256,7 @@ dma_region_free(&video->packet_buf); video->packet_buf_size = 0; - debug_printk("dv1394: shutdown complete\n"); - - return 0; + debug_printk("dv1394: shutdown OK\n"); } /* @@ -1777,7 +1743,8 @@ } case DV1394_SHUTDOWN: case DV1394_IOC_SHUTDOWN: - ret = do_dv1394_shutdown(video, 0); + do_dv1394_shutdown(video, 0); + ret = 0; break; case DV1394_GET_STATUS: @@ -2147,6 +2114,9 @@ spin_lock(&video->spinlock); + if(!video->dma_running) + goto out; + irq_printk("ContextControl = %08x, CommandPtr = %08x\n", reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), reg_read(video->ohci, video->ohci_IsoXmitCommandPtr) @@ -2273,14 +2243,15 @@ } /* for(each frame) */ } - spin_unlock(&video->spinlock); - if(wake) { kill_fasync(&video->fasync, SIGIO, POLL_OUT); /* wake readers/writers/ioctl'ers */ wake_up_interruptible(&video->waitq); } + +out: + spin_unlock(&video->spinlock); } static void ir_tasklet_func(unsigned long data) @@ -2290,8 +2261,11 @@ spin_lock(&video->spinlock); - if( (video->ohci_ir_ctx != -1) - && (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) + if(!video->dma_running) + goto out; + + if( (video->ohci_ir_ctx != -1) && + (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { int sof=0; /* start-of-frame flag */ @@ -2431,14 +2405,15 @@ } /* receive interrupt */ - spin_unlock(&video->spinlock); - if(wake) { kill_fasync(&video->fasync, SIGIO, POLL_IN); /* wake readers/writers/ioctl'ers */ wake_up_interruptible(&video->waitq); } + +out: + spin_unlock(&video->spinlock); } static struct file_operations dv1394_fops= @@ -2652,6 +2627,7 @@ clear_bit(0, &video->open); spin_lock_init(&video->spinlock); + video->dma_running = 0; init_MUTEX(&video->sem); init_waitqueue_head(&video->waitq); video->fasync = NULL; @@ -2823,6 +2799,9 @@ spin_lock_irqsave(&video->spinlock, flags); + if(!video->dma_running) + goto out; + /* check IT context */ if(video->ohci_it_ctx != -1) { u32 ctx; @@ -2895,7 +2874,8 @@ reg_read(video->ohci, video->ohci_IsoRcvCommandPtr)); } } - + +out: spin_unlock_irqrestore(&video->spinlock, flags); /* wake readers/writers/ioctl'ers */ |