linux1394-cvslog Mailing List for IEEE 1394 for Linux (Page 6)
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. <dm...@li...> - 2003-02-01 13:59:41
|
Author: dmaas Date: 2003-01-03 19:22:32 -0500 (Fri, 03 Jan 2003) New Revision: 734 Modified: trunk/iso.c Log: fix off-by-one in iso packet buffer checking Modified: trunk/iso.c ============================================================================== --- trunk/iso.c (original) +++ trunk/iso.c 2003-02-01 08:59:08.000000000 -0500 @@ -300,7 +300,7 @@ len = info->len; /* make sure the packet does not go beyond the end of the buffer */ - if(offset + len >= iso->buf_size) + if(offset + len > iso->buf_size) return -EFAULT; /* check for wrap-around */ |
From: SVN U. <ben...@li...> - 2003-02-01 13:59:40
|
Author: bencollins Date: 2003-01-03 01:15:04 -0500 (Fri, 03 Jan 2003) New Revision: 733 Modified: trunk/pcilynx.c Log: Patch from Adrian Bunk for more C99 initializer conversions. Modified: trunk/pcilynx.c ============================================================================== --- trunk/pcilynx.c (original) +++ trunk/pcilynx.c 2003-02-01 08:59:07.000000000 -0500 @@ -128,23 +128,20 @@ } static struct i2c_algo_bit_data bit_data = { - NULL, - bit_setsda, - bit_setscl, - bit_getsda, - bit_getscl, - 5, 5, 100, /* waits, timeout */ + .setsda = bit_setsda, + .setscl = bit_setscl, + .getsda = bit_getsda, + .getscl = bit_getscl, + .udelay = 5, + .mdelay = 5, + .timeout = 100, }; static struct i2c_adapter bit_ops = { - "PCILynx I2C adapter", - 0xAA, //FIXME: probably we should get an id in i2c-id.h - NULL, - NULL, - NULL, - NULL, - bit_reg, - bit_unreg, + .name = "PCILynx I2C adapter", + .id = 0xAA, //FIXME: probably we should get an id in i2c-id.h + .client_register = bit_reg, + .client_unregister = bit_unreg, }; |
From: SVN U. <dm...@li...> - 2003-02-01 13:59:39
|
Author: dmaas Date: 2003-01-02 15:20:46 -0500 (Thu, 02 Jan 2003) New Revision: 732 Modified: trunk/ohci1394.c Log: forgot to update this debugging message Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-01 08:59:06.000000000 -0500 @@ -1168,11 +1168,10 @@ /* write the DMA program */ ohci_iso_recv_program(iso); - DBGMSG(ohci->id, "ohci_iso_recv_init: DMA buffer is %lu pages (%u info + %lu data)" - "(%u bytes), using %u blocks, block_irq_interval %d", - iso->buf_size/PAGE_SIZE, iso->info_pages, - iso->buf_size/PAGE_SIZE - iso->info_pages, - iso->buf_size, recv->nblocks, recv->block_irq_interval); + DBGMSG(ohci->id, "ohci_iso_recv_init: DMA buffer is %lu pages" + " (%u bytes), using %u blocks, block_irq_interval %d", + iso->buf_size/PAGE_SIZE, iso->buf_size, + recv->nblocks, recv->block_irq_interval); return 0; |
From: SVN U. <ben...@li...> - 2003-02-01 13:59:36
|
Author: bencollins Date: 2002-12-29 11:52:31 -0500 (Sun, 29 Dec 2002) New Revision: 731 Modified: branches/linux-2.4/Makefile Log: Fix from Erik Andersen for static compiles Modified: branches/linux-2.4/Makefile ============================================================================== --- branches/linux-2.4/Makefile (original) +++ branches/linux-2.4/Makefile 2003-02-01 08:59:04.000000000 -0500 @@ -18,7 +18,7 @@ obj-$(CONFIG_IEEE1394_AMDTP) += amdtp.o obj-$(CONFIG_IEEE1394_CMP) += cmp.o -include $(TOPDIR)/Rules.make - ieee1394.o: $(ieee1394-objs) $(LD) $(LDFLAGS) -r -o $@ $(ieee1394-objs) + +include $(TOPDIR)/Rules.make |
From: SVN U. <dm...@li...> - 2003-02-01 13:59:36
|
Author: dmaas Date: 2002-12-25 22:01:18 -0500 (Wed, 25 Dec 2002) New Revision: 730 Modified: trunk/ohci1394.c Log: fix typo in my last update - thanks to Drew Perttula for pointing this out Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-01 08:59:02.000000000 -0500 @@ -1997,7 +1997,7 @@ iso->first_packet = (iso->first_packet+1) % iso->buf_packets; iso->xmit_cycle = (iso->xmit_cycle+1) % 8000; iso->n_ready_packets--; - spin_unlock_irqrestore(&irq->lock, flags); + spin_unlock_irqrestore(&iso->lock, flags); return 0; } |
From: SVN U. <dm...@li...> - 2003-02-01 13:59:34
|
Author: dmaas Date: 2002-12-23 21:58:38 -0500 (Mon, 23 Dec 2002) New Revision: 729 Modified: trunk/dma.c trunk/hosts.h trunk/ieee1394_core.c trunk/iso.c trunk/iso.h trunk/ohci1394.c trunk/ohci1394.h trunk/raw1394.c trunk/raw1394.h Log: dmaas - large isochronous update: - switched ohci from packet-per-buffer to buffer-fill receive (necessary to enable multi-channel reception and contiguous batch reception) - added multichannel ops to iso.[ch] and raw1394 - changed iso packet buffer layout - packet descriptors are no longer embedded in buffer, instead they are passed to and from the kernel in raw1394 ioctls (XMIT/RECV_PACKETS) [ this breaks the kernel<->libraw interface, you will need to get the latest libraw code from SVN for iso to work ] - implement multi-channel reception in ohci. Note that you won't be able to use it yet, since the legacy ISO API claims the single multi-channel context for its exclusive use. (we will need to remove the legacy ISO API to make further progress - I'll bring this up on the list) Modified: trunk/iso.h ============================================================================== --- trunk/iso.h (original) +++ trunk/iso.h 2003-02-01 08:58:58.000000000 -0500 @@ -17,25 +17,37 @@ /* high-level ISO interface */ -/* per-packet data embedded in the ringbuffer */ +/* This API sends and receives isochronous packets on a large, + virtually-contiguous kernel memory buffer. The buffer may be mapped + into a user-space process for zero-copy transmission and reception. + + There are no explicit boundaries between packets in the buffer. A + packet may be transmitted or received at any location. However, + low-level drivers may impose certain restrictions on alignment or + size of packets. (e.g. in OHCI no packet may cross a page boundary, + and packets should be quadlet-aligned) +*/ + +/* Packet descriptor - the API maintains a ring buffer of these packet + descriptors in kernel memory (hpsb_iso.infos[]). */ + struct hpsb_iso_packet_info { - unsigned short len; - unsigned short cycle; - unsigned char channel; /* recv only */ - unsigned char tag; - unsigned char sy; -}; + /* offset of data payload relative to the first byte of the buffer */ + __u32 offset; + + /* length of the data payload, in bytes (not including the isochronous header) */ + __u16 len; -/* - * each packet in the ringbuffer consists of three things: - * 1. the packet's data payload (no isochronous header) - * 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 - */ + /* (recv only) the cycle number (mod 8000) on which the packet was received */ + __u16 cycle; + + /* (recv only) channel on which the packet was received */ + __u8 channel; + + /* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */ + __u8 tag; + __u8 sy; +}; enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 }; @@ -45,48 +57,42 @@ /* pointer to low-level driver and its private data */ struct hpsb_host *host; void *hostdata; - - /* function to be called (from interrupt context) when the iso status changes */ + + /* a function to be called (from interrupt context) after + outgoing packets have been sent, or incoming packets have + arrived */ void (*callback)(struct hpsb_iso*); int speed; /* SPEED_100, 200, or 400 */ - int channel; + int channel; /* -1 if multichannel */ /* greatest # of packets between interrupts - controls the maximum latency of the buffer */ int irq_interval; - - /* the packet ringbuffer */ - struct dma_region buf; + + /* the buffer for packet data payloads */ + struct dma_region data_buf; + + /* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */ + unsigned int buf_size; + + /* ringbuffer of packet descriptors in regular kernel memory */ + struct hpsb_iso_packet_info *infos; /* # of packets in the ringbuffer */ unsigned int buf_packets; - /* offset between successive packets, in bytes - - you can assume that this is a power of 2, - and less than or equal to the page size */ - 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; + /* protects packet cursors */ + spinlock_t lock; /* 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 packets, starting at first_packet: + (transmit) are ready to be filled with data + (receive) contain received data */ + int n_ready_packets; /* how many times the buffer has overflowed or underflowed */ atomic_t overflows; @@ -99,8 +105,12 @@ /* # of packets left to prebuffer (xmit only) */ int prebuffer; - /* starting cycle (xmit only) */ + /* starting cycle for DMA (xmit only) */ int start_cycle; + + /* cycle at which next packet will be transmitted, + -1 if not known */ + int xmit_cycle; }; /* functions available to high-level drivers (e.g. raw1394) */ @@ -108,20 +118,26 @@ /* allocate the buffer and DMA context */ struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, + unsigned int data_buf_size, unsigned int buf_packets, - unsigned int max_packet_size, int channel, int speed, int irq_interval, void (*callback)(struct hpsb_iso*)); +/* note: if channel = -1, multi-channel receive is enabled */ struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, + unsigned int data_buf_size, unsigned int buf_packets, - unsigned int max_packet_size, int channel, int irq_interval, void (*callback)(struct hpsb_iso*)); +/* multi-channel only */ +int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel); +int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel); +int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask); + /* start/stop DMA */ 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); @@ -139,10 +155,10 @@ /* 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); +/* check to make sure the user has not supplied bogus offset/len values that would + cause the kernel to access memory outside the buffer. Writes the sanitized values + to *offset and *len. Returns 0 if OK, otherwise -EFAULT or -EINVAL. */ +int hpsb_iso_check_offset_len(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info, + unsigned int *out_offset, unsigned short *out_len); #endif /* IEEE1394_ISO_H */ Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2003-02-01 08:58:58.000000000 -0500 @@ -1000,7 +1000,7 @@ struct file_operations *file_ops) { int retval; - + if( (blocknum < 0) || (blocknum > 15) ) return -EINVAL; @@ -1016,7 +1016,7 @@ /* block already taken */ retval = -EBUSY; } - + write_unlock(&ieee1394_chardevs_lock); return retval; @@ -1027,14 +1027,14 @@ { if( (blocknum < 0) || (blocknum > 15) ) return; - + write_lock(&ieee1394_chardevs_lock); - + if(ieee1394_chardevs[blocknum].file_ops) { ieee1394_chardevs[blocknum].file_ops = NULL; ieee1394_chardevs[blocknum].module = NULL; } - + write_unlock(&ieee1394_chardevs_lock); } @@ -1072,7 +1072,7 @@ /* success! */ ret = 1; - + out: read_unlock(&ieee1394_chardevs_lock); return ret; @@ -1102,11 +1102,11 @@ reference count of whatever module file->f_op->owner points to, immediately after this function returns. */ - + /* shift away lower four bits of the minor to get the index of the ieee1394_driver we want */ - + blocknum = (minor(inode->i_rdev) >> 4) & 0xF; /* look up the driver */ @@ -1151,7 +1151,7 @@ if(module) __MOD_DEC_USE_COUNT(module); - + /* point the file's f_ops back to ieee1394. The VFS will then decrement ieee1394's reference count immediately after this function returns. */ @@ -1209,10 +1209,10 @@ kmem_cache_destroy(hpsb_packet_cache); unregister_chrdev(IEEE1394_MAJOR, "ieee1394"); - + /* it's ok to pass a NULL devfs_handle to devfs_unregister */ devfs_unregister(ieee1394_devfs_handle); - + remove_proc_entry("ieee1394", proc_bus); } @@ -1308,10 +1308,12 @@ EXPORT_SYMBOL(hpsb_iso_recv_init); EXPORT_SYMBOL(hpsb_iso_xmit_start); EXPORT_SYMBOL(hpsb_iso_recv_start); +EXPORT_SYMBOL(hpsb_iso_recv_listen_channel); +EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel); +EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask); 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); +EXPORT_SYMBOL(hpsb_iso_check_offset_len); Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-01 08:58:59.000000000 -0500 @@ -311,7 +311,7 @@ /* SelfID Ok, reset error counter. */ ohci->self_id_errors = 0; - + size = ((self_id_count & 0x00001FFC) >> 2) - 1; q++; @@ -373,12 +373,12 @@ "Running dma failed because Node ID == 63"); return -1; } - + /* Run the dma context */ reg_write(ohci, reg, 0x8000); - + if (msg) PRINT(KERN_DEBUG, ohci->id, "%s", msg); - + return 0; } @@ -450,7 +450,7 @@ reg_write(ohci, reg, 0xffffffff); tmp = reg_read(ohci, reg); - + DBGMSG(ohci->id,"Iso contexts reg: %08x implemented: %08x", reg, tmp); /* Count the number of contexts */ @@ -829,7 +829,7 @@ spin_lock_irqsave(&d->lock,flags); list_add_tail(&packet->driver_list, &d->pending_list); - + dma_trm_flush(ohci, d); spin_unlock_irqrestore(&d->lock,flags); @@ -898,11 +898,11 @@ case GET_CYCLE_COUNTER: retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer); break; - + case SET_CYCLE_COUNTER: reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg); break; - + case SET_BUS_ID: PRINT(KERN_ERR, ohci->id, "devctl command SET_BUS_ID err"); break; @@ -1024,22 +1024,65 @@ * rawiso ISO reception * ***********************************/ +/* + We use buffer-fill DMA mode. The DMA buffer is split into "blocks" + of one page each. It would be fairly easy to make blocks smaller + than a page, but I think the latency is good enough already. + + There is one little wrinkle with buffer-fill mode: a packet that + starts in the final block may wrap around into the first block. But + the user API expects all packets to be contiguous. Our solution is + to keep the very last page of the DMA buffer in reserve - if a + packet span the gap, we copy its tail into this page. +*/ + 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 */ + /* memory and PCI mapping for the DMA descriptors */ + struct dma_prog_region prog; + struct dma_cmd *block; /* = (struct dma_cmd*) prog.virt */ + + /* how many INPUT_MORE blocks fit in the buffer */ + unsigned int nblocks; + + /* number of blocks to batch between interrupts */ + int block_irq_interval; + + /* block that the reader will release next */ + int block_reader; + + /* bytes of buffer the reader has released, less than one block */ + int released_bytes; + + /* cycle of last-received packet; used to detecting dropouts */ + int last_cycle; + + /* the following four fields are used exclusively by the interrupt + (no locking is required) */ + + /* index into the info array for next packet to appear */ int pkt_dma; - + + /* block that DMA will finish next */ + int block_dma; + + /* buffer offset at which the next packet will appear */ + int dma_offset; + + /* throttle the rate of buffer-space warnings to avoid + spamming the syslog */ + int warn_backoff; + + /* OHCI DMA context control registers */ u32 ContextControlSet; u32 ContextControlClear; u32 CommandPtr; u32 ContextMatch; + }; static void ohci_iso_recv_task(unsigned long data); @@ -1051,34 +1094,68 @@ static int ohci_iso_recv_init(struct hpsb_iso *iso) { + struct ti_ohci *ohci = iso->host->hostdata; struct ohci_iso_recv *recv; - unsigned int prog_size; + unsigned int nblocks; int ctx; int ret = -ENOMEM; - + + /* one block per page of data in the DMA buffer, minus the final guard page */ + nblocks = iso->buf_size/PAGE_SIZE - 1; + if(nblocks < 3) { + DBGMSG(ohci->id, "ohci_iso_recv_init: DMA buffer too small"); + return -EINVAL; + } + recv = kmalloc(sizeof(*recv), SLAB_KERNEL); - if(!recv) + if(!recv) { return -ENOMEM; + } iso->hostdata = recv; - recv->ohci = iso->host->hostdata; + recv->ohci = ohci; recv->task_active = 0; - recv->pkt_dma = iso->first_packet; - dma_prog_region_init(&recv->prog); + recv->block = NULL; + recv->nblocks = nblocks; + +#if 0 + /* DJM - disable for now; irq_interval > 1 results in many overflows... */ + /* iso->irq_interval is in packets - translate that to blocks */ + recv->block_irq_interval = (iso->irq_interval * iso->max_packet_size) / PAGE_SIZE; + if(recv->block_irq_interval < 1) + recv->block_irq_interval = 1; + else if(recv->block_irq_interval*4 > recv->nblocks) + recv->block_irq_interval = nblocks/4; +#else + recv->block_irq_interval = 1; +#endif - /* 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)) + recv->block_reader = 0; + recv->released_bytes = 0; + recv->last_cycle = -1; + + recv->block_dma = 0; + recv->dma_offset = recv->block_dma * PAGE_SIZE; + recv->pkt_dma = 0; + recv->warn_backoff = 0; + + /* size of DMA program = one INPUT_MORE per block */ + if(dma_prog_region_alloc(&recv->prog, + sizeof(struct dma_cmd) * recv->nblocks, + recv->ohci->dev)) goto err; - ohci1394_init_iso_tasklet(&recv->task, OHCI_ISO_RECEIVE, + recv->block = (struct dma_cmd*) recv->prog.kvirt; + + ohci1394_init_iso_tasklet(&recv->task, + iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE : + 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 */ @@ -1088,12 +1165,15 @@ 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); - + + DBGMSG(ohci->id, "ohci_iso_recv_init: DMA buffer is %lu pages (%u info + %lu data)" + "(%u bytes), using %u blocks, block_irq_interval %d", + iso->buf_size/PAGE_SIZE, iso->info_pages, + iso->buf_size/PAGE_SIZE - iso->info_pages, + iso->buf_size, recv->nblocks, recv->block_irq_interval); + return 0; err: @@ -1107,7 +1187,7 @@ /* disable interrupts */ reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context); - + /* halt DMA */ ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL); } @@ -1121,91 +1201,139 @@ ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task); recv->task_active = 0; } - + dma_prog_region_free(&recv->prog); kfree(recv); iso->hostdata = NULL; } +/* set up a "gapped" ring buffer DMA program */ 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; + /* start at block_dma and go around the whole buffer */ + int blk = recv->block_dma; 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; - /* offset of the DMA descriptor relative to the DMA prog buffer */ - unsigned long prog_offset = pkt * sizeof(struct dma_cmd); + for(i = 0; i < recv->nblocks; i++) { + /* the DMA descriptor */ + struct dma_cmd *im = &recv->block[blk]; - /* offset of this bus_cycle within the DMA buffer */ - unsigned long buf_offset = hpsb_iso_packet_data(iso, pkt) - iso->buf.kvirt; + /* offset of the DMA descriptor relative to the DMA prog buffer */ + unsigned long prog_offset = blk * sizeof(struct dma_cmd); - /* back up 8 bytes for the iso header */ - buf_offset -= 8; - data_size = iso->max_packet_size + 8; + /* offset of this packet's data within the DMA buffer */ + unsigned long buf_offset = blk*PAGE_SIZE; - /* ask for an interrupt every now and then, and - always interrupt on the final descriptor */ + unsigned short data_size = PAGE_SIZE; - if( ((i % iso->irq_interval) == 0) || - (i == (iso->buf_packets - 1)) ) { - want_interrupt = 1; - } else { - want_interrupt = 0; + im->control = 2 << 28; /* INPUT_MORE */ + im->control |= 8 << 24; /* s = 1, update xferStatus and resCount */ + + /* interrupt on last block, and at intervals */ + if(i == recv->nblocks-1 || (i % recv->block_irq_interval) == 0) { + im->control |= 3 << 20; /* want interrupt */ } - - /* 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; + im->control |= 3 << 18; /* enable branch to address */ + im->control |= data_size; + + im->address = dma_region_offset_to_bus(&iso->data_buf, buf_offset); + im->branchAddress = 0; /* filled in on next loop */ + im->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 = dma_prog_region_offset_to_bus(&recv->prog, + prog_offset); *prev_branch |= 1; /* set Z=1 */ } - prev_branch = &il->branchAddress; + prev_branch = &im->branchAddress; - pkt = (pkt + 1) % iso->buf_packets; + blk = (blk + 1) % recv->nblocks; } /* the final descriptor's branch address and Z should be left at 0 */ } +/* listen or unlisten to a specific channel (multi-channel mode only) */ +static void ohci_iso_recv_change_channel(struct hpsb_iso *iso, unsigned char channel, int listen) +{ + struct ohci_iso_recv *recv = iso->hostdata; + int reg, i; + + if(channel < 32) { + reg = listen ? OHCI1394_IRMultiChanMaskLoSet : OHCI1394_IRMultiChanMaskLoClear; + i = channel; + } else { + reg = listen ? OHCI1394_IRMultiChanMaskHiSet : OHCI1394_IRMultiChanMaskHiClear; + i = channel - 32; + } + + reg_write(recv->ohci, reg, (1 << i)); + + /* issue a dummy read to force all PCI writes to be posted immediately */ + mb(); + reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); +} + +static void ohci_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) +{ + struct ohci_iso_recv *recv = iso->hostdata; + int i; + + for(i = 0; i < 64; i++) { + if(mask & (1ULL << i)) { + if(i < 32) + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoSet, (1 << i)); + else + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiSet, (1 << (i-32))); + } else { + if(i < 32) + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, (1 << i)); + else + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, (1 << (i-32))); + } + } + + /* issue a dummy read to force all PCI writes to be posted immediately */ + mb(); + reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); +} + static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle) { struct ohci_iso_recv *recv = iso->hostdata; u32 command, contextMatch; - + + recv->last_cycle = -1; + 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)); + /* use buffer-fill mode, and keep ISO headers (required for multichannel) */ + reg_write(recv->ohci, recv->ContextControlSet, (1 << 31) | (1 << 30)); + + /* match on all tags */ + contextMatch = 0xF0000000; + + if(iso->channel == -1) { + /* enable multichannel reception */ + reg_write(recv->ohci, recv->ContextControlSet, (1 << 28)); + + /* clear channel selection mask */ + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, 0xFFFFFFFF); + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, 0xFFFFFFFF); + } else { + /* listen on channel */ + contextMatch |= iso->channel; + } - /* match on all tags, listen on channel */ - contextMatch = 0xF0000000 | iso->channel; - if(cycle != -1) { u32 seconds; @@ -1230,7 +1358,8 @@ 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)); + command = dma_prog_region_offset_to_bus(&recv->prog, + recv->block_dma * sizeof(struct dma_cmd)); command |= 1; /* Z=1 */ reg_write(recv->ohci, recv->CommandPtr, command); @@ -1250,7 +1379,8 @@ /* check RUN */ if(!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) { - PRINT(KERN_ERR, recv->ohci->id, "Error starting IR DMA (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; } @@ -1258,124 +1388,322 @@ return 0; } -static void ohci_iso_recv_release_one(struct hpsb_iso *iso) +static void ohci_iso_recv_check_block_overflow(struct ohci_iso_recv *recv) { - struct ohci_iso_recv *recv = iso->hostdata; + /* see how close we are to running out of blocks */ + int gap = 0; + int blk = recv->block_reader; + while(blk != recv->block_dma) { + blk = (blk+1) % recv->nblocks; + gap++; + } - /* re-use the DMA descriptor for first_packet */ + if(gap*2 > recv->nblocks) { + DBGMSG(recv->ohci->id, + "Running out of DMA blocks for ISO reception - " + "overrun likely (gap = %d)", gap); + } +} + +static void ohci_iso_recv_release_block(struct hpsb_iso *iso, struct ohci_iso_recv *recv) +{ + /* re-use the DMA descriptor for block_reader */ /* 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 */ + int next_i = recv->block_reader; + int prev_i = (next_i == 0) ? (recv->nblocks - 1) : (next_i - 1); + + struct dma_cmd *next = &recv->block[next_i]; + struct dma_cmd *prev = &recv->block[prev_i]; + ohci_iso_recv_check_block_overflow(recv); + + /* 'next' becomes the new end of the DMA chain, + so disable branch and enable interrupt */ + + next->branchAddress = 0; + next->control |= 3 << 20; + /* link prev to next */ - if(prev_i % iso->irq_interval) { - prev->control &= ~(3 << 20); /* no interrupt */ - } else { + prev->branchAddress = dma_prog_region_offset_to_bus(&recv->prog, + sizeof(struct dma_cmd) * next_i) + | 1; /* Z=1 */ + + /* disable interrupt on previous DMA descriptor, except at intervals */ + if((prev_i % recv->block_irq_interval) == 0) { prev->control |= 3 << 20; /* enable interrupt */ + } else { + prev->control &= ~(3<<20); /* disable 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 block cursor */ + recv->block_reader = (recv->block_reader + 1) % recv->nblocks; +} + +static void ohci_iso_recv_release_one_packet(struct hpsb_iso *iso, struct ohci_iso_recv *recv) +{ + int flags; + int len; + + /* release the memory where the packet was */ + /* note: we can't trust len, but the worst the user + can do is mess up his own received packets */ + + len = iso->infos[iso->first_packet].len; + + /* add the wasted space for padding to 4 bytes */ + if(len % 4) + len += 4 - (len % 4); + + /* add 8 bytes for the OHCI DMA data format overhead */ + len += 8; + + recv->released_bytes += len; + + /* have we released enough memory for one block? */ + while(recv->released_bytes > PAGE_SIZE) { + ohci_iso_recv_release_block(iso, recv); + recv->released_bytes -= PAGE_SIZE; + } + /* advance packet cursors */ iso->first_packet = (iso->first_packet+1) % iso->buf_packets; - atomic_inc(&iso->n_dma_packets); + + spin_lock_irqsave(&iso->lock, flags); + iso->n_ready_packets--; + spin_unlock_irqrestore(&iso->lock, flags); } 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); + ohci_iso_recv_release_one_packet(iso, (struct ohci_iso_recv*) iso->hostdata); } -static void ohci_iso_recv_task(unsigned long data) +/* parse all packets from blocks that have been fully received */ +static void ohci_iso_recv_bytes(struct hpsb_iso *iso, struct ohci_iso_recv *recv) { - struct hpsb_iso *iso = (struct hpsb_iso*) data; - struct ohci_iso_recv *recv = iso->hostdata; - - int count; int wake = 0; - - /* loop over the entire buffer */ - for(count = 0; count < iso->buf_packets; count++) { - u32 packet_len = 0; + int runaway = 0; + + while(1) { + /* we expect the next parsable packet to begin at recv->dma_offset */ + /* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */ + + unsigned int offset; + unsigned short len, cycle; + unsigned char channel, tag, sy; - /* pointer to the DMA descriptor */ - struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + recv->pkt_dma; + unsigned long flags; + unsigned char *p = iso->data_buf.kvirt; - /* check the DMA descriptor for new writes to xferStatus */ - u16 xferstatus = il->status >> 16; - u16 rescount = il->status & 0xFFFF; + unsigned int this_block = recv->dma_offset/PAGE_SIZE; - unsigned char event = xferstatus & 0x1F; + /* don't loop indefinitely */ + if(runaway++ > 100000) { + atomic_inc(&iso->overflows); + PRINT(KERN_ERR, recv->ohci->id, + "IR DMA error - Runaway during buffer parsing!\n"); + break; + } - if(!event) { - /* this packet hasn't come in yet; we are done for now */ - goto out; + /* stop parsing once we arrive at block_dma (i.e. don't get ahead of DMA) */ + if(this_block == recv->block_dma) + break; + + wake = 1; + + /* parse data length, tag, channel, and sy */ + + /* note: we keep our own local copies of 'len' and 'offset' + so the user can't mess with them by poking in the mmap area */ + + len = p[recv->dma_offset+2] | (p[recv->dma_offset+3] << 8); + + if(len > PAGE_SIZE) { + PRINT(KERN_ERR, recv->ohci->id, + "IR DMA error - bogus 'len' value %u\n", len); } - if(event == 0x11) { - /* packet received successfully! */ - - /* 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) { - PRINT(KERN_ERR, recv->ohci->id, "IR DMA error - OHCI error code 0x%02x\n", event); + channel = p[recv->dma_offset+1] & 0x3F; + tag = p[recv->dma_offset+1] >> 6; + sy = p[recv->dma_offset+0] & 0xF; + + /* advance to data payload */ + recv->dma_offset += 4; + + /* check for wrap-around */ + if(recv->dma_offset >= PAGE_SIZE*recv->nblocks) { + recv->dma_offset -= PAGE_SIZE*recv->nblocks; } - /* sync our view of the buffer */ - dma_region_sync(&iso->buf, recv->pkt_dma * iso->buf_stride, iso->buf_stride); + /* dma_offset now points to the first byte of the data payload */ + offset = recv->dma_offset; + + /* advance to xferStatus/timeStamp */ + recv->dma_offset += len; + + /* payload is padded to 4 bytes */ + if(len % 4) { + recv->dma_offset += 4 - (len%4); + } + + /* check for wrap-around */ + if(recv->dma_offset >= PAGE_SIZE*recv->nblocks) { + /* uh oh, the packet data wraps from the last + to the first DMA block - make the packet + contiguous by copying its "tail" into the + guard page */ + + int guard_off = recv->nblocks*PAGE_SIZE; + int tail_len = len - (guard_off - offset); + + if(tail_len > 0 && tail_len < PAGE_SIZE) { + memcpy(iso->data_buf.kvirt + guard_off, + iso->data_buf.kvirt, + tail_len); + } + + recv->dma_offset -= PAGE_SIZE*recv->nblocks; + } + + /* parse timestamp */ + cycle = p[recv->dma_offset+0] | (p[recv->dma_offset+1]<<8); + cycle &= 0x1FFF; + + /* check for cycle discontinuity */ + if(recv->last_cycle != -1) { + /* for multichannel, we have to allow cycle == last_cycle */ + if((cycle != (recv->last_cycle+1) % 8000) && + (cycle != recv->last_cycle)) { + atomic_inc(&iso->overflows); + DBGMSG(recv->ohci->id, "ISO reception overflow - " + "cycle discontinuity detected (cycle %4u last %4d)", + cycle, recv->last_cycle); + } + } + recv->last_cycle = cycle; + + /* advance to next packet */ + recv->dma_offset += 4; + + /* check for wrap-around */ + if(recv->dma_offset >= PAGE_SIZE*recv->nblocks) { + recv->dma_offset -= PAGE_SIZE*recv->nblocks; + } + + /* check if we have overflowed the ringbuffer of packet_infos */ + spin_lock_irqsave(&iso->lock, flags); + if(iso->n_ready_packets == iso->buf_packets) { + /* overflow! */ + atomic_inc(&iso->overflows); + + if(recv->warn_backoff == 0) { + DBGMSG(recv->ohci->id, + "ISO reception overflow - packet info buffer full"); + recv->warn_backoff = 10000; + } else { + recv->warn_backoff--; + } - /* record the per-packet info */ - { - /* iso header is 8 bytes ahead of the data payload */ - unsigned char *hdr = hpsb_iso_packet_data(iso, recv->pkt_dma) - 8; + } else { + /* good, no overflow; fill out the packet_info */ + struct hpsb_iso_packet_info *info = &iso->infos[recv->pkt_dma]; + info->offset = offset; + info->len = len; + info->cycle = cycle; + info->channel = channel; + info->tag = tag; + info->sy = sy; + wmb(); - struct hpsb_iso_packet_info *info = hpsb_iso_packet_info(iso, recv->pkt_dma); + /* one more packet for the user, one less for us */ + recv->pkt_dma = (recv->pkt_dma + 1) % iso->buf_packets; + iso->n_ready_packets++; - 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; + if(iso->n_ready_packets*2 > iso->buf_packets) { + if(recv->warn_backoff == 0) { + DBGMSG(recv->ohci->id, + "Running out of packet info buffer space " + "for ISO reception - overrun likely (%u/%u packets)", + iso->n_ready_packets, iso->buf_packets); + recv->warn_backoff = 10000; + } else { + recv->warn_backoff--; + } + } } + spin_unlock_irqrestore(&iso->lock, flags); + } + + if(wake && iso->callback) + iso->callback(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 loop; + + /* loop over all blocks */ + for(loop = 0; loop < recv->nblocks; loop++) { - /* at least one packet came in, so wake up the reader */ - wake = 1; + /* check block_dma to see if it's done */ + + struct dma_cmd *im = &recv->block[recv->block_dma]; + + /* check the DMA descriptor for new writes to xferStatus */ + u16 xferstatus = im->status >> 16; + + /* rescount is the number of bytes *remaining to be written* in the block */ + u16 rescount = im->status & 0xFFFF; - /* reset the DMA descriptor */ - il->status = iso->max_packet_size; + unsigned char event = xferstatus & 0x1F; + + if(!event) { + /* nothing has happened to this block yet */ + break; + } + + if(event != 0x11) { + atomic_inc(&iso->overflows); + PRINT(KERN_ERR, recv->ohci->id, + "IR DMA error - OHCI error code 0x%02x\n", event); + } - /* advance DMA packet cursor */ - recv->pkt_dma = (recv->pkt_dma + 1) % iso->buf_packets; + if(rescount != 0) { + /* the card is still writing to this block; + we can't touch it until it's done */ + break; + } + + /* OK, the block is finished... */ + + /* sync our view of the block */ + dma_region_sync(&iso->data_buf, recv->block_dma*PAGE_SIZE, PAGE_SIZE); + + /* reset the DMA descriptor */ + im->status = PAGE_SIZE; + + /* advance block_dma */ + recv->block_dma = (recv->block_dma + 1) % recv->nblocks; - /* 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 */ + if((recv->block_dma+1) % recv->nblocks == recv->block_reader) { atomic_inc(&iso->overflows); + DBGMSG(recv->ohci->id, "ISO reception overflow - " + "ran out of DMA blocks"); } } -out: - if(wake && iso->callback) { - iso->callback(iso); - } + /* parse any packets that have arrived */ + ohci_iso_recv_bytes(iso, recv); } @@ -1418,7 +1746,7 @@ unsigned int prog_size; int ctx; int ret = -ENOMEM; - + xmit = kmalloc(sizeof(*xmit), SLAB_KERNEL); if(!xmit) return -ENOMEM; @@ -1430,18 +1758,18 @@ xmit->last_cycle = -1; 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 */ @@ -1482,7 +1810,7 @@ ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task); xmit->task_active = 0; } - + dma_prog_region_free(&xmit->prog); kfree(xmit); iso->hostdata = NULL; @@ -1492,9 +1820,12 @@ { struct hpsb_iso *iso = (struct hpsb_iso*) data; struct ohci_iso_xmit *xmit = iso->hostdata; + unsigned long flags; int wake = 0; int count; + spin_lock_irqsave(&iso->lock, flags); + /* check the whole buffer if necessary, starting at pkt_dma */ for(count = 0; count < iso->buf_packets; count++) { @@ -1507,7 +1838,7 @@ if(!event) { /* packet hasn't been sent yet; we are done for now */ - goto out; + break; } if(event != 0x11) { @@ -1517,10 +1848,9 @@ /* at least one packet went out, so wake up the writer */ wake = 1; - + /* parse cycle */ { - struct hpsb_iso_packet_info* info = hpsb_iso_packet_info(iso, xmit->pkt_dma); unsigned int cycle = cmd->output_last.status & 0x1FFF; /* check for discontinuity */ @@ -1529,14 +1859,14 @@ } xmit->last_cycle = cycle; - /* predict the timestamp pkt_dma will have - next time around the buffer */ - - cycle += iso->buf_packets; + /* predict the timestamp of the next packet to be queued */ + + /* jump ahead by the number of packets that are already buffered */ + cycle += iso->buf_packets - iso->n_ready_packets; while(cycle >= 8000) cycle -= 8000; - info->cycle = cycle; + iso->xmit_cycle = cycle; } /* reset the DMA descriptor for next time */ @@ -1544,15 +1874,16 @@ /* 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)) { + iso->n_ready_packets += 1; + + if(iso->n_ready_packets == iso->buf_packets) { /* underflow */ atomic_inc(&iso->overflows); } } -out: + spin_unlock_irqrestore(&iso->lock, flags); + if(wake && iso->callback) { iso->callback(iso); } @@ -1560,27 +1891,53 @@ static int ohci_iso_xmit_queue_one(struct hpsb_iso *iso) { + unsigned long flags; struct ohci_iso_xmit *xmit = iso->hostdata; - struct hpsb_iso_packet_info *info; + int next_i, prev_i; struct iso_xmit_cmd *next, *prev; - + + unsigned int offset; + unsigned short len; + unsigned char tag, sy; + + /* grab the packet offset, length, tag, and sy fields from the + buffer. NOTE: we cannot trust the user to supply a valid + offset and length! */ + { + struct hpsb_iso_packet_info *info = &iso->infos[iso->first_packet]; + + /* check for bogus offset/length */ + int ret = hpsb_iso_check_offset_len(iso, info, &offset, &len); + if(ret) + return ret; + + /* also check that the packet doesn't cross a page boundary + (we could allow this if we added OUTPUT_MORE descriptor support) */ + if(cross_bound(offset, len)) { + PRINT(KERN_ERR, xmit->ohci->id, + "rawiso xmit: packet %u crosses a page boundary", + iso->first_packet); + return -EINVAL; + } + + tag = info->tag; + sy = info->sy; + } + /* sync up the card's view of the buffer */ - dma_region_sync(&iso->buf, iso->first_packet * iso->buf_stride, iso->buf_stride); + dma_region_sync(&iso->data_buf, offset, len); /* 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 descriptor */ memset(next, 0, sizeof(struct iso_xmit_cmd)); next->output_more_immediate.control = 0x02000008; @@ -1588,29 +1945,28 @@ /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */ /* tcode = 0xA, and sy */ - next->iso_hdr[0] = 0xA0 | (info->sy & 0xF); + next->iso_hdr[0] = 0xA0 | (sy & 0xF); /* tag and channel number */ - next->iso_hdr[1] = (info->tag << 6) | (iso->channel & 0x3F); + next->iso_hdr[1] = (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; + next->iso_hdr[6] = len & 0xFF; + next->iso_hdr[7] = 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; + next->output_last.control |= 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); - + next->output_last.address = dma_region_offset_to_bus(&iso->data_buf, offset); + /* leave branchAddress at zero for now */ /* re-write the previous DMA descriptor to chain to this one */ @@ -1618,7 +1974,7 @@ /* 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 */ @@ -1637,8 +1993,11 @@ reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer); /* increment cursors */ + spin_lock_irqsave(&iso->lock, flags); iso->first_packet = (iso->first_packet+1) % iso->buf_packets; - atomic_inc(&iso->n_dma_packets); + iso->xmit_cycle = (iso->xmit_cycle+1) % 8000; + iso->n_ready_packets--; + spin_unlock_irqrestore(&irq->lock, flags); return 0; } @@ -1705,18 +2064,18 @@ reg_read(xmit->ohci, xmit->ContextControlSet)); return -1; } - + return 0; } -static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, int arg) +static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, unsigned long arg) { - + switch(cmd) { case XMIT_INIT: return ohci_iso_xmit_init(iso); case XMIT_START: - return ohci_iso_xmit_start(iso, arg); + return ohci_iso_xmit_start(iso, arg < 8000 ? arg : -1); case XMIT_STOP: ohci_iso_xmit_stop(iso); return 0; @@ -1729,7 +2088,7 @@ case RECV_INIT: return ohci_iso_recv_init(iso); case RECV_START: - return ohci_iso_recv_start(iso, arg); + return ohci_iso_recv_start(iso, arg < 8000 ? arg : -1); case RECV_STOP: ohci_iso_recv_stop(iso); return 0; @@ -1739,7 +2098,16 @@ case RECV_SHUTDOWN: ohci_iso_recv_shutdown(iso); return 0; - + case RECV_LISTEN_CHANNEL: + ohci_iso_recv_change_channel(iso, arg, 1); + return 0; + case RECV_UNLISTEN_CHANNEL: + ohci_iso_recv_change_channel(iso, arg, 0); + return 0; + case RECV_SET_CHANNEL_MASK: + ohci_iso_recv_set_channel_mask(iso, *((u64*) arg)); + return 0; + default: PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet", cmd); @@ -2378,7 +2746,7 @@ return; DBGMSG(d->ohci->id, "Freeing dma_rcv_ctx %d", d->ctx); - + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); if (d->type == DMA_CTX_ISO) @@ -2499,7 +2867,7 @@ spin_lock_init(&d->lock); if (type == DMA_CTX_ISO) { - ohci1394_init_iso_tasklet(&ohci->ir_tasklet, OHCI_ISO_RECEIVE, + ohci1394_init_iso_tasklet(&ohci->ir_tasklet, OHCI_ISO_MULTICHANNEL_RECEIVE, dma_rcv_tasklet, (unsigned long) d); if (ohci1394_register_iso_tasklet(ohci, &ohci->ir_tasklet) < 0) { @@ -2810,7 +3178,7 @@ struct hpsb_host *host; struct ti_ohci *ohci; /* shortcut to currently handled device */ unsigned long ohci_base; - + if (version_printed++ == 0) PRINT_G(KERN_INFO, "%s", version); @@ -2886,7 +3254,7 @@ pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, &ohci->selfid_buf_bus); OHCI_DMA_ALLOC("consistent selfid_buf"); - + if (ohci->selfid_buf_cpu == NULL) FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets"); ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER; @@ -2966,7 +3334,7 @@ OHCI1394_IsoRcvContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate IR context"); - + /* IT DMA context allocation */ if (alloc_dma_trm_ctx(ohci, &ohci->it_context, DMA_CTX_ISO, 0, IT_NUM_DESC, @@ -3020,7 +3388,7 @@ /* Free IT dma */ free_dma_trm_ctx(&ohci->it_context); - + case OHCI_INIT_HAVE_SELFID_BUFFER: pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, ohci->selfid_buf_cpu, @@ -3162,7 +3530,7 @@ } spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); - + return r; } Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2003-02-01 08:59:00.000000000 -0500 @@ -171,7 +171,7 @@ /* dma buffer for self-id packets */ quadlet_t *selfid_buf_cpu; dma_addr_t selfid_buf_bus; - + /* buffer for csr config rom */ quadlet_t *csr_config_rom_cpu; dma_addr_t csr_config_rom_bus; @@ -194,13 +194,13 @@ int nb_iso_rcv_ctx; unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ unsigned int ir_multichannel_used; /* ditto */ - + /* iso transmit */ struct dma_trm_ctx it_context; struct ohci1394_iso_tasklet it_tasklet; int nb_iso_xmit_ctx; unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */ - + u64 ISO_channel_usage; /* IEEE-1394 part follows */ @@ -215,10 +215,10 @@ /* Tasklets for iso receive and transmit, used by video1394, * amdtp and dv1394 */ - + struct list_head iso_tasklet_list; spinlock_t iso_tasklet_list_lock; - + /* Swap the selfid buffer? */ unsigned int selfid_swap:1; /* Some Apple chipset seem to swap incoming headers for us */ Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2003-02-01 08:59:00.000000000 -0500 @@ -2004,7 +2004,7 @@ { 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) { @@ -2019,7 +2019,7 @@ static void queue_rawiso_event(struct file_info *fi) { unsigned long flags; - + spin_lock_irqsave(&fi->reqlists_lock, flags); /* only one ISO activity event may be in the queue */ @@ -2049,7 +2049,7 @@ spin_lock_irqsave(&host_info_lock, flags); hi = find_host_info(iso->host); - + if (hi != NULL) { list_for_each(lh, &hi->file_info_list) { struct file_info *fi = list_entry(lh, struct file_info, list); @@ -2057,24 +2057,21 @@ queue_rawiso_event(fi); } } - + spin_unlock_irqrestore(&host_info_lock, 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) { + stat->config.data_buf_size = iso->buf_size; 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->xmit_cycle = iso->xmit_cycle; } static int raw1394_iso_xmit_init(struct file_info *fi, void *uaddr) @@ -2083,10 +2080,10 @@ if(copy_from_user(&stat, uaddr, sizeof(stat))) return -EFAULT; - + fi->iso_handle = hpsb_iso_xmit_init(fi->host, + stat.config.data_buf_size, stat.config.buf_packets, - stat.config.max_packet_size, stat.config.channel, stat.config.speed, stat.config.irq_interval, @@ -2095,14 +2092,14 @@ 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; /* queue an event to get things started */ rawiso_activity_cb(fi->iso_handle); - + return 0; } @@ -2112,10 +2109,10 @@ if(copy_from_user(&stat, uaddr, sizeof(stat))) return -EFAULT; - + fi->iso_handle = hpsb_iso_recv_init(fi->host, + stat.config.data_buf_size, stat.config.buf_packets, - stat.config.max_packet_size, stat.config.channel, stat.config.irq_interval, rawiso_activity_cb); @@ -2123,7 +2120,7 @@ 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; @@ -2141,15 +2138,77 @@ /* reset overflow counter */ atomic_set(&iso->overflows, 0); - + + return 0; +} + +/* copy N packet_infos out of the ringbuffer into user-supplied array */ +static int raw1394_iso_recv_packets(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_packets upackets; + unsigned int packet = fi->iso_handle->first_packet; + int i; + + if(copy_from_user(&upackets, uaddr, sizeof(upackets))) + return -EFAULT; + + if(upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) + return -EINVAL; + + /* ensure user-supplied buffer is accessible and big enough */ + if(verify_area(VERIFY_WRITE, upackets.infos, + upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + /* copy the packet_infos out */ + for(i = 0; i < upackets.n_packets; i++) { + if(__copy_to_user(&upackets.infos[i], + &fi->iso_handle->infos[packet], + sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + packet = (packet + 1) % fi->iso_handle->buf_packets; + } + return 0; } +/* copy N packet_infos from user to ringbuffer, and queue them for transmission */ +static int raw1394_iso_send_packets(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_packets upackets; + unsigned int packet = fi->iso_handle->first_packet; + int i; + + if(copy_from_user(&upackets, uaddr, sizeof(upackets))) + return -EFAULT; + + if(upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) + return -EINVAL; + + /* ensure user-supplied buffer is accessible and big enough */ + if(verify_area(VERIFY_READ, upackets.infos, + upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + /* copy the packet_infos in */ + for(i = 0; i < upackets.n_packets; i++) { + if(__copy_from_user(&fi->iso_handle->infos[packet], + &upackets.infos[i], + sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + packet = (packet + 1) % fi->iso_handle->buf_packets; + } + + return hpsb_iso_xmit_queue_packets(fi->iso_handle, upackets.n_packets); +} + 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; } @@ -2162,14 +2221,14 @@ if(fi->iso_state == RAW1394_ISO_INACTIVE) return -EINVAL; - return dma_region_mmap(&fi->iso_handle->buf, file, vma); + return dma_region_mmap(&fi->iso_handle->data_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) { @@ -2188,17 +2247,26 @@ case RAW1394_ISO_STOP: hpsb_iso_stop(fi->iso_handle); return 0; - + case RAW1394_ISO_RECV_LISTEN_CHANNEL: + return hpsb_iso_recv_listen_channel(fi->iso_handle, arg); + case RAW1394_ISO_RECV_UNLISTEN_CHANNEL: + return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg); + case RAW1394_ISO_RECV_SET_CHANNEL_MASK: { + /* copy the u64 from user-space */ + u64 mask; + if(copy_from_user(&mask, (void*) arg, sizeof(mask))) + return -EFAULT; + return hpsb_iso_recv_set_channel_mask(fi->iso_handle, mask); + } case RAW1394_ISO_GET_STATUS: return raw1394_iso_get_status(fi, (void*) arg); - - case RAW1394_ISO_PRODUCE_CONSUME: + case RAW1394_ISO_RECV_PACKETS: + return raw1394_iso_recv_packets(fi, (void*) arg); + case RAW1394_ISO_RECV_RELEASE_PACKETS: return hpsb_iso_recv_release_packets(fi->iso_handle, arg); - case RAW1394_ISO_SHUTDOWN: raw1394_iso_shutdown(fi); return 0; - case RAW1394_ISO_QUEUE_ACTIVITY: queue_rawiso_event(fi); return 0; @@ -2216,17 +2284,13 @@ 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_XMIT_PACKETS: + return raw1394_iso_send_packets(fi, (void*) arg); case RAW1394_ISO_SHUTDOWN: raw1394_iso_shutdown(fi); return 0; - case RAW1394_ISO_QUEUE_ACTIVITY: queue_rawiso_event(fi); return 0; @@ -2235,7 +2299,7 @@ default: break; } - + return -EINVAL; } @@ -2251,7 +2315,7 @@ mask |= POLLIN | POLLRDNORM; } spin_unlock_irq(&fi->reqlists_lock); - + return mask; } @@ -2301,7 +2365,7 @@ 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); Modified: trunk/raw1394.h ============================================================================== --- trunk/raw1394.h (original) +++ trunk/raw1394.h 2003-02-01 08:59:00.000000000 -0500 @@ -118,31 +118,53 @@ /* rawiso API */ /* ioctls */ -#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 /* arg: raw1394_iso_status* */ -#define RAW1394_ISO_PRODUCE_CONSUME 6 /* arg: int, # of packets */ -#define RAW1394_ISO_SHUTDOWN 7 -#define RAW1394_ISO_QUEUE_ACTIVITY 9 - +#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 /* arg: raw1394_iso_status* */ +#define RAW1394_ISO_PRODUCE_CONSUME 6 /* no longer used */ +#define RAW1394_ISO_SHUTDOWN 7 +#define RAW1394_ISO_QUEUE_ACTIVITY 9 +#define RAW1394_ISO_RECV_LISTEN_CHANNEL 10 /* arg: channel number */ +#define RAW1394_ISO_RECV_UNLISTEN_CHANNEL 11 /* arg: channel number */ +#define RAW1394_ISO_RECV_SET_CHANNEL_MASK 12 /* arg: pointer to 64-bit mask */ +#define RAW1394_ISO_RECV_PACKETS 13 /* arg: struct raw1394_iso_packets* */ +#define RAW1394_ISO_RECV_RELEASE_PACKETS 14 /* arg: int n_packets */ +#define RAW1394_ISO_XMIT_PACKETS 15 /* arg: struct raw1394_iso_packets* */ + /* per-packet metadata embedded in the ringbuffer */ /* must be identical to hpsb_iso_packet_info in iso.h! */ struct raw1394_iso_packet_info { + __u32 offset; __u16 len; - __u16 cycle; + __u16 cycle; /* recv only */ __u8 channel; /* recv only */ __u8 tag; - __u8 sy; + __u8 sy; +}; + +/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */ +struct raw1394_iso_packets { + __u32 n_packets; + struct raw1394_iso_packet_info *infos; }; struct raw1394_iso_config { + /* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */ + __u32 data_buf_size; + + /* # of packets to buffer */ __u32 buf_packets; - __u32 max_packet_size; - __u32 channel; - __u32 speed; /* xmit only */ + + /* iso channel (set to -1 for multi-channel recv) */ + __s32 channel; + + /* xmit only - iso transmission speed */ + __u8 speed; + + /* max. latency of buffer, in packets (-1 if you don't care) */ __s32 irq_interval; }; @@ -150,19 +172,6 @@ struct raw1394_iso_status { /* current settings */ struct raw1394_iso_config config; - - /* byte offset between successive packets in the buffer */ - __s32 buf_stride; - - /* byte offset of data payload within each packet */ - __s32 packet_data_offset; - - /* byte offset of struct iso_packet_info within each packet */ - __s32 packet_info_offset; - - /* index of next packet to fill with data (ISO transmission) - or next packet containing data recieved (ISO reception) */ - __u32 first_packet; /* number of packets waiting to be filled with data (ISO transmission) or containing data received (ISO reception) */ @@ -172,6 +181,10 @@ underflow of the packet buffer (a value of zero guarantees that no packets have been dropped) */ __u32 overflows; + + /* cycle number at which next packet will be transmitted; + -1 if not known */ + __s16 xmit_cycle; }; #endif /* IEEE1394_RAW1394_H */ Modified: trunk/dma.c ============================================================================== --- trunk/dma.c (original) +++ trunk/dma.c 2003-02-01 08:59:00.000000000 -0500 @@ -26,7 +26,7 @@ { /* round up to page size */ n_bytes = round_up_to_page(n_bytes); - + prog->n_pages = n_bytes / PAGE_SIZE; prog->kvirt = pci_alloc_consistent(dev, prog->n_pages * PAGE_SIZE, &prog->bus_addr); @@ -46,7 +46,7 @@ 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; @@ -70,9 +70,9 @@ /* round up to page size */ n_bytes = round_up_to_page(n_bytes); - + 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"); @@ -80,7 +80,7 @@ } dma->n_pages = n_pages; - + /* Clear the ram out, no junk to the user */ memset(dma->kvirt, 0, n_pages * PAGE_SIZE); @@ -112,7 +112,7 @@ dma->dev = dev; dma->direction = direction; - + return 0; err: @@ -146,7 +146,7 @@ { 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; @@ -155,14 +155,14 @@ 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; } @@ -174,10 +174,10 @@ 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); } @@ -214,7 +214,7 @@ int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma) { unsigned long size; - + if(!dma->kvirt) return -EINVAL; @@ -231,6 +231,6 @@ vma->vm_private_data = dma; vma->vm_file = file; vma->vm_flags |= VM_RESERVED; - + return 0; } Modified: trunk/hosts.h ============================================================================== --- trunk/hosts.h (original) +++ trunk/hosts.h 2003-02-01 08:59:00.000000000 -0500 @@ -113,14 +113,17 @@ * QUEUE/RELEASE = produce/consume packets (arg: # of packets) * SHUTDOWN = deallocate resources */ - + XMIT_INIT, XMIT_START, XMIT_STOP, XMIT_QUEUE, XMIT_SHUTDOWN, - + RECV_INIT, + RECV_LISTEN_CHANNEL, /* multi-channel only */ + RECV_UNLISTEN_CHANNEL, /* multi-channel only */ + RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */ RECV_START, RECV_STOP, RECV_RELEASE, @@ -173,8 +176,8 @@ /* 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 ... [truncated message content] |
From: SVN U. <we...@li...> - 2003-02-01 13:59:29
|
Author: weihs Date: 2002-12-23 15:51:50 -0500 (Mon, 23 Dec 2002) New Revision: 728 Modified: trunk/ohci1394.c trunk/ohci1394.h Log: correctly handle OHCI evt_* Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-01 08:58:56.000000000 -0500 @@ -2251,7 +2251,7 @@ struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); struct hpsb_packet *packet; unsigned long flags; - u32 ack; + u32 status, ack; size_t datasize; spin_lock_irqsave(&d->lock, flags); @@ -2260,25 +2260,16 @@ packet = driver_packet(d->fifo_list.next); datasize = packet->data_size; if (datasize && packet->type != hpsb_raw) - ack = le32_to_cpu( + status = le32_to_cpu( d->prg_cpu[d->sent_ind]->end.status) >> 16; else - ack = le32_to_cpu( + status = le32_to_cpu( d->prg_cpu[d->sent_ind]->begin.status) >> 16; - if (ack == 0) + if (status == 0) /* this packet hasn't been sent yet*/ break; - if (!(ack & 0x10)) { - /* XXX: This is an OHCI evt_* code. We need to handle - * this specially! For right now, we just fake an - * ackx_send_error. */ - PRINT(KERN_DEBUG, ohci->id, "Received OHCI evt_* error 0x%x", - ack & 0xf); - ack = (ack & 0xffe0) | ACK_BUSY_A; - } - #ifdef OHCI1394_DEBUG if (datasize) DBGMSG(ohci->id, @@ -2290,7 +2281,7 @@ >>4)&0xf, (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) >>10)&0x3f, - ack&0x1f, (ack>>5)&0x3, + status&0x1f, (status>>5)&0x3, le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]) >>16, d->ctx); @@ -2304,13 +2295,64 @@ >>4)&0xf, (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) >>10)&0x3f, - ack&0x1f, (ack>>5)&0x3, + status&0x1f, (status>>5)&0x3, le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]), d->ctx); #endif + if (status & 0x10) { + ack = status & 0xf; + } else { + switch (status & 0x1f) { + case EVT_NO_STATUS: /* that should never happen */ + case EVT_RESERVED_A: /* that should never happen */ + case EVT_LONG_PACKET: /* that should never happen */ + PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f); + ack = ACKX_SEND_ERROR; + break; + case EVT_MISSING_ACK: + ack = ACKX_TIMEOUT; + break; + case EVT_UNDERRUN: + ack = ACKX_SEND_ERROR; + break; + case EVT_OVERRUN: /* that should never happen */ + PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f); + ack = ACKX_SEND_ERROR; + break; + case EVT_DESCRIPTOR_READ: + case EVT_DATA_READ: + case EVT_DATA_WRITE: + ack = ACKX_SEND_ERROR; + break; + case EVT_BUS_RESET: /* that should never happen */ + PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f); + ack = ACKX_SEND_ERROR; + break; + case EVT_TIMEOUT: + ack = ACKX_TIMEOUT; + break; + case EVT_TCODE_ERR: + ack = ACKX_SEND_ERROR; + break; + case EVT_RESERVED_B: /* that should never happen */ + case EVT_RESERVED_C: /* that should never happen */ + PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f); + ack = ACKX_SEND_ERROR; + break; + case EVT_UNKNOWN: + case EVT_FLUSHED: + ack = ACKX_SEND_ERROR; + break; + default: + PRINT(KERN_ERR, ohci->id, "Unhandled OHCI evt_* error 0x%x", status & 0x1f); + ack = ACKX_SEND_ERROR; + BUG(); + } + } + list_del(&packet->driver_list); - hpsb_packet_sent(ohci->host, packet, ack & 0xf); + hpsb_packet_sent(ohci->host, packet, ack); if (datasize) { pci_unmap_single(ohci->dev, Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2003-02-01 08:58:57.000000000 -0500 @@ -387,7 +387,7 @@ /* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */ #define EVT_NO_STATUS 0x0 /* No event status */ -#define EVT_RESERVED 0x1 /* Reserved, not used !!! */ +#define EVT_RESERVED_A 0x1 /* Reserved, not used !!! */ #define EVT_LONG_PACKET 0x2 /* The revc data was longer than the buf */ #define EVT_MISSING_ACK 0x3 /* A subaction gap was detected before an ack arrived, or recv'd ack had a parity error */ @@ -406,6 +406,17 @@ 16-bit host memory write */ #define EVT_BUS_RESET 0x9 /* Identifies a PHY packet in the recv buffer as being a synthesized bus reset packet */ +#define EVT_TIMEOUT 0xa /* Indicates that the asynchronous transmit response + packet expired and was not transmitted, or that an + IT DMA context experienced a skip processing overflow */ +#define EVT_TCODE_ERR 0xb /* A bad tCode is associated with this packet. + The packet was flushed */ +#define EVT_RESERVED_B 0xc /* Reserved, not used !!! */ +#define EVT_RESERVED_C 0xd /* Reserved, not used !!! */ +#define EVT_UNKNOWN 0xe /* An error condition has occurred that cannot be + represented by any other event codes defined herein. */ +#define EVT_FLUSHED 0xf /* Send by the link side of output FIFO when asynchronous + packets are being flushed due to a bus reset. */ #define OHCI1394_TCODE_PHY 0xE |
From: SVN U. <ben...@li...> - 2003-02-01 13:59:27
|
Author: bencollins Date: 2002-12-23 15:36:10 -0500 (Mon, 23 Dec 2002) New Revision: 727 Modified: branches/linux-2.4/eth1394.c branches/linux-2.4/eth1394.h branches/linux-2.4/hosts.c branches/linux-2.4/hosts.h branches/linux-2.4/ieee1394_core.c branches/linux-2.4/ieee1394_core.h branches/linux-2.4/ieee1394_types.h branches/linux-2.4/pcilynx.c branches/linux-2.4/raw1394.c branches/linux-2.4/raw1394.h branches/linux-2.4/sbp2.c branches/linux-2.4/sbp2.h Log: Remove some old compatiblity code. Modified: branches/linux-2.4/ieee1394_core.c ============================================================================== --- branches/linux-2.4/ieee1394_core.c (original) +++ branches/linux-2.4/ieee1394_core.c 2003-02-01 08:58:54.000000000 -0500 @@ -81,10 +81,10 @@ struct list_head *lh, *next; list_for_each_safe(lh, next, &packet->complete_tq) { - struct hpsb_queue_struct *tq = - list_entry(lh, struct hpsb_queue_struct, hpsb_queue_list); - list_del(&tq->hpsb_queue_list); - hpsb_schedule_work(tq); + struct tq_struct *tq = + list_entry(lh, struct tq_struct, list); + list_del(&tq->list); + schedule_task(tq); } return; @@ -93,11 +93,11 @@ /** * hpsb_add_packet_complete_task - add a new task for when a packet completes * @packet: the packet whose completion we want the task added to - * @tq: the hpsb_queue_struct describing the task to add + * @tq: the tq_struct describing the task to add */ -void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq) +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq) { - list_add_tail(&tq->hpsb_queue_list, &packet->complete_tq); + list_add_tail(&tq->list, &packet->complete_tq); return; } @@ -437,7 +437,7 @@ spin_unlock_irqrestore(&host->pending_pkt_lock, flags); up(&packet->state_change); - hpsb_schedule_work(&host->timeout_tq); + schedule_task(&host->timeout_tq); } /** @@ -881,7 +881,7 @@ } if (!list_empty(&host->pending_packets)) - hpsb_schedule_work(&host->timeout_tq); + schedule_task(&host->timeout_tq); spin_unlock_irqrestore(&host->pending_pkt_lock, flags); @@ -1030,7 +1030,7 @@ to get the index of the ieee1394_driver we want */ - blocknum = (minor(inode->i_rdev) >> 4) & 0xF; + blocknum = (MINOR(inode->i_rdev) >> 4) & 0xF; /* look up the driver */ Modified: branches/linux-2.4/ieee1394_core.h ============================================================================== --- branches/linux-2.4/ieee1394_core.h (original) +++ branches/linux-2.4/ieee1394_core.h 2003-02-01 08:58:54.000000000 -0500 @@ -77,7 +77,7 @@ }; /* add a new task for when a packet completes */ -void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq); +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq); static inline struct hpsb_packet *driver_packet(struct list_head *l) { @@ -194,7 +194,7 @@ /* return the index (within a minor number block) of a file */ static inline unsigned char ieee1394_file_to_instance(struct file *file) { - unsigned char minor = minor(file->f_dentry->d_inode->i_rdev); + unsigned char minor = MINOR(file->f_dentry->d_inode->i_rdev); /* return lower 4 bits */ return minor & 0xF; Modified: branches/linux-2.4/raw1394.c ============================================================================== --- branches/linux-2.4/raw1394.c (original) +++ branches/linux-2.4/raw1394.c 2003-02-01 08:58:54.000000000 -0500 @@ -107,7 +107,7 @@ if (req != NULL) { memset(req, 0, sizeof(struct pending_request)); INIT_LIST_HEAD(&req->list); - HPSB_INIT_WORK(&req->tq, (void(*)(void*))queue_complete_cb, NULL); + INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL); } return req; @@ -797,7 +797,7 @@ return sizeof(struct raw1394_request); } - HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req); + PREPARE_TQUEUE(&req->tq, (void (*)(void*))queue_complete_req, req); req->req.length = 0; hpsb_add_packet_complete_task(packet, &req->tq); @@ -860,7 +860,7 @@ packet->header_size=header_length; packet->data_size=req->req.length-header_length; - HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req); + PREPARE_TQUEUE(&req->tq, (void (*)(void*))queue_complete_req, req); req->req.length = 0; hpsb_add_packet_complete_task(packet, &req->tq); Modified: branches/linux-2.4/raw1394.h ============================================================================== --- branches/linux-2.4/raw1394.h (original) +++ branches/linux-2.4/raw1394.h 2003-02-01 08:58:54.000000000 -0500 @@ -164,7 +164,7 @@ struct list_head list; struct file_info *file_info; struct hpsb_packet *packet; - struct hpsb_queue_struct tq; + struct tq_struct tq; struct iso_block_store *ibs; quadlet_t *data; int free_data; Modified: branches/linux-2.4/hosts.c ============================================================================== --- branches/linux-2.4/hosts.c (original) +++ branches/linux-2.4/hosts.c 2003-02-01 08:58:54.000000000 -0500 @@ -138,7 +138,7 @@ atomic_set(&h->generation, 0); - HPSB_INIT_WORK(&h->timeout_tq, (void (*)(void*))abort_timedouts, h); + INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h); h->topology_map = h->csr.topology_map + 3; h->speed_map = (u8 *)(h->csr.speed_map + 2); Modified: branches/linux-2.4/eth1394.c ============================================================================== --- branches/linux-2.4/eth1394.c (original) +++ branches/linux-2.4/eth1394.c 2003-02-01 08:58:54.000000000 -0500 @@ -682,8 +682,8 @@ ptask->skb = skb; ptask->addr = addr; ptask->dest_node = dest_node; - HPSB_INIT_WORK(&ptask->tq, hpsb_write_sched, ptask); - hpsb_schedule_work(&ptask->tq); + INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask); + schedule_task(&ptask->tq); return 0; fail: Modified: branches/linux-2.4/hosts.h ============================================================================== --- branches/linux-2.4/hosts.h (original) +++ branches/linux-2.4/hosts.h 2003-02-01 08:58:54.000000000 -0500 @@ -3,6 +3,7 @@ #include <linux/wait.h> #include <linux/list.h> +#include <linux/tqueue.h> #include <asm/semaphore.h> #include "ieee1394_types.h" @@ -30,7 +31,7 @@ struct list_head pending_packets; spinlock_t pending_pkt_lock; - struct hpsb_queue_struct timeout_tq; + struct tq_struct timeout_tq; /* A bitmask where a set bit means that this tlabel is in use. * FIXME - should be handled per node instead of per bus. */ Modified: branches/linux-2.4/sbp2.c ============================================================================== --- branches/linux-2.4/sbp2.c (original) +++ branches/linux-2.4/sbp2.c 2003-02-01 08:58:54.000000000 -0500 @@ -801,7 +801,7 @@ * Set up a task queue completion routine, which returns * the packet to the free list and releases the tlabel. */ - HPSB_PREPARE_WORK(&request_packet->tq, + PREPARE_TQUEUE(&request_packet->tq, (void (*)(void*))sbp2util_free_request_packet, request_packet); request_packet->hi_context = hi; Modified: branches/linux-2.4/eth1394.h ============================================================================== --- branches/linux-2.4/eth1394.h (original) +++ branches/linux-2.4/eth1394.h 2003-02-01 08:58:54.000000000 -0500 @@ -56,7 +56,7 @@ struct sk_buff *skb; /* Socket buffer we are sending */ nodeid_t dest_node; /* Destination of the packet */ u64 addr; /* Address */ - struct hpsb_queue_struct tq; /* The task */ + struct tq_struct tq; /* The task */ }; /* IP1394 headers */ Modified: branches/linux-2.4/sbp2.h ============================================================================== --- branches/linux-2.4/sbp2.h (original) +++ branches/linux-2.4/sbp2.h 2003-02-01 08:58:54.000000000 -0500 @@ -319,7 +319,7 @@ struct list_head list; struct hpsb_packet *packet; - struct hpsb_queue_struct tq; + struct tq_struct tq; void *hi_context; }; Modified: branches/linux-2.4/ieee1394_types.h ============================================================================== --- branches/linux-2.4/ieee1394_types.h (original) +++ branches/linux-2.4/ieee1394_types.h 2003-02-01 08:58:54.000000000 -0500 @@ -10,27 +10,6 @@ #include <asm/byteorder.h> -/* The great kdev_t changeover in 2.5.x */ -#include <linux/kdev_t.h> -#ifndef minor -#define minor(dev) MINOR(dev) -#endif - -#ifndef __devexit_p -#define __devexit_p(x) x -#endif - -#include <linux/spinlock.h> - -#ifndef list_for_each_safe -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -#endif - -#define pte_offset_kernel pte_offset - #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif @@ -40,15 +19,6 @@ #endif -/* Use task queue */ -#include <linux/tqueue.h> -#define hpsb_queue_struct tq_struct -#define hpsb_queue_list list -#define hpsb_schedule_work(x) schedule_task(x) -#define HPSB_INIT_WORK(x,y,z) INIT_TQUEUE(x,y,z) -#define HPSB_PREPARE_WORK(x,y,z) PREPARE_TQUEUE(x,y,z) - - typedef u32 quadlet_t; typedef u64 octlet_t; typedef u16 nodeid_t; Modified: branches/linux-2.4/pcilynx.c ============================================================================== --- branches/linux-2.4/pcilynx.c (original) +++ branches/linux-2.4/pcilynx.c 2003-02-01 08:58:54.000000000 -0500 @@ -792,7 +792,7 @@ static int mem_open(struct inode *inode, struct file *file) { - int cid = minor(inode->i_rdev); + int cid = MINOR(inode->i_rdev); enum { t_rom, t_aux, t_ram } type; struct memdata *md; @@ -1817,7 +1817,7 @@ .name = PCILYNX_DRIVER_NAME, .id_table = pci_table, .probe = add_card, - .remove = __devexit_p(remove_card), + .remove = remove_card, }; static struct hpsb_host_driver lynx_driver = { |
From: SVN U. <ben...@li...> - 2003-02-01 13:59:25
|
Author: bencollins Date: 2002-12-23 12:57:10 -0500 (Mon, 23 Dec 2002) New Revision: 726 Modified: trunk/TODO Log: Add todo for video1394 conversion to pci dma routines Modified: trunk/TODO ============================================================================== --- trunk/TODO (original) +++ trunk/TODO 2003-02-01 08:58:53.000000000 -0500 @@ -12,3 +12,6 @@ - Implement per-node queueing options for SBP-2 (look at sym2 driver for example). + +- Fix Video1394 to use the PCI DMA routines, so it works with non-32bit + machines and > 1gig of ram (especially with highmem support). |
From: SVN U. <ben...@li...> - 2003-02-01 13:59:24
|
Author: bencollins Date: 2002-12-23 11:03:59 -0500 (Mon, 23 Dec 2002) New Revision: 725 Modified: branches/linux-2.4/ohci1394.c Log: Backport dma_trm_tasklet fix from trunk Modified: branches/linux-2.4/ohci1394.c ============================================================================== --- branches/linux-2.4/ohci1394.c (original) +++ branches/linux-2.4/ohci1394.c 2003-02-01 08:58:52.000000000 -0500 @@ -1739,7 +1739,7 @@ /* initialize tasklet */ if (type == DMA_CTX_ISO) { ohci1394_init_iso_tasklet(&ohci->it_tasklet, OHCI_ISO_TRANSMIT, - dma_rcv_tasklet, (unsigned long) d); + dma_trm_tasklet, (unsigned long) d); if (ohci1394_register_iso_tasklet(ohci, &ohci->it_tasklet) < 0) { PRINT(KERN_ERR, ohci->id, "No IT DMA context available"); |
From: SVN U. <we...@li...> - 2003-02-01 13:59:23
|
Author: weihs Date: 2002-12-23 06:17:07 -0500 (Mon, 23 Dec 2002) New Revision: 724 Modified: branches/linux-2.4/ohci1394.c Log: backport fix from trunk: avoid unnecessary and incorrect error message about unhandled interrupt in case of bus reset storms Modified: branches/linux-2.4/ohci1394.c ============================================================================== --- branches/linux-2.4/ohci1394.c (original) +++ branches/linux-2.4/ohci1394.c 2003-02-01 08:58:51.000000000 -0500 @@ -1225,8 +1225,8 @@ PRINT(KERN_ERR, ohci->id, "SelfID received outside of bus reset sequence"); - event &= ~OHCI1394_selfIDComplete; selfid_not_valid: + event &= ~OHCI1394_selfIDComplete; } /* Make sure we handle everything, just in case we accidentally |
From: SVN U. <we...@li...> - 2003-02-01 13:59:23
|
Author: weihs Date: 2002-12-23 06:14:58 -0500 (Mon, 23 Dec 2002) New Revision: 723 Modified: trunk/ohci1394.c Log: avoid unnecessary and incorrect error message about unhandled interrupt in case of bus reset storms Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-01 08:58:49.000000000 -0500 @@ -2037,8 +2037,8 @@ PRINT(KERN_ERR, ohci->id, "SelfID received outside of bus reset sequence"); - event &= ~OHCI1394_selfIDComplete; selfid_not_valid: + event &= ~OHCI1394_selfIDComplete; } /* Make sure we handle everything, just in case we accidentally |
From: SVN U. <ben...@li...> - 2003-02-01 13:59:19
|
Author: bencollins Date: 2002-12-22 11:20:17 -0500 (Sun, 22 Dec 2002) New Revision: 722 Modified: branches/linux-2.4/sbp2.c Log: Fix sbp2.c hpsb_address_op functions to fit the prototypes. Modified: branches/linux-2.4/sbp2.c ============================================================================== --- branches/linux-2.4/sbp2.c (original) +++ branches/linux-2.4/sbp2.c 2003-02-01 08:58:47.000000000 -0500 @@ -1512,7 +1512,7 @@ * physical dma in hardware). Mostly just here for debugging... */ static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data, - u64 addr, unsigned int length) + u64 addr, unsigned int length, u16 flags) { /* @@ -1528,7 +1528,7 @@ * physical dma in hardware). Mostly just here for debugging... */ static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length) + u64 addr, unsigned int length, u16 flags) { /* |
From: SVN U. <ben...@li...> - 2003-02-01 13:57:29
|
Author: bencollins Date: 2003-01-30 21:14:45 -0500 (Thu, 30 Jan 2003) New Revision: 759 Modified: trunk/dv1394-private.h trunk/dv1394.c Log: Merge devfs changes from 2.5.59 Modified: trunk/dv1394-private.h ============================================================================== --- trunk/dv1394-private.h (original) +++ trunk/dv1394-private.h 2003-02-01 08:56:56.000000000 -0500 @@ -583,8 +583,5 @@ #define CIP_N_PAL 1 #define CIP_D_PAL 16 -/* Base for our DevFS entries */ -#define DV1394_DEV_BASE "ieee1394/dv" - #endif /* _DV_1394_PRIVATE_H */ Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2003-02-01 08:56:57.000000000 -0500 @@ -175,6 +175,15 @@ static struct hpsb_highlevel *hl_handle; /* = NULL; */ +static LIST_HEAD(dv1394_devfs); +struct dv1394_devfs_entry { + struct list_head list; + devfs_handle_t devfs; + char name[32]; + struct dv1394_devfs_entry *parent; +}; +static spinlock_t dv1394_devfs_lock = SPIN_LOCK_UNLOCKED; + /* translate from a struct file* to the corresponding struct video_card* */ static inline struct video_card* file_to_video_card(struct file *file) @@ -2447,40 +2456,135 @@ /*** DEVFS HELPERS *********************************************************/ +struct dv1394_devfs_entry * +dv1394_devfs_find( char *name) +{ + struct list_head *lh; + struct dv1394_devfs_entry *p; + + spin_lock( &dv1394_devfs_lock); + if(!list_empty(&dv1394_devfs)) { + list_for_each(lh, &dv1394_devfs) { + p = list_entry(lh, struct dv1394_devfs_entry, list); + if(!strncmp(p->name, name, sizeof(p->name))) { + goto found; + } + } + } + p = NULL; + +found: + spin_unlock( &dv1394_devfs_lock); + return p; +} + #ifdef CONFIG_DEVFS_FS static int dv1394_devfs_add_entry(struct video_card *video) { - char buf[64]; - snprintf(buf, sizeof(buf), DV1394_DEV_BASE "/host%d/%s/%s", - (video->id>>2), - (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), - (video->mode == MODE_RECEIVE ? "in" : "out")); + char buf[32]; + struct dv1394_devfs_entry *p; + struct dv1394_devfs_entry *parent; - video->devfs_handle = devfs_register(NULL, buf, DEVFS_FL_NONE, + p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL); + if(!p) { + printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n"); + goto err; + } + memset(p, 0, sizeof(struct dv1394_devfs_entry)); + + snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2), + (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL")); + + parent = dv1394_devfs_find(buf); + if (parent == NULL) { + printk(KERN_ERR "dv1394: unable to locate parent devfs of %s\n", buf); + goto err_free; + } + + video->devfs_handle = devfs_register( + parent->devfs, + (video->mode == MODE_RECEIVE ? "in" : "out"), + DEVFS_FL_NONE, IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394*16 + video->id, S_IFCHR | S_IRUGO | S_IWUGO, &dv1394_fops, (void*) video); + p->devfs = video->devfs_handle; + if (p->devfs == NULL) { + printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s/%s\n", + parent->name, + (video->mode == MODE_RECEIVE ? "in" : "out")); + goto err_free; + } + + spin_lock( &dv1394_devfs_lock); + INIT_LIST_HEAD(&p->list); + list_add_tail(&p->list, &dv1394_devfs); + spin_unlock( &dv1394_devfs_lock); + return 0; + + err_free: + kfree(p); + err: + return -ENOMEM; } -static int dv1394_devfs_add_dir(char *name) +static int +dv1394_devfs_add_dir( char *name, + struct dv1394_devfs_entry *parent, + struct dv1394_devfs_entry **out) { - if (!devfs_mk_dir(NULL, name, NULL)) - printk(KERN_ERR "dv1394: unable to create /dev/%s\n", name); - return -ENOMEM; + struct dv1394_devfs_entry *p; + + p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL); + if(!p) { + printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n"); + goto err; + } + memset(p, 0, sizeof(struct dv1394_devfs_entry)); + + if (parent == NULL) { + snprintf(p->name, sizeof(p->name), "%s", name); + p->devfs = devfs_mk_dir(ieee1394_devfs_handle, name, NULL); + } else { + snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name); + p->devfs = devfs_mk_dir(parent->devfs, name, NULL); + } + if (p->devfs == NULL) { + printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s\n", p->name); + goto err_free; } + p->parent = parent; + if (out != NULL) *out = p; + + spin_lock( &dv1394_devfs_lock); + INIT_LIST_HEAD(&p->list); + list_add_tail(&p->list, &dv1394_devfs); + spin_unlock( &dv1394_devfs_lock); + return 0; + + err_free: + kfree(p); + err: + return -ENOMEM; } void dv1394_devfs_del( char *name) { - char s[64]; - sprintf(s, "ieee1394/%s", name); - devfs_find_and_unregister(NULL, s, 0, 0, 0, 0); + struct dv1394_devfs_entry *p = dv1394_devfs_find(name); + if (p != NULL) { + devfs_unregister(p->devfs); + + spin_lock( &dv1394_devfs_lock); + list_del(&p->list); + spin_unlock( &dv1394_devfs_lock); + kfree(p); + } } #endif /* CONFIG_DEVFS_FS */ @@ -2664,12 +2768,15 @@ #endif #ifdef CONFIG_DEVFS_FS - snprintf(buf, sizeof(buf), DV1394_DEV_BASE "/host%d", ohci->id); - dv1394_devfs_add_dir(buf); - snprintf(buf, sizeof(buf), DV1394_DEV_BASE "/host%d/NTSC", ohci->id); - dv1394_devfs_add_dir(buf); - snprintf(buf, sizeof(buf), DV1394_DEV_BASE "/host%d/PAL", ohci->id); - dv1394_devfs_add_dir(buf); +{ + struct dv1394_devfs_entry *devfs_entry = dv1394_devfs_find("dv"); + if (devfs_entry != NULL) { + snprintf(buf, sizeof(buf), "host%d", ohci->id); + dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry); + dv1394_devfs_add_dir("NTSC", devfs_entry, NULL); + dv1394_devfs_add_dir("PAL", devfs_entry, NULL); + } +} #endif dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE); @@ -2829,8 +2936,8 @@ } #ifdef CONFIG_DEVFS_FS - if (dv1394_devfs_add_dir(DV1394_DEV_BASE) < 0) { - printk(KERN_ERR "dv1394: unable to create /dev/%s\n", DV1394_DEV_BASE); + if (dv1394_devfs_add_dir("dv", NULL, NULL) < 0) { + printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/dv\n"); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); return -ENOMEM; } @@ -2838,7 +2945,7 @@ #ifdef CONFIG_PROC_FS if (dv1394_procfs_add_dir("dv",NULL,NULL) < 0) { - printk(KERN_ERR "dv1394: unable to create /proc/bus/%s\n", DV1394_DEV_BASE); + printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv\n"); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); #ifdef CONFIG_DEVFS_FS dv1394_devfs_del("dv"); |
From: SVN U. <ben...@li...> - 2003-02-01 13:57:16
|
Author: bencollins Date: 2003-02-01 00:53:54 -0500 (Sat, 01 Feb 2003) New Revision: 761 Modified: trunk/video1394.c Log: Phase 1 of 2. Using dma routines for dma region. Replaces old kvirt_to_bus interface. Modified: trunk/video1394.c ============================================================================== --- trunk/video1394.c (original) +++ trunk/video1394.c 2003-02-01 08:56:44.000000000 -0500 @@ -50,6 +50,7 @@ #include "ieee1394_core.h" #include "highlevel.h" #include "video1394.h" +#include "dma.h" #include "ohci1394.h" @@ -94,7 +95,9 @@ unsigned int packet_size; unsigned int left_size; unsigned int nb_cmd; - unsigned char *buf; + + struct dma_region dma; + struct dma_cmd **ir_prg; struct it_dma_prg **it_prg; unsigned int *buffer_status; @@ -159,74 +162,6 @@ static devfs_handle_t devfs_handle; static struct hpsb_highlevel *hl_handle = NULL; -/* Code taken from bttv.c */ - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = virt_to_bus((void *)kva); - return ret; -} - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = __pa(kva); - return ret; -} - -static void * rvmalloc(unsigned long size) -{ - void * mem; - unsigned long adr; - - size=PAGE_ALIGN(size); - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, - no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - mem_map_reserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - unsigned long adr; - - if (mem) - { - adr=(unsigned long) mem; - while ((long) size > 0) - { - mem_map_unreserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } -} -/* End of code taken from bttv.c */ static int free_dma_iso_ctx(struct dma_iso_ctx *d) { @@ -238,18 +173,19 @@ if (d->iso_tasklet.link.next != NULL) ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet); - if (d->buf) - rvfree((void *)d->buf, d->num_desc * d->buf_size); + dma_region_free(&d->dma); if (d->ir_prg) { - for (i=0;i<d->num_desc;i++) - if (d->ir_prg[i]) kfree(d->ir_prg[i]); + for (i = 0; i < d->num_desc; i++) + if (d->ir_prg[i]) + kfree(d->ir_prg[i]); kfree(d->ir_prg); } if (d->it_prg) { - for (i=0;i<d->num_desc;i++) - if (d->it_prg[i]) kfree(d->it_prg[i]); + for (i = 0; i < d->num_desc; i++) + if (d->it_prg[i]) + kfree(d->it_prg[i]); kfree(d->it_prg); } @@ -291,18 +227,14 @@ d->frame_size = buf_size; d->buf_size = PAGE_ALIGN(buf_size); d->last_buffer = -1; - d->buf = NULL; - d->ir_prg = NULL; + dma_region_init(&d->dma); init_waitqueue_head(&d->waitq); - d->buf = rvmalloc(d->num_desc * d->buf_size); - - if (d->buf == NULL) { + if (dma_region_alloc(&d->dma, d->buf_size, ohci->dev, PCI_DMA_BIDIRECTIONAL)) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); free_dma_iso_ctx(d); return NULL; } - memset(d->buf, 0, d->num_desc * d->buf_size); if (type == OHCI_ISO_RECEIVE) ohci1394_init_iso_tasklet(&d->iso_tasklet, type, @@ -354,8 +286,7 @@ } } - } - else { /* OHCI_ISO_TRANSMIT */ + } else { /* OHCI_ISO_TRANSMIT */ d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx; d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx; d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx; @@ -460,7 +391,7 @@ static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) { struct dma_cmd *ir_prg = d->ir_prg[n]; - unsigned long buf = (unsigned long)d->buf+n*d->buf_size; + unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size; int i; /* the first descriptor will read only 4 bytes */ @@ -471,21 +402,25 @@ if (flags & VIDEO1394_SYNC_FRAMES) ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT); - ir_prg[0].address = cpu_to_le32(kvirt_to_bus(buf)); + ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf - + (unsigned long)d->dma.kvirt)); ir_prg[0].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[1].control)) & 0xfffffff0) | 0x1); /* the second descriptor will read PAGE_SIZE-4 bytes */ ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH | (PAGE_SIZE-4)); - ir_prg[1].address = cpu_to_le32(kvirt_to_bus(buf+4)); + ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf + 4) - + (unsigned long)d->dma.kvirt)); ir_prg[1].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[2].control)) & 0xfffffff0) | 0x1); for (i=2;i<d->nb_cmd-1;i++) { ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH | PAGE_SIZE); - ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE)); + ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, + (buf+(i-1)*PAGE_SIZE) - + (unsigned long)d->dma.kvirt)); ir_prg[i].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[i+1].control)) @@ -495,7 +430,9 @@ /* the last descriptor will generate an interrupt */ ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size); - ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE)); + ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, + (buf+(i-1)*PAGE_SIZE) - + (unsigned long)d->dma.kvirt)); } static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags) @@ -574,7 +511,7 @@ static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d, int n) { - unsigned char* buf = d->buf + n * d->buf_size; + unsigned char* buf = d->dma.kvirt + n * d->buf_size; u32 cycleTimer; u32 timeStamp; @@ -603,7 +540,7 @@ if (n == -1) { return; } - buf = d->buf + n * d->buf_size; + buf = d->dma.kvirt + n * d->buf_size; timeStamp += (d->last_used_cmd[n] << 12) & 0xffff; @@ -650,7 +587,7 @@ static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) { struct it_dma_prg *it_prg = d->it_prg[n]; - unsigned long buf = (unsigned long)d->buf+n*d->buf_size; + unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size; int i; d->last_used_cmd[n] = d->nb_cmd - 1; for (i=0;i<d->nb_cmd;i++) { @@ -674,7 +611,8 @@ it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH); it_prg[i].end.address = - cpu_to_le32(kvirt_to_bus(buf+i*d->packet_size)); + cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) - + (unsigned long)d->dma.kvirt)); if (i<d->nb_cmd-1) { it_prg[i].end.control |= cpu_to_le32(d->packet_size); @@ -694,15 +632,6 @@ it_prg[i].end.branchAddress = 0; } it_prg[i].end.status = 0; - -#if 0 - printk("%d:%d: %08x-%08x ctrl %08x brch %08x d0 %08x d1 %08x\n",n,i, - virt_to_bus(&(it_prg[i].begin.control)), - virt_to_bus(&(it_prg[i].end.control)), - it_prg[i].end.control, - it_prg[i].end.branchAddress, - it_prg[i].data[0], it_prg[i].data[1]); -#endif } } @@ -769,37 +698,6 @@ reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx); } -static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d, - struct vm_area_struct *vma) -{ - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long page, pos; - - if (size > d->num_desc * d->buf_size) { - PRINT(KERN_ERR, ohci->id, - "iso context %d buf size is different from mmap size", - d->ctx); - return -EINVAL; - } - if (!d->buf) { - PRINT(KERN_ERR, ohci->id, - "iso context %d is not allocated", d->ctx); - return -EINVAL; - } - - pos = (unsigned long) d->buf; - while (size > 0) { - page = kvirt_to_pa(pos); - if (remap_page_range_1394(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - return 0; -} - static int video1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -1254,7 +1152,7 @@ if (ctx->current_ctx == NULL) { PRINT(KERN_ERR, ctx->video->ohci->id, "Current iso context not set"); } else - res = do_iso_mmap(ctx->video->ohci, ctx->current_ctx, vma); + res = dma_region_mmap(&ctx->current_ctx->dma, file, vma); unlock_kernel(); return res; |
From: SVN U. <ben...@li...> - 2003-02-01 13:56:07
|
Author: bencollins Date: 2003-02-01 00:53:54 -0500 (Sat, 01 Feb 2003) New Revision: 761 Modified: trunk/video1394.c Log: Phase 1 of 2. Using dma routines for dma region. Replaces old kvirt_to_bus interface. Modified: trunk/video1394.c ============================================================================== --- trunk/video1394.c (original) +++ trunk/video1394.c 2003-02-01 08:55:34.000000000 -0500 @@ -50,6 +50,7 @@ #include "ieee1394_core.h" #include "highlevel.h" #include "video1394.h" +#include "dma.h" #include "ohci1394.h" @@ -94,7 +95,9 @@ unsigned int packet_size; unsigned int left_size; unsigned int nb_cmd; - unsigned char *buf; + + struct dma_region dma; + struct dma_cmd **ir_prg; struct it_dma_prg **it_prg; unsigned int *buffer_status; @@ -159,74 +162,6 @@ static devfs_handle_t devfs_handle; static struct hpsb_highlevel *hl_handle = NULL; -/* Code taken from bttv.c */ - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = virt_to_bus((void *)kva); - return ret; -} - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = __pa(kva); - return ret; -} - -static void * rvmalloc(unsigned long size) -{ - void * mem; - unsigned long adr; - - size=PAGE_ALIGN(size); - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, - no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - mem_map_reserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - unsigned long adr; - - if (mem) - { - adr=(unsigned long) mem; - while ((long) size > 0) - { - mem_map_unreserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } -} -/* End of code taken from bttv.c */ static int free_dma_iso_ctx(struct dma_iso_ctx *d) { @@ -238,18 +173,19 @@ if (d->iso_tasklet.link.next != NULL) ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet); - if (d->buf) - rvfree((void *)d->buf, d->num_desc * d->buf_size); + dma_region_free(&d->dma); if (d->ir_prg) { - for (i=0;i<d->num_desc;i++) - if (d->ir_prg[i]) kfree(d->ir_prg[i]); + for (i = 0; i < d->num_desc; i++) + if (d->ir_prg[i]) + kfree(d->ir_prg[i]); kfree(d->ir_prg); } if (d->it_prg) { - for (i=0;i<d->num_desc;i++) - if (d->it_prg[i]) kfree(d->it_prg[i]); + for (i = 0; i < d->num_desc; i++) + if (d->it_prg[i]) + kfree(d->it_prg[i]); kfree(d->it_prg); } @@ -291,18 +227,14 @@ d->frame_size = buf_size; d->buf_size = PAGE_ALIGN(buf_size); d->last_buffer = -1; - d->buf = NULL; - d->ir_prg = NULL; + dma_region_init(&d->dma); init_waitqueue_head(&d->waitq); - d->buf = rvmalloc(d->num_desc * d->buf_size); - - if (d->buf == NULL) { + if (dma_region_alloc(&d->dma, d->buf_size, ohci->dev, PCI_DMA_BIDIRECTIONAL)) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); free_dma_iso_ctx(d); return NULL; } - memset(d->buf, 0, d->num_desc * d->buf_size); if (type == OHCI_ISO_RECEIVE) ohci1394_init_iso_tasklet(&d->iso_tasklet, type, @@ -354,8 +286,7 @@ } } - } - else { /* OHCI_ISO_TRANSMIT */ + } else { /* OHCI_ISO_TRANSMIT */ d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx; d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx; d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx; @@ -460,7 +391,7 @@ static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) { struct dma_cmd *ir_prg = d->ir_prg[n]; - unsigned long buf = (unsigned long)d->buf+n*d->buf_size; + unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size; int i; /* the first descriptor will read only 4 bytes */ @@ -471,21 +402,25 @@ if (flags & VIDEO1394_SYNC_FRAMES) ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT); - ir_prg[0].address = cpu_to_le32(kvirt_to_bus(buf)); + ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf - + (unsigned long)d->dma.kvirt)); ir_prg[0].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[1].control)) & 0xfffffff0) | 0x1); /* the second descriptor will read PAGE_SIZE-4 bytes */ ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH | (PAGE_SIZE-4)); - ir_prg[1].address = cpu_to_le32(kvirt_to_bus(buf+4)); + ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf + 4) - + (unsigned long)d->dma.kvirt)); ir_prg[1].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[2].control)) & 0xfffffff0) | 0x1); for (i=2;i<d->nb_cmd-1;i++) { ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH | PAGE_SIZE); - ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE)); + ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, + (buf+(i-1)*PAGE_SIZE) - + (unsigned long)d->dma.kvirt)); ir_prg[i].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[i+1].control)) @@ -495,7 +430,9 @@ /* the last descriptor will generate an interrupt */ ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size); - ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE)); + ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, + (buf+(i-1)*PAGE_SIZE) - + (unsigned long)d->dma.kvirt)); } static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags) @@ -574,7 +511,7 @@ static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d, int n) { - unsigned char* buf = d->buf + n * d->buf_size; + unsigned char* buf = d->dma.kvirt + n * d->buf_size; u32 cycleTimer; u32 timeStamp; @@ -603,7 +540,7 @@ if (n == -1) { return; } - buf = d->buf + n * d->buf_size; + buf = d->dma.kvirt + n * d->buf_size; timeStamp += (d->last_used_cmd[n] << 12) & 0xffff; @@ -650,7 +587,7 @@ static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) { struct it_dma_prg *it_prg = d->it_prg[n]; - unsigned long buf = (unsigned long)d->buf+n*d->buf_size; + unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size; int i; d->last_used_cmd[n] = d->nb_cmd - 1; for (i=0;i<d->nb_cmd;i++) { @@ -674,7 +611,8 @@ it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH); it_prg[i].end.address = - cpu_to_le32(kvirt_to_bus(buf+i*d->packet_size)); + cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) - + (unsigned long)d->dma.kvirt)); if (i<d->nb_cmd-1) { it_prg[i].end.control |= cpu_to_le32(d->packet_size); @@ -694,15 +632,6 @@ it_prg[i].end.branchAddress = 0; } it_prg[i].end.status = 0; - -#if 0 - printk("%d:%d: %08x-%08x ctrl %08x brch %08x d0 %08x d1 %08x\n",n,i, - virt_to_bus(&(it_prg[i].begin.control)), - virt_to_bus(&(it_prg[i].end.control)), - it_prg[i].end.control, - it_prg[i].end.branchAddress, - it_prg[i].data[0], it_prg[i].data[1]); -#endif } } @@ -769,37 +698,6 @@ reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx); } -static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d, - struct vm_area_struct *vma) -{ - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long page, pos; - - if (size > d->num_desc * d->buf_size) { - PRINT(KERN_ERR, ohci->id, - "iso context %d buf size is different from mmap size", - d->ctx); - return -EINVAL; - } - if (!d->buf) { - PRINT(KERN_ERR, ohci->id, - "iso context %d is not allocated", d->ctx); - return -EINVAL; - } - - pos = (unsigned long) d->buf; - while (size > 0) { - page = kvirt_to_pa(pos); - if (remap_page_range_1394(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - return 0; -} - static int video1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -1254,7 +1152,7 @@ if (ctx->current_ctx == NULL) { PRINT(KERN_ERR, ctx->video->ohci->id, "Current iso context not set"); } else - res = do_iso_mmap(ctx->video->ohci, ctx->current_ctx, vma); + res = dma_region_mmap(&ctx->current_ctx->dma, file, vma); unlock_kernel(); return res; |
From: SVN U. <ben...@li...> - 2003-02-01 13:51:58
|
Author: bencollins Date: 2003-02-01 00:53:54 -0500 (Sat, 01 Feb 2003) New Revision: 761 Modified: trunk/video1394.c Log: Phase 1 of 2. Using dma routines for dma region. Replaces old kvirt_to_bus interface. Modified: trunk/video1394.c ============================================================================== --- trunk/video1394.c (original) +++ trunk/video1394.c 2003-02-01 08:51:25.000000000 -0500 @@ -50,6 +50,7 @@ #include "ieee1394_core.h" #include "highlevel.h" #include "video1394.h" +#include "dma.h" #include "ohci1394.h" @@ -94,7 +95,9 @@ unsigned int packet_size; unsigned int left_size; unsigned int nb_cmd; - unsigned char *buf; + + struct dma_region dma; + struct dma_cmd **ir_prg; struct it_dma_prg **it_prg; unsigned int *buffer_status; @@ -159,74 +162,6 @@ static devfs_handle_t devfs_handle; static struct hpsb_highlevel *hl_handle = NULL; -/* Code taken from bttv.c */ - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = virt_to_bus((void *)kva); - return ret; -} - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = __pa(kva); - return ret; -} - -static void * rvmalloc(unsigned long size) -{ - void * mem; - unsigned long adr; - - size=PAGE_ALIGN(size); - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, - no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - mem_map_reserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - unsigned long adr; - - if (mem) - { - adr=(unsigned long) mem; - while ((long) size > 0) - { - mem_map_unreserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } -} -/* End of code taken from bttv.c */ static int free_dma_iso_ctx(struct dma_iso_ctx *d) { @@ -238,18 +173,19 @@ if (d->iso_tasklet.link.next != NULL) ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet); - if (d->buf) - rvfree((void *)d->buf, d->num_desc * d->buf_size); + dma_region_free(&d->dma); if (d->ir_prg) { - for (i=0;i<d->num_desc;i++) - if (d->ir_prg[i]) kfree(d->ir_prg[i]); + for (i = 0; i < d->num_desc; i++) + if (d->ir_prg[i]) + kfree(d->ir_prg[i]); kfree(d->ir_prg); } if (d->it_prg) { - for (i=0;i<d->num_desc;i++) - if (d->it_prg[i]) kfree(d->it_prg[i]); + for (i = 0; i < d->num_desc; i++) + if (d->it_prg[i]) + kfree(d->it_prg[i]); kfree(d->it_prg); } @@ -291,18 +227,14 @@ d->frame_size = buf_size; d->buf_size = PAGE_ALIGN(buf_size); d->last_buffer = -1; - d->buf = NULL; - d->ir_prg = NULL; + dma_region_init(&d->dma); init_waitqueue_head(&d->waitq); - d->buf = rvmalloc(d->num_desc * d->buf_size); - - if (d->buf == NULL) { + if (dma_region_alloc(&d->dma, d->buf_size, ohci->dev, PCI_DMA_BIDIRECTIONAL)) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); free_dma_iso_ctx(d); return NULL; } - memset(d->buf, 0, d->num_desc * d->buf_size); if (type == OHCI_ISO_RECEIVE) ohci1394_init_iso_tasklet(&d->iso_tasklet, type, @@ -354,8 +286,7 @@ } } - } - else { /* OHCI_ISO_TRANSMIT */ + } else { /* OHCI_ISO_TRANSMIT */ d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx; d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx; d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx; @@ -460,7 +391,7 @@ static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) { struct dma_cmd *ir_prg = d->ir_prg[n]; - unsigned long buf = (unsigned long)d->buf+n*d->buf_size; + unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size; int i; /* the first descriptor will read only 4 bytes */ @@ -471,21 +402,25 @@ if (flags & VIDEO1394_SYNC_FRAMES) ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT); - ir_prg[0].address = cpu_to_le32(kvirt_to_bus(buf)); + ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf - + (unsigned long)d->dma.kvirt)); ir_prg[0].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[1].control)) & 0xfffffff0) | 0x1); /* the second descriptor will read PAGE_SIZE-4 bytes */ ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH | (PAGE_SIZE-4)); - ir_prg[1].address = cpu_to_le32(kvirt_to_bus(buf+4)); + ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf + 4) - + (unsigned long)d->dma.kvirt)); ir_prg[1].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[2].control)) & 0xfffffff0) | 0x1); for (i=2;i<d->nb_cmd-1;i++) { ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH | PAGE_SIZE); - ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE)); + ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, + (buf+(i-1)*PAGE_SIZE) - + (unsigned long)d->dma.kvirt)); ir_prg[i].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[i+1].control)) @@ -495,7 +430,9 @@ /* the last descriptor will generate an interrupt */ ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size); - ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE)); + ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, + (buf+(i-1)*PAGE_SIZE) - + (unsigned long)d->dma.kvirt)); } static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags) @@ -574,7 +511,7 @@ static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d, int n) { - unsigned char* buf = d->buf + n * d->buf_size; + unsigned char* buf = d->dma.kvirt + n * d->buf_size; u32 cycleTimer; u32 timeStamp; @@ -603,7 +540,7 @@ if (n == -1) { return; } - buf = d->buf + n * d->buf_size; + buf = d->dma.kvirt + n * d->buf_size; timeStamp += (d->last_used_cmd[n] << 12) & 0xffff; @@ -650,7 +587,7 @@ static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) { struct it_dma_prg *it_prg = d->it_prg[n]; - unsigned long buf = (unsigned long)d->buf+n*d->buf_size; + unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size; int i; d->last_used_cmd[n] = d->nb_cmd - 1; for (i=0;i<d->nb_cmd;i++) { @@ -674,7 +611,8 @@ it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH); it_prg[i].end.address = - cpu_to_le32(kvirt_to_bus(buf+i*d->packet_size)); + cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) - + (unsigned long)d->dma.kvirt)); if (i<d->nb_cmd-1) { it_prg[i].end.control |= cpu_to_le32(d->packet_size); @@ -694,15 +632,6 @@ it_prg[i].end.branchAddress = 0; } it_prg[i].end.status = 0; - -#if 0 - printk("%d:%d: %08x-%08x ctrl %08x brch %08x d0 %08x d1 %08x\n",n,i, - virt_to_bus(&(it_prg[i].begin.control)), - virt_to_bus(&(it_prg[i].end.control)), - it_prg[i].end.control, - it_prg[i].end.branchAddress, - it_prg[i].data[0], it_prg[i].data[1]); -#endif } } @@ -769,37 +698,6 @@ reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx); } -static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d, - struct vm_area_struct *vma) -{ - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long page, pos; - - if (size > d->num_desc * d->buf_size) { - PRINT(KERN_ERR, ohci->id, - "iso context %d buf size is different from mmap size", - d->ctx); - return -EINVAL; - } - if (!d->buf) { - PRINT(KERN_ERR, ohci->id, - "iso context %d is not allocated", d->ctx); - return -EINVAL; - } - - pos = (unsigned long) d->buf; - while (size > 0) { - page = kvirt_to_pa(pos); - if (remap_page_range_1394(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - return 0; -} - static int video1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -1254,7 +1152,7 @@ if (ctx->current_ctx == NULL) { PRINT(KERN_ERR, ctx->video->ohci->id, "Current iso context not set"); } else - res = do_iso_mmap(ctx->video->ohci, ctx->current_ctx, vma); + res = dma_region_mmap(&ctx->current_ctx->dma, file, vma); unlock_kernel(); return res; |
From: SVN U. <ben...@li...> - 2003-02-01 13:36:51
|
Author: bencollins Date: 2003-02-01 00:18:11 -0500 (Sat, 01 Feb 2003) New Revision: 760 Modified: trunk/ trunk/Makefile trunk/nodemgr.c trunk/ohci1394.h Log: Minor 2.5.59 changes. Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2003-02-01 08:36:12.000000000 -0500 @@ -191,7 +191,7 @@ /* iso receive */ int nb_iso_rcv_ctx; unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ - unsigned int ir_multichannel_used; /* ditto */ + unsigned long ir_multichannel_used; /* ditto */ spinlock_t IR_channel_lock; /* iso receive (legacy API) */ Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2003-02-01 08:36:12.000000000 -0500 @@ -1089,8 +1089,7 @@ static void nodemgr_remove_node(struct node_entry *ne) { - HPSB_DEBUG("%s removed: Node[" NODE_BUS_FMT "] GUID[%016Lx] [%s]", - (ne->host->node_id == ne->nodeid) ? "Host" : "Device", + HPSB_DEBUG("Device removed: Node[" NODE_BUS_FMT "] GUID[%016Lx] [%s]", NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid, ne->vendor_name ?: "Unknown"); Modified: trunk/Makefile ============================================================================== --- trunk/Makefile (original) +++ trunk/Makefile 2003-02-01 08:36:12.000000000 -0500 @@ -20,8 +20,6 @@ clean-files := oui.c -include $(TOPDIR)/Rules.make - ieee1394.o: $(ieee1394-objs) $(LD) $(LDFLAGS) -r -o $@ $(ieee1394-objs) |
From: SVN U. <we...@li...> - 2002-12-22 14:51:24
|
Author: weihs Date: 2002-12-21 20:28:19 -0500 (Sat, 21 Dec 2002) New Revision: 721 Modified: branches/linux-2.4/pcilynx.c branches/linux-2.4/pcilynx.h Log: backport from trunk: Fix for a crash, when async transmission and bus reset are reported by one single interrupt. Correctly calculated CRCs in configuration ROM image. Correct interpretation of the argument, when resetting the bus on request. Modified: branches/linux-2.4/pcilynx.c ============================================================================== --- branches/linux-2.4/pcilynx.c (original) +++ branches/linux-2.4/pcilynx.c 2002-12-22 09:50:51.000000000 -0500 @@ -19,6 +19,17 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* + * Contributions: + * + * Manfred Weihs <we...@ic...> + * reading bus info block (containing GUID) from serial + * eeprom via i2c and storing it in config ROM + * Reworked code for initiating bus resets + * (long, short, with or without hold-off) + * Enhancements in async and iso send code + */ + #include <linux/config.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -450,7 +461,7 @@ if (host->in_bus_reset) return; /* in bus reset again */ - if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); + if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); //FIXME: I do not think, we need this here reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN); @@ -466,7 +477,14 @@ struct hpsb_packet *packet; d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async); + if (!list_empty(&d->pcl_queue)) { + PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo"); + BUG(); + } + packet = driver_packet(d->queue.next); + list_del(&packet->driver_list); + list_add_tail(&packet->driver_list, &d->pcl_queue); d->header_dma = pci_map_single(lynx->dev, packet->header, packet->header_size, PCI_DMA_TODEVICE); @@ -480,6 +498,7 @@ pcl.next = PCL_NEXT_INVALID; pcl.async_error_next = PCL_NEXT_INVALID; + pcl.pcl_status = 0; #ifdef __BIG_ENDIAN pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size; #else @@ -546,7 +565,7 @@ spin_lock_irqsave(&d->queue_lock, flags); list_add_tail(&packet->driver_list, &d->queue); - if (d->queue.next == &packet->driver_list) + if (list_empty(&d->pcl_queue)) send_next(lynx, packet->type); spin_unlock_irqrestore(&d->queue_lock, flags); @@ -563,6 +582,7 @@ struct hpsb_packet *packet; LIST_HEAD(packet_list); unsigned long flags; + int phy_reg; switch (cmd) { case RESET_BUS: @@ -571,21 +591,47 @@ break; } - if (arg) { - arg = 3 << 6; - } else { - arg = 1 << 6; - } - - retval = get_phy_reg(lynx, 1); - arg |= (retval == -1 ? 63 : retval); - retval = 0; - - PRINT(KERN_INFO, lynx->id, "resetting bus on request"); + switch (arg) { + case SHORT_RESET: + if (lynx->phyic.reg_1394a) { + phy_reg = get_phy_reg(lynx, 5); + if (phy_reg == -1) { + PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); + retval = -1; + break; + } + phy_reg |= 0x40; + + PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset) on request"); + + lynx->selfid_size = -1; + lynx->phy_reg0 = -1; + set_phy_reg(lynx, 5, phy_reg); /* set ISBR */ + break; + } else { + PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy"); + /* fall through to long bus reset */ + } + case LONG_RESET: + phy_reg = get_phy_reg(lynx, 1); + if (phy_reg == -1) { + PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); + retval = -1; + break; + } + phy_reg |= 0x40; + + PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset) on request"); + + lynx->selfid_size = -1; + lynx->phy_reg0 = -1; + set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */ + break; + default: + PRINT(KERN_ERR, lynx->id, "unknown argument for reset_bus command %d", arg); + retval = -1; + } - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - set_phy_reg(lynx, 1, arg); break; case GET_CYCLE_COUNTER: @@ -618,7 +664,44 @@ list_splice(&lynx->async.queue, &packet_list); INIT_LIST_HEAD(&lynx->async.queue); - spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + if (list_empty(&lynx->async.pcl_queue)) { + spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + PRINTD(KERN_DEBUG, lynx->id, "no async packet in PCL to cancel"); + } else { + struct ti_pcl pcl; + u32 ack; + struct hpsb_packet *packet; + + PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL"); + + get_pcl(lynx, lynx->async.pcl, &pcl); + + packet = driver_packet(lynx->async.pcl_queue.next); + list_del(&packet->driver_list); + + pci_unmap_single(lynx->dev, lynx->async.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->async.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } + + spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + + if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { + if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { + ack = (pcl.pcl_status >> 15) & 0xf; + PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); + ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); + } else { + ack = (pcl.pcl_status >> 15) & 0xf; + } + } else { + PRINT(KERN_INFO, lynx->id, "async packet was not completed"); + ack = ACKX_ABORTED; + } + hpsb_packet_sent(host, packet, ack); + } while (!list_empty(&packet_list)) { packet = driver_packet(packet_list.next); @@ -1015,11 +1098,11 @@ linkint = reg_read(lynx, LINK_INT_STATUS); intmask = reg_read(lynx, PCI_INT_STATUS); + if (!(intmask & PCI_INT_INT_PEND)) return; + PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask, linkint); - if (!(intmask & PCI_INT_INT_PEND)) return; - reg_write(lynx, LINK_INT_STATUS, linkint); reg_write(lynx, PCI_INT_STATUS, intmask); @@ -1118,62 +1201,96 @@ } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) { - u32 ack; - struct hpsb_packet *packet; - + PRINTD(KERN_DEBUG, lynx->id, "async sent"); spin_lock(&lynx->async.queue_lock); - ack = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_SEND)); - - packet = driver_packet(lynx->async.queue.next); - list_del(&packet->driver_list); - - pci_unmap_single(lynx->dev, lynx->async.header_dma, - packet->header_size, PCI_DMA_TODEVICE); - if (packet->data_size) { - pci_unmap_single(lynx->dev, lynx->async.data_dma, - packet->data_size, PCI_DMA_TODEVICE); - } + if (list_empty(&lynx->async.pcl_queue)) { + spin_unlock(&lynx->async.queue_lock); + PRINT(KERN_WARNING, lynx->id, "async dma halted, but no queued packet (maybe it was cancelled)"); + } else { + struct ti_pcl pcl; + u32 ack; + struct hpsb_packet *packet; + + get_pcl(lynx, lynx->async.pcl, &pcl); + + packet = driver_packet(lynx->async.pcl_queue.next); + list_del(&packet->driver_list); + + pci_unmap_single(lynx->dev, lynx->async.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->async.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } - if (!list_empty(&lynx->async.queue)) { - send_next(lynx, hpsb_async); - } + if (!list_empty(&lynx->async.queue)) { + send_next(lynx, hpsb_async); + } - spin_unlock(&lynx->async.queue_lock); + spin_unlock(&lynx->async.queue_lock); - if (ack & DMA_CHAN_STAT_SPECIALACK) { - ack = (ack >> 15) & 0xf; - PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); - ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); - } else { - ack = (ack >> 15) & 0xf; + if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { + if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { + ack = (pcl.pcl_status >> 15) & 0xf; + PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); + ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); + } else { + ack = (pcl.pcl_status >> 15) & 0xf; + } + } else { + PRINT(KERN_INFO, lynx->id, "async packet was not completed"); + ack = ACKX_SEND_ERROR; + } + hpsb_packet_sent(host, packet, ack); } - - hpsb_packet_sent(host, packet, ack); } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) { - struct hpsb_packet *packet; - + PRINTD(KERN_DEBUG, lynx->id, "iso sent"); spin_lock(&lynx->iso_send.queue_lock); - packet = driver_packet(lynx->iso_send.queue.next); - list_del(&packet->driver_list); + if (list_empty(&lynx->iso_send.pcl_queue)) { + spin_unlock(&lynx->iso_send.queue_lock); + PRINT(KERN_ERR, lynx->id, "iso send dma halted, but no queued packet"); + } else { + struct ti_pcl pcl; + u32 ack; + struct hpsb_packet *packet; + + get_pcl(lynx, lynx->iso_send.pcl, &pcl); + + packet = driver_packet(lynx->iso_send.pcl_queue.next); + list_del(&packet->driver_list); + + pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->iso_send.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } - pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, - packet->header_size, PCI_DMA_TODEVICE); - if (packet->data_size) { - pci_unmap_single(lynx->dev, lynx->iso_send.data_dma, - packet->data_size, PCI_DMA_TODEVICE); - } + if (!list_empty(&lynx->iso_send.queue)) { + send_next(lynx, hpsb_iso); + } - if (!list_empty(&lynx->iso_send.queue)) { - send_next(lynx, hpsb_iso); - } + spin_unlock(&lynx->iso_send.queue_lock); - spin_unlock(&lynx->iso_send.queue_lock); + if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { + if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { + ack = (pcl.pcl_status >> 15) & 0xf; + PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); + ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); + } else { + ack = (pcl.pcl_status >> 15) & 0xf; + } + } else { + PRINT(KERN_INFO, lynx->id, "iso send packet was not completed"); + ack = ACKX_SEND_ERROR; + } - hpsb_packet_sent(host, packet, ACK_COMPLETE); + hpsb_packet_sent(host, packet, ack); //FIXME: maybe we should just use ACK_COMPLETE and ACKX_SEND_ERROR + } } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) { @@ -1475,7 +1592,9 @@ lynx->phy_reg0 = -1; INIT_LIST_HEAD(&lynx->async.queue); + INIT_LIST_HEAD(&lynx->async.pcl_queue); INIT_LIST_HEAD(&lynx->iso_send.queue); + INIT_LIST_HEAD(&lynx->iso_send.pcl_queue); pcl.next = pcl_bus(lynx, lynx->rcv_pcl); put_pcl(lynx, lynx->rcv_pcl_start, &pcl); Modified: branches/linux-2.4/pcilynx.h ============================================================================== --- branches/linux-2.4/pcilynx.h (original) +++ branches/linux-2.4/pcilynx.h 2002-12-22 09:50:51.000000000 -0500 @@ -95,6 +95,7 @@ struct lynx_send_data { pcl_t pcl_start, pcl; struct list_head queue; + struct list_head pcl_queue; /* this queue contains at most one packet */ spinlock_t queue_lock; dma_addr_t header_dma, data_dma; int channel; @@ -514,13 +515,13 @@ static quadlet_t lynx_csr_rom[] = { /* bus info block offset (hex) */ - _(0x04040000), /* info/CRC length, CRC 400 */ + _(0x04046aaf), /* info/CRC length, CRC 400 */ _(0x31333934), /* 1394 magic number 404 */ _(0xf064a000), /* misc. settings 408 */ _(0x08002850), /* vendor ID, chip ID high 40c */ _(0x0000ffff), /* chip ID low 410 */ /* root directory */ - _(0x00090000), /* directory length, CRC 414 */ + _(0x00095778), /* directory length, CRC 414 */ _(0x03080028), /* vendor ID (Texas Instr.) 418 */ _(0x81000008), /* offset to textual ID 41c */ _(0x0c000200), /* node capabilities 420 */ @@ -530,8 +531,8 @@ _(0x81000014), /* offset to textual ID 430 */ _(0x09000000), /* node hardware version 434 */ _(0x81000018), /* offset to textual ID 438 */ - /* module vendor ID textual */ - _(0x00070000), /* CRC length, CRC 43c */ +/* module vendor ID textual */ + _(0x00070812), /* CRC length, CRC 43c */ _(0x00000000), /* 440 */ _(0x00000000), /* 444 */ _(0x54455841), /* "Texas Instruments" 448 */ @@ -540,25 +541,25 @@ _(0x4d454e54), /* 454 */ _(0x53000000), /* 458 */ /* node unique ID leaf */ - _(0x00020000), /* CRC length, CRC 45c */ + _(0x00022ead), /* CRC length, CRC 45c */ _(0x08002850), /* vendor ID, chip ID high 460 */ _(0x0000ffff), /* chip ID low 464 */ /* module dependent info */ - _(0x00050000), /* CRC length, CRC 468 */ + _(0x0005d837), /* CRC length, CRC 468 */ _(0x81000012), /* offset to module textual ID 46c */ _(0x81000017), /* textual descriptor 470 */ _(0x39010000), /* SRAM size 474 */ _(0x3a010000), /* AUXRAM size 478 */ _(0x3b000000), /* AUX device 47c */ /* module textual ID */ - _(0x00050000), /* CRC length, CRC 480 */ + _(0x000594df), /* CRC length, CRC 480 */ _(0x00000000), /* 484 */ _(0x00000000), /* 488 */ _(0x54534231), /* "TSB12LV21" 48c */ _(0x324c5632), /* 490 */ _(0x31000000), /* 494 */ /* part number */ - _(0x00060000), /* CRC length, CRC 498 */ + _(0x00068405), /* CRC length, CRC 498 */ _(0x00000000), /* 49c */ _(0x00000000), /* 4a0 */ _(0x39383036), /* "9806000-0001" 4a4 */ @@ -566,14 +567,14 @@ _(0x30303031), /* 4ac */ _(0x20000001), /* 4b0 */ /* module hardware version textual */ - _(0x00050000), /* CRC length, CRC 4b4 */ + _(0x00056501), /* CRC length, CRC 4b4 */ _(0x00000000), /* 4b8 */ _(0x00000000), /* 4bc */ _(0x5453424b), /* "TSBKPCITST" 4c0 */ _(0x50434954), /* 4c4 */ _(0x53540000), /* 4c8 */ /* node hardware version textual */ - _(0x00050000), /* CRC length, CRC 4d0 */ + _(0x0005d805), /* CRC length, CRC 4d0 */ _(0x00000000), /* 4d4 */ _(0x00000000), /* 4d8 */ _(0x54534232), /* "TSB21LV03" 4dc */ |
From: SVN U. <we...@li...> - 2002-12-22 14:51:21
|
Author: weihs Date: 2002-12-21 20:21:09 -0500 (Sat, 21 Dec 2002) New Revision: 720 Modified: trunk/pcilynx.c trunk/pcilynx.h Log: * Fix possible crash, if transmission of async packet is immediately followed by a bus reset and both events are handled by one singel interrupt. * Read transmission status from PCL rather than DMA channel status register (that is cleaner, avoids a race condition and allows a possible future extension to queue more than one packet in PCL at once) * Use correctly calculated CRCs in the configuration ROM image. Modified: trunk/pcilynx.c ============================================================================== --- trunk/pcilynx.c (original) +++ trunk/pcilynx.c 2002-12-22 09:50:49.000000000 -0500 @@ -27,6 +27,7 @@ * eeprom via i2c and storing it in config ROM * Reworked code for initiating bus resets * (long, short, with or without hold-off) + * Enhancements in async and iso send code */ #include <linux/config.h> @@ -476,7 +477,14 @@ struct hpsb_packet *packet; d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async); + if (!list_empty(&d->pcl_queue)) { + PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo"); + BUG(); + } + packet = driver_packet(d->queue.next); + list_del(&packet->driver_list); + list_add_tail(&packet->driver_list, &d->pcl_queue); d->header_dma = pci_map_single(lynx->dev, packet->header, packet->header_size, PCI_DMA_TODEVICE); @@ -490,6 +498,7 @@ pcl.next = PCL_NEXT_INVALID; pcl.async_error_next = PCL_NEXT_INVALID; + pcl.pcl_status = 0; #ifdef __BIG_ENDIAN pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size; #else @@ -556,7 +565,7 @@ spin_lock_irqsave(&d->queue_lock, flags); list_add_tail(&packet->driver_list, &d->queue); - if (d->queue.next == &packet->driver_list) + if (list_empty(&d->pcl_queue)) send_next(lynx, packet->type); spin_unlock_irqrestore(&d->queue_lock, flags); @@ -748,7 +757,44 @@ list_splice(&lynx->async.queue, &packet_list); INIT_LIST_HEAD(&lynx->async.queue); - spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + if (list_empty(&lynx->async.pcl_queue)) { + spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + PRINTD(KERN_DEBUG, lynx->id, "no async packet in PCL to cancel"); + } else { + struct ti_pcl pcl; + u32 ack; + struct hpsb_packet *packet; + + PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL"); + + get_pcl(lynx, lynx->async.pcl, &pcl); + + packet = driver_packet(lynx->async.pcl_queue.next); + list_del(&packet->driver_list); + + pci_unmap_single(lynx->dev, lynx->async.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->async.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } + + spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + + if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { + if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { + ack = (pcl.pcl_status >> 15) & 0xf; + PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); + ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); + } else { + ack = (pcl.pcl_status >> 15) & 0xf; + } + } else { + PRINT(KERN_INFO, lynx->id, "async packet was not completed"); + ack = ACKX_ABORTED; + } + hpsb_packet_sent(host, packet, ack); + } while (!list_empty(&packet_list)) { packet = driver_packet(packet_list.next); @@ -1145,11 +1191,11 @@ linkint = reg_read(lynx, LINK_INT_STATUS); intmask = reg_read(lynx, PCI_INT_STATUS); + if (!(intmask & PCI_INT_INT_PEND)) return; + PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask, linkint); - if (!(intmask & PCI_INT_INT_PEND)) return; - reg_write(lynx, LINK_INT_STATUS, linkint); reg_write(lynx, PCI_INT_STATUS, intmask); @@ -1248,62 +1294,96 @@ } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) { - u32 ack; - struct hpsb_packet *packet; - + PRINTD(KERN_DEBUG, lynx->id, "async sent"); spin_lock(&lynx->async.queue_lock); - ack = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_SEND)); - - packet = driver_packet(lynx->async.queue.next); - list_del(&packet->driver_list); - - pci_unmap_single(lynx->dev, lynx->async.header_dma, - packet->header_size, PCI_DMA_TODEVICE); - if (packet->data_size) { - pci_unmap_single(lynx->dev, lynx->async.data_dma, - packet->data_size, PCI_DMA_TODEVICE); - } + if (list_empty(&lynx->async.pcl_queue)) { + spin_unlock(&lynx->async.queue_lock); + PRINT(KERN_WARNING, lynx->id, "async dma halted, but no queued packet (maybe it was cancelled)"); + } else { + struct ti_pcl pcl; + u32 ack; + struct hpsb_packet *packet; + + get_pcl(lynx, lynx->async.pcl, &pcl); + + packet = driver_packet(lynx->async.pcl_queue.next); + list_del(&packet->driver_list); + + pci_unmap_single(lynx->dev, lynx->async.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->async.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } - if (!list_empty(&lynx->async.queue)) { - send_next(lynx, hpsb_async); - } + if (!list_empty(&lynx->async.queue)) { + send_next(lynx, hpsb_async); + } - spin_unlock(&lynx->async.queue_lock); + spin_unlock(&lynx->async.queue_lock); - if (ack & DMA_CHAN_STAT_SPECIALACK) { - ack = (ack >> 15) & 0xf; - PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); - ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); - } else { - ack = (ack >> 15) & 0xf; + if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { + if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { + ack = (pcl.pcl_status >> 15) & 0xf; + PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); + ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); + } else { + ack = (pcl.pcl_status >> 15) & 0xf; + } + } else { + PRINT(KERN_INFO, lynx->id, "async packet was not completed"); + ack = ACKX_SEND_ERROR; + } + hpsb_packet_sent(host, packet, ack); } - - hpsb_packet_sent(host, packet, ack); } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) { - struct hpsb_packet *packet; - + PRINTD(KERN_DEBUG, lynx->id, "iso sent"); spin_lock(&lynx->iso_send.queue_lock); - packet = driver_packet(lynx->iso_send.queue.next); - list_del(&packet->driver_list); + if (list_empty(&lynx->iso_send.pcl_queue)) { + spin_unlock(&lynx->iso_send.queue_lock); + PRINT(KERN_ERR, lynx->id, "iso send dma halted, but no queued packet"); + } else { + struct ti_pcl pcl; + u32 ack; + struct hpsb_packet *packet; + + get_pcl(lynx, lynx->iso_send.pcl, &pcl); + + packet = driver_packet(lynx->iso_send.pcl_queue.next); + list_del(&packet->driver_list); + + pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->iso_send.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } - pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, - packet->header_size, PCI_DMA_TODEVICE); - if (packet->data_size) { - pci_unmap_single(lynx->dev, lynx->iso_send.data_dma, - packet->data_size, PCI_DMA_TODEVICE); - } + if (!list_empty(&lynx->iso_send.queue)) { + send_next(lynx, hpsb_iso); + } - if (!list_empty(&lynx->iso_send.queue)) { - send_next(lynx, hpsb_iso); - } + spin_unlock(&lynx->iso_send.queue_lock); - spin_unlock(&lynx->iso_send.queue_lock); + if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { + if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { + ack = (pcl.pcl_status >> 15) & 0xf; + PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); + ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); + } else { + ack = (pcl.pcl_status >> 15) & 0xf; + } + } else { + PRINT(KERN_INFO, lynx->id, "iso send packet was not completed"); + ack = ACKX_SEND_ERROR; + } - hpsb_packet_sent(host, packet, ACK_COMPLETE); + hpsb_packet_sent(host, packet, ack); //FIXME: maybe we should just use ACK_COMPLETE and ACKX_SEND_ERROR + } } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) { @@ -1605,7 +1685,9 @@ lynx->phy_reg0 = -1; INIT_LIST_HEAD(&lynx->async.queue); + INIT_LIST_HEAD(&lynx->async.pcl_queue); INIT_LIST_HEAD(&lynx->iso_send.queue); + INIT_LIST_HEAD(&lynx->iso_send.pcl_queue); pcl.next = pcl_bus(lynx, lynx->rcv_pcl); put_pcl(lynx, lynx->rcv_pcl_start, &pcl); Modified: trunk/pcilynx.h ============================================================================== --- trunk/pcilynx.h (original) +++ trunk/pcilynx.h 2002-12-22 09:50:49.000000000 -0500 @@ -95,6 +95,7 @@ struct lynx_send_data { pcl_t pcl_start, pcl; struct list_head queue; + struct list_head pcl_queue; /* this queue contains at most one packet */ spinlock_t queue_lock; dma_addr_t header_dma, data_dma; int channel; @@ -514,13 +515,13 @@ static quadlet_t lynx_csr_rom[] = { /* bus info block offset (hex) */ - _(0x04040000), /* info/CRC length, CRC 400 */ + _(0x04046aaf), /* info/CRC length, CRC 400 */ _(0x31333934), /* 1394 magic number 404 */ _(0xf064a000), /* misc. settings 408 */ _(0x08002850), /* vendor ID, chip ID high 40c */ _(0x0000ffff), /* chip ID low 410 */ /* root directory */ - _(0x00090000), /* directory length, CRC 414 */ + _(0x00095778), /* directory length, CRC 414 */ _(0x03080028), /* vendor ID (Texas Instr.) 418 */ _(0x81000008), /* offset to textual ID 41c */ _(0x0c000200), /* node capabilities 420 */ @@ -530,8 +531,8 @@ _(0x81000014), /* offset to textual ID 430 */ _(0x09000000), /* node hardware version 434 */ _(0x81000018), /* offset to textual ID 438 */ - /* module vendor ID textual */ - _(0x00070000), /* CRC length, CRC 43c */ +/* module vendor ID textual */ + _(0x00070812), /* CRC length, CRC 43c */ _(0x00000000), /* 440 */ _(0x00000000), /* 444 */ _(0x54455841), /* "Texas Instruments" 448 */ @@ -540,25 +541,25 @@ _(0x4d454e54), /* 454 */ _(0x53000000), /* 458 */ /* node unique ID leaf */ - _(0x00020000), /* CRC length, CRC 45c */ + _(0x00022ead), /* CRC length, CRC 45c */ _(0x08002850), /* vendor ID, chip ID high 460 */ _(0x0000ffff), /* chip ID low 464 */ /* module dependent info */ - _(0x00050000), /* CRC length, CRC 468 */ + _(0x0005d837), /* CRC length, CRC 468 */ _(0x81000012), /* offset to module textual ID 46c */ _(0x81000017), /* textual descriptor 470 */ _(0x39010000), /* SRAM size 474 */ _(0x3a010000), /* AUXRAM size 478 */ _(0x3b000000), /* AUX device 47c */ /* module textual ID */ - _(0x00050000), /* CRC length, CRC 480 */ + _(0x000594df), /* CRC length, CRC 480 */ _(0x00000000), /* 484 */ _(0x00000000), /* 488 */ _(0x54534231), /* "TSB12LV21" 48c */ _(0x324c5632), /* 490 */ _(0x31000000), /* 494 */ /* part number */ - _(0x00060000), /* CRC length, CRC 498 */ + _(0x00068405), /* CRC length, CRC 498 */ _(0x00000000), /* 49c */ _(0x00000000), /* 4a0 */ _(0x39383036), /* "9806000-0001" 4a4 */ @@ -566,14 +567,14 @@ _(0x30303031), /* 4ac */ _(0x20000001), /* 4b0 */ /* module hardware version textual */ - _(0x00050000), /* CRC length, CRC 4b4 */ + _(0x00056501), /* CRC length, CRC 4b4 */ _(0x00000000), /* 4b8 */ _(0x00000000), /* 4bc */ _(0x5453424b), /* "TSBKPCITST" 4c0 */ _(0x50434954), /* 4c4 */ _(0x53540000), /* 4c8 */ /* node hardware version textual */ - _(0x00050000), /* CRC length, CRC 4d0 */ + _(0x0005d805), /* CRC length, CRC 4d0 */ _(0x00000000), /* 4d4 */ _(0x00000000), /* 4d8 */ _(0x54534232), /* "TSB21LV03" 4dc */ |
From: SVN U. <ano...@li...> - 2002-12-22 14:51:18
|
Author: anonymous Date: 2002-12-20 04:37:35 -0500 (Fri, 20 Dec 2002) New Revision: 719 Modified: trunk/ohci1394.c Log: whoa, we have the receive and transmit contexts mixed up! How could this have gone unnoticed for so long? Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-12-22 09:50:46.000000000 -0500 @@ -2554,7 +2554,7 @@ /* initialize tasklet */ if (type == DMA_CTX_ISO) { ohci1394_init_iso_tasklet(&ohci->it_tasklet, OHCI_ISO_TRANSMIT, - dma_rcv_tasklet, (unsigned long) d); + dma_trm_tasklet, (unsigned long) d); if (ohci1394_register_iso_tasklet(ohci, &ohci->it_tasklet) < 0) { PRINT(KERN_ERR, ohci->id, "No IT DMA context available"); |
From: SVN U. <ano...@li...> - 2002-12-22 14:51:16
|
Author: anonymous Date: 2002-12-20 03:23:56 -0500 (Fri, 20 Dec 2002) New Revision: 718 Modified: trunk/ohci1394.c Log: also check iso transmit starting cycle to make sure it is correct Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-12-22 09:50:44.000000000 -0500 @@ -1682,6 +1682,11 @@ start |= (seconds & 3) << 13; reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16)); + + if(cycle == 0) + xmit->last_cycle = 7999; + else + xmit->last_cycle = cycle - 1; } /* enable interrupts */ |
From: SVN U. <ano...@li...> - 2002-12-22 14:51:14
|
Author: anonymous Date: 2002-12-20 03:20:59 -0500 (Fri, 20 Dec 2002) New Revision: 717 Modified: trunk/ohci1394.c Log: improve iso transmit underflow detection by checking for discontinuity of cycle count Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-12-22 09:50:42.000000000 -0500 @@ -1389,6 +1389,7 @@ struct ohci1394_iso_tasklet task; int task_active; int pkt_dma; + int last_cycle; u32 ContextControlSet; u32 ContextControlClear; @@ -1426,7 +1427,8 @@ xmit->ohci = iso->host->hostdata; xmit->task_active = 0; xmit->pkt_dma = iso->first_packet; - + xmit->last_cycle = -1; + dma_prog_region_init(&xmit->prog); prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets; @@ -1509,24 +1511,34 @@ } if(event != 0x11) { + atomic_inc(&iso->overflows); 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 */ + + /* parse cycle */ { struct hpsb_iso_packet_info* info = hpsb_iso_packet_info(iso, xmit->pkt_dma); unsigned int cycle = cmd->output_last.status & 0x1FFF; + /* check for discontinuity */ + if(xmit->last_cycle != -1 && cycle != (xmit->last_cycle+1) % 8000) { + atomic_inc(&iso->overflows); + } + xmit->last_cycle = cycle; + + /* predict the timestamp pkt_dma will have + next time around the buffer */ + cycle += iso->buf_packets; - while(cycle > 8000) + while(cycle >= 8000) cycle -= 8000; - + info->cycle = cycle; } - + /* reset the DMA descriptor for next time */ cmd->output_last.status = 0; @@ -1646,6 +1658,8 @@ { struct ohci_iso_xmit *xmit = iso->hostdata; + xmit->last_cycle = -1; + /* clear out the control register */ reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF); wmb(); |
From: SVN U. <ano...@li...> - 2002-12-22 14:51:12
|
Author: anonymous Date: 2002-12-20 03:12:30 -0500 (Fri, 20 Dec 2002) New Revision: 716 Modified: trunk/ohci1394.c Log: couple of minor ohci1394 ISO DMA improvements Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-12-22 09:50:39.000000000 -0500 @@ -1104,7 +1104,10 @@ static void ohci_iso_recv_stop(struct hpsb_iso *iso) { struct ohci_iso_recv *recv = iso->hostdata; - + + /* disable interrupts */ + reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context); + /* halt DMA */ ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL); } @@ -1114,12 +1117,7 @@ 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); - + ohci_iso_recv_stop(iso); ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task); recv->task_active = 0; } @@ -1230,14 +1228,18 @@ } 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)); command |= 1; /* Z=1 */ - + reg_write(recv->ohci, recv->CommandPtr, command); + + /* enable interrupts */ + reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << recv->task.context); + wmb(); - + /* run */ reg_write(recv->ohci, recv->ContextControlSet, 0x8000); @@ -1446,11 +1448,6 @@ 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); - return 0; err: @@ -1461,7 +1458,17 @@ 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); + + /* disable interrupts */ + reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context); + + /* halt DMA */ + if(ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL)) { + /* XXX the DMA context will lock up if you try to send too much data! */ + PRINT(KERN_ERR, xmit->ohci->id, + "you probably exceeded the OHCI card's bandwidth limit - " + "reload the module and reduce xmit bandwidth"); + } } static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso) @@ -1469,12 +1476,7 @@ 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); - + ohci_iso_xmit_stop(iso); ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task); xmit->task_active = 0; } @@ -1544,7 +1546,7 @@ } } -static void ohci_iso_xmit_queue_one(struct hpsb_iso *iso) +static int ohci_iso_xmit_queue_one(struct hpsb_iso *iso) { struct ohci_iso_xmit *xmit = iso->hostdata; struct hpsb_iso_packet_info *info; @@ -1625,13 +1627,19 @@ /* increment cursors */ iso->first_packet = (iso->first_packet+1) % iso->buf_packets; atomic_inc(&iso->n_dma_packets); + + return 0; } -static void ohci_iso_xmit_queue(struct hpsb_iso *iso, int n_packets) +static int 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); + int i, ret; + for(i = 0; i < n_packets; i++) { + ret = ohci_iso_xmit_queue_one(iso); + if(ret) + return ret; + } + return 0; } static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle) @@ -1662,13 +1670,16 @@ reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16)); } + /* enable interrupts */ + reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << xmit->task.context); + /* 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 IT DMA (ContextControl 0x%08x)\n", @@ -1691,8 +1702,7 @@ ohci_iso_xmit_stop(iso); return 0; case XMIT_QUEUE: - ohci_iso_xmit_queue(iso, arg); - return 0; + return ohci_iso_xmit_queue(iso, arg); case XMIT_SHUTDOWN: ohci_iso_xmit_shutdown(iso); return 0; |
From: SVN U. <ano...@li...> - 2002-12-22 14:51:09
|
Author: anonymous Date: 2002-12-20 02:58:27 -0500 (Fri, 20 Dec 2002) New Revision: 715 Modified: trunk/ohci1394.c trunk/ohci1394.h Log: first little bit of multichannel ISO receive infrastructure Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-12-22 09:50:36.000000000 -0500 @@ -1780,7 +1780,7 @@ if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask) tasklet_schedule(&t->tasklet); - if (t->type == OHCI_ISO_RECEIVE && rx_event & mask) + else if (rx_event & mask) tasklet_schedule(&t->tasklet); } @@ -3025,7 +3025,7 @@ /* essentially the only purpose of this code is to allow another module to hook into ohci's interrupt handler */ -void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) +int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) { int i=0; @@ -3037,11 +3037,15 @@ i++; if (i>5000) { PRINT(KERN_ERR, ohci->id, - "Runaway loop while stopping context..."); - break; + "Runaway loop while stopping context: %s...", msg ? msg : ""); + return 1; } + + mb(); + udelay(10); } if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg); + return 0; } void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type, @@ -3067,6 +3071,13 @@ else { n = ohci->nb_iso_rcv_ctx; usage = &ohci->ir_ctx_usage; + + /* only one receive context can be multichannel (OHCI sec 10.4.1) */ + if(tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) { + if(test_and_set_bit(0, &ohci->ir_multichannel_used)) { + return r; + } + } } spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); @@ -3095,9 +3106,14 @@ if (tasklet->type == OHCI_ISO_TRANSMIT) clear_bit(tasklet->context, &ohci->it_ctx_usage); - else + else { clear_bit(tasklet->context, &ohci->ir_ctx_usage); + if(tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) { + clear_bit(0, &ohci->ir_multichannel_used); + } + } + list_del(&tasklet->link); spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2002-12-22 09:50:36.000000000 -0500 @@ -145,7 +145,8 @@ struct tasklet_struct tasklet; struct list_head link; int context; - enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE } type; + enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE, + OHCI_ISO_MULTICHANNEL_RECEIVE } type; }; struct ti_ohci { @@ -192,6 +193,7 @@ spinlock_t IR_channel_lock; int nb_iso_rcv_ctx; unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ + unsigned int ir_multichannel_used; /* ditto */ /* iso transmit */ struct dma_trm_ctx it_context; @@ -416,8 +418,8 @@ void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, struct ohci1394_iso_tasklet *tasklet); -void ohci1394_stop_context (struct ti_ohci *ohci, int reg, char *msg); +/* returns zero if successful, one if DMA context is locked up */ +int ohci1394_stop_context (struct ti_ohci *ohci, int reg, char *msg); struct ti_ohci *ohci1394_get_struct(int card_num); #endif - |