Thread: [Linux1394-cvslog] rev 664 - trunk
Brought to you by:
aeb,
bencollins
From: SVN U. <dm...@li...> - 2002-11-07 03:36:15
|
Author: dmaas Date: 2002-11-06 22:36:07 -0500 (Wed, 06 Nov 2002) New Revision: 664 Modified: trunk/dv1394-private.h trunk/dv1394.c Log: Dan waves his hand and *poof*, 300 lines of code disappear (- convert dv1394 to use the PCI DMA wrappers rather than its own code) Modified: trunk/dv1394-private.h ============================================================================== --- trunk/dv1394-private.h (original) +++ trunk/dv1394-private.h 2002-11-06 22:36:08.000000000 -0500 @@ -28,8 +28,7 @@ #include "ieee1394.h" #include "ohci1394.h" -#include <linux/pci.h> -#include <asm/scatterlist.h> +#include "dma.h" /* data structures private to the dv1394 driver */ /* none of this is exposed to user-space */ @@ -384,35 +383,6 @@ /* reset f so that it can be used again */ static void frame_reset(struct frame *f); - -/* structure for bookkeeping of a large non-physically-contiguous DMA buffer */ - -struct dma_region { - unsigned int n_pages; - unsigned int n_dma_pages; - struct scatterlist *sglist; -}; - -/* return the DMA bus address of the byte with the given offset - relative to the beginning of the dma_region */ - -static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long offset) -{ - int i; - struct scatterlist *sg; - - for(i = 0, sg = &dma->sglist[0]; i < dma->n_dma_pages; i++, sg++) { - if(offset < sg_dma_len(sg)) { - return sg_dma_address(sg) + offset; - } - offset -= sg_dma_len(sg); - } - - printk(KERN_ERR "dv1394: dma_offset_to_bus failed for offset %lu!\n", offset); - return 0; -} - - /* struct video_card contains all data associated with one instance of the dv1394 driver */ @@ -509,9 +479,8 @@ /* the large, non-contiguous (rvmalloc()) ringbuffer for DV data, exposed to user-space via mmap() */ - unsigned char *user_buf; - unsigned long user_buf_size; - struct dma_region user_dma; + unsigned long dv_buf_size; + struct dma_region dv_buf; /* next byte in the ringbuffer that a write() call will fill */ size_t write_off; @@ -580,9 +549,8 @@ /* physically contiguous packet ringbuffer for receive */ - struct packet *packet_buffer; - struct dma_region packet_buffer_dma; - unsigned long packet_buffer_size; + struct dma_region packet_buf; + unsigned long packet_buf_size; unsigned int current_packet; int first_frame; /* received first start frame marker? */ Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2002-11-06 22:36:08.000000000 -0500 @@ -190,39 +190,6 @@ return (struct video_card*) file->private_data; } - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -/* note: we no longer use mem_map_reserve, because it causes a memory - leak, and setting vma->vm_flags to VM_RESERVED should be sufficient - to pin the pages in memory anyway. */ - -static void * rvmalloc(unsigned long size) -{ - void * mem; - - mem = vmalloc_32(size); - - if(mem) - memset(mem, 0, size); /* Clear the ram out, - no junk to the user */ - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - if (mem) { - vfree(mem); - } -} - -/***********************************/ -/* END Memory management functions */ -/***********************************/ - - /*** FRAME METHODS *********************************************************/ static void frame_reset(struct frame *f) @@ -451,11 +418,7 @@ /******************************/ /* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */ - fill_output_more_immediate( &(block->u.out.omi), - /* tag - what is this??? */ 1, - video->channel, - /* sync tag - what is this??? */ 0, - payload_size); + fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size); if(empty_packet) { /* second descriptor - OUTPUT_LAST for CIP header */ @@ -506,8 +469,8 @@ PAGE_SIZE - (data_p % PAGE_SIZE), /* DMA address of data_p */ - dma_offset_to_bus(&f->video->user_dma, - data_p - (unsigned long) f->video->user_buf)); + dma_region_offset_to_bus(&video->dv_buf, + data_p - (unsigned long) video->dv_buf.kvirt)); fill_output_last( &(block->u.out.u.full.u.cross.ol), @@ -521,8 +484,8 @@ 480 - (PAGE_SIZE - (data_p % PAGE_SIZE)), /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */ - dma_offset_to_bus(&f->video->user_dma, - data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) f->video->user_buf)); + dma_region_offset_to_bus(&video->dv_buf, + data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt)); if(first_packet) f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]); @@ -556,8 +519,8 @@ /* DMA address of data_p */ - dma_offset_to_bus(&f->video->user_dma, - data_p - (unsigned long) f->video->user_buf)); + dma_region_offset_to_bus(&video->dv_buf, + data_p - (unsigned long) video->dv_buf.kvirt)); if(first_packet) f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]); @@ -598,13 +561,8 @@ to loop back up to the top */ *(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors); - - /* make the latest version of the frame buffer visible to the PCI card */ - /* could optimize this by only syncing the pages associated with this frame */ - pci_dma_sync_sg(video->ohci->dev, - &video->user_dma.sglist[0], - video->user_dma.n_dma_pages, - PCI_DMA_TODEVICE); + /* make the latest version of this frame visible to the PCI card */ + dma_region_sync(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size); /* lock against DMA interrupt */ spin_lock_irqsave(&video->spinlock, irq_flags); @@ -922,9 +880,9 @@ 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) ); + data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i; + data_dma = dma_region_offset_to_bus( &video->packet_buf, + ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) ); /* setup DMA descriptor block */ want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1)); @@ -989,10 +947,8 @@ 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->user_buf) && - (video->user_buf_size != new_buf_size) ) { + if(video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) goto err; - } /* shutdown the card if it's currently active */ /* (the card should not be reset if the parameters are screwy) */ @@ -1096,118 +1052,37 @@ } } - - if(video->user_buf == NULL) { - unsigned int i; - + if(!video->dv_buf.kvirt) { /* allocate the ringbuffer */ - video->user_buf = rvmalloc(new_buf_size); - if(!video->user_buf) { - printk(KERN_ERR "dv1394: Cannot allocate frame buffers\n"); + retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE); + if(retval) goto err_frames; - } - video->user_buf_size = new_buf_size; - - /* allocate the sglist to hold the DMA addresses */ - video->user_dma.n_pages = video->user_buf_size / PAGE_SIZE; - video->user_dma.sglist = kmalloc(video->user_dma.n_pages * sizeof(struct scatterlist), GFP_KERNEL); - if(!video->user_dma.sglist) { - printk(KERN_ERR "dv1394: Cannot allocate sglist for user buffer\n"); - goto err_user_buf; - } - - /* initialize all fields of all sglist entries to zero - (new requirement due to PCI changes in 2.4.13) */ - - memset(video->user_dma.sglist, 0, video->user_dma.n_pages * sizeof(struct scatterlist)); + + video->dv_buf_size = new_buf_size; - - /* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */ - for(i = 0; i < video->user_dma.n_pages; i++) { - unsigned long va = (unsigned long) video->user_buf + i * PAGE_SIZE; - - video->user_dma.sglist[i].page = vmalloc_to_page((void *)va); - video->user_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->user_dma.n_dma_pages = pci_map_sg(video->ohci->dev, - &video->user_dma.sglist[0], - video->user_dma.n_pages, - PCI_DMA_TODEVICE); - if(video->user_dma.n_dma_pages == 0) { - printk(KERN_ERR "dv1394: Error mapping user buffer to the IOMMU\n"); - goto err_user_buf; - } - debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", - video->n_frames, video->user_dma.n_pages, - video->user_dma.n_dma_pages, video->user_buf_size); + video->n_frames, video->dv_buf.n_pages, + video->dv_buf.n_dma_pages, video->dv_buf_size); } /* set up the frame->data pointers */ for(i = 0; i < video->n_frames; i++) - video->frames[i]->data = (unsigned long) video->user_buf + i * video->frame_size; + video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size; - - if(video->packet_buffer == NULL) { - unsigned int i; - + if(!video->packet_buf.kvirt) { /* 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; - } + video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS; + if (video->packet_buf_size % PAGE_SIZE) + video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE); + + retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size, + video->ohci->dev, PCI_DMA_FROMDEVICE); + if(retval) + goto err_dv_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); + video->n_frames*MAX_PACKETS, video->packet_buf.n_pages, + video->packet_buf.n_dma_pages, video->packet_buf_size); } /* set up register offsets for IT context */ @@ -1233,46 +1108,9 @@ 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) { - if(video->user_dma.n_dma_pages > 0) { - /* unmap it from the IOMMU */ - pci_unmap_sg(video->ohci->dev, - video->user_dma.sglist, - video->user_dma.n_pages, - PCI_DMA_TODEVICE); - video->user_dma.n_dma_pages = 0; - } - kfree(video->user_dma.sglist); - video->user_dma.sglist = NULL; - video->user_dma.n_pages = 0; - } - rvfree(video->user_buf, video->user_buf_size); - video->user_buf = NULL; - video->user_buf_size = 0; - } - + err_dv_buf: + dma_region_free(&video->dv_buf); + err_frames: for(i = 0; i < DV1394_MAX_FRAMES; i++) { if(video->frames[i]) @@ -1367,7 +1205,7 @@ -static int do_dv1394_shutdown(struct video_card *video, int free_user_buf) +static int do_dv1394_shutdown(struct video_card *video, int free_dv_buf) { int i; unsigned long flags; @@ -1445,51 +1283,20 @@ /* we can't free the DMA buffer unless it is guaranteed that no more user-space mappings exist */ - if(free_user_buf && video->user_buf) { - if(video->user_dma.sglist) { - if(video->user_dma.n_dma_pages > 0) { - /* unmap it from the IOMMU */ - pci_unmap_sg(video->ohci->dev, - video->user_dma.sglist, - video->user_dma.n_pages, - PCI_DMA_TODEVICE); - video->user_dma.n_dma_pages = 0; - } - kfree(video->user_dma.sglist); - video->user_dma.sglist = NULL; - video->user_dma.n_pages = 0; - } - rvfree(video->user_buf, video->user_buf_size); - video->user_buf = NULL; - video->user_buf_size = 0; - } - - 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; + if(free_dv_buf) { + dma_region_free(&video->dv_buf); + video->dv_buf_size = 0; } + /* free packet buffer */ + dma_region_free(&video->packet_buf); + video->packet_buf_size = 0; + debug_printk("dv1394: shutdown complete\n"); return 0; } - - /* ********************************** *** MMAP() THEORY OF OPERATION *** @@ -1512,96 +1319,28 @@ force the user to choose one buffer size and stick with it. This small sacrifice is worth the huge reduction in error-prone code in dv1394. - - Note: dv1394_mmap does no page table manipulation. The page - table entries are created by the dv1394_nopage() handler as - page faults are taken by the user. -*/ - -static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access) -{ - unsigned long offset; - unsigned long kernel_virt_addr; - struct page *ret = NOPAGE_SIGBUS; - - struct video_card *video = (struct video_card*) area->vm_private_data; - - /* guard against process-context operations and the interrupt */ - /* (by definition page faults are taken in interrupt context) */ - spin_lock(&video->spinlock); - - if(!video->user_buf) - goto out; - - if( (address < (unsigned long) area->vm_start) || - (address > (unsigned long) area->vm_start + video->user_buf_size) ) - goto out; - - offset = address - area->vm_start; - kernel_virt_addr = (unsigned long) video->user_buf + offset; - ret = vmalloc_to_page((void *)kernel_virt_addr); - get_page(ret); - - out: - spin_unlock(&video->spinlock); - return ret; -} - -static struct vm_operations_struct dv1394_vm_ops = { - .nopage = dv1394_nopage -}; - -/* - dv1394_mmap does no page table manipulation. The page table entries - are created by the dv1394_nopage() handler as page faults are taken - by the user. */ int dv1394_mmap(struct file *file, struct vm_area_struct *vma) { struct video_card *video = file_to_video_card(file); - unsigned long size; - int res = -EINVAL; + int retval = -EINVAL; /* serialize mmap */ down(&video->sem); if( ! video_card_initialized(video) ) { - res = do_dv1394_init_default(video); - if(res) - goto err; + retval = do_dv1394_init_default(video); + if(retval) + goto out; } - /* region must be page-aligned */ - if(vma->vm_pgoff != 0) - goto err; - - /* check the size the user is trying to map */ - size = vma->vm_end - vma->vm_start; - if(size > video->user_buf_size) - goto err; - - /* - we don't actually mess with the page tables here. - (nopage() takes care of that from the page fault handler) - Just set up the vma->vm_ops. - */ - - vma->vm_ops = &dv1394_vm_ops; - vma->vm_private_data = video; - vma->vm_file = file; - - /* don't try to swap this out =) */ - vma->vm_flags |= VM_RESERVED; - + retval = dma_region_mmap(&video->dv_buf, file, vma); +out: up(&video->sem); - return 0; - err: - up(&video->sem); - return res; + return retval; } - /*** DEVICE FILE INTERFACE *************************************************/ /* no need to serialize, multiple threads OK */ @@ -1717,7 +1456,7 @@ continue; /* start over from 'while(count > 0)...' */ } - if(copy_from_user(video->user_buf + video->write_off, buffer, cnt)) { + if(copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) { if(!ret) ret = -EFAULT; break; @@ -1821,7 +1560,7 @@ continue; /* start over from 'while(count > 0)...' */ } - if(copy_to_user(buffer, video->user_buf + video->write_off, cnt)) { + if(copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) { if(!ret) ret = -EFAULT; break; @@ -2566,12 +2305,14 @@ /* 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); + struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet); + + packet_length = le16_to_cpu(p->data_length); + packet_time = le16_to_cpu(p->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]); + p->data[0], p->data[1]); /* get the descriptor based on packet_buffer cursor */ f = video->frames[video->current_packet / MAX_PACKETS]; @@ -2589,10 +2330,9 @@ /* 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); + sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0); - dbc = (int) (video->packet_buffer[video->current_packet].cip_h1 >> 24); + dbc = (int) (p->cip_h1 >> 24); if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) ) video->dropped_frames++; video->continuity_counter = dbc; @@ -2631,13 +2371,12 @@ 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); + /* make sure we are seeing the latest changes to packet_buf */ + dma_region_sync(&video->packet_buf, + (unsigned long) p - (unsigned long) video->packet_buf.kvirt, + sizeof(struct packet)); - frame_put_packet( f, &video->packet_buffer[video->current_packet]); + frame_put_packet(f, p); } /* first_frame */ @@ -2874,10 +2613,10 @@ for(i = 0; i < DV1394_MAX_FRAMES; i++) video->frames[i] = NULL; - video->user_buf = NULL; - video->user_buf_size = 0; - video->packet_buffer = NULL; - video->packet_buffer_size = 0; + dma_region_init(&video->dv_buf); + video->dv_buf_size = 0; + dma_region_init(&video->packet_buf); + video->packet_buf_size = 0; clear_bit(0, &video->open); spin_lock_init(&video->spinlock); |