linux1394-cvslog Mailing List for IEEE 1394 for Linux (Page 9)
Brought to you by:
aeb,
bencollins
You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(10) |
Jul
(12) |
Aug
(8) |
Sep
(9) |
Oct
(4) |
Nov
(5) |
Dec
(5) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(7) |
Feb
(3) |
Mar
(15) |
Apr
(12) |
May
(5) |
Jun
(9) |
Jul
(32) |
Aug
(39) |
Sep
(42) |
Oct
(22) |
Nov
(28) |
Dec
(8) |
2002 |
Jan
(37) |
Feb
(47) |
Mar
(6) |
Apr
(29) |
May
(33) |
Jun
(9) |
Jul
(28) |
Aug
(30) |
Sep
(15) |
Oct
(75) |
Nov
(37) |
Dec
(31) |
2003 |
Jan
|
Feb
(89) |
Mar
(41) |
Apr
(13) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: SVN U. <ben...@li...> - 2002-11-16 04:58:38
|
Author: bencollins Date: 2002-11-15 23:58:04 -0500 (Fri, 15 Nov 2002) New Revision: 668 Removed: branches/gasp/ Log: Delete old gasp branch |
From: SVN U. <ben...@li...> - 2002-11-16 04:49:46
|
Author: bencollins Date: 2002-11-15 23:49:12 -0500 (Fri, 15 Nov 2002) New Revision: 667 Modified: trunk/ohci1394.c Log: For self-id interrupt: Do not mdelay for invalid nodeid. Instead accept it and hope that this means another bus reset occured and will follow us. To help this along, we move the clearing of the clearing of the bus reset and enabling of the bus reset interrupt into the valid node-id block. We don't want to be enabling all of this underneath of a self-id phase in another interrupt. Moved setting of phys-dma filters into same block, and shifted things around so that hopefully the mdelay there wont be needed aswell. Based on Manfred's patch. Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-11-15 23:49:13.000000000 -0500 @@ -1873,16 +1873,11 @@ event &= ~OHCI1394_isochTx; } if (event & OHCI1394_selfIDComplete) { + event &= ~OHCI1394_selfIDComplete; + if (host->in_bus_reset) { node_id = reg_read(ohci, OHCI1394_NodeID); - /* If our nodeid is not valid, give a msec delay - * to let it settle in and try again. */ - if (!(node_id & 0x80000000)) { - mdelay(1); - node_id = reg_read(ohci, OHCI1394_NodeID); - } - if (node_id & 0x80000000) { /* NodeID valid */ phyid = node_id & 0x0000003f; isroot = (node_id & 0x40000000) != 0; @@ -1896,52 +1891,41 @@ phyid, isroot); } else { PRINT(KERN_ERR, ohci->id, - "SelfID interrupt received, but " - "NodeID is not valid: %08X", + "SelfID received, but NodeID invalid " + "(probably new bus reset occured): %08X", node_id); } + /* Clear the bus reset event and re-enable the + * busReset interrupt. */ + spin_lock_irqsave(&ohci->event_lock, flags); + reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); + reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); + spin_unlock_irqrestore(&ohci->event_lock, flags); + /* Accept Physical requests from all nodes. */ - reg_write(ohci,OHCI1394_AsReqFilterHiSet, - 0xffffffff); - reg_write(ohci,OHCI1394_AsReqFilterLoSet, - 0xffffffff); + reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff); + reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff); + + /* Turn on phys dma reception. + * + * TODO: Enable some sort of filtering management. + */ + if (phys_dma) { + reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0xffffffff); + reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0xffffffff); + reg_write(ohci,OHCI1394_PhyUpperBound, 0xffff0000); + } else { + reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0x00000000); + reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0x00000000); + } + + DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n", + reg_read(ohci,OHCI1394_PhyReqFilterHiSet), + reg_read(ohci,OHCI1394_PhyReqFilterLoSet)); } else PRINT(KERN_ERR, ohci->id, "SelfID received outside of bus reset sequence"); - - /* Finally, we clear the busReset event and reenable - * the busReset interrupt. */ - spin_lock_irqsave(&ohci->event_lock, flags); - reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); - reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); - spin_unlock_irqrestore(&ohci->event_lock, flags); - event &= ~OHCI1394_selfIDComplete; - - /* Turn on phys dma reception. We should - * probably manage the filtering somehow, - * instead of blindly turning it on. */ - - /* - * CAUTION! - * Some chips (TI TSB43AB22) won't take a value in - * the PhyReqFilter register until after the IntEvent - * is cleared for bus reset, and even then a short - * delay is required. - */ - if (phys_dma) { - mdelay(1); - reg_write(ohci,OHCI1394_PhyReqFilterHiSet, - 0xffffffff); - reg_write(ohci,OHCI1394_PhyReqFilterLoSet, - 0xffffffff); - reg_write(ohci,OHCI1394_PhyUpperBound, - 0xffff0000); - } - - DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n", - reg_read(ohci,OHCI1394_PhyReqFilterHiSet), - reg_read(ohci,OHCI1394_PhyReqFilterLoSet)); } /* Make sure we handle everything, just in case we accidentally |
From: SVN U. <ben...@li...> - 2002-11-11 20:46:12
|
Author: bencollins Date: 2002-11-11 15:46:03 -0500 (Mon, 11 Nov 2002) New Revision: 666 Modified: trunk/dma.c trunk/iso.c Log: Let's include some headers so these things actually compile. Modified: trunk/dma.c ============================================================================== --- trunk/dma.c (original) +++ trunk/dma.c 2002-11-11 15:46:04.000000000 -0500 @@ -8,6 +8,8 @@ */ #include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> #include "dma.h" /* dma_prog_region */ Modified: trunk/iso.c ============================================================================== --- trunk/iso.c (original) +++ trunk/iso.c 2002-11-11 15:46:04.000000000 -0500 @@ -9,6 +9,7 @@ * directory of the kernel sources for details. */ +#include <linux/slab.h> #include "iso.h" void hpsb_iso_stop(struct hpsb_iso *iso) |
From: SVN U. <dm...@li...> - 2002-11-07 04:03:44
|
Author: dmaas Date: 2002-11-06 23:03:39 -0500 (Wed, 06 Nov 2002) New Revision: 665 Modified: trunk/dv1394.c Log: dv1394 - sync DMA mapping of packet earlier in the IR tasklet Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2002-11-06 23:03:40.000000000 -0500 @@ -2306,7 +2306,12 @@ /* loop over all descriptors in all frames */ for (i = 0; i < video->n_frames*MAX_PACKETS; i++) { struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet); - + + /* make sure we are seeing the latest changes to p */ + dma_region_sync(&video->packet_buf, + (unsigned long) p - (unsigned long) video->packet_buf.kvirt, + sizeof(struct packet)); + packet_length = le16_to_cpu(p->data_length); packet_time = le16_to_cpu(p->timestamp); @@ -2370,16 +2375,10 @@ 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_buf */ - dma_region_sync(&video->packet_buf, - (unsigned long) p - (unsigned long) video->packet_buf.kvirt, - sizeof(struct packet)); frame_put_packet(f, p); } /* first_frame */ - } /* stop, end of ready packets */ |
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); |
From: SVN U. <dm...@li...> - 2002-11-07 02:20:14
|
Author: dmaas Date: 2002-11-06 21:20:11 -0500 (Wed, 06 Nov 2002) New Revision: 663 Modified: trunk/ohci1394.c Log: rawiso/ohci1394 - implement cycle matching on iso receive Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-11-06 21:20:12.000000000 -0500 @@ -1156,20 +1156,39 @@ static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle) { struct ohci_iso_recv *recv = iso->hostdata; - u32 command; + u32 command, contextMatch; reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF); wmb(); /* use packet-per-buffer mode, and keep ISO headers */ reg_write(recv->ohci, recv->ContextControlSet, (1 << 30)); - - /* match on all tags, listen on channel */ - reg_write(recv->ohci, recv->ContextMatch, 0xF0000000 | iso->channel); + /* match on all tags, listen on channel */ + contextMatch = 0xF0000000 | iso->channel; + if(cycle != -1) { - /* XXX DJM use cycleMatch */ + u32 seconds; + + /* enable cycleMatch */ + reg_write(recv->ohci, recv->ContextControlSet, (1 << 29)); + + /* set starting cycle */ + cycle &= 0x1FFF; + + /* 'cycle' is only mod 8000, but we also need two 'seconds' bits - + just snarf them from the current time */ + seconds = reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer) >> 25; + + /* advance one second to give some extra time for DMA to start */ + seconds += 1; + + cycle |= (seconds & 3) << 13; + + contextMatch |= cycle << 12; } + + reg_write(recv->ohci, recv->ContextMatch, contextMatch); /* address of first descriptor block */ command = dma_prog_region_offset_to_bus(&recv->prog, recv->pkt_dma * sizeof(struct dma_cmd)); |
From: SVN U. <dm...@li...> - 2002-11-07 01:51:46
|
Author: dmaas Date: 2002-11-06 20:51:34 -0500 (Wed, 06 Nov 2002) New Revision: 662 Modified: trunk/iso.c trunk/iso.h trunk/ohci1394.c trunk/raw1394.c trunk/raw1394.h Log: rawiso update - use a callback in struct hpsb_iso instead of a wait_queue - notify raw1394 users of isochronous activity via a queued read() event, instead of poll() (This is less of a hack than the poll() method and restores the old poll() behavior) Modified: trunk/iso.h ============================================================================== --- trunk/iso.h (original) +++ trunk/iso.h 2002-11-06 20:51:35.000000000 -0500 @@ -46,8 +46,8 @@ struct hpsb_host *host; void *hostdata; - /* pointer to a wait queue that will receive wakeups */ - wait_queue_head_t *waitq; + /* function to be called (from interrupt context) when the iso status changes */ + void (*callback)(struct hpsb_iso*); int speed; /* SPEED_100, 200, or 400 */ int channel; @@ -108,19 +108,19 @@ /* allocate the buffer and DMA context */ struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, - unsigned int buf_packets, - unsigned int max_packet_size, - int channel, - int speed, - int irq_interval, - wait_queue_head_t *waitq); + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int speed, + int irq_interval, + void (*callback)(struct hpsb_iso*)); struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, - unsigned int buf_packets, - unsigned int max_packet_size, - int channel, - int irq_interval, - wait_queue_head_t *waitq); + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)); /* start/stop DMA */ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle, int prebuffer); Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-11-06 20:51:35.000000000 -0500 @@ -1311,8 +1311,8 @@ } out: - if(wake && iso->waitq) { - wake_up_interruptible(iso->waitq); + if(wake && iso->callback) { + iso->callback(iso); } } @@ -1479,8 +1479,8 @@ } out: - if(wake && iso->waitq) { - wake_up_interruptible(iso->waitq); + if(wake && iso->callback) { + iso->callback(iso); } } Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2002-11-06 20:51:35.000000000 -0500 @@ -133,18 +133,25 @@ kfree(req); } +/* fi->reqlists_lock must be taken */ +static void __queue_complete_req(struct pending_request *req) +{ + struct file_info *fi = req->file_info; + list_del(&req->list); + list_add_tail(&req->list, &fi->req_complete); + + up(&fi->complete_sem); + wake_up_interruptible(&fi->poll_wait_complete); +} + static void queue_complete_req(struct pending_request *req) { unsigned long flags; struct file_info *fi = req->file_info; spin_lock_irqsave(&fi->reqlists_lock, flags); - list_del(&req->list); - list_add_tail(&req->list, &fi->req_complete); + __queue_complete_req(req); spin_unlock_irqrestore(&fi->reqlists_lock, flags); - - up(&fi->complete_sem); - wake_up_interruptible(&fi->poll_wait_complete); } static void queue_complete_cb(struct pending_request *req) @@ -1995,6 +2002,62 @@ /* rawiso operations */ +/* check if any RAW1394_REQ_RAWISO_ACTIVITY event is already in the + * completion queue (reqlists_lock must be taken) */ +static inline int __rawiso_event_in_queue(struct file_info *fi) +{ + struct list_head *lh; + struct pending_request *req; + + list_for_each(lh, &fi->req_complete) { + req = list_entry(lh, struct pending_request, list); + if(req->req.type == RAW1394_REQ_RAWISO_ACTIVITY) { + return 1; + } + } + + return 0; +} + +static void rawiso_activity_cb(struct hpsb_iso *iso) +{ + unsigned long host_flags; + struct list_head *lh; + struct host_info *hi; + + spin_lock_irqsave(&host_info_lock, host_flags); + hi = find_host_info(iso->host); + + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + unsigned long reqlist_flags; + struct file_info *fi = list_entry(lh, struct file_info, list); + + spin_lock_irqsave(&fi->reqlists_lock, reqlist_flags); + + /* only one ISO activity event may be in the queue */ + if(!__rawiso_event_in_queue(fi)) { + struct pending_request *req = __alloc_pending_request(SLAB_ATOMIC); + + if(req) { + req->file_info = fi; + req->req.type = RAW1394_REQ_RAWISO_ACTIVITY; + req->req.generation = get_hpsb_generation(iso->host); + __queue_complete_req(req); + } else { + /* on allocation failure, signal an overflow */ + if(fi->iso_handle) { + atomic_inc(&fi->iso_handle->overflows); + } + } + } + spin_unlock_irqrestore(&fi->reqlists_lock, reqlist_flags); + } + } + + spin_unlock_irqrestore(&host_info_lock, host_flags); +} + /* helper function - gather all the kernel iso status bits for returning to user-space */ static void raw1394_iso_fill_status(struct hpsb_iso *iso, struct raw1394_iso_status *stat) { @@ -2024,7 +2087,7 @@ stat.config.channel, stat.config.speed, stat.config.irq_interval, - &fi->poll_wait_complete); + rawiso_activity_cb); if(!fi->iso_handle) return -ENOMEM; @@ -2033,6 +2096,10 @@ raw1394_iso_fill_status(fi->iso_handle, &stat); if(copy_to_user(uaddr, &stat, sizeof(stat))) return -EFAULT; + + /* queue an event to get things started */ + rawiso_activity_cb(fi->iso_handle); + return 0; } @@ -2048,7 +2115,7 @@ stat.config.max_packet_size, stat.config.channel, stat.config.irq_interval, - &fi->poll_wait_complete); + rawiso_activity_cb); if(!fi->iso_handle) return -ENOMEM; @@ -2161,15 +2228,6 @@ return -EINVAL; } -/* Queued read() events and isochronous readiness are two completely - * independent sources of input. We must provide unique POLL values - * for each, so that libraw can distinguish between them. Older versions - * of libraw expect POLLIN to mean only that a read() event is pending. - * So, we have to use something other than POLLIN. The best choice seems - * to be POLLPRI ("urgent out-of-band input") - which also allows us - * to support select(), since POLLPRI signals "exception" activity - */ - static unsigned int raw1394_poll(struct file *file, poll_table *pt) { struct file_info *fi = file->private_data; @@ -2177,18 +2235,11 @@ poll_wait(file, &fi->poll_wait_complete, pt); - /* check for pending read() events */ spin_lock_irq(&fi->reqlists_lock); if (!list_empty(&fi->req_complete)) { mask |= POLLIN | POLLRDNORM; } spin_unlock_irq(&fi->reqlists_lock); - - /* check for isochronous activity */ - if(fi->iso_state != RAW1394_ISO_INACTIVE) { - if(hpsb_iso_n_ready(fi->iso_handle) > 0) - mask |= POLLPRI; - } return mask; } Modified: trunk/raw1394.h ============================================================================== --- trunk/raw1394.h (original) +++ trunk/raw1394.h 2002-11-06 20:51:35.000000000 -0500 @@ -36,10 +36,11 @@ #define RAW1394_REQ_PHYPACKET 500 /* kernel to user */ -#define RAW1394_REQ_BUS_RESET 10000 -#define RAW1394_REQ_ISO_RECEIVE 10001 -#define RAW1394_REQ_FCP_REQUEST 10002 -#define RAW1394_REQ_ARM 10003 +#define RAW1394_REQ_BUS_RESET 10000 +#define RAW1394_REQ_ISO_RECEIVE 10001 +#define RAW1394_REQ_FCP_REQUEST 10002 +#define RAW1394_REQ_ARM 10003 +#define RAW1394_REQ_RAWISO_ACTIVITY 10004 /* error codes */ #define RAW1394_ERROR_NONE 0 Modified: trunk/iso.c ============================================================================== --- trunk/iso.c (original) +++ trunk/iso.c 2002-11-06 20:51:35.000000000 -0500 @@ -33,11 +33,11 @@ } static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_iso_type type, - unsigned int buf_packets, - unsigned int max_packet_size, - int channel, - int irq_interval, - wait_queue_head_t *waitq) + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)) { struct hpsb_iso *iso; unsigned int packet_plus_info; @@ -86,7 +86,7 @@ iso->type = type; iso->host = host; iso->hostdata = NULL; - iso->waitq = waitq; + iso->callback = callback; iso->channel = channel; iso->irq_interval = irq_interval; dma_region_init(&iso->buf); @@ -133,11 +133,11 @@ int channel, int speed, int irq_interval, - wait_queue_head_t *waitq) + void (*callback)(struct hpsb_iso*)) { struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT, buf_packets, max_packet_size, - channel, irq_interval, waitq); + channel, irq_interval, callback); if(!iso) return NULL; @@ -160,11 +160,11 @@ unsigned int max_packet_size, int channel, int irq_interval, - wait_queue_head_t *waitq) + void (*callback)(struct hpsb_iso*)) { struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV, buf_packets, max_packet_size, - channel, irq_interval, waitq); + channel, irq_interval, callback); if(!iso) return NULL; |
From: SVN U. <hog...@li...> - 2002-11-06 16:28:34
|
Author: hogsberg Date: 2002-11-06 11:28:26 -0500 (Wed, 06 Nov 2002) New Revision: 661 Modified: trunk/amdtp.c Log: Fix sloppy buffer action, set correct header bits for raw format Modified: trunk/amdtp.c ============================================================================== --- trunk/amdtp.c (original) +++ trunk/amdtp.c 2002-11-06 11:28:27.000000000 -0500 @@ -688,7 +688,7 @@ return get_iec958_header_bits(s, sub_frame, sample); case AMDTP_FORMAT_RAW: - return 0x40000000; + return 0x40; default: return 0; @@ -1109,7 +1109,7 @@ */ for (i = 0; i < count; i += length) { - p = buffer_put_bytes(s->input, count, &length); + p = buffer_put_bytes(s->input, count - i, &length); copy_from_user(p, buffer + i, length); if (s->input->length < s->input->size) continue; |
From: SVN U. <dm...@li...> - 2002-11-06 04:10:44
|
Author: dmaas Date: 2002-11-05 23:10:39 -0500 (Tue, 05 Nov 2002) New Revision: 660 Modified: trunk/iso.c trunk/ohci1394.c Log: rawiso - keep iso headers on receive so we can record the tag/sy/channel/cycle info Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-11-05 23:10:40.000000000 -0500 @@ -1100,6 +1100,8 @@ int i; for(i = 0; i < iso->buf_packets; i++) { + int want_interrupt; + unsigned int data_size; /* pointer to the DMA descriptor */ struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + pkt; @@ -1109,9 +1111,10 @@ /* offset of this bus_cycle within the DMA buffer */ unsigned long buf_offset = hpsb_iso_packet_data(iso, pkt) - iso->buf.kvirt; - - int want_interrupt; - unsigned int data_size = iso->max_packet_size; + + /* back up 8 bytes for the iso header */ + buf_offset -= 8; + data_size = iso->max_packet_size + 8; /* ask for an interrupt every now and then, and always interrupt on the final descriptor */ @@ -1158,14 +1161,14 @@ reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF); wmb(); - /* use packet-per-buffer mode, and do not keep ISO headers */ - reg_write(recv->ohci, recv->ContextControlSet, 0x00000000); + /* use packet-per-buffer mode, and keep ISO headers */ + reg_write(recv->ohci, recv->ContextControlSet, (1 << 30)); /* match on all tags, listen on channel */ reg_write(recv->ohci, recv->ContextMatch, 0xF0000000 | iso->channel); if(cycle != -1) { - /* XXX use cycleMatch */ + /* XXX DJM use cycleMatch */ } /* address of first descriptor block */ @@ -1185,7 +1188,7 @@ /* check RUN */ if(!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) { - PRINT(KERN_ERR, recv->ohci->id, "Error starting ISO DMA reception (ContextControl 0x%08x)\n", + PRINT(KERN_ERR, recv->ohci->id, "Error starting IR DMA (ContextControl 0x%08x)\n", reg_read(recv->ohci, recv->ContextControlSet)); return -1; } @@ -1246,7 +1249,6 @@ /* loop over the entire buffer */ for(count = 0; count < iso->buf_packets; count++) { u32 packet_len = 0; - struct hpsb_iso_packet_info *info; /* pointer to the DMA descriptor */ struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + recv->pkt_dma; @@ -1268,7 +1270,7 @@ /* rescount is the number of bytes *remaining* in the packet buffer, after the packet was written */ packet_len = iso->max_packet_size - rescount; - + } else if(event == 0x02) { PRINT(KERN_ERR, recv->ohci->id, "IR DMA error - packet too long for buffer\n"); } else if(event) { @@ -1279,10 +1281,18 @@ dma_region_sync(&iso->buf, recv->pkt_dma * iso->buf_stride, iso->buf_stride); /* record the per-packet info */ - info = hpsb_iso_packet_info(iso, recv->pkt_dma); - info->len = packet_len; - - /* XXX record channel, sy, tag, cycle */ + { + /* iso header is 8 bytes ahead of the data payload */ + unsigned char *hdr = hpsb_iso_packet_data(iso, recv->pkt_dma) - 8; + + struct hpsb_iso_packet_info *info = hpsb_iso_packet_info(iso, recv->pkt_dma); + + info->len = packet_len; + info->cycle = (hdr[0] | (hdr[1] << 8)) & 0x1FFF; + info->channel = hdr[5] & 0x3F; + info->tag = hdr[5] >> 6; + info->sy = hdr[4] & 0xF; + } /* at least one packet came in, so wake up the reader */ wake = 1; Modified: trunk/iso.c ============================================================================== --- trunk/iso.c (original) +++ trunk/iso.c 2002-11-05 23:10:40.000000000 -0500 @@ -42,11 +42,21 @@ struct hpsb_iso *iso; unsigned int packet_plus_info; int dma_direction; + int iso_header_bytes; + const int info_bytes = sizeof(struct hpsb_iso_packet_info); /* make sure driver supports the ISO API */ if(!host->driver->isoctl) return NULL; + if(type == HPSB_ISO_RECV) { + /* when receiving, leave 8 extra bytes in front + of the data payload for the iso header */ + iso_header_bytes = 8; + } else { + iso_header_bytes = 0; + } + /* sanitize parameters */ if(buf_packets < 2) @@ -55,14 +65,14 @@ if(irq_interval < 1 || irq_interval > buf_packets / 2) irq_interval = buf_packets / 2; - if(max_packet_size + sizeof(struct hpsb_iso_packet_info) > PAGE_SIZE) + if(max_packet_size + info_bytes + iso_header_bytes > PAGE_SIZE) return NULL; /* size of packet payload plus the per-packet info must be a power of 2 and at most equal to the page size */ for(packet_plus_info = 256; packet_plus_info < PAGE_SIZE; packet_plus_info *= 2) { - if(packet_plus_info >= (max_packet_size + sizeof(struct hpsb_iso_packet_info))) { + if(packet_plus_info >= (max_packet_size + info_bytes + iso_header_bytes)) { break; } } @@ -83,8 +93,8 @@ iso->buf_packets = buf_packets; iso->buf_stride = packet_plus_info; iso->max_packet_size = max_packet_size; - iso->packet_data_offset = 0; - iso->packet_info_offset = max_packet_size; + iso->packet_data_offset = iso_header_bytes; + iso->packet_info_offset = iso_header_bytes + max_packet_size; iso->first_packet = 0; if(iso->type == HPSB_ISO_XMIT) { |
From: SVN U. <dm...@li...> - 2002-11-06 03:27:48
|
Author: dmaas Date: 2002-11-05 22:27:36 -0500 (Tue, 05 Nov 2002) New Revision: 659 Modified: trunk/dma.c trunk/dma.h trunk/ieee1394_core.c trunk/iso.c trunk/iso.h trunk/ohci1394.c trunk/raw1394.c trunk/raw1394.h Log: rawiso updates - make the PCI DMA wrapper a tiny bit more efficient - remove iso_status.first_packet_cycle; cycle tracking is now done in the packet_info struct only - make ISO xmit prebuffering the kernel's responsibility - change raw1394 ISO_XMIT_START ioctl to take prebuffer argument - clean up & improve ohci1394 implementation of rawiso - added timestamp prediction for xmit - recv side still needs a little more work Modified: trunk/iso.h ============================================================================== --- trunk/iso.h (original) +++ trunk/iso.h 2002-11-05 22:27:38.000000000 -0500 @@ -20,8 +20,8 @@ /* per-packet data embedded in the ringbuffer */ struct hpsb_iso_packet_info { unsigned short len; - unsigned short cycle; /* receive only */ - unsigned char channel; /* receive only */ + unsigned short cycle; + unsigned char channel; /* recv only */ unsigned char tag; unsigned char sy; }; @@ -29,7 +29,6 @@ /* * each packet in the ringbuffer consists of three things: * 1. the packet's data payload (no isochronous header) - * XXX ^^ this must change * 2. a struct hpsb_iso_packet_info * 3. some empty space before the next packet * @@ -63,9 +62,9 @@ /* # of packets in the ringbuffer */ unsigned int buf_packets; - /* offset between successive packets - + /* offset between successive packets, in bytes - you can assume that this is a power of 2, - and that packets will never cross a page boundary */ + and less than or equal to the page size */ int buf_stride; /* largest possible packet size, in bytes */ @@ -92,11 +91,16 @@ /* how many times the buffer has overflowed or underflowed */ atomic_t overflows; - /* transmit only - the cycle number at which first_packet will be sent */ - int first_packet_cycle; + /* private flags to track initialization progress */ +#define HPSB_ISO_DRIVER_INIT (1<<0) +#define HPSB_ISO_DRIVER_STARTED (1<<1) + unsigned int flags; - /* flags to track initialization progress */ - int driver_init, driver_started; + /* # of packets left to prebuffer (xmit only) */ + int prebuffer; + + /* starting cycle (xmit only) */ + int start_cycle; }; /* functions available to high-level drivers (e.g. raw1394) */ @@ -119,7 +123,8 @@ wait_queue_head_t *waitq); /* start/stop DMA */ -int hpsb_iso_start(struct hpsb_iso *iso, int start_on_cycle); +int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle, int prebuffer); +int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle); void hpsb_iso_stop(struct hpsb_iso *iso); /* deallocate buffer and DMA context */ Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2002-11-05 22:27:38.000000000 -0500 @@ -1276,11 +1276,13 @@ EXPORT_SYMBOL(dma_region_free); EXPORT_SYMBOL(dma_region_sync); EXPORT_SYMBOL(dma_region_mmap); +EXPORT_SYMBOL(dma_region_offset_to_bus); /** iso.c **/ EXPORT_SYMBOL(hpsb_iso_xmit_init); EXPORT_SYMBOL(hpsb_iso_recv_init); -EXPORT_SYMBOL(hpsb_iso_start); +EXPORT_SYMBOL(hpsb_iso_xmit_start); +EXPORT_SYMBOL(hpsb_iso_recv_start); EXPORT_SYMBOL(hpsb_iso_stop); EXPORT_SYMBOL(hpsb_iso_shutdown); EXPORT_SYMBOL(hpsb_iso_xmit_queue_packets); Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-11-05 22:27:38.000000000 -0500 @@ -1242,8 +1242,6 @@ int count; int wake = 0; - int good_packets = 0; - int bad_packets = 0; /* loop over the entire buffer */ for(count = 0; count < iso->buf_packets; count++) { @@ -1259,35 +1257,32 @@ unsigned char event = xferstatus & 0x1F; + if(!event) { + /* this packet hasn't come in yet; we are done for now */ + goto out; + } + if(event == 0x11) { /* packet received successfully! */ - good_packets++; /* rescount is the number of bytes *remaining* in the packet buffer, after the packet was written */ packet_len = iso->max_packet_size - rescount; } else if(event == 0x02) { - PRINT(KERN_ERR, recv->ohci->id, - "ISO DMA reception error - packet too long for buffer\n"); - bad_packets++; + PRINT(KERN_ERR, recv->ohci->id, "IR DMA error - packet too long for buffer\n"); } else if(event) { - PRINT(KERN_ERR, recv->ohci->id, - "ISO DMA reception error - OHCI error code 0x%02x\n", event); - bad_packets++; - } - - if(!event) { - /* this packet hasn't come in yet; we are done for now */ - goto out; + PRINT(KERN_ERR, recv->ohci->id, "IR DMA error - OHCI error code 0x%02x\n", event); } /* sync our view of the buffer */ - dma_region_sync(&iso->buf); + dma_region_sync(&iso->buf, recv->pkt_dma * iso->buf_stride, iso->buf_stride); /* record the per-packet info */ info = hpsb_iso_packet_info(iso, recv->pkt_dma); info->len = packet_len; + + /* XXX record channel, sy, tag, cycle */ /* at least one packet came in, so wake up the reader */ wake = 1; @@ -1303,7 +1298,6 @@ /* if n_dma_packets reaches zero, we have an overflow */ atomic_inc(&iso->overflows); } - } out: @@ -1345,28 +1339,6 @@ static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso); static void ohci_iso_xmit_task(unsigned long data); -static int ohci_iso_xmit_suggest_start_cycle(struct ti_ohci *ohci) -{ - u32 cycleTimer, sec, cyc, off; - - cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer); - sec = cycleTimer >> 25; - cyc = (cycleTimer >> 12) & 0x1FFF; - off = cycleTimer & 0xFFF; - - /* go ahead 500 cycles - if the user doesn't xmit_produce() a - packet within this time, we will end up waiting until the - 4-bit second counter wraps around to start transmission... - is there a better way? */ - - cyc += 500; - - sec += cyc/8000; - cyc %= 8000; - - return ((sec & 0x3) << 13) | cyc; -} - static int ohci_iso_xmit_init(struct hpsb_iso *iso) { struct ohci_iso_xmit *xmit; @@ -1409,9 +1381,6 @@ /* enable interrupts */ reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << ctx); - /* suggest a starting cycle */ - iso->first_packet_cycle = ohci_iso_xmit_suggest_start_cycle(xmit->ohci); - return 0; err: @@ -1450,39 +1419,45 @@ struct hpsb_iso *iso = (struct hpsb_iso*) data; struct ohci_iso_xmit *xmit = iso->hostdata; int wake = 0; - unsigned int good_packets = 0; - unsigned int bad_packets = 0; int count; - /* check the whole buffer if necessary, starting at pkt_dma*/ + /* check the whole buffer if necessary, starting at pkt_dma */ for(count = 0; count < iso->buf_packets; count++) { - struct iso_xmit_cmd *cmd = - dma_region_i(&xmit->prog, struct iso_xmit_cmd, xmit->pkt_dma); - + + /* DMA descriptor */ + struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, xmit->pkt_dma); + /* check for new writes to xferStatus */ u16 xferstatus = cmd->output_last.status >> 16; - unsigned char event = xferstatus & 0x1F; - - if(event == 0x11) { - /* packet sent successfully */ - good_packets++; - } else if(event) { - PRINT(KERN_ERR, xmit->ohci->id, - "ISO DMA transmission error - OHCI error code 0x%02x\n", event); - bad_packets++; - } + u8 event = xferstatus & 0x1F; if(!event) { /* packet hasn't been sent yet; we are done for now */ goto out; } - /* at least one packet came in, so wake up the writer */ + if(event != 0x11) { + PRINT(KERN_ERR, xmit->ohci->id, "IT DMA error - OHCI error code 0x%02x\n", event); + } + + /* at least one packet went out, so wake up the writer */ wake = 1; - + + /* predict the timestamp pkt_dma will have next time around the buffer */ + { + struct hpsb_iso_packet_info* info = hpsb_iso_packet_info(iso, xmit->pkt_dma); + unsigned int cycle = cmd->output_last.status & 0x1FFF; + + cycle += iso->buf_packets; + while(cycle > 8000) + cycle -= 8000; + + info->cycle = cycle; + } + /* reset the DMA descriptor for next time */ cmd->output_last.status = 0; - + /* advance packet cursor */ xmit->pkt_dma = (xmit->pkt_dma + 1) % iso->buf_packets; @@ -1507,7 +1482,7 @@ struct iso_xmit_cmd *next, *prev; /* sync up the card's view of the buffer */ - dma_region_sync(&iso->buf); + dma_region_sync(&iso->buf, iso->first_packet * iso->buf_stride, iso->buf_stride); /* append first_packet to the DMA chain */ /* by linking the previous descriptor to it */ @@ -1522,7 +1497,7 @@ /* retrieve the packet info stashed in the buffer */ info = hpsb_iso_packet_info(iso, iso->first_packet); - /* set up the OUTPUT_MORE_IMMEDIATE */ + /* set up the OUTPUT_MORE_IMMEDIATE descriptor */ memset(next, 0, sizeof(struct iso_xmit_cmd)); next->output_more_immediate.control = 0x02000008; @@ -1579,8 +1554,6 @@ /* increment cursors */ iso->first_packet = (iso->first_packet+1) % iso->buf_packets; - iso->first_packet_cycle = (iso->first_packet_cycle+1) % iso->buf_packets; - atomic_inc(&iso->n_dma_packets); } @@ -1605,8 +1578,18 @@ /* cycle match */ if(cycle != -1) { - /* XXX pick a cycle and set iso->first_packet_cycle */ - reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (cycle << 16)); + u32 start = cycle & 0x1FFF; + + /* 'cycle' is only mod 8000, but we also need two 'seconds' bits - + just snarf them from the current time */ + u32 seconds = reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer) >> 25; + + /* advance one second to give some extra time for DMA to start */ + seconds += 1; + + start |= (seconds & 3) << 13; + + reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16)); } /* run */ @@ -1618,7 +1601,7 @@ /* check the RUN bit */ if(!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) { - PRINT(KERN_ERR, xmit->ohci->id, "Error starting ISO DMA transmission (ContextControl 0x%08x)\n", + PRINT(KERN_ERR, xmit->ohci->id, "Error starting IT DMA (ContextControl 0x%08x)\n", reg_read(xmit->ohci, xmit->ContextControlSet)); return -1; } Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2002-11-05 22:27:38.000000000 -0500 @@ -2009,7 +2009,6 @@ stat->first_packet = iso->first_packet; stat->n_packets = hpsb_iso_n_ready(iso); stat->overflows = atomic_read(&iso->overflows); - stat->first_packet_cycle = iso->first_packet_cycle; } static int raw1394_iso_xmit_init(struct file_info *fi, void *uaddr) @@ -2114,8 +2113,8 @@ break; case RAW1394_ISO_RECV: switch(cmd) { - case RAW1394_ISO_START: - return hpsb_iso_start(fi->iso_handle, arg); + case RAW1394_ISO_RECV_START: + return hpsb_iso_recv_start(fi->iso_handle, arg); case RAW1394_ISO_STOP: hpsb_iso_stop(fi->iso_handle); return 0; @@ -2133,8 +2132,13 @@ break; case RAW1394_ISO_XMIT: switch(cmd) { - case RAW1394_ISO_START: - return hpsb_iso_start(fi->iso_handle, arg); + case RAW1394_ISO_XMIT_START: { + /* copy two ints from user-space */ + int args[2]; + if(copy_from_user(&args[0], (void*) arg, sizeof(args))) + return -EFAULT; + return hpsb_iso_xmit_start(fi->iso_handle, args[0], args[1]); + } case RAW1394_ISO_STOP: hpsb_iso_stop(fi->iso_handle); return 0; Modified: trunk/raw1394.h ============================================================================== --- trunk/raw1394.h (original) +++ trunk/raw1394.h 2002-11-05 22:27:39.000000000 -0500 @@ -118,12 +118,13 @@ /* rawiso API */ /* ioctls */ -#define RAW1394_ISO_XMIT_INIT 1 -#define RAW1394_ISO_RECV_INIT 2 -#define RAW1394_ISO_START 3 +#define RAW1394_ISO_XMIT_INIT 1 /* arg: raw1394_iso_status* */ +#define RAW1394_ISO_RECV_INIT 2 /* arg: raw1394_iso_status* */ +#define RAW1394_ISO_RECV_START 3 /* arg: int, starting cycle */ +#define RAW1394_ISO_XMIT_START 8 /* arg: int[2], { starting cycle, prebuffer } */ #define RAW1394_ISO_STOP 4 -#define RAW1394_ISO_GET_STATUS 5 -#define RAW1394_ISO_PRODUCE_CONSUME 6 +#define RAW1394_ISO_GET_STATUS 5 /* arg: raw1394_iso_status* */ +#define RAW1394_ISO_PRODUCE_CONSUME 6 /* arg: int, # of packets */ #define RAW1394_ISO_SHUTDOWN 7 /* per-packet metadata embedded in the ringbuffer */ @@ -131,7 +132,7 @@ struct raw1394_iso_packet_info { unsigned short len; unsigned short cycle; - unsigned char channel; + unsigned char channel; /* recv only */ unsigned char tag; unsigned char sy; }; @@ -170,10 +171,6 @@ underflow of the packet buffer (a value of zero guarantees that no packets have been dropped) */ unsigned int overflows; - - /* (transmission only) the value the ISO CYCLE_COUNT register - will have when the first_packet is sent */ - int first_packet_cycle; }; #ifdef __KERNEL__ Modified: trunk/dma.c ============================================================================== --- trunk/dma.c (original) +++ trunk/dma.c 2002-11-05 22:27:39.000000000 -0500 @@ -140,10 +140,45 @@ } } -void dma_region_sync(struct dma_region *dma) +/* find the scatterlist index and remaining offset corresponding to a + given offset from the beginning of the buffer */ +static inline int dma_region_find(struct dma_region *dma, unsigned long offset, unsigned long *rem) { - /* XXX DJM - inefficient - add address/length argument */ - pci_dma_sync_sg(dma->dev, &dma->sglist[0], dma->n_dma_pages, dma->direction); + int i; + unsigned long off = offset; + + for(i = 0; i < dma->n_dma_pages; i++) { + if(off < sg_dma_len(&dma->sglist[i])) { + *rem = off; + return i; + } + + off -= sg_dma_len(&dma->sglist[i]); + } + + panic("dma_region_find: offset %lu beyond end of DMA mapping\n", offset); +} + +dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset) +{ + unsigned long rem; + + struct scatterlist *sg = &dma->sglist[dma_region_find(dma, offset, &rem)]; + return sg_dma_address(sg) + rem; +} + +void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len) +{ + int first, last; + unsigned long rem; + + if(!len) + len = 1; + + first = dma_region_find(dma, offset, &rem); + last = dma_region_find(dma, offset + len - 1, &rem); + + pci_dma_sync_sg(dma->dev, &dma->sglist[first], last - first + 1, dma->direction); } /* nopage() handler for mmap access */ Modified: trunk/dma.h ============================================================================== --- trunk/dma.h (original) +++ trunk/dma.h 2002-11-05 22:27:39.000000000 -0500 @@ -13,8 +13,11 @@ #include <linux/pci.h> #include <asm/scatterlist.h> -/* structure for bookkeeping of a small, physically-contiguous DMA buffer - with random-access, synchronous usage characteristics */ +/* struct dma_prog_region + + a small, physically-contiguous DMA buffer with random-access, + synchronous usage characteristics +*/ struct dma_prog_region { unsigned char *kvirt; /* kernel virtual address */ @@ -33,17 +36,18 @@ return prog->bus_addr + offset; } - - -/* structure for bookkeeping of a large, non-physically-contiguous DMA buffer - with streaming, asynchronous usage characteristics */ +/* struct dma_region + + a large, non-physically-contiguous DMA buffer with streaming, + asynchronous usage characteristics +*/ struct dma_region { unsigned char *kvirt; /* kernel virtual address */ struct pci_dev *dev; /* PCI device */ unsigned int n_pages; /* # of kernel pages */ unsigned int n_dma_pages; /* # of IOMMU pages */ - struct scatterlist *sglist; + struct scatterlist *sglist; /* IOMMU mapping */ int direction; /* PCI_DMA_TODEVICE, etc */ }; @@ -57,30 +61,16 @@ void dma_region_free(struct dma_region *dma); /* sync the IO bus' view of the buffer with the CPU's view */ -/* XXX DJM - add addr, len arguments */ -void dma_region_sync(struct dma_region *dma); +void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len); /* map the buffer into a user space process */ int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma); -/* macro to index into a DMA region */ +/* macro to index into a DMA region (or dma_prog_region) */ #define dma_region_i(_dma, _type, _index) ( ((_type*) ((_dma)->kvirt)) + (_index) ) /* return the DMA bus address of the byte with the given offset relative to the beginning of the dma_region */ -/* XXX DJM take out of line and use binary search */ -static inline dma_addr_t dma_region_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); - } - return 0; -} +dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset); #endif /* IEEE1394_DMA_H */ Modified: trunk/iso.c ============================================================================== --- trunk/iso.c (original) +++ trunk/iso.c 2002-11-05 22:27:39.000000000 -0500 @@ -13,19 +13,19 @@ void hpsb_iso_stop(struct hpsb_iso *iso) { - if(!iso->driver_started) + if(!iso->flags & HPSB_ISO_DRIVER_STARTED) return; iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_STOP : RECV_STOP, 0); - iso->driver_started = 0; + iso->flags &= ~HPSB_ISO_DRIVER_STARTED; } void hpsb_iso_shutdown(struct hpsb_iso *iso) { - if(iso->driver_init) { + if(iso->flags & HPSB_ISO_DRIVER_INIT) { hpsb_iso_stop(iso); iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_SHUTDOWN : RECV_SHUTDOWN, 0); - iso->driver_init = 0; + iso->flags &= ~HPSB_ISO_DRIVER_INIT; } dma_region_free(&iso->buf); @@ -96,10 +96,9 @@ } atomic_set(&iso->overflows, 0); - iso->first_packet_cycle = 0; - iso->driver_init = 0; - iso->driver_started = 0; - + iso->flags = 0; + iso->prebuffer = 0; + /* allocate the packet buffer */ if(dma_region_alloc(&iso->buf, iso->buf_packets * iso->buf_stride, host->pdev, dma_direction)) @@ -137,8 +136,8 @@ /* tell the driver to start working */ if(host->driver->isoctl(iso, XMIT_INIT, 0)) goto err; - - iso->driver_init = 1; + + iso->flags |= HPSB_ISO_DRIVER_INIT; return iso; err: @@ -162,8 +161,8 @@ /* tell the driver to start working */ if(host->driver->isoctl(iso, RECV_INIT, 0)) goto err; - - iso->driver_init = 1; + + iso->flags |= HPSB_ISO_DRIVER_INIT; return iso; err: @@ -171,25 +170,81 @@ return NULL; } -int hpsb_iso_start(struct hpsb_iso *iso, int cycle) +static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle) +{ + int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle); + if(retval) + return retval; + + iso->flags |= HPSB_ISO_DRIVER_STARTED; + return retval; +} + +int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer) +{ + if(iso->type != HPSB_ISO_XMIT) + return -1; + + if(iso->flags & HPSB_ISO_DRIVER_STARTED) + return 0; + + if(prebuffer < 1) + prebuffer = 1; + + if(prebuffer > iso->buf_packets) + prebuffer = iso->buf_packets; + + iso->prebuffer = prebuffer; + + if(cycle != -1) { + /* pre-fill info->cycle */ + int pkt = iso->first_packet; + int c, i; + + cycle %= 8000; + + c = cycle; + for(i = 0; i < iso->buf_packets; i++) { + struct hpsb_iso_packet_info *info = hpsb_iso_packet_info(iso, pkt); + + info->cycle = c; + + c = (c+1) % 8000; + pkt = (pkt+1) % iso->buf_packets; + } + } + + /* remember the starting cycle; DMA will commence from xmit_queue_packets() */ + iso->start_cycle = cycle; + + return 0; +} + +int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle) { int retval = 0; + + if(iso->type != HPSB_ISO_RECV) + return -1; - if(iso->driver_started) + if(iso->flags & HPSB_ISO_DRIVER_STARTED) return 0; - retval = iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_START : RECV_START, cycle); + retval = iso->host->driver->isoctl(iso, RECV_START, cycle); if(retval) return retval; - - iso->driver_started = 1; + + iso->flags |= HPSB_ISO_DRIVER_STARTED; return retval; } int hpsb_iso_xmit_queue_packets(struct hpsb_iso *iso, unsigned int n_packets) { - int i; + int i, retval; int pkt = iso->first_packet; + + if(iso->type != HPSB_ISO_XMIT) + return -1; /* check packet sizes for sanity */ for(i = 0; i < n_packets; i++) { @@ -202,12 +257,28 @@ pkt = (pkt+1) % iso->buf_packets; } - - return iso->host->driver->isoctl(iso, XMIT_QUEUE, n_packets); + + retval = iso->host->driver->isoctl(iso, XMIT_QUEUE, n_packets); + if(retval) + return retval; + + if(iso->prebuffer != 0) { + iso->prebuffer -= n_packets; + if(iso->prebuffer <= 0) { + iso->prebuffer = 0; + return do_iso_xmit_start(iso, + iso->start_cycle); + } + } + + return 0; } int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) { + if(iso->type != HPSB_ISO_RECV) + return -1; + return iso->host->driver->isoctl(iso, RECV_RELEASE, n_packets); } |
From: SVN U. <ben...@li...> - 2002-11-04 23:16:43
|
Author: bencollins Date: 2002-11-04 18:16:23 -0500 (Mon, 04 Nov 2002) New Revision: 658 Modified: trunk/ieee1394_transactions.c Log: Fix logic in hpsb_make{read,write}_packet. Patch from Manfred Weihs. Modified: trunk/ieee1394_transactions.c ============================================================================== --- trunk/ieee1394_transactions.c (original) +++ trunk/ieee1394_transactions.c 2002-11-04 18:16:23.000000000 -0500 @@ -250,10 +250,7 @@ if (length == 0) return NULL; - if (length % 4) - length += 4 - (length % 4); - - packet = alloc_hpsb_packet(length); + packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0)); if (!packet) return NULL; @@ -281,14 +278,13 @@ if (length == 0) return NULL; - if (length % 4) - length += 4 - (length % 4); - - packet = alloc_hpsb_packet(length); + packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0)); if (!packet) return NULL; - packet->data[length >> 2] = 0; + if (length % 4) { /* zero padding bytes */ + packet->data[length >> 2] = 0; + } packet->host = host; packet->node_id = node; |
From: SVN U. <dm...@li...> - 2002-10-29 03:19:44
|
Author: dmaas Date: 2002-10-28 22:19:41 -0500 (Mon, 28 Oct 2002) New Revision: 657 Modified: trunk/raw1394.c Log: rawiso merge part 5 - last one - change raw1394 poll() to return POLLPRI for isochronous activity. There is a slight chance this could break some existing applications - if they (incorrectly) assume that POLLPRI or an exception return from select() means there are pending read events, they could end up stuck in raw1394_loop_iterate(). If that happens, we need to find another way to signal isochronous activity. Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2002-10-28 22:19:42.000000000 -0500 @@ -2157,6 +2157,15 @@ return -EINVAL; } +/* Queued read() events and isochronous readiness are two completely + * independent sources of input. We must provide unique POLL values + * for each, so that libraw can distinguish between them. Older versions + * of libraw expect POLLIN to mean only that a read() event is pending. + * So, we have to use something other than POLLIN. The best choice seems + * to be POLLPRI ("urgent out-of-band input") - which also allows us + * to support select(), since POLLPRI signals "exception" activity + */ + static unsigned int raw1394_poll(struct file *file, poll_table *pt) { struct file_info *fi = file->private_data; @@ -2164,12 +2173,19 @@ poll_wait(file, &fi->poll_wait_complete, pt); + /* check for pending read() events */ spin_lock_irq(&fi->reqlists_lock); if (!list_empty(&fi->req_complete)) { mask |= POLLIN | POLLRDNORM; } spin_unlock_irq(&fi->reqlists_lock); + /* check for isochronous activity */ + if(fi->iso_state != RAW1394_ISO_INACTIVE) { + if(hpsb_iso_n_ready(fi->iso_handle) > 0) + mask |= POLLPRI; + } + return mask; } |
From: SVN U. <dm...@li...> - 2002-10-29 02:45:14
|
Author: dmaas Date: 2002-10-28 21:45:09 -0500 (Mon, 28 Oct 2002) New Revision: 656 Modified: trunk/raw1394.c trunk/raw1394.h Log: rawiso merge part 4 - expose rawiso to user-space through raw1394 (except poll() change) Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2002-10-28 21:45:10.000000000 -0500 @@ -47,6 +47,7 @@ #include "ieee1394_core.h" #include "hosts.h" #include "highlevel.h" +#include "iso.h" #include "ieee1394_transactions.h" #include "raw1394.h" @@ -1992,6 +1993,170 @@ return retval; } +/* rawiso operations */ + +/* helper function - gather all the kernel iso status bits for returning to user-space */ +static void raw1394_iso_fill_status(struct hpsb_iso *iso, struct raw1394_iso_status *stat) +{ + stat->config.buf_packets = iso->buf_packets; + stat->config.max_packet_size = iso->max_packet_size; + stat->config.channel = iso->channel; + stat->config.speed = iso->speed; + stat->config.irq_interval = iso->irq_interval; + stat->buf_stride = iso->buf_stride; + stat->packet_data_offset = iso->packet_data_offset; + stat->packet_info_offset = iso->packet_info_offset; + stat->first_packet = iso->first_packet; + stat->n_packets = hpsb_iso_n_ready(iso); + stat->overflows = atomic_read(&iso->overflows); + stat->first_packet_cycle = iso->first_packet_cycle; +} + +static int raw1394_iso_xmit_init(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_status stat; + + if(copy_from_user(&stat, uaddr, sizeof(stat))) + return -EFAULT; + + fi->iso_handle = hpsb_iso_xmit_init(fi->host, + stat.config.buf_packets, + stat.config.max_packet_size, + stat.config.channel, + stat.config.speed, + stat.config.irq_interval, + &fi->poll_wait_complete); + if(!fi->iso_handle) + return -ENOMEM; + + fi->iso_state = RAW1394_ISO_XMIT; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; + return 0; +} + +static int raw1394_iso_recv_init(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_status stat; + + if(copy_from_user(&stat, uaddr, sizeof(stat))) + return -EFAULT; + + fi->iso_handle = hpsb_iso_recv_init(fi->host, + stat.config.buf_packets, + stat.config.max_packet_size, + stat.config.channel, + stat.config.irq_interval, + &fi->poll_wait_complete); + if(!fi->iso_handle) + return -ENOMEM; + + fi->iso_state = RAW1394_ISO_RECV; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; + return 0; +} + +static int raw1394_iso_get_status(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_status stat; + struct hpsb_iso *iso = fi->iso_handle; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; + + /* reset overflow counter */ + atomic_set(&iso->overflows, 0); + + return 0; +} + +static void raw1394_iso_shutdown(struct file_info *fi) +{ + if(fi->iso_handle) + hpsb_iso_shutdown(fi->iso_handle); + + fi->iso_handle = NULL; + fi->iso_state = RAW1394_ISO_INACTIVE; +} + +/* mmap the rawiso xmit/recv buffer */ +static int raw1394_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct file_info *fi = file->private_data; + + if(fi->iso_state == RAW1394_ISO_INACTIVE) + return -EINVAL; + + return dma_region_mmap(&fi->iso_handle->buf, file, vma); +} + +/* ioctl is only used for rawiso operations */ +static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct file_info *fi = file->private_data; + + switch(fi->iso_state) { + case RAW1394_ISO_INACTIVE: + switch(cmd) { + case RAW1394_ISO_XMIT_INIT: + return raw1394_iso_xmit_init(fi, (void*) arg); + case RAW1394_ISO_RECV_INIT: + return raw1394_iso_recv_init(fi, (void*) arg); + default: + break; + } + break; + case RAW1394_ISO_RECV: + switch(cmd) { + case RAW1394_ISO_START: + return hpsb_iso_start(fi->iso_handle, arg); + case RAW1394_ISO_STOP: + hpsb_iso_stop(fi->iso_handle); + return 0; + + case RAW1394_ISO_GET_STATUS: + return raw1394_iso_get_status(fi, (void*) arg); + + case RAW1394_ISO_PRODUCE_CONSUME: + return hpsb_iso_recv_release_packets(fi->iso_handle, arg); + + case RAW1394_ISO_SHUTDOWN: + raw1394_iso_shutdown(fi); + return 0; + } + break; + case RAW1394_ISO_XMIT: + switch(cmd) { + case RAW1394_ISO_START: + return hpsb_iso_start(fi->iso_handle, arg); + case RAW1394_ISO_STOP: + hpsb_iso_stop(fi->iso_handle); + return 0; + + case RAW1394_ISO_GET_STATUS: + return raw1394_iso_get_status(fi, (void*) arg); + + case RAW1394_ISO_PRODUCE_CONSUME: + return hpsb_iso_xmit_queue_packets(fi->iso_handle, arg); + + case RAW1394_ISO_SHUTDOWN: + raw1394_iso_shutdown(fi); + return 0; + } + break; + default: + break; + } + + return -EINVAL; +} + static unsigned int raw1394_poll(struct file *file, poll_table *pt) { struct file_info *fi = file->private_data; @@ -2052,6 +2217,9 @@ struct arm_addr *arm_addr = NULL; int another_host; + if(fi->iso_state != RAW1394_ISO_INACTIVE) + raw1394_iso_shutdown(fi); + for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { hpsb_unlisten_channel(hl_handle, fi->host, i); @@ -2159,7 +2327,9 @@ static struct file_operations file_ops = { .owner = THIS_MODULE, .read = raw1394_read, - .write = raw1394_write, + .write = raw1394_write, + .mmap = raw1394_mmap, + .ioctl = raw1394_ioctl, .poll = raw1394_poll, .open = raw1394_open, .release = raw1394_release, Modified: trunk/raw1394.h ============================================================================== --- trunk/raw1394.h (original) +++ trunk/raw1394.h 2002-10-28 21:45:10.000000000 -0500 @@ -115,6 +115,67 @@ struct arm_response *response; } *arm_request_response_t; +/* rawiso API */ + +/* ioctls */ +#define RAW1394_ISO_XMIT_INIT 1 +#define RAW1394_ISO_RECV_INIT 2 +#define RAW1394_ISO_START 3 +#define RAW1394_ISO_STOP 4 +#define RAW1394_ISO_GET_STATUS 5 +#define RAW1394_ISO_PRODUCE_CONSUME 6 +#define RAW1394_ISO_SHUTDOWN 7 + +/* per-packet metadata embedded in the ringbuffer */ +/* must be identical to hpsb_iso_packet_info in iso.h! */ +struct raw1394_iso_packet_info { + unsigned short len; + unsigned short cycle; + unsigned char channel; + unsigned char tag; + unsigned char sy; +}; + +struct raw1394_iso_config { + unsigned int buf_packets; + unsigned int max_packet_size; + int channel; + int speed; /* xmit only */ + int irq_interval; +}; + +/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */ +struct raw1394_iso_status { + /* current settings */ + struct raw1394_iso_config config; + + /* byte offset between successive packets in the buffer */ + int buf_stride; + + /* byte offset of data payload within each packet */ + int packet_data_offset; + + /* byte offset of struct iso_packet_info within each packet */ + int packet_info_offset; + + /* index of next packet to fill with data (ISO transmission) + or next packet containing data recieved (ISO reception) */ + unsigned int first_packet; + + /* number of packets waiting to be filled with data (ISO transmission) + or containing data received (ISO reception) */ + unsigned int n_packets; + + /* approximate number of packets dropped due to overflow or + underflow of the packet buffer (a value of zero guarantees + that no packets have been dropped) */ + unsigned int overflows; + + /* (transmission only) the value the ISO CYCLE_COUNT register + will have when the first_packet is sent */ + int first_packet_cycle; +}; + #ifdef __KERNEL__ struct iso_block_store { @@ -123,6 +184,10 @@ quadlet_t data[0]; }; +enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0, + RAW1394_ISO_RECV = 1, + RAW1394_ISO_XMIT = 2 }; + struct file_info { struct list_head list; @@ -141,11 +206,16 @@ u8 *fcp_buffer; + /* old ISO API */ u64 listen_channels; quadlet_t *iso_buffer; size_t iso_buffer_length; u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */ + + /* new rawiso API */ + enum raw1394_iso_state iso_state; + struct hpsb_iso *iso_handle; }; struct arm_addr { |
From: SVN U. <dm...@li...> - 2002-10-29 02:21:56
|
Author: dmaas Date: 2002-10-28 21:21:52 -0500 (Mon, 28 Oct 2002) New Revision: 655 Modified: trunk/ohci1394.c Log: rawiso merge part 3 - OHCI rawiso implementation Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-10-28 21:21:54.000000000 -0500 @@ -112,6 +112,8 @@ #include "ieee1394.h" #include "ieee1394_types.h" #include "hosts.h" +#include "dma.h" +#include "iso.h" #include "ieee1394_core.h" #include "highlevel.h" #include "ohci1394.h" @@ -977,6 +979,693 @@ return retval; } +/*********************************** + * rawiso ISO reception * + ***********************************/ + +struct ohci_iso_recv { + struct ti_ohci *ohci; + + /* memory and PCI mapping for the DMA descriptors */ + struct dma_prog_region prog; + + struct ohci1394_iso_tasklet task; + int task_active; + + /* index of next packet to arrive */ + int pkt_dma; + + u32 ContextControlSet; + u32 ContextControlClear; + u32 CommandPtr; + u32 ContextMatch; +}; + +static void ohci_iso_recv_task(unsigned long data); +static void ohci_iso_recv_stop(struct hpsb_iso *iso); +static void ohci_iso_recv_shutdown(struct hpsb_iso *iso); +static void ohci_iso_recv_program(struct hpsb_iso *iso); +static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle); + + +static int ohci_iso_recv_init(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv; + unsigned int prog_size; + int ctx; + int ret = -ENOMEM; + + recv = kmalloc(sizeof(*recv), SLAB_KERNEL); + if(!recv) + return -ENOMEM; + + iso->hostdata = recv; + recv->ohci = iso->host->hostdata; + recv->task_active = 0; + recv->pkt_dma = iso->first_packet; + + dma_prog_region_init(&recv->prog); + + /* size of DMA program = one INPUT_LAST per packet in the buffer */ + prog_size = sizeof(struct dma_cmd) * iso->buf_packets; + + if(dma_prog_region_alloc(&recv->prog, prog_size, recv->ohci->dev)) + goto err; + + ohci1394_init_iso_tasklet(&recv->task, OHCI_ISO_RECEIVE, + ohci_iso_recv_task, (unsigned long) iso); + + if(ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) + goto err; + + recv->task_active = 1; + + /* recv context registers are spaced 32 bytes apart */ + ctx = recv->task.context; + recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx; + recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx; + recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx; + recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx; + + /* enable interrupts */ + reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << ctx); + + /* write the DMA program */ + ohci_iso_recv_program(iso); + + return 0; + +err: + ohci_iso_recv_shutdown(iso); + return ret; +} + +static void ohci_iso_recv_stop(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + + /* halt DMA */ + ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL); +} + +static void ohci_iso_recv_shutdown(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + + if(recv->task_active) { + /* halt DMA */ + ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL); + + /* disable interrupts */ + reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context); + + ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task); + recv->task_active = 0; + } + + dma_prog_region_free(&recv->prog); + kfree(recv); + iso->hostdata = NULL; +} + +static void ohci_iso_recv_program(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + + /* address of 'branch' field in previous DMA descriptor */ + u32 *prev_branch = NULL; + + /* start at pkt_dma and go around the whole buffer */ + int pkt = recv->pkt_dma; + int i; + + for(i = 0; i < iso->buf_packets; i++) { + + /* pointer to the DMA descriptor */ + struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + pkt; + + /* offset of the DMA descriptor relative to the DMA prog buffer */ + unsigned long prog_offset = pkt * sizeof(struct dma_cmd); + + /* offset of this bus_cycle within the DMA buffer */ + unsigned long buf_offset = hpsb_iso_packet_data(iso, pkt) - iso->buf.kvirt; + + int want_interrupt; + unsigned int data_size = iso->max_packet_size; + + /* ask for an interrupt every now and then, and + always interrupt on the final descriptor */ + + if( ((i % iso->irq_interval) == 0) || + (i == (iso->buf_packets - 1)) ) { + want_interrupt = 1; + } else { + want_interrupt = 0; + } + + /* write the DMA descriptor */ + + il->control = 3 << 28; /* INPUT_LAST */ + il->control |= 8 << 24; /* s = 1, update xferStatus and resCount */ + if(want_interrupt) + il->control |= 3 << 20; + il->control |= 0xC << 16; /* enable branch to address */ + il->control |= data_size; + + il->address = dma_region_offset_to_bus(&iso->buf, buf_offset); + il->branchAddress = 0; /* filled in on next loop */ + il->status = data_size; + + /* link the previous descriptor to this one */ + if(prev_branch) { + *prev_branch = dma_prog_region_offset_to_bus(&recv->prog, prog_offset); + *prev_branch |= 1; /* set Z=1 */ + } + + prev_branch = &il->branchAddress; + + pkt = (pkt + 1) % iso->buf_packets; + } + + /* the final descriptor's branch address and Z should be left at 0 */ +} + +static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle) +{ + struct ohci_iso_recv *recv = iso->hostdata; + u32 command; + + reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF); + wmb(); + + /* use packet-per-buffer mode, and do not keep ISO headers */ + reg_write(recv->ohci, recv->ContextControlSet, 0x00000000); + + /* match on all tags, listen on channel */ + reg_write(recv->ohci, recv->ContextMatch, 0xF0000000 | iso->channel); + + if(cycle != -1) { + /* XXX use cycleMatch */ + } + + /* address of first descriptor block */ + command = dma_prog_region_offset_to_bus(&recv->prog, recv->pkt_dma * sizeof(struct dma_cmd)); + command |= 1; /* Z=1 */ + + reg_write(recv->ohci, recv->CommandPtr, command); + wmb(); + + /* run */ + reg_write(recv->ohci, recv->ContextControlSet, 0x8000); + + /* issue a dummy read of the cycle timer register to force + all PCI writes to be posted immediately */ + mb(); + reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); + + /* check RUN */ + if(!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) { + PRINT(KERN_ERR, recv->ohci->id, "Error starting ISO DMA reception (ContextControl 0x%08x)\n", + reg_read(recv->ohci, recv->ContextControlSet)); + return -1; + } + + return 0; +} + +static void ohci_iso_recv_release_one(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + + /* re-use the DMA descriptor for first_packet */ + /* by linking the previous descriptor to it */ + + int next_i = iso->first_packet; + int prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1); + + struct dma_cmd *next = dma_region_i(&recv->prog, struct dma_cmd, next_i); + struct dma_cmd *prev = dma_region_i(&recv->prog, struct dma_cmd, prev_i); + + /* 'next' becomes the new end of the DMA chain */ + next->control |= 3 << 20; /* enable interrupt */ + next->branchAddress = 0; /* disable branch */ + + /* link prev to next */ + if(prev_i % iso->irq_interval) { + prev->control &= ~(3 << 20); /* no interrupt */ + } else { + prev->control |= 3 << 20; /* enable interrupt */ + } + prev->branchAddress = dma_prog_region_offset_to_bus(&recv->prog, + sizeof(struct dma_cmd) * next_i) | 1; + wmb(); + + /* wake up DMA in case it fell asleep */ + reg_write(recv->ohci, recv->ContextControlSet, (1 << 12)); + + /* advance packet cursors */ + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + atomic_inc(&iso->n_dma_packets); +} + +static void ohci_iso_recv_release(struct hpsb_iso *iso, int n_packets) +{ + int i; + for(i = 0; i < n_packets; i++) + ohci_iso_recv_release_one(iso); +} + +static void ohci_iso_recv_task(unsigned long data) +{ + struct hpsb_iso *iso = (struct hpsb_iso*) data; + struct ohci_iso_recv *recv = iso->hostdata; + + int count; + int wake = 0; + int good_packets = 0; + int bad_packets = 0; + + /* loop over the entire buffer */ + for(count = 0; count < iso->buf_packets; count++) { + u32 packet_len = 0; + struct hpsb_iso_packet_info *info; + + /* pointer to the DMA descriptor */ + struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + recv->pkt_dma; + + /* check the DMA descriptor for new writes to xferStatus */ + u16 xferstatus = il->status >> 16; + u16 rescount = il->status & 0xFFFF; + + unsigned char event = xferstatus & 0x1F; + + if(event == 0x11) { + /* packet received successfully! */ + good_packets++; + + /* rescount is the number of bytes *remaining* in the packet buffer, + after the packet was written */ + packet_len = iso->max_packet_size - rescount; + + } else if(event == 0x02) { + PRINT(KERN_ERR, recv->ohci->id, + "ISO DMA reception error - packet too long for buffer\n"); + bad_packets++; + } else if(event) { + PRINT(KERN_ERR, recv->ohci->id, + "ISO DMA reception error - OHCI error code 0x%02x\n", event); + bad_packets++; + } + + if(!event) { + /* this packet hasn't come in yet; we are done for now */ + goto out; + } + + /* sync our view of the buffer */ + dma_region_sync(&iso->buf); + + /* record the per-packet info */ + info = hpsb_iso_packet_info(iso, recv->pkt_dma); + info->len = packet_len; + + /* at least one packet came in, so wake up the reader */ + wake = 1; + + /* reset the DMA descriptor */ + il->status = iso->max_packet_size; + + /* advance DMA packet cursor */ + recv->pkt_dma = (recv->pkt_dma + 1) % iso->buf_packets; + + /* one more packet for the user, one less for us */ + if(atomic_dec_and_test(&iso->n_dma_packets)) { + /* if n_dma_packets reaches zero, we have an overflow */ + atomic_inc(&iso->overflows); + } + + } + +out: + if(wake && iso->waitq) { + wake_up_interruptible(iso->waitq); + } +} + + +/*********************************** + * rawiso ISO transmission * + ***********************************/ + +struct ohci_iso_xmit { + struct ti_ohci *ohci; + struct dma_prog_region prog; + struct ohci1394_iso_tasklet task; + int task_active; + int pkt_dma; + + u32 ContextControlSet; + u32 ContextControlClear; + u32 CommandPtr; +}; + +/* transmission DMA program: + one OUTPUT_MORE_IMMEDIATE for the IT header + one OUTPUT_LAST for the buffer data */ + +struct iso_xmit_cmd { + struct dma_cmd output_more_immediate; + u8 iso_hdr[8]; + u32 unused[2]; + struct dma_cmd output_last; +}; + +static int ohci_iso_xmit_init(struct hpsb_iso *iso); +static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle); +static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso); +static void ohci_iso_xmit_task(unsigned long data); + +static int ohci_iso_xmit_suggest_start_cycle(struct ti_ohci *ohci) +{ + u32 cycleTimer, sec, cyc, off; + + cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + sec = cycleTimer >> 25; + cyc = (cycleTimer >> 12) & 0x1FFF; + off = cycleTimer & 0xFFF; + + /* go ahead 500 cycles - if the user doesn't xmit_produce() a + packet within this time, we will end up waiting until the + 4-bit second counter wraps around to start transmission... + is there a better way? */ + + cyc += 500; + + sec += cyc/8000; + cyc %= 8000; + + return ((sec & 0x3) << 13) | cyc; +} + +static int ohci_iso_xmit_init(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit; + unsigned int prog_size; + int ctx; + int ret = -ENOMEM; + + xmit = kmalloc(sizeof(*xmit), SLAB_KERNEL); + if(!xmit) + return -ENOMEM; + + iso->hostdata = xmit; + xmit->ohci = iso->host->hostdata; + xmit->task_active = 0; + xmit->pkt_dma = iso->first_packet; + + dma_prog_region_init(&xmit->prog); + + prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets; + + if(dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev)) + goto err; + + ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT, + ohci_iso_xmit_task, (unsigned long) iso); + + if(ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) + goto err; + + xmit->task_active = 1; + + /* xmit context registers are spaced 16 bytes apart */ + ctx = xmit->task.context; + xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx; + xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx; + xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx; + + reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF); + + /* enable interrupts */ + reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << ctx); + + /* suggest a starting cycle */ + iso->first_packet_cycle = ohci_iso_xmit_suggest_start_cycle(xmit->ohci); + + return 0; + +err: + ohci_iso_xmit_shutdown(iso); + return ret; +} + +static void ohci_iso_xmit_stop(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL); +} + +static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + + if(xmit->task_active) { + /* halt DMA */ + ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL); + + /* disable interrupts */ + reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context); + + ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task); + xmit->task_active = 0; + } + + dma_prog_region_free(&xmit->prog); + kfree(xmit); + iso->hostdata = NULL; +} + +static void ohci_iso_xmit_task(unsigned long data) +{ + struct hpsb_iso *iso = (struct hpsb_iso*) data; + struct ohci_iso_xmit *xmit = iso->hostdata; + int wake = 0; + unsigned int good_packets = 0; + unsigned int bad_packets = 0; + int count; + + /* check the whole buffer if necessary, starting at pkt_dma*/ + for(count = 0; count < iso->buf_packets; count++) { + struct iso_xmit_cmd *cmd = + dma_region_i(&xmit->prog, struct iso_xmit_cmd, xmit->pkt_dma); + + /* check for new writes to xferStatus */ + u16 xferstatus = cmd->output_last.status >> 16; + unsigned char event = xferstatus & 0x1F; + + if(event == 0x11) { + /* packet sent successfully */ + good_packets++; + } else if(event) { + PRINT(KERN_ERR, xmit->ohci->id, + "ISO DMA transmission error - OHCI error code 0x%02x\n", event); + bad_packets++; + } + + if(!event) { + /* packet hasn't been sent yet; we are done for now */ + goto out; + } + + /* at least one packet came in, so wake up the writer */ + wake = 1; + + /* reset the DMA descriptor for next time */ + cmd->output_last.status = 0; + + /* advance packet cursor */ + xmit->pkt_dma = (xmit->pkt_dma + 1) % iso->buf_packets; + + /* one less packet for us */ + if(atomic_dec_and_test(&iso->n_dma_packets)) { + /* underflow */ + atomic_inc(&iso->overflows); + } + } + +out: + if(wake && iso->waitq) { + wake_up_interruptible(iso->waitq); + } +} + +static void ohci_iso_xmit_queue_one(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + struct hpsb_iso_packet_info *info; + int next_i, prev_i; + struct iso_xmit_cmd *next, *prev; + + /* sync up the card's view of the buffer */ + dma_region_sync(&iso->buf); + + /* append first_packet to the DMA chain */ + /* by linking the previous descriptor to it */ + /* (next will become the new end of the DMA chain) */ + + next_i = iso->first_packet; + prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1); + + next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i); + prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i); + + /* retrieve the packet info stashed in the buffer */ + info = hpsb_iso_packet_info(iso, iso->first_packet); + + /* set up the OUTPUT_MORE_IMMEDIATE */ + memset(next, 0, sizeof(struct iso_xmit_cmd)); + next->output_more_immediate.control = 0x02000008; + + /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */ + + /* tcode = 0xA, and sy */ + next->iso_hdr[0] = 0xA0 | (info->sy & 0xF); + + /* tag and channel number */ + next->iso_hdr[1] = (info->tag << 6) | (iso->channel & 0x3F); + + /* transmission speed */ + next->iso_hdr[2] = iso->speed & 0x7; + + /* payload size */ + next->iso_hdr[6] = info->len & 0xFF; + next->iso_hdr[7] = info->len >> 8; + + /* set up the OUTPUT_LAST */ + next->output_last.control = 1 << 28; + next->output_last.control |= 1 << 27; /* update timeStamp */ + next->output_last.control |= 3 << 20; /* want interrupt */ + next->output_last.control |= 3 << 18; /* enable branch */ + next->output_last.control |= info->len; + + /* payload bus address */ + next->output_last.address = dma_region_offset_to_bus(&iso->buf, + hpsb_iso_packet_data(iso, iso->first_packet) - iso->buf.kvirt); + + /* leave branchAddress at zero for now */ + + /* re-write the previous DMA descriptor to chain to this one */ + + /* set prev branch address to point to next (Z=3) */ + prev->output_last.branchAddress = + dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3; + + /* disable interrupt, unless required by the IRQ interval */ + if(prev_i % iso->irq_interval) { + prev->output_last.control &= ~(3 << 20); /* no interrupt */ + } else { + prev->output_last.control |= 3 << 20; /* enable interrupt */ + } + + wmb(); + + /* wake DMA in case it is sleeping */ + reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12); + + /* issue a dummy read of the cycle timer to force all PCI + writes to be posted immediately */ + mb(); + reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer); + + /* increment cursors */ + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + iso->first_packet_cycle = (iso->first_packet_cycle+1) % iso->buf_packets; + + atomic_inc(&iso->n_dma_packets); +} + +static void ohci_iso_xmit_queue(struct hpsb_iso *iso, int n_packets) +{ + int i; + for(i = 0; i < n_packets; i++) + ohci_iso_xmit_queue_one(iso); +} + +static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + + /* clear out the control register */ + reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF); + wmb(); + + /* address and length of first descriptor block (Z=3) */ + reg_write(xmit->ohci, xmit->CommandPtr, + dma_prog_region_offset_to_bus(&xmit->prog, xmit->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3); + + /* cycle match */ + if(cycle != -1) { + /* XXX pick a cycle and set iso->first_packet_cycle */ + reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (cycle << 16)); + } + + /* run */ + reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000); + mb(); + + /* wait 100 usec to give the card time to go active */ + udelay(100); + + /* check the RUN bit */ + if(!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) { + PRINT(KERN_ERR, xmit->ohci->id, "Error starting ISO DMA transmission (ContextControl 0x%08x)\n", + reg_read(xmit->ohci, xmit->ContextControlSet)); + return -1; + } + + return 0; +} + +static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, int arg) +{ + + switch(cmd) { + case XMIT_INIT: + return ohci_iso_xmit_init(iso); + case XMIT_START: + return ohci_iso_xmit_start(iso, arg); + case XMIT_STOP: + ohci_iso_xmit_stop(iso); + return 0; + case XMIT_QUEUE: + ohci_iso_xmit_queue(iso, arg); + return 0; + case XMIT_SHUTDOWN: + ohci_iso_xmit_shutdown(iso); + return 0; + + case RECV_INIT: + return ohci_iso_recv_init(iso); + case RECV_START: + return ohci_iso_recv_start(iso, arg); + case RECV_STOP: + ohci_iso_recv_stop(iso); + return 0; + case RECV_RELEASE: + ohci_iso_recv_release(iso, arg); + return 0; + case RECV_SHUTDOWN: + ohci_iso_recv_shutdown(iso); + return 0; + + default: + PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet", + cmd); + break; + } + return -EINVAL; +} + /*************************************** * IEEE-1394 functionality section END * ***************************************/ @@ -1944,7 +2633,7 @@ .get_rom = ohci_get_rom, .transmit_packet = ohci_transmit, .devctl = ohci_devctl, - .isoctl = NULL, + .isoctl = ohci_isoctl, .hw_csr_reg = ohci_hw_csr_reg, }; |
From: SVN U. <dm...@li...> - 2002-10-29 02:11:50
|
Author: dmaas Date: 2002-10-28 21:11:46 -0500 (Mon, 28 Oct 2002) New Revision: 654 Modified: trunk/Makefile trunk/dma.c trunk/ieee1394_core.c Log: put rawiso exports in ieee1394_core.c Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2002-10-28 21:11:46.000000000 -0500 @@ -42,6 +42,8 @@ #include "csr.h" #include "nodemgr.h" #include "ieee1394_hotplug.h" +#include "dma.h" +#include "iso.h" /* * Disable the nodemgr detection and config rom reading functionality. @@ -1264,3 +1266,25 @@ /** csr.c **/ EXPORT_SYMBOL(hpsb_update_config_rom); EXPORT_SYMBOL(hpsb_get_config_rom); + +/** dma.c **/ +EXPORT_SYMBOL(dma_prog_region_init); +EXPORT_SYMBOL(dma_prog_region_alloc); +EXPORT_SYMBOL(dma_prog_region_free); +EXPORT_SYMBOL(dma_region_init); +EXPORT_SYMBOL(dma_region_alloc); +EXPORT_SYMBOL(dma_region_free); +EXPORT_SYMBOL(dma_region_sync); +EXPORT_SYMBOL(dma_region_mmap); + +/** iso.c **/ +EXPORT_SYMBOL(hpsb_iso_xmit_init); +EXPORT_SYMBOL(hpsb_iso_recv_init); +EXPORT_SYMBOL(hpsb_iso_start); +EXPORT_SYMBOL(hpsb_iso_stop); +EXPORT_SYMBOL(hpsb_iso_shutdown); +EXPORT_SYMBOL(hpsb_iso_xmit_queue_packets); +EXPORT_SYMBOL(hpsb_iso_recv_release_packets); +EXPORT_SYMBOL(hpsb_iso_n_ready); +EXPORT_SYMBOL(hpsb_iso_packet_data); +EXPORT_SYMBOL(hpsb_iso_packet_info); Modified: trunk/Makefile ============================================================================== --- trunk/Makefile (original) +++ trunk/Makefile 2002-10-28 21:11:47.000000000 -0500 @@ -2,7 +2,7 @@ # Makefile for the Linux IEEE 1394 implementation # -export-objs := ieee1394_core.o ohci1394.o cmp.o dma.o +export-objs := ieee1394_core.o ohci1394.o cmp.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ highlevel.o csr.o nodemgr.o oui.o dma.o iso.o Modified: trunk/dma.c ============================================================================== --- trunk/dma.c (original) +++ trunk/dma.c 2002-10-28 21:11:47.000000000 -0500 @@ -199,12 +199,3 @@ return 0; } - -EXPORT_SYMBOL(dma_prog_region_init); -EXPORT_SYMBOL(dma_prog_region_alloc); -EXPORT_SYMBOL(dma_prog_region_free); -EXPORT_SYMBOL(dma_region_init); -EXPORT_SYMBOL(dma_region_alloc); -EXPORT_SYMBOL(dma_region_free); -EXPORT_SYMBOL(dma_region_sync); -EXPORT_SYMBOL(dma_region_mmap); |
From: SVN U. <dm...@li...> - 2002-10-29 02:07:40
|
Author: dmaas Date: 2002-10-28 21:07:36 -0500 (Mon, 28 Oct 2002) New Revision: 653 Added: trunk/iso.c trunk/iso.h Modified: trunk/Makefile trunk/hosts.h trunk/ohci1394.c trunk/pcilynx.c Log: rawiso merge part 2 - kernel-level rawiso API Added: trunk/iso.h ============================================================================== --- trunk/iso.h (original) +++ trunk/iso.h 2002-10-28 21:07:37.000000000 -0500 @@ -0,0 +1,143 @@ +/* + * IEEE 1394 for Linux + * + * kernel ISO transmission/reception + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#ifndef IEEE1394_ISO_H +#define IEEE1394_ISO_H + +#include "hosts.h" +#include "dma.h" + +/* high-level ISO interface */ + +/* per-packet data embedded in the ringbuffer */ +struct hpsb_iso_packet_info { + unsigned short len; + unsigned short cycle; /* receive only */ + unsigned char channel; /* receive only */ + unsigned char tag; + unsigned char sy; +}; + +/* + * each packet in the ringbuffer consists of three things: + * 1. the packet's data payload (no isochronous header) + * XXX ^^ this must change + * 2. a struct hpsb_iso_packet_info + * 3. some empty space before the next packet + * + * packets are separated by hpsb_iso.buf_stride bytes + * an even number of packets fit on one page + * no packet can be larger than one page + */ + +enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 }; + +struct hpsb_iso { + enum hpsb_iso_type type; + + /* pointer to low-level driver and its private data */ + struct hpsb_host *host; + void *hostdata; + + /* pointer to a wait queue that will receive wakeups */ + wait_queue_head_t *waitq; + + int speed; /* SPEED_100, 200, or 400 */ + int channel; + + /* greatest # of packets between interrupts - controls + the maximum latency of the buffer */ + int irq_interval; + + /* the packet ringbuffer */ + struct dma_region buf; + + /* # of packets in the ringbuffer */ + unsigned int buf_packets; + + /* offset between successive packets - + you can assume that this is a power of 2, + and that packets will never cross a page boundary */ + int buf_stride; + + /* largest possible packet size, in bytes */ + unsigned int max_packet_size; + + /* offset relative to (buf.kvirt + N*buf_stride) at which + the data payload begins for packet N */ + int packet_data_offset; + + /* offset relative to (buf.kvirt + N*buf_stride) at which the + struct hpsb_iso_packet_info is stored for packet N */ + int packet_info_offset; + + /* the index of the next packet that will be produced + or consumed by the user */ + int first_packet; + + /* number of packets owned by the low-level driver and + queued for transmission or reception. + this is related to the number of packets available + to the user process: n_ready = buf_packets - n_dma_packets */ + atomic_t n_dma_packets; + + /* how many times the buffer has overflowed or underflowed */ + atomic_t overflows; + + /* transmit only - the cycle number at which first_packet will be sent */ + int first_packet_cycle; + + /* flags to track initialization progress */ + int driver_init, driver_started; +}; + +/* functions available to high-level drivers (e.g. raw1394) */ + +/* allocate the buffer and DMA context */ + +struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int speed, + int irq_interval, + wait_queue_head_t *waitq); + +struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int irq_interval, + wait_queue_head_t *waitq); + +/* start/stop DMA */ +int hpsb_iso_start(struct hpsb_iso *iso, int start_on_cycle); +void hpsb_iso_stop(struct hpsb_iso *iso); + +/* deallocate buffer and DMA context */ +void hpsb_iso_shutdown(struct hpsb_iso *iso); + +/* N packets have been written to the buffer; queue them for transmission */ +int hpsb_iso_xmit_queue_packets(struct hpsb_iso *xmit, unsigned int n_packets); + +/* N packets have been read out of the buffer, re-use the buffer space */ +int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, unsigned int n_packets); + +/* returns # of packets ready to send or receive */ +int hpsb_iso_n_ready(struct hpsb_iso *iso); + +/* returns a pointer to the payload of packet 'pkt' */ +unsigned char* hpsb_iso_packet_data(struct hpsb_iso *iso, unsigned int pkt); + +/* returns a pointer to the info struct of packet 'pkt' */ +struct hpsb_iso_packet_info* hpsb_iso_packet_info(struct hpsb_iso *iso, unsigned int pkt); + +#endif /* IEEE1394_ISO_H */ Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-10-28 21:07:37.000000000 -0500 @@ -1944,6 +1944,7 @@ .get_rom = ohci_get_rom, .transmit_packet = ohci_transmit, .devctl = ohci_devctl, + .isoctl = NULL, .hw_csr_reg = ohci_hw_csr_reg, }; Modified: trunk/Makefile ============================================================================== --- trunk/Makefile (original) +++ trunk/Makefile 2002-10-28 21:07:37.000000000 -0500 @@ -5,7 +5,7 @@ export-objs := ieee1394_core.o ohci1394.o cmp.o dma.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ - highlevel.o csr.o nodemgr.o oui.o dma.o + highlevel.o csr.o nodemgr.o oui.o dma.o iso.o obj-$(CONFIG_IEEE1394) += ieee1394.o obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o Modified: trunk/hosts.h ============================================================================== --- trunk/hosts.h (original) +++ trunk/hosts.h 2002-10-28 21:07:37.000000000 -0500 @@ -18,6 +18,7 @@ #define CSR_CONFIG_ROM_SIZE 0x100 struct hpsb_packet; +struct hpsb_iso; struct hpsb_host { struct list_head host_list; @@ -104,6 +105,28 @@ ISO_UNLISTEN_CHANNEL }; +enum isoctl_cmd { + /* rawiso API - see iso.h for the meanings of these commands + * INIT = allocate resources + * START = begin transmission/reception (arg: cycle to start on) + * STOP = halt transmission/reception + * QUEUE/RELEASE = produce/consume packets (arg: # of packets) + * SHUTDOWN = deallocate resources + */ + + XMIT_INIT, + XMIT_START, + XMIT_STOP, + XMIT_QUEUE, + XMIT_SHUTDOWN, + + RECV_INIT, + RECV_START, + RECV_STOP, + RECV_RELEASE, + RECV_SHUTDOWN, +}; + enum reset_types { /* 166 microsecond reset -- only type of reset available on non-1394a capable IEEE 1394 controllers */ @@ -141,6 +164,11 @@ */ int (*devctl) (struct hpsb_host *host, enum devctl_cmd command, int arg); + /* ISO transmission/reception functions. Return 0 on success, -1 on failure. + * If the low-level driver does not support the new ISO API, set isoctl to NULL. + */ + int (*isoctl) (struct hpsb_iso *iso, enum isoctl_cmd command, int arg); + /* This function is mainly to redirect local CSR reads/locks to the iso * management registers (bus manager id, bandwidth available, channels * available) to the hardware registers in OHCI. reg is 0,1,2,3 for bus Modified: trunk/pcilynx.c ============================================================================== --- trunk/pcilynx.c (original) +++ trunk/pcilynx.c 2002-10-28 21:07:37.000000000 -0500 @@ -1706,6 +1706,7 @@ .get_rom = get_lynx_rom, .transmit_packet = lynx_transmit, .devctl = lynx_devctl, + .isoctl = NULL, }; MODULE_AUTHOR("Andreas E. Bombe <and...@mu...>"); Added: trunk/iso.c ============================================================================== --- trunk/iso.c (original) +++ trunk/iso.c 2002-10-28 21:07:38.000000000 -0500 @@ -0,0 +1,224 @@ +/* + * IEEE 1394 for Linux + * + * kernel ISO transmission/reception + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include "iso.h" + +void hpsb_iso_stop(struct hpsb_iso *iso) +{ + if(!iso->driver_started) + return; + + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_STOP : RECV_STOP, 0); + iso->driver_started = 0; +} + +void hpsb_iso_shutdown(struct hpsb_iso *iso) +{ + if(iso->driver_init) { + hpsb_iso_stop(iso); + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_SHUTDOWN : RECV_SHUTDOWN, 0); + iso->driver_init = 0; + } + + dma_region_free(&iso->buf); + kfree(iso); +} + +static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_iso_type type, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int irq_interval, + wait_queue_head_t *waitq) +{ + struct hpsb_iso *iso; + unsigned int packet_plus_info; + int dma_direction; + + /* make sure driver supports the ISO API */ + if(!host->driver->isoctl) + return NULL; + + /* sanitize parameters */ + + if(buf_packets < 2) + buf_packets = 2; + + if(irq_interval < 1 || irq_interval > buf_packets / 2) + irq_interval = buf_packets / 2; + + if(max_packet_size + sizeof(struct hpsb_iso_packet_info) > PAGE_SIZE) + return NULL; + + /* size of packet payload plus the per-packet info must be a power of 2 + and at most equal to the page size */ + + for(packet_plus_info = 256; packet_plus_info < PAGE_SIZE; packet_plus_info *= 2) { + if(packet_plus_info >= (max_packet_size + sizeof(struct hpsb_iso_packet_info))) { + break; + } + } + + /* allocate and write the struct hpsb_iso */ + + iso = kmalloc(sizeof(*iso), SLAB_KERNEL); + if(!iso) + return NULL; + + iso->type = type; + iso->host = host; + iso->hostdata = NULL; + iso->waitq = waitq; + iso->channel = channel; + iso->irq_interval = irq_interval; + dma_region_init(&iso->buf); + iso->buf_packets = buf_packets; + iso->buf_stride = packet_plus_info; + iso->max_packet_size = max_packet_size; + iso->packet_data_offset = 0; + iso->packet_info_offset = max_packet_size; + iso->first_packet = 0; + + if(iso->type == HPSB_ISO_XMIT) { + atomic_set(&iso->n_dma_packets, 0); + dma_direction = PCI_DMA_TODEVICE; + } else { + atomic_set(&iso->n_dma_packets, iso->buf_packets); + dma_direction = PCI_DMA_FROMDEVICE; + } + + atomic_set(&iso->overflows, 0); + iso->first_packet_cycle = 0; + iso->driver_init = 0; + iso->driver_started = 0; + + /* allocate the packet buffer */ + if(dma_region_alloc(&iso->buf, iso->buf_packets * iso->buf_stride, + host->pdev, dma_direction)) + goto err; + + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +int hpsb_iso_n_ready(struct hpsb_iso* iso) +{ + return iso->buf_packets - atomic_read(&iso->n_dma_packets); +} + + +struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int speed, + int irq_interval, + wait_queue_head_t *waitq) +{ + struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT, + buf_packets, max_packet_size, + channel, irq_interval, waitq); + if(!iso) + return NULL; + + iso->speed = speed; + + /* tell the driver to start working */ + if(host->driver->isoctl(iso, XMIT_INIT, 0)) + goto err; + + iso->driver_init = 1; + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int irq_interval, + wait_queue_head_t *waitq) +{ + struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV, + buf_packets, max_packet_size, + channel, irq_interval, waitq); + if(!iso) + return NULL; + + /* tell the driver to start working */ + if(host->driver->isoctl(iso, RECV_INIT, 0)) + goto err; + + iso->driver_init = 1; + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +int hpsb_iso_start(struct hpsb_iso *iso, int cycle) +{ + int retval = 0; + + if(iso->driver_started) + return 0; + + retval = iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_START : RECV_START, cycle); + if(retval) + return retval; + + iso->driver_started = 1; + return retval; +} + +int hpsb_iso_xmit_queue_packets(struct hpsb_iso *iso, unsigned int n_packets) +{ + int i; + int pkt = iso->first_packet; + + /* check packet sizes for sanity */ + for(i = 0; i < n_packets; i++) { + struct hpsb_iso_packet_info *info = hpsb_iso_packet_info(iso, pkt); + if(info->len > iso->max_packet_size) { + printk(KERN_ERR "hpsb_iso_xmit_queue_packets: packet too long (%u, max is %u)\n", + info->len, iso->max_packet_size); + return -EINVAL; + } + + pkt = (pkt+1) % iso->buf_packets; + } + + return iso->host->driver->isoctl(iso, XMIT_QUEUE, n_packets); +} + +int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) +{ + return iso->host->driver->isoctl(iso, RECV_RELEASE, n_packets); +} + +unsigned char* hpsb_iso_packet_data(struct hpsb_iso *iso, unsigned int pkt) +{ + return (iso->buf.kvirt + pkt * iso->buf_stride) + + iso->packet_data_offset; +} + +struct hpsb_iso_packet_info* hpsb_iso_packet_info(struct hpsb_iso *iso, unsigned int pkt) +{ + return (struct hpsb_iso_packet_info*) ((iso->buf.kvirt + pkt * iso->buf_stride) + + iso->packet_info_offset); +} |
From: SVN U. <dm...@li...> - 2002-10-29 01:33:53
|
Author: dmaas Date: 2002-10-28 20:33:47 -0500 (Mon, 28 Oct 2002) New Revision: 652 Added: trunk/dma.c trunk/dma.h Modified: trunk/Makefile Log: rawiso merge part 1 - DMA library Modified: trunk/Makefile ============================================================================== --- trunk/Makefile (original) +++ trunk/Makefile 2002-10-28 20:33:48.000000000 -0500 @@ -2,10 +2,10 @@ # Makefile for the Linux IEEE 1394 implementation # -export-objs := ieee1394_core.o ohci1394.o cmp.o +export-objs := ieee1394_core.o ohci1394.o cmp.o dma.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ - highlevel.o csr.o nodemgr.o oui.o + highlevel.o csr.o nodemgr.o oui.o dma.o obj-$(CONFIG_IEEE1394) += ieee1394.o obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o Added: trunk/dma.c ============================================================================== --- trunk/dma.c (original) +++ trunk/dma.c 2002-10-28 20:33:48.000000000 -0500 @@ -0,0 +1,210 @@ +/* + * DMA region bookkeeping routines + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include <linux/module.h> +#include "dma.h" + +/* dma_prog_region */ + +void dma_prog_region_init(struct dma_prog_region *prog) +{ + prog->kvirt = NULL; + prog->dev = NULL; + prog->n_pages = 0; + prog->bus_addr = 0; +} + +int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev) +{ + /* round up to page size */ + if(n_bytes % PAGE_SIZE) + n_bytes += PAGE_SIZE - (n_bytes & PAGE_SIZE); + + prog->n_pages = n_bytes / PAGE_SIZE; + + prog->kvirt = pci_alloc_consistent(dev, prog->n_pages * PAGE_SIZE, &prog->bus_addr); + if(!prog->kvirt) { + printk(KERN_ERR "dma_prog_region_alloc: pci_alloc_consistent() failed\n"); + dma_prog_region_free(prog); + return -ENOMEM; + } + + prog->dev = dev; + + return 0; +} + +void dma_prog_region_free(struct dma_prog_region *prog) +{ + if(prog->kvirt) { + pci_free_consistent(prog->dev, prog->n_pages * PAGE_SIZE, prog->kvirt, prog->bus_addr); + } + + prog->kvirt = NULL; + prog->dev = NULL; + prog->n_pages = 0; + prog->bus_addr = 0; +} + +/* dma_region */ + +void dma_region_init(struct dma_region *dma) +{ + dma->kvirt = NULL; + dma->dev = NULL; + dma->n_pages = 0; + dma->n_dma_pages = 0; + dma->sglist = NULL; +} + +int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction) +{ + unsigned int i, n_pages; + + /* round up to page size */ + if(n_bytes % PAGE_SIZE) + n_bytes += PAGE_SIZE - (n_bytes & PAGE_SIZE); + + n_pages = n_bytes / PAGE_SIZE; + + dma->kvirt = vmalloc_32(n_pages * PAGE_SIZE); + if(!dma->kvirt) { + printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n"); + goto err; + } + + dma->n_pages = n_pages; + + /* Clear the ram out, no junk to the user */ + memset(dma->kvirt, 0, n_pages * PAGE_SIZE); + + /* allocate scatter/gather list */ + dma->sglist = kmalloc(dma->n_pages * sizeof(struct scatterlist), GFP_KERNEL); + if(!dma->sglist) { + printk(KERN_ERR "dma_region_alloc: kmalloc(sglist) failed\n"); + goto err; + } + + /* just to be safe - this will become unnecessary once sglist->address goes away */ + memset(dma->sglist, 0, dma->n_pages * sizeof(struct scatterlist)); + + /* fill scatter/gather list with pages */ + for(i = 0; i < dma->n_pages; i++) { + unsigned long va = (unsigned long) dma->kvirt + i * PAGE_SIZE; + + dma->sglist[i].page = vmalloc_to_page((void *)va); + dma->sglist[i].length = PAGE_SIZE; + } + + /* map sglist to the IOMMU */ + dma->n_dma_pages = pci_map_sg(dev, &dma->sglist[0], dma->n_pages, direction); + + if(dma->n_dma_pages == 0) { + printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n"); + goto err; + } + + dma->dev = dev; + dma->direction = direction; + + return 0; + +err: + dma_region_free(dma); + return -ENOMEM; +} + +void dma_region_free(struct dma_region *dma) +{ + if(dma->n_dma_pages) { + pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages, dma->direction); + dma->n_dma_pages = 0; + dma->dev = NULL; + } + + if(dma->sglist) { + kfree(dma->sglist); + dma->sglist = NULL; + } + + if(dma->kvirt) { + vfree(dma->kvirt); + dma->kvirt = NULL; + dma->n_pages = 0; + } +} + +void dma_region_sync(struct dma_region *dma) +{ + /* XXX DJM - inefficient - add address/length argument */ + pci_dma_sync_sg(dma->dev, &dma->sglist[0], dma->n_dma_pages, dma->direction); +} + +/* nopage() handler for mmap access */ + +static struct page* +dma_region_pagefault(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 dma_region *dma = (struct dma_region*) area->vm_private_data; + + if(!dma->kvirt) + goto out; + + if( (address < (unsigned long) area->vm_start) || + (address > (unsigned long) area->vm_start + (PAGE_SIZE * dma->n_pages)) ) + goto out; + + offset = address - area->vm_start; + kernel_virt_addr = (unsigned long) dma->kvirt + offset; + ret = vmalloc_to_page((void*) kernel_virt_addr); + get_page(ret); +out: + return ret; +} + +static struct vm_operations_struct dma_region_vm_ops = { + nopage: dma_region_pagefault, +}; + +int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma) +{ + unsigned long size; + + if(!dma->kvirt) + return -EINVAL; + + /* must be page-aligned */ + if(vma->vm_pgoff != 0) + return -EINVAL; + + /* check the length */ + size = vma->vm_end - vma->vm_start; + if(size > (PAGE_SIZE * dma->n_pages)) + return -EINVAL; + + vma->vm_ops = &dma_region_vm_ops; + vma->vm_private_data = dma; + vma->vm_file = file; + vma->vm_flags |= VM_RESERVED; + + return 0; +} + +EXPORT_SYMBOL(dma_prog_region_init); +EXPORT_SYMBOL(dma_prog_region_alloc); +EXPORT_SYMBOL(dma_prog_region_free); +EXPORT_SYMBOL(dma_region_init); +EXPORT_SYMBOL(dma_region_alloc); +EXPORT_SYMBOL(dma_region_free); +EXPORT_SYMBOL(dma_region_sync); +EXPORT_SYMBOL(dma_region_mmap); Added: trunk/dma.h ============================================================================== --- trunk/dma.h (original) +++ trunk/dma.h 2002-10-28 20:33:48.000000000 -0500 @@ -0,0 +1,86 @@ +/* + * DMA region bookkeeping routines + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#ifndef IEEE1394_DMA_H +#define IEEE1394_DMA_H + +#include <linux/pci.h> +#include <asm/scatterlist.h> + +/* structure for bookkeeping of a small, physically-contiguous DMA buffer + with random-access, synchronous usage characteristics */ + +struct dma_prog_region { + unsigned char *kvirt; /* kernel virtual address */ + struct pci_dev *dev; /* PCI device */ + unsigned int n_pages; /* # of kernel pages */ + dma_addr_t bus_addr; /* base bus address */ +}; + +/* clear out all fields but do not allocate any memory */ +void dma_prog_region_init(struct dma_prog_region *prog); +int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev); +void dma_prog_region_free(struct dma_prog_region *prog); + +static inline dma_addr_t dma_prog_region_offset_to_bus(struct dma_prog_region *prog, unsigned long offset) +{ + return prog->bus_addr + offset; +} + + + +/* structure for bookkeeping of a large, non-physically-contiguous DMA buffer + with streaming, asynchronous usage characteristics */ + +struct dma_region { + unsigned char *kvirt; /* kernel virtual address */ + struct pci_dev *dev; /* PCI device */ + unsigned int n_pages; /* # of kernel pages */ + unsigned int n_dma_pages; /* # of IOMMU pages */ + struct scatterlist *sglist; + int direction; /* PCI_DMA_TODEVICE, etc */ +}; + +/* clear out all fields but do not allocate anything */ +void dma_region_init(struct dma_region *dma); + +/* allocate the buffer and map it to the IOMMU */ +int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction); + +/* unmap and free the buffer */ +void dma_region_free(struct dma_region *dma); + +/* sync the IO bus' view of the buffer with the CPU's view */ +/* XXX DJM - add addr, len arguments */ +void dma_region_sync(struct dma_region *dma); + +/* map the buffer into a user space process */ +int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma); + +/* macro to index into a DMA region */ +#define dma_region_i(_dma, _type, _index) ( ((_type*) ((_dma)->kvirt)) + (_index) ) + +/* return the DMA bus address of the byte with the given offset + relative to the beginning of the dma_region */ +/* XXX DJM take out of line and use binary search */ +static inline dma_addr_t dma_region_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); + } + return 0; +} + +#endif /* IEEE1394_DMA_H */ |
From: SVN U. <dde...@li...> - 2002-10-28 23:01:51
|
Author: ddennedy Date: 2002-10-28 18:01:40 -0500 (Mon, 28 Oct 2002) New Revision: 651 Modified: trunk/raw1394.c Log: fix broken quadlet async write Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2002-10-28 18:01:41.000000000 -0500 @@ -656,19 +656,33 @@ break; - case RAW1394_REQ_ASYNC_WRITE: + case RAW1394_REQ_ASYNC_WRITE: DBGMSG("write_request called"); - packet = hpsb_make_writepacket(fi->host, node, addr, NULL, - req->req.length); - if (!packet) - return -ENOMEM; - - if (copy_from_user(packet->data, int2ptr(req->req.sendb), - req->req.length)) + if (req->req.length == 4) { + quadlet_t x; + + if (copy_from_user(&x, int2ptr(req->req.sendb), + req->req.length)) req->req.error = RAW1394_ERROR_MEMFAULT; + + packet = hpsb_make_writepacket(fi->host, node, addr, &x, + req->req.length); + if (!packet) + return -ENOMEM; + + } else { + packet = hpsb_make_writepacket(fi->host, node, addr, NULL, + req->req.length); + if (!packet) + return -ENOMEM; - req->req.length = 0; - break; + if (copy_from_user(packet->data, int2ptr(req->req.sendb), + req->req.length)) + req->req.error = RAW1394_ERROR_MEMFAULT; + } + + req->req.length = 0; + break; case RAW1394_REQ_LOCK: DBGMSG("lock_request called"); |
From: SVN U. <hog...@li...> - 2002-10-27 22:03:14
|
Author: hogsberg Date: 2002-10-27 17:03:07 -0500 (Sun, 27 Oct 2002) New Revision: 650 Modified: trunk/hosts.c Log: Doh, remember to init the extra tlabel pool. Use nifty ARRAY_SIZE() macro. Modified: trunk/hosts.c ============================================================================== --- trunk/hosts.c (original) +++ trunk/hosts.c 2002-10-27 17:03:08.000000000 -0500 @@ -134,7 +134,7 @@ INIT_LIST_HEAD(&h->pending_packets); spin_lock_init(&h->pending_pkt_lock); - for (i = 0; i < 63; i++) + for (i = 0; i < ARRAY_SIZE(h->tpool); i++) HPSB_TPOOL_INIT(&h->tpool[i]); atomic_set(&h->generation, 0); |
From: SVN U. <hog...@li...> - 2002-10-27 21:05:08
|
Author: hogsberg Date: 2002-10-27 16:05:00 -0500 (Sun, 27 Oct 2002) New Revision: 649 Modified: trunk/hosts.h Log: Add tlabel pool for broadcast requests. Modified: trunk/hosts.h ============================================================================== --- trunk/hosts.h (original) +++ trunk/hosts.h 2002-10-27 16:05:00.000000000 -0500 @@ -58,7 +58,7 @@ struct csr_control csr; /* Per node tlabel pool allocation */ - struct hpsb_tlabel_pool tpool[63]; + struct hpsb_tlabel_pool tpool[64]; struct hpsb_host_driver *driver; |
From: SVN U. <ben...@li...> - 2002-10-27 02:02:08
|
Author: bencollins Date: 2002-10-26 22:02:05 -0400 (Sat, 26 Oct 2002) New Revision: 648 Modified: trunk/csr.c Log: Better FCP mod param description from Stefan Richter. Modified: trunk/csr.c ============================================================================== --- trunk/csr.c (original) +++ trunk/csr.c 2002-10-26 22:02:06.000000000 -0400 @@ -28,7 +28,7 @@ /* Module Parameters */ /* this module parameter can be used to disable mapping of the FCP registers */ MODULE_PARM(fcp,"i"); -MODULE_PARM_DESC(fcp, "FCP-registers"); +MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0)."); static int fcp = 1; static u16 csr_crc16(unsigned *data, int length) |
From: SVN U. <dde...@li...> - 2002-10-26 18:46:02
|
Author: ddennedy Date: 2002-10-26 14:45:56 -0400 (Sat, 26 Oct 2002) New Revision: 647 Modified: trunk/dv1394.c Log: unregister iso tasklets on shutdown; fix multiple non-devfs minors Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2002-10-26 14:45:57.000000000 -0400 @@ -137,7 +137,7 @@ (will cause undeflows if your machine is too slow!) */ -#define DV1394_DEBUG_LEVEL 0 +#define DV1394_DEBUG_LEVEL 1 /* for debugging use ONLY: allow more than one open() of the device */ /* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */ @@ -1408,6 +1408,16 @@ } spin_unlock_irqrestore(&video->spinlock, flags); + + /* remove tasklets */ + 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; + } /* release the ISO channel */ if(video->channel != -1) { @@ -2108,7 +2118,7 @@ struct video_card *p; list_for_each(lh, &dv1394_cards) { p = list_entry(lh, struct video_card, list); - if((p->id >> 2) == ieee1394_file_to_instance(file)) { + if((p->id) == ieee1394_file_to_instance(file)) { video = p; break; } @@ -2828,6 +2838,10 @@ /* lower 2 bits of id indicate which of four "plugs" per host */ video->id = ohci->id << 2; + if (format == DV1394_NTSC) + video->id |= mode; + else + video->id |= 2 + mode; video->ohci_it_ctx = -1; video->ohci_ir_ctx = -1; @@ -2876,10 +2890,6 @@ list_add_tail(&video->list, &dv1394_cards); spin_unlock_irqrestore(&dv1394_cards_lock, flags); - if (format == DV1394_NTSC) - video->id |= mode; - else video->id |= 2 + mode; - #ifdef CONFIG_DEVFS_FS if (dv1394_devfs_add_entry(video) < 0) goto err_free; |
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); |
From: SVN U. <dm...@li...> - 2002-10-26 03:13:40
|
Author: dmaas Date: 2002-10-25 23:13:33 -0400 (Fri, 25 Oct 2002) New Revision: 645 Modified: branches/rawiso/iso.h branches/rawiso/raw1394.c branches/rawiso/raw1394.h Log: change struct iso_packet_info layout and raw1394 poll behavior Modified: branches/rawiso/iso.h ============================================================================== --- branches/rawiso/iso.h (original) +++ branches/rawiso/iso.h 2002-10-25 23:13:33.000000000 -0400 @@ -20,9 +20,9 @@ /* per-packet data embedded in the ringbuffer */ struct hpsb_iso_packet_info { unsigned short len; + unsigned short cycle; unsigned char channel; unsigned char tag; - unsigned char tcode; unsigned char sy; }; Modified: branches/rawiso/raw1394.c ============================================================================== --- branches/rawiso/raw1394.c (original) +++ branches/rawiso/raw1394.c 2002-10-25 23:13:33.000000000 -0400 @@ -1058,8 +1058,8 @@ } /* - POLLIN/OUT is for read/write requests - POLLPRI is for ISO transmission and reception + POLLIN is for read requests + POLLOUT is for ISO transmission and reception */ static unsigned int raw1394_poll(struct file *file, poll_table *pt) { @@ -1076,7 +1076,7 @@ if(fi->iso_state != RAW1394_ISO_INACTIVE) { if(hpsb_iso_n_ready(fi->iso_handle) > 0) - mask |= POLLPRI; + mask |= POLLOUT; } return mask; Modified: branches/rawiso/raw1394.h ============================================================================== --- branches/rawiso/raw1394.h (original) +++ branches/rawiso/raw1394.h 2002-10-25 23:13:33.000000000 -0400 @@ -84,9 +84,9 @@ /* must be identical to hpsb_iso_packet_info in iso.h! */ struct raw1394_iso_packet_info { unsigned short len; + unsigned short cycle; unsigned char channel; unsigned char tag; - unsigned char tcode; unsigned char sy; }; |
From: SVN U. <dm...@li...> - 2002-10-25 03:54:28
|
Author: dmaas Date: 2002-10-24 23:54:19 -0400 (Thu, 24 Oct 2002) New Revision: 644 Modified: branches/rawiso/hosts.h branches/rawiso/ieee1394_core.c branches/rawiso/iso.c branches/rawiso/iso.h branches/rawiso/ohci1394.c branches/rawiso/raw1394.c branches/rawiso/raw1394.h Log: rawiso kernel API changes Modified: branches/rawiso/iso.h ============================================================================== --- branches/rawiso/iso.h (original) +++ branches/rawiso/iso.h 2002-10-24 23:54:21.000000000 -0400 @@ -83,14 +83,14 @@ /* used for cycle matching */ int first_packet_cycle; - int driver_started; + int driver_init, driver_started; }; /* functions available to high-level drivers (e.g. raw1394) */ -/* allocate the buffer and DMA context - transmission will begin - at the first following call to xmit_produce() */ -struct hpsb_iso* hpsb_iso_xmit_start(struct hpsb_host *host, +/* allocate the buffer and DMA context */ + +struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, unsigned int buf_packets, unsigned int max_packet_size, int channel, @@ -98,26 +98,26 @@ int irq_interval, wait_queue_head_t *waitq); -/* N packets have been written to the buffer and can be queued for transmission */ -int hpsb_iso_xmit_produce(struct hpsb_iso *xmit, unsigned int n_packets); - -/* halt transmission, deallocate buffer and DMA context */ -void hpsb_iso_xmit_stop(struct hpsb_iso *iso); - -/* allocate the buffer and DMA context, and start filling the buffer - with packets */ -struct hpsb_iso* hpsb_iso_recv_start(struct hpsb_host *host, +struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, unsigned int buf_packets, unsigned int max_packet_size, int channel, int irq_interval, wait_queue_head_t *waitq); -/* N packets have been read out of the buffer, re-use the buffer space */ -int hpsb_iso_recv_consume(struct hpsb_iso *recv, unsigned int n_packets); +/* start/stop DMA */ +int hpsb_iso_start(struct hpsb_iso *iso, int start_on_cycle); +void hpsb_iso_stop(struct hpsb_iso *iso); -/* halt reception, deallocate buffer and DMA context */ -void hpsb_iso_recv_stop(struct hpsb_iso *iso); +/* deallocate buffer and DMA context */ +void hpsb_iso_shutdown(struct hpsb_iso *iso); + + +/* N packets have been written to the buffer and can be queued for transmission */ +int hpsb_iso_xmit_queue_packets(struct hpsb_iso *xmit, unsigned int n_packets); + +/* N packets have been read out of the buffer, re-use the buffer space */ +int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, unsigned int n_packets); /* returns # of packets ready to send or receive */ int hpsb_iso_n_ready(struct hpsb_iso *iso); Modified: branches/rawiso/ieee1394_core.c ============================================================================== --- branches/rawiso/ieee1394_core.c (original) +++ branches/rawiso/ieee1394_core.c 2002-10-24 23:54:21.000000000 -0400 @@ -1130,12 +1130,13 @@ EXPORT_SYMBOL(highlevel_remove_host); EXPORT_SYMBOL(highlevel_host_reset); -EXPORT_SYMBOL(hpsb_iso_xmit_start); -EXPORT_SYMBOL(hpsb_iso_xmit_produce); -EXPORT_SYMBOL(hpsb_iso_xmit_stop); -EXPORT_SYMBOL(hpsb_iso_recv_start); -EXPORT_SYMBOL(hpsb_iso_recv_consume); -EXPORT_SYMBOL(hpsb_iso_recv_stop); +EXPORT_SYMBOL(hpsb_iso_xmit_init); +EXPORT_SYMBOL(hpsb_iso_recv_init); +EXPORT_SYMBOL(hpsb_iso_start); +EXPORT_SYMBOL(hpsb_iso_stop); +EXPORT_SYMBOL(hpsb_iso_shutdown); +EXPORT_SYMBOL(hpsb_iso_xmit_queue_packets); +EXPORT_SYMBOL(hpsb_iso_recv_release_packets); EXPORT_SYMBOL(hpsb_iso_n_ready); EXPORT_SYMBOL(hpsb_iso_packet_data); EXPORT_SYMBOL(hpsb_iso_packet_info); Modified: branches/rawiso/ohci1394.c ============================================================================== --- branches/rawiso/ohci1394.c (original) +++ branches/rawiso/ohci1394.c 2002-10-24 23:54:21.000000000 -0400 @@ -1005,11 +1005,12 @@ static void ohci_iso_recv_task(unsigned long data); static void ohci_iso_recv_stop(struct hpsb_iso *iso); +static void ohci_iso_recv_shutdown(struct hpsb_iso *iso); static void ohci_iso_recv_program(struct hpsb_iso *iso); -static int ohci_iso_recv_start_dma(struct hpsb_iso *iso); +static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle); -static int ohci_iso_recv_start(struct hpsb_iso *iso) +static int ohci_iso_recv_init(struct hpsb_iso *iso) { struct ohci_iso_recv *recv; unsigned int prog_size; @@ -1053,22 +1054,25 @@ /* write the DMA program */ ohci_iso_recv_program(iso); - - /* go! */ - if(ohci_iso_recv_start_dma(iso)) - goto err; return 0; err: - ohci_iso_recv_stop(iso); + ohci_iso_recv_shutdown(iso); return ret; } - static void ohci_iso_recv_stop(struct hpsb_iso *iso) { struct ohci_iso_recv *recv = iso->hostdata; + + /* halt DMA */ + ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL); +} + +static void ohci_iso_recv_shutdown(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; if(recv->task_active) { /* halt DMA */ @@ -1148,7 +1152,7 @@ /* the final descriptor's branch address and Z should be left at 0 */ } -static int ohci_iso_recv_start_dma(struct hpsb_iso *iso) +static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle) { struct ohci_iso_recv *recv = iso->hostdata; u32 command; @@ -1162,6 +1166,10 @@ /* match on all tags, listen on channel */ reg_write(recv->ohci, recv->ContextMatch, 0xF0000000 | iso->channel); + if(cycle != -1) { + /* XXX use cycleMatch */ + } + /* address of first descriptor block */ command = dma_prog_region_offset_to_bus(&recv->prog, recv->pkt_dma * sizeof(struct dma_cmd)); command |= 1; /* Z=1 */ @@ -1187,7 +1195,7 @@ return 0; } -static void ohci_iso_recv_consume_one(struct hpsb_iso *iso) +static void ohci_iso_recv_release_one(struct hpsb_iso *iso) { struct ohci_iso_recv *recv = iso->hostdata; @@ -1222,11 +1230,11 @@ atomic_inc(&iso->n_dma_packets); } -static void ohci_iso_recv_consume(struct hpsb_iso *iso, int n_packets) +static void ohci_iso_recv_release(struct hpsb_iso *iso, int n_packets) { int i; for(i = 0; i < n_packets; i++) - ohci_iso_recv_consume_one(iso); + ohci_iso_recv_release_one(iso); } static void ohci_iso_recv_task(unsigned long data) @@ -1334,9 +1342,9 @@ struct dma_cmd output_last; }; -static int ohci_iso_xmit_start(struct hpsb_iso *iso); -static int ohci_iso_xmit_start_dma(struct hpsb_iso *iso, int cycle); -static void ohci_iso_xmit_stop(struct hpsb_iso *iso); +static int ohci_iso_xmit_init(struct hpsb_iso *iso); +static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle); +static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso); static void ohci_iso_xmit_task(unsigned long data); static int ohci_iso_xmit_suggest_start_cycle(struct ti_ohci *ohci) @@ -1361,7 +1369,7 @@ return ((sec & 0x3) << 13) | cyc; } -static int ohci_iso_xmit_start(struct hpsb_iso *iso) +static int ohci_iso_xmit_init(struct hpsb_iso *iso) { struct ohci_iso_xmit *xmit; unsigned int prog_size; @@ -1409,13 +1417,19 @@ return 0; err: - ohci_iso_xmit_stop(iso); + ohci_iso_xmit_shutdown(iso); return ret; } static void ohci_iso_xmit_stop(struct hpsb_iso *iso) { struct ohci_iso_xmit *xmit = iso->hostdata; + ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL); +} + +static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; if(xmit->task_active) { /* halt DMA */ @@ -1487,7 +1501,7 @@ } } -static void ohci_iso_xmit_produce_one(struct hpsb_iso *iso) +static void ohci_iso_xmit_queue_one(struct hpsb_iso *iso) { struct ohci_iso_xmit *xmit = iso->hostdata; struct hpsb_iso_packet_info *info; @@ -1572,23 +1586,14 @@ atomic_inc(&iso->n_dma_packets); } -static void ohci_iso_xmit_produce(struct hpsb_iso *iso, int n_packets) +static void ohci_iso_xmit_queue(struct hpsb_iso *iso, int n_packets) { - struct ohci_iso_xmit *xmit = iso->hostdata; int i; - - /* record the starting cycle here, since produce_one() bumps first_packet_cycle */ - int starting_cycle = iso->first_packet_cycle; - for(i = 0; i < n_packets; i++) - ohci_iso_xmit_produce_one(iso); - - /* if DMA is not running, start it up */ - if(!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) - ohci_iso_xmit_start_dma(iso, starting_cycle); + ohci_iso_xmit_queue_one(iso); } -static int ohci_iso_xmit_start_dma(struct hpsb_iso *iso, int cycle) +static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle) { struct ohci_iso_xmit *xmit = iso->hostdata; @@ -1601,7 +1606,7 @@ dma_prog_region_offset_to_bus(&xmit->prog, xmit->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3); /* cycle match */ - if(cycle >= 0) { + if(cycle != -1) { reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (cycle << 16)); } @@ -1627,22 +1632,34 @@ { switch(cmd) { + case XMIT_INIT: + return ohci_iso_xmit_init(iso); case XMIT_START: - return ohci_iso_xmit_start(iso); - case XMIT_PRODUCE: - ohci_iso_xmit_produce(iso, arg); - return 0; + return ohci_iso_xmit_start(iso, arg); case XMIT_STOP: ohci_iso_xmit_stop(iso); return 0; - case RECV_START: - return ohci_iso_recv_start(iso); - case RECV_CONSUME: - ohci_iso_recv_consume(iso, arg); + case XMIT_QUEUE: + ohci_iso_xmit_queue(iso, arg); return 0; + case XMIT_SHUTDOWN: + ohci_iso_xmit_shutdown(iso); + return 0; + + case RECV_INIT: + return ohci_iso_recv_init(iso); + case RECV_START: + return ohci_iso_recv_start(iso, arg); case RECV_STOP: ohci_iso_recv_stop(iso); return 0; + case RECV_RELEASE: + ohci_iso_recv_release(iso, arg); + return 0; + case RECV_SHUTDOWN: + ohci_iso_recv_shutdown(iso); + return 0; + default: PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet", cmd); Modified: branches/rawiso/raw1394.c ============================================================================== --- branches/rawiso/raw1394.c (original) +++ branches/rawiso/raw1394.c 2002-10-24 23:54:21.000000000 -0400 @@ -893,68 +893,79 @@ return retval; } -/* ISO operations */ +/* new ISO operations */ -static int raw1394_iso_start_xmit(struct file_info *fi, void *uaddr) +static void raw1394_iso_fill_status(struct hpsb_iso *iso, struct raw1394_iso_status *stat) { - struct raw1394_kernel_iso_config config; + stat->config.buf_packets = iso->buf_packets; + stat->config.max_packet_size = iso->max_packet_size; + stat->config.channel = iso->channel; + stat->config.speed = iso->speed; + stat->config.irq_interval = iso->irq_interval; + stat->buf_stride = iso->buf_stride; + stat->packet_data_offset = iso->packet_data_offset; + stat->packet_info_offset = iso->packet_info_offset; + stat->first_packet = iso->first_packet; + stat->n_packets = hpsb_iso_n_ready(iso); + stat->overflows = atomic_read(&iso->overflows); + stat->first_packet_cycle = iso->first_packet_cycle; +} + +static int raw1394_iso_xmit_init(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_status stat; - if(copy_from_user(&config, uaddr, sizeof(config))) + if(copy_from_user(&stat, uaddr, sizeof(stat))) return -EFAULT; - fi->iso_handle = hpsb_iso_xmit_start(fi->host, - config.buf_packets, - config.max_packet_size, - config.channel, - config.speed, - config.irq_interval, - &fi->poll_wait_complete); + fi->iso_handle = hpsb_iso_xmit_init(fi->host, + stat.config.buf_packets, + stat.config.max_packet_size, + stat.config.channel, + stat.config.speed, + stat.config.irq_interval, + &fi->poll_wait_complete); if(!fi->iso_handle) return -ENOMEM; - + fi->iso_state = RAW1394_ISO_XMIT; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; return 0; } -static int raw1394_iso_start_recv(struct file_info *fi, void *uaddr) +static int raw1394_iso_recv_init(struct file_info *fi, void *uaddr) { - struct raw1394_kernel_iso_config config; + struct raw1394_iso_status stat; - if(copy_from_user(&config, uaddr, sizeof(config))) + if(copy_from_user(&stat, uaddr, sizeof(stat))) return -EFAULT; - fi->iso_handle = hpsb_iso_recv_start(fi->host, - config.buf_packets, - config.max_packet_size, - config.channel, - config.irq_interval, - &fi->poll_wait_complete); + fi->iso_handle = hpsb_iso_recv_init(fi->host, + stat.config.buf_packets, + stat.config.max_packet_size, + stat.config.channel, + stat.config.irq_interval, + &fi->poll_wait_complete); if(!fi->iso_handle) return -ENOMEM; - + fi->iso_state = RAW1394_ISO_RECV; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; return 0; } static int raw1394_iso_get_status(struct file_info *fi, void *uaddr) { - struct raw1394_kernel_iso_status stat; + struct raw1394_iso_status stat; struct hpsb_iso *iso = fi->iso_handle; - - stat.config.buf_packets = iso->buf_packets; - stat.config.max_packet_size = iso->max_packet_size; - stat.config.channel = iso->channel; - stat.config.speed = iso->speed; - stat.config.irq_interval = iso->irq_interval; - - stat.buf_stride = iso->buf_stride; - stat.packet_data_offset = iso->packet_data_offset; - stat.packet_info_offset = iso->packet_info_offset; - stat.first_packet = iso->first_packet; - stat.n_packets = hpsb_iso_n_ready(iso); - stat.overflows = atomic_read(&iso->overflows); - stat.first_packet_cycle = iso->first_packet_cycle; - + + raw1394_iso_fill_status(fi->iso_handle, &stat); if(copy_to_user(uaddr, &stat, sizeof(stat))) return -EFAULT; @@ -964,15 +975,12 @@ return 0; } -static void raw1394_iso_stop(struct file_info *fi) +static void raw1394_iso_shutdown(struct file_info *fi) { - if(fi->iso_state == RAW1394_ISO_RECV) - hpsb_iso_recv_stop(fi->iso_handle); - else - hpsb_iso_xmit_stop(fi->iso_handle); - - fi->iso_handle = NULL; + if(fi->iso_handle) + hpsb_iso_shutdown(fi->iso_handle); + fi->iso_handle = NULL; fi->iso_state = RAW1394_ISO_INACTIVE; } @@ -996,33 +1004,49 @@ switch(fi->iso_state) { case RAW1394_ISO_INACTIVE: switch(cmd) { - case RAW1394_ISO_START_XMIT: - return raw1394_iso_start_xmit(fi, (void*) arg); - case RAW1394_ISO_START_RECV: - return raw1394_iso_start_recv(fi, (void*) arg); + case RAW1394_ISO_XMIT_INIT: + return raw1394_iso_xmit_init(fi, (void*) arg); + case RAW1394_ISO_RECV_INIT: + return raw1394_iso_recv_init(fi, (void*) arg); default: break; } break; case RAW1394_ISO_RECV: switch(cmd) { + case RAW1394_ISO_START: + return hpsb_iso_start(fi->iso_handle, arg); + case RAW1394_ISO_STOP: + hpsb_iso_stop(fi->iso_handle); + return 0; + case RAW1394_ISO_GET_STATUS: return raw1394_iso_get_status(fi, (void*) arg); + case RAW1394_ISO_PRODUCE_CONSUME: - return hpsb_iso_recv_consume(fi->iso_handle, arg); - case RAW1394_ISO_STOP: - raw1394_iso_stop(fi); + return hpsb_iso_recv_release_packets(fi->iso_handle, arg); + + case RAW1394_ISO_SHUTDOWN: + raw1394_iso_shutdown(fi); return 0; } break; case RAW1394_ISO_XMIT: switch(cmd) { + case RAW1394_ISO_START: + return hpsb_iso_start(fi->iso_handle, arg); + case RAW1394_ISO_STOP: + hpsb_iso_stop(fi->iso_handle); + return 0; + case RAW1394_ISO_GET_STATUS: return raw1394_iso_get_status(fi, (void*) arg); + case RAW1394_ISO_PRODUCE_CONSUME: - return hpsb_iso_xmit_produce(fi->iso_handle, arg); - case RAW1394_ISO_STOP: - raw1394_iso_stop(fi); + return hpsb_iso_xmit_queue_packets(fi->iso_handle, arg); + + case RAW1394_ISO_SHUTDOWN: + raw1394_iso_shutdown(fi); return 0; } break; @@ -1093,7 +1117,7 @@ int done = 0, i; if(fi->iso_state != RAW1394_ISO_INACTIVE) - raw1394_iso_stop(fi); + raw1394_iso_shutdown(fi); for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { Modified: branches/rawiso/raw1394.h ============================================================================== --- branches/rawiso/raw1394.h (original) +++ branches/rawiso/raw1394.h 2002-10-24 23:54:21.000000000 -0400 @@ -72,14 +72,25 @@ /* new ISO API */ /* ioctls */ -#define RAW1394_ISO_START_XMIT 1 -#define RAW1394_ISO_START_RECV 2 -#define RAW1394_ISO_GET_STATUS 3 +#define RAW1394_ISO_XMIT_INIT 1 +#define RAW1394_ISO_RECV_INIT 2 +#define RAW1394_ISO_START 3 #define RAW1394_ISO_STOP 4 -#define RAW1394_ISO_PRODUCE_CONSUME 5 +#define RAW1394_ISO_GET_STATUS 5 +#define RAW1394_ISO_PRODUCE_CONSUME 6 +#define RAW1394_ISO_SHUTDOWN 7 + +/* per-packet metadata embedded in the ringbuffer */ +/* must be identical to hpsb_iso_packet_info in iso.h! */ +struct raw1394_iso_packet_info { + unsigned short len; + unsigned char channel; + unsigned char tag; + unsigned char tcode; + unsigned char sy; +}; -/* argument to RAW1394_ISO_START_RECV, XMIT */ -struct raw1394_kernel_iso_config { +struct raw1394_iso_config { unsigned int buf_packets; unsigned int max_packet_size; int channel; @@ -87,9 +98,10 @@ int irq_interval; }; -struct raw1394_kernel_iso_status { +/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */ +struct raw1394_iso_status { /* current settings */ - struct raw1394_kernel_iso_config config; + struct raw1394_iso_config config; /* byte offset between successive packets in the buffer */ int buf_stride; Modified: branches/rawiso/hosts.h ============================================================================== --- branches/rawiso/hosts.h (original) +++ branches/rawiso/hosts.h 2002-10-24 23:54:21.000000000 -0400 @@ -100,15 +100,25 @@ }; enum isoctl_cmd { - /* see iso.h for the meanings of these commands */ + /* see iso.h... + * INIT = allocate resources + * START = begin transmission/reception (arg: cycle) + * STOP = halt transmission/reception + * QUEUE/RELEASE = produce/consume packets (arg: # of packets) + * SHUTDOWN = deallocate resources + */ + XMIT_INIT, XMIT_START, - XMIT_PRODUCE, XMIT_STOP, + XMIT_QUEUE, + XMIT_SHUTDOWN, + RECV_INIT, RECV_START, - RECV_CONSUME, - RECV_STOP + RECV_STOP, + RECV_RELEASE, + RECV_SHUTDOWN, }; enum reset_types { Modified: branches/rawiso/iso.c ============================================================================== --- branches/rawiso/iso.c (original) +++ branches/rawiso/iso.c 2002-10-24 23:54:21.000000000 -0400 @@ -11,17 +11,28 @@ #include "iso.h" -static void hpsb_iso_common_stop(struct hpsb_iso *iso) +void hpsb_iso_stop(struct hpsb_iso *iso) { - if(iso->driver_started) { - iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_STOP : RECV_STOP, 0); + if(!iso->driver_started) + return; + + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_STOP : RECV_STOP, 0); + iso->driver_started = 0; +} + +void hpsb_iso_shutdown(struct hpsb_iso *iso) +{ + if(iso->driver_init) { + hpsb_iso_stop(iso); + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_SHUTDOWN : RECV_SHUTDOWN, 0); + iso->driver_init = 0; } dma_region_free(&iso->buf); kfree(iso); } -static struct hpsb_iso* hpsb_iso_common_start(struct hpsb_host *host, enum hpsb_iso_type type, +static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_iso_type type, unsigned int buf_packets, unsigned int max_packet_size, int channel, @@ -60,7 +71,7 @@ iso = kmalloc(sizeof(*iso), SLAB_KERNEL); if(!iso) return NULL; - + iso->type = type; iso->host = host; iso->hostdata = NULL; @@ -85,6 +96,7 @@ atomic_set(&iso->overflows, 0); iso->first_packet_cycle = 0; + iso->driver_init = 0; iso->driver_started = 0; /* allocate the packet buffer */ @@ -95,7 +107,7 @@ return iso; err: - hpsb_iso_common_stop(iso); + hpsb_iso_shutdown(iso); return NULL; } @@ -105,70 +117,75 @@ } -struct hpsb_iso* hpsb_iso_xmit_start(struct hpsb_host *host, - unsigned int buf_packets, - unsigned int max_packet_size, - int channel, - int speed, - int irq_interval, - wait_queue_head_t *waitq) -{ - struct hpsb_iso *iso = hpsb_iso_common_start(host, HPSB_ISO_XMIT, - buf_packets, max_packet_size, - channel, irq_interval, waitq); +struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int speed, + int irq_interval, + wait_queue_head_t *waitq) +{ + struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT, + buf_packets, max_packet_size, + channel, irq_interval, waitq); if(!iso) return NULL; iso->speed = speed; /* tell the driver to start working */ - if(host->driver->isoctl(iso, XMIT_START, 0)) + if(host->driver->isoctl(iso, XMIT_INIT, 0)) goto err; - iso->driver_started = 1; + iso->driver_init = 1; return iso; err: - hpsb_iso_common_stop(iso); + hpsb_iso_shutdown(iso); return NULL; } -struct hpsb_iso* hpsb_iso_recv_start(struct hpsb_host *host, - unsigned int buf_packets, - unsigned int max_packet_size, - int channel, - int irq_interval, - wait_queue_head_t *waitq) -{ - struct hpsb_iso *iso = hpsb_iso_common_start(host, HPSB_ISO_RECV, - buf_packets, max_packet_size, - channel, irq_interval, waitq); +struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int irq_interval, + wait_queue_head_t *waitq) +{ + struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV, + buf_packets, max_packet_size, + channel, irq_interval, waitq); if(!iso) return NULL; /* tell the driver to start working */ - if(host->driver->isoctl(iso, RECV_START, 0)) + if(host->driver->isoctl(iso, RECV_INIT, 0)) goto err; - iso->driver_started = 1; + iso->driver_init = 1; return iso; err: - hpsb_iso_common_stop(iso); + hpsb_iso_shutdown(iso); return NULL; } -void hpsb_iso_xmit_stop(struct hpsb_iso *iso) +int hpsb_iso_start(struct hpsb_iso *iso, int cycle) { - hpsb_iso_common_stop(iso); -} + int retval = 0; + + if(iso->driver_started) + return 0; -void hpsb_iso_recv_stop(struct hpsb_iso *iso) -{ - hpsb_iso_common_stop(iso); + retval = iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_START : RECV_START, cycle); + if(retval) + return retval; + + iso->driver_started = 1; + return retval; } -int hpsb_iso_xmit_produce(struct hpsb_iso *iso, unsigned int n_packets) +int hpsb_iso_xmit_queue_packets(struct hpsb_iso *iso, unsigned int n_packets) { int i; int pkt = iso->first_packet; @@ -177,7 +194,7 @@ for(i = 0; i < n_packets; i++) { struct hpsb_iso_packet_info *info = hpsb_iso_packet_info(iso, pkt); if(info->len > iso->max_packet_size) { - printk(KERN_ERR "hpsb_iso_xmit_produce: packet too long (%u, max is %u)\n", + printk(KERN_ERR "hpsb_iso_xmit_queue_packets: packet too long (%u, max is %u)\n", info->len, iso->max_packet_size); return -EINVAL; } @@ -185,22 +202,22 @@ pkt = (pkt+1) % iso->buf_packets; } - return iso->host->driver->isoctl(iso, XMIT_PRODUCE, n_packets); + return iso->host->driver->isoctl(iso, XMIT_QUEUE, n_packets); } -int hpsb_iso_recv_consume(struct hpsb_iso *iso, unsigned int n_packets) +int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) { - return iso->host->driver->isoctl(iso, RECV_CONSUME, n_packets); + return iso->host->driver->isoctl(iso, RECV_RELEASE, n_packets); } unsigned char* hpsb_iso_packet_data(struct hpsb_iso *iso, unsigned int pkt) { - return (iso->buf.kvirt + pkt * iso->buf_stride) + iso->packet_data_offset; + return (iso->buf.kvirt + pkt * iso->buf_stride) + + iso->packet_data_offset; } struct hpsb_iso_packet_info* hpsb_iso_packet_info(struct hpsb_iso *iso, unsigned int pkt) { - return (struct hpsb_iso_packet_info*) (iso->buf.kvirt + - pkt * iso->buf_stride + - iso->packet_info_offset); + return (struct hpsb_iso_packet_info*) ((iso->buf.kvirt + pkt * iso->buf_stride) + + iso->packet_info_offset); } |