[Linux1394-cvslog] rev 646 - trunk
Brought to you by:
aeb,
bencollins
From: SVN U. <dde...@li...> - 2002-10-26 15:38:43
|
Author: ddennedy Date: 2002-10-26 11:38:36 -0400 (Sat, 26 Oct 2002) New Revision: 646 Modified: trunk/dv1394-private.h trunk/dv1394.c Log: enhance dv1394 capture integrity Modified: trunk/dv1394-private.h ============================================================================== --- trunk/dv1394-private.h (original) +++ trunk/dv1394-private.h 2002-10-26 11:38:37.000000000 -0400 @@ -167,12 +167,14 @@ } static inline void fill_input_last(struct input_last *il, + int want_interrupt, unsigned int data_size, unsigned long data_phys_addr) { u32 temp = 3 << 28; /* INPUT_LAST */ temp |= 8 << 24; /* s = 1, update xferStatus and resCount */ - temp |= 3 << 20; /* enable interrupts */ + if (want_interrupt) + temp |= 3 << 20; /* enable interrupts */ temp |= 0xC << 16; /* enable branch to address */ /* disable wait on sync field, not used in DV :-( */ temp |= data_size; @@ -301,8 +303,7 @@ unsigned long data; /* Max # of packets per frame */ - /* 320 is enough for NTSC, need to check what PAL is */ - #define MAX_PACKETS 500 +#define MAX_PACKETS 500 /* a PAGE_SIZE memory pool for allocating CIP headers @@ -579,9 +580,8 @@ /* physically contiguous packet ringbuffer for receive */ -#define MAX_PACKET_BUFFER 30 struct packet *packet_buffer; - dma_addr_t packet_buffer_dma; + struct dma_region packet_buffer_dma; unsigned long packet_buffer_size; unsigned int current_packet; Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2002-10-26 11:38:37.000000000 -0400 @@ -53,6 +53,10 @@ via pci_alloc_consistent() DONE: + - reduce irq rate during reception (1/250 packets). + - add many more internal buffers during reception with scatter/gather dma. + - add dbc (continuity) checking on receive, increment status.dropped_frames + if not continuous. - restart IT DMA after a bus reset - safely obtain and release ISO Tx channels in cooperation with OHCI driver - map received DIF blocks to their proper location in DV frame (ensure @@ -97,6 +101,7 @@ #include <asm/io.h> #include <asm/uaccess.h> #include <linux/proc_fs.h> +#include <linux/tqueue.h> #include <linux/delay.h> #include <asm/pgtable.h> #include <asm/page.h> @@ -825,47 +830,64 @@ } -static void start_dma_receive(struct video_card *video, struct frame *frame) +static void start_dma_receive(struct video_card *video) { - /* reset iso recv control register */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF); - wmb(); - - /* clear bufferFill, set isochHeader and speed (0=100) */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000); - - /* match on all tags, listen on channel */ - reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel); - - /* address and first descriptor block + Z=1 */ - reg_write(video->ohci, video->ohci_IsoRcvCommandPtr, - frame->descriptor_pool_dma | 1); /* Z=1 */ - wmb(); + if (video->first_run == 1) { + video->first_run = 0; + + /* start DMA once all of the frames are READY */ + video->n_clear_frames = 0; + video->first_clear_frame = -1; + video->current_packet = 0; + video->active_frame = 0; + + /* reset iso recv control register */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF); + wmb(); + + /* clear bufferFill, set isochHeader and speed (0=100) */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000); - /* run */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000); - flush_pci_write(video->ohci); + /* match on all tags, listen on channel */ + reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel); + + /* address and first descriptor block + Z=1 */ + reg_write(video->ohci, video->ohci_IsoRcvCommandPtr, + video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */ + wmb(); + + /* run */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000); + flush_pci_write(video->ohci); + + debug_printk("dv1394: DMA started\n"); - debug_printk("dv1394: DMA started\n"); - #if DV1394_DEBUG_LEVEL >= 2 - { - int i; - - for(i = 0; i < 1000; ++i) { - mdelay(1); - if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) { - printk("DMA ACTIVE after %d msec\n", i); - break; + { + int i; + + for(i = 0; i < 1000; ++i) { + mdelay(1); + if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) { + printk("DMA ACTIVE after %d msec\n", i); + break; + } } + if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) { + printk("DEAD, event = %x\n", + reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F); + } else + printk("RUNNING!\n"); } - if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) { - printk("DEAD, event = %x\n", - reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F); - } else - printk("RUNNING!\n"); - } #endif + } + else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) { + debug_printk("DEAD, event = %x\n", + reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F); + + /* wake */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12)); + } } @@ -873,7 +895,7 @@ receive_packets() - build the DMA program for receiving */ -static void receive_packets(struct video_card *video, struct frame *f) +static void receive_packets(struct video_card *video) { struct DMA_descriptor_block *block = NULL; dma_addr_t block_dma = 0; @@ -881,52 +903,50 @@ dma_addr_t data_dma = 0; u32 *last_branch_address = NULL; unsigned long irq_flags; + int want_interrupt = 0; + struct frame *f = NULL; + int i, j; spin_lock_irqsave(&video->spinlock, irq_flags); - video->n_clear_frames = 0; - video->first_clear_frame = -1; + for (j = 0; j < video->n_frames; j++) { - for (video->current_packet = 0; video->current_packet < MAX_PACKET_BUFFER; ++video->current_packet) { - /* locate a descriptor block and packet from the buffer */ - block = &(f->descriptor_pool[video->current_packet]); - block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma; - - data = &(video->packet_buffer[video->current_packet]); - data_dma = ((unsigned long) data - (unsigned long) video->packet_buffer) + video->packet_buffer_dma; - - /* setup DMA descriptor block */ - fill_input_last( &(block->u.in.il), 512, data_dma); + /* connect frames */ + if (j > 0 && f != NULL && f->frame_end_branch != NULL) + *(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */ - /* link descriptors */ - last_branch_address = f->frame_end_branch; + f = video->frames[j]; - if (last_branch_address) - *(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */ - - f->frame_end_branch = &(block->u.in.il.q[2]); - } + for (i = 0; i < MAX_PACKETS; i++) { + /* locate a descriptor block and packet from the buffer */ + block = &(f->descriptor_pool[i]); + block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma; + + data = &(video->packet_buffer[(f->frame_num * MAX_PACKETS) + i]); + data_dma = dma_offset_to_bus( &video->packet_buffer_dma, + ((unsigned long) data - (unsigned long) video->packet_buffer) ); + + /* setup DMA descriptor block */ + want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1)); + fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma); + + /* link descriptors */ + last_branch_address = f->frame_end_branch; + + if (last_branch_address != NULL) + *(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */ + f->frame_end_branch = &(block->u.in.il.q[2]); + } + + } /* next j */ + /* loop tail to head */ - if (f->frame_end_branch) - *(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | 1); /* set Z=1 */ + if (f != NULL && f->frame_end_branch != NULL) + *(f->frame_end_branch) = cpu_to_le32(video->frames[0]->descriptor_pool_dma | 1); /* set Z=1 */ spin_unlock_irqrestore(&video->spinlock, irq_flags); - if (video->first_run) { - /* start DMA once all of the frames are READY */ - video->first_run = 0; - video->current_packet = 0; - video->active_frame = f->frame_num; - start_dma_receive(video, f); - } - else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) { - debug_printk("DEAD, event = %x\n", - reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F); - - /* wake */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12)); - } } @@ -1076,7 +1096,6 @@ } } - if(video->user_buf == NULL) { unsigned int i; @@ -1132,37 +1151,65 @@ for(i = 0; i < video->n_frames; i++) video->frames[i]->data = (unsigned long) video->user_buf + i * video->frame_size; - /* allocate packet buffers */ - video->packet_buffer_size = sizeof(struct packet) * MAX_PACKET_BUFFER; - if (video->packet_buffer_size % PAGE_SIZE) - video->packet_buffer_size += PAGE_SIZE - (video->packet_buffer_size % PAGE_SIZE); - - - video->packet_buffer = kmalloc(video->packet_buffer_size, GFP_KERNEL); - - if(!video->packet_buffer) { - printk(KERN_ERR "dv1394: Cannot allocate packet buffers"); - retval = -ENOMEM; - goto err_user_buf; - } - - /* map the packet buffer into the IOMMU */ - video->packet_buffer_dma = pci_map_single(video->ohci->dev, - video->packet_buffer, - video->packet_buffer_size, - PCI_DMA_FROMDEVICE); - if(!video->packet_buffer_dma) { - printk(KERN_ERR "dv1394: Cannot map packet buffer to IOMMU"); - kfree(video->packet_buffer); - video->packet_buffer = NULL; - retval = -ENOMEM; - goto err_user_buf; + + if(video->packet_buffer == NULL) { + unsigned int i; + + /* allocate packet buffer */ + video->packet_buffer_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS; + if (video->packet_buffer_size % PAGE_SIZE) + video->packet_buffer_size += PAGE_SIZE - (video->packet_buffer_size % PAGE_SIZE); + video->packet_buffer_dma.n_pages = video->packet_buffer_size / PAGE_SIZE; + + + video->packet_buffer = rvmalloc(video->packet_buffer_size); + + if(!video->packet_buffer) { + printk(KERN_ERR "dv1394: Cannot allocate packet buffer"); + retval = -ENOMEM; + goto err_user_buf; + } + + /* allocate the sglist to hold the DMA addresses */ + video->packet_buffer_dma.n_pages = video->packet_buffer_size / PAGE_SIZE; + video->packet_buffer_dma.sglist = kmalloc(video->packet_buffer_dma.n_pages * + sizeof(struct scatterlist), GFP_KERNEL); + if(!video->packet_buffer_dma.sglist) { + printk(KERN_ERR "dv1394: Cannot allocate sglist for packet buffer\n"); + goto err_packet_buf; + } + + /* initialize all fields of all sglist entries to zero + (new requirement due to PCI changes in 2.4.13) */ + memset(video->packet_buffer_dma.sglist, 0, + video->packet_buffer_dma.n_pages * sizeof(struct scatterlist)); + + + /* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */ + for(i = 0; i < video->packet_buffer_dma.n_pages; i++) { + unsigned long va = (unsigned long) video->packet_buffer + i * PAGE_SIZE; + + video->packet_buffer_dma.sglist[i].page = vmalloc_to_page((void *)va); + video->packet_buffer_dma.sglist[i].length = PAGE_SIZE; + } + + /* map the buffer in the IOMMU */ + /* the user_data buffer only allows DMA *to* the card for transmission; + incoming DV data comes through the packet_buffer first, and then is copied to user_data */ + video->packet_buffer_dma.n_dma_pages = pci_map_sg(video->ohci->dev, + &video->packet_buffer_dma.sglist[0], + video->packet_buffer_dma.n_pages, + PCI_DMA_FROMDEVICE); + if(video->packet_buffer_dma.n_dma_pages == 0) { + printk(KERN_ERR "dv1394: Error mapping packet buffer to the IOMMU\n"); + goto err_packet_buf; + } + + debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n", + video->n_frames*MAX_PACKETS, video->packet_buffer_dma.n_pages, + video->packet_buffer_dma.n_dma_pages, video->packet_buffer_size); } - - debug_printk("dv1394: Allocated %d packet buffers for receive, total %lu bytes\n", - MAX_PACKET_BUFFER, video->packet_buffer_size); - - + /* set up register offsets for IT context */ /* IT DMA context registers are spaced 16 bytes apart */ video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx; @@ -1186,6 +1233,26 @@ return 0; + err_packet_buf: + if(video->packet_buffer) { + if(video->packet_buffer_dma.sglist) { + if(video->packet_buffer_dma.n_dma_pages > 0) { + /* unmap it from the IOMMU */ + pci_unmap_sg(video->ohci->dev, + video->packet_buffer_dma.sglist, + video->packet_buffer_dma.n_pages, + PCI_DMA_FROMDEVICE); + video->packet_buffer_dma.n_dma_pages = 0; + } + kfree(video->packet_buffer_dma.sglist); + video->packet_buffer_dma.sglist = NULL; + video->packet_buffer_dma.n_pages = 0; + } + rvfree(video->packet_buffer, video->packet_buffer_size); + video->packet_buffer = NULL; + video->packet_buffer_size = 0; + } + err_user_buf: if(video->user_buf) { if(video->user_dma.sglist) { @@ -1270,7 +1337,6 @@ video->active_frame = -1; video->first_run = 1; - /* wait until DMA really stops */ i = 0; @@ -1389,11 +1455,20 @@ } if (video->packet_buffer) { - pci_unmap_single(video->ohci->dev, - video->packet_buffer_dma, - video->packet_buffer_size, - PCI_DMA_FROMDEVICE); - kfree(video->packet_buffer); + if(video->packet_buffer_dma.sglist) { + if(video->packet_buffer_dma.n_dma_pages > 0) { + /* unmap it from the IOMMU */ + pci_unmap_sg(video->ohci->dev, + video->packet_buffer_dma.sglist, + video->packet_buffer_dma.n_pages, + PCI_DMA_FROMDEVICE); + video->packet_buffer_dma.n_dma_pages = 0; + } + kfree(video->packet_buffer_dma.sglist); + video->packet_buffer_dma.sglist = NULL; + video->packet_buffer_dma.n_pages = 0; + } + rvfree(video->packet_buffer, video->packet_buffer_size); video->packet_buffer = NULL; video->packet_buffer_size = 0; } @@ -1679,7 +1754,11 @@ up(&video->sem); return ret; } - receive_packets(video, video->frames[video->first_clear_frame]); + video->continuity_counter = -1; + + receive_packets(video); + + start_dma_receive(video); } ret = 0; @@ -1921,14 +2000,17 @@ } case DV1394_START_RECEIVE: { - if( !video_card_initialized(video) ) { ret = do_dv1394_init_default(video); if(ret) goto out; } - receive_packets(video, video->frames[video->first_clear_frame]); + video->continuity_counter = -1; + + receive_packets(video); + + start_dma_receive(video); ret = 0; break; @@ -2318,9 +2400,7 @@ struct video_card *video = (struct video_card*) data; spin_lock(&video->spinlock); - - irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n", - (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent); + irq_printk("ContextControl = %08x, CommandPtr = %08x\n", reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), reg_read(video->ohci, video->ohci_IsoXmitCommandPtr) @@ -2462,80 +2542,112 @@ int wake = 0; struct video_card *video = (struct video_card*) data; + spin_lock(&video->spinlock); + if( (video->ohci_ir_ctx != -1) && (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { int sof=0; /* start-of-frame flag */ struct frame *f; u16 packet_length, packet_time; - - packet_length = le16_to_cpu(video->packet_buffer[video->current_packet].data_length); - packet_time = le16_to_cpu(video->packet_buffer[video->current_packet].timestamp); - - irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet, - packet_time, packet_length, - video->packet_buffer[video->current_packet].data[0], video->packet_buffer[video->current_packet].data[1]); - - f = video->frames[video->active_frame]; - - /* exclude empty packet */ - if (packet_length > 8) { - - /* check for start of frame */ - sof = (video->packet_buffer[video->current_packet].data[0] == 0x1f && - video->packet_buffer[video->current_packet].data[1] == 0x07); - - if (!video->first_frame) { - if (sof) { - video->first_frame = 1; - } - - } else if (sof) { - /* close current frame */ - frame_reset(f); /* f->state = STATE_CLEAR */ - video->n_clear_frames++; - if (video->n_clear_frames > video->n_frames) { - video->n_clear_frames = video->n_frames; + int i, dbc=0; + struct DMA_descriptor_block *block = NULL; + u16 xferstatus; + + /* loop over all descriptors in all frames */ + for (i = 0; i < video->n_frames*MAX_PACKETS; i++) { + packet_length = le16_to_cpu(video->packet_buffer[video->current_packet].data_length); + packet_time = le16_to_cpu(video->packet_buffer[video->current_packet].timestamp); + + irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet, + packet_time, packet_length, + video->packet_buffer[video->current_packet].data[0], video->packet_buffer[video->current_packet].data[1]); + + /* get the descriptor based on packet_buffer cursor */ + f = video->frames[video->current_packet / MAX_PACKETS]; + block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]); + xferstatus = le16_to_cpu(block->u.in.il.q[3] >> 16); + xferstatus &= 0x1F; + + /* get the current frame */ + f = video->frames[video->active_frame]; + + /* exclude empty packet */ + if (packet_length > 8 && xferstatus == 0x11) { + irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) ); + + /* check for start of frame */ + /* DRD> Changed to check section type ([0]>>5==0) + and dif sequence ([1]>>4==0) */ + sof = ( (video->packet_buffer[video->current_packet].data[0] >> 5) == 0 && + (video->packet_buffer[video->current_packet].data[1] >> 4) == 0); + + dbc = (int) (video->packet_buffer[video->current_packet].cip_h1 >> 24); + if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) ) video->dropped_frames++; - } - if (video->first_clear_frame == -1) - video->first_clear_frame = video->active_frame; - - /* get the next frame */ - video->active_frame = (video->active_frame + 1) % video->n_frames; - f = video->frames[video->active_frame]; - - irq_printk(" frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n", - video->active_frame, video->n_clear_frames, video->first_clear_frame); - } - if (video->first_frame) { - if (sof) { - /* open next frame */ - f->state = FRAME_READY; - } + video->continuity_counter = dbc; - /* copy to buffer */ - if (f->n_packets > (video->frame_size / 480)) { - printk(KERN_ERR "frame buffer overflow during receive\n"); - } - - /* make sure we are seeing the latest changes to packet_buffer */ - pci_dma_sync_single(video->ohci->dev, - video->packet_buffer_dma, - video->packet_buffer_size, - PCI_DMA_FROMDEVICE); + if (!video->first_frame) { + if (sof) { + video->first_frame = 1; + } + + } else if (sof) { + /* close current frame */ + frame_reset(f); /* f->state = STATE_CLEAR */ + video->n_clear_frames++; + if (video->n_clear_frames > video->n_frames) { + video->n_clear_frames = video->n_frames; + video->dropped_frames++; + } + if (video->first_clear_frame == -1) + video->first_clear_frame = video->active_frame; + + /* get the next frame */ + video->active_frame = (video->active_frame + 1) % video->n_frames; + f = video->frames[video->active_frame]; - frame_put_packet( f, &video->packet_buffer[video->current_packet]); + irq_printk(" frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n", + video->active_frame, video->n_clear_frames, video->first_clear_frame); + } + if (video->first_frame) { + if (sof) { + /* open next frame */ + f->state = FRAME_READY; + } + + /* copy to buffer */ + if (f->n_packets > (video->frame_size / 480)) { + printk(KERN_ERR "frame buffer overflow during receive\n"); + } + + /* make sure we are seeing the latest changes to packet_buffer */ + pci_dma_sync_sg(video->ohci->dev, + video->packet_buffer_dma.sglist, + video->packet_buffer_dma.n_dma_pages, + PCI_DMA_FROMDEVICE); + + frame_put_packet( f, &video->packet_buffer[video->current_packet]); + + } /* first_frame */ - } /* first_frame */ - - } /* not empty packet */ - - /* advance packet_buffer cursor */ - video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER; + } + + /* stop, end of ready packets */ + else if (xferstatus == 0) { + break; + } + + /* reset xferStatus & resCount */ + block->u.in.il.q[3] = cpu_to_le32(512); + + /* advance packet_buffer cursor */ + video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames); + + } /* for all packets */ wake = 1; /* why the hell not? */ - + } /* receive interrupt */ spin_unlock(&video->spinlock); @@ -2750,6 +2862,8 @@ video->user_buf = NULL; video->user_buf_size = 0; + video->packet_buffer = NULL; + video->packet_buffer_size = 0; clear_bit(0, &video->open); spin_lock_init(&video->spinlock); |