Thread: [Linux1394-cvslog] rev 749 - trunk
Brought to you by:
aeb,
bencollins
From: SVN U. <dm...@li...> - 2003-02-01 14:00:03
|
Author: dmaas Date: 2003-01-15 06:32:32 -0500 (Wed, 15 Jan 2003) New Revision: 749 Modified: trunk/ieee1394_core.c trunk/iso.c trunk/iso.h trunk/ohci1394.c trunk/raw1394.c trunk/raw1394.h Log: rawiso update - unify common code in iso.c and other housekeeping cleanups - no functionality changes Modified: trunk/iso.h ============================================================================== --- trunk/iso.h (original) +++ trunk/iso.h 2003-02-01 08:59:29.000000000 -0500 @@ -63,6 +63,9 @@ arrived */ void (*callback)(struct hpsb_iso*); + /* wait for buffer space */ + wait_queue_head_t waitq; + int speed; /* SPEED_100, 200, or 400 */ int channel; /* -1 if multichannel */ @@ -89,6 +92,10 @@ or consumed by the user */ int first_packet; + /* the index of the next packet that will be transmitted + or received by the 1394 hardware */ + int pkt_dma; + /* how many packets, starting at first_packet: (transmit) are ready to be filled with data (receive) contain received data */ @@ -146,8 +153,12 @@ /* deallocate buffer and DMA context */ void hpsb_iso_shutdown(struct hpsb_iso *iso); -/* N packets have been written to the buffer; queue them for transmission */ -int hpsb_iso_xmit_queue_packets(struct hpsb_iso *xmit, unsigned int n_packets); +/* queue a packet for transmission. 'offset' is relative to the beginning of the + DMA buffer, where the packet's data payload should already have been placed */ +int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy); + +/* wait until all queued packets have been transmitted to the bus */ +int hpsb_iso_xmit_sync(struct hpsb_iso *iso); /* N packets have been read out of the buffer, re-use the buffer space */ int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, unsigned int n_packets); @@ -155,10 +166,19 @@ /* returns # of packets ready to send or receive */ int hpsb_iso_n_ready(struct hpsb_iso *iso); -/* 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); +/* the following are callbacks available to low-level drivers */ + +/* call after a packet has been transmitted to the bus (interrupt context is OK) + 'cycle' is the _exact_ cycle the packet was sent on + 'error' should be non-zero if some sort of error occurred when sending the packet +*/ +void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error); + +/* call after a packet has been received (interrupt context OK) */ +void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, + u16 cycle, u8 channel, u8 tag, u8 sy); + +/* call to wake waiting processes after buffer space has opened up. */ +void hpsb_iso_wake(struct hpsb_iso *iso); #endif /* IEEE1394_ISO_H */ Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2003-02-01 08:59:29.000000000 -0500 @@ -1313,7 +1313,11 @@ 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_xmit_queue_packet); +EXPORT_SYMBOL(hpsb_iso_xmit_sync); EXPORT_SYMBOL(hpsb_iso_recv_release_packets); EXPORT_SYMBOL(hpsb_iso_n_ready); -EXPORT_SYMBOL(hpsb_iso_check_offset_len); +EXPORT_SYMBOL(hpsb_iso_packet_sent); +EXPORT_SYMBOL(hpsb_iso_packet_received); +EXPORT_SYMBOL(hpsb_iso_wake); + Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-01 08:59:29.000000000 -0500 @@ -1120,9 +1120,6 @@ /* 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; @@ -1175,24 +1172,19 @@ 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; + /* (err, sort of... 1 is always the safest value) */ + recv->block_irq_interval = iso->irq_interval / nblocks; 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 recv->block_reader = 0; recv->released_bytes = 0; 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 */ @@ -1553,7 +1545,6 @@ unsigned short len, cycle; unsigned char channel, tag, sy; - unsigned long flags; unsigned char *p = iso->data_buf.kvirt; unsigned int this_block = recv->dma_offset/PAGE_SIZE; @@ -1638,52 +1629,11 @@ 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--; - } - - } 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(); - - /* one more packet for the user, one less for us */ - recv->pkt_dma = (recv->pkt_dma + 1) % iso->buf_packets; - iso->n_ready_packets++; - - 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); + hpsb_iso_packet_received(iso, offset, len, cycle, channel, tag, sy); } - if(wake && iso->callback) - iso->callback(iso); + if(wake) + hpsb_iso_wake(iso); } static void ohci_iso_recv_task(unsigned long data) @@ -1757,7 +1707,6 @@ struct dma_prog_region prog; struct ohci1394_iso_tasklet task; int task_active; - int pkt_dma; u32 ContextControlSet; u32 ContextControlClear; @@ -1794,7 +1743,6 @@ iso->hostdata = xmit; xmit->ohci = iso->host->hostdata; xmit->task_active = 0; - xmit->pkt_dma = iso->first_packet; dma_prog_region_init(&xmit->prog); @@ -1859,17 +1807,15 @@ { 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++) { - + int cycle; + /* DMA descriptor */ - struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, xmit->pkt_dma); + struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma); /* check for new writes to xferStatus */ u16 xferstatus = cmd->output_last.status >> 16; @@ -1880,51 +1826,29 @@ break; } - if(event != 0x11) { - atomic_inc(&iso->overflows); - PRINT(KERN_ERR, xmit->ohci->id, "IT DMA error - OHCI error code 0x%02x\n", event); - } + if(event != 0x11) + PRINT(KERN_ERR, xmit->ohci->id, + "IT DMA error - OHCI error code 0x%02x\n", event); /* at least one packet went out, so wake up the writer */ wake = 1; /* parse cycle */ - { - unsigned int cycle = cmd->output_last.status & 0x1FFF; - - /* 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; - - iso->xmit_cycle = cycle; - } + cycle = cmd->output_last.status & 0x1FFF; + /* tell the subsystem the packet has gone out */ + hpsb_iso_packet_sent(iso, cycle, event != 0x11); + /* reset the DMA descriptor for next time */ cmd->output_last.status = 0; - - /* advance packet cursor */ - xmit->pkt_dma = (xmit->pkt_dma + 1) % iso->buf_packets; - iso->n_ready_packets += 1; - - if(iso->n_ready_packets == iso->buf_packets) { - /* underflow */ - atomic_inc(&iso->overflows); - } } - spin_unlock_irqrestore(&iso->lock, flags); - - if(wake && iso->callback) { - iso->callback(iso); - } + if(wake) + hpsb_iso_wake(iso); } -static int ohci_iso_xmit_queue_one(struct hpsb_iso *iso) +static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info) { - unsigned long flags; struct ohci_iso_xmit *xmit = iso->hostdata; int next_i, prev_i; @@ -1934,30 +1858,20 @@ 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; + /* check that the packet doesn't cross a page boundary + (we could allow this if we added OUTPUT_MORE descriptor support) */ + if(cross_bound(info->offset, info->len)) { + PRINT(KERN_ERR, xmit->ohci->id, + "rawiso xmit: packet %u crosses a page boundary", + iso->first_packet); + return -EINVAL; } + offset = info->offset; + len = info->len; + tag = info->tag; + sy = info->sy; + /* sync up the card's view of the buffer */ dma_region_sync(&iso->data_buf, offset, len); @@ -2025,24 +1939,6 @@ mb(); reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer); - /* increment cursors */ - spin_lock_irqsave(&iso->lock, flags); - 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(&iso->lock, flags); - - return 0; -} - -static int ohci_iso_xmit_queue(struct hpsb_iso *iso, int n_packets) -{ - int i, ret; - for(i = 0; i < n_packets; i++) { - ret = ohci_iso_xmit_queue_one(iso); - if(ret) - return ret; - } return 0; } @@ -2056,7 +1952,7 @@ /* address and length of first descriptor block (Z=3) */ reg_write(xmit->ohci, xmit->CommandPtr, - dma_prog_region_offset_to_bus(&xmit->prog, xmit->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3); + dma_prog_region_offset_to_bus(&xmit->prog, iso->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3); /* cycle match */ if(cycle != -1) { @@ -2101,12 +1997,12 @@ case XMIT_INIT: return ohci_iso_xmit_init(iso); case XMIT_START: - return ohci_iso_xmit_start(iso, arg < 8000 ? arg : -1); + return ohci_iso_xmit_start(iso, arg); case XMIT_STOP: ohci_iso_xmit_stop(iso); return 0; case XMIT_QUEUE: - return ohci_iso_xmit_queue(iso, arg); + return ohci_iso_xmit_queue(iso, (struct hpsb_iso_packet_info*) arg); case XMIT_SHUTDOWN: ohci_iso_xmit_shutdown(iso); return 0; Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2003-02-01 08:59:30.000000000 -0500 @@ -2180,8 +2180,7 @@ 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; + int i, rv; if(copy_from_user(&upackets, uaddr, sizeof(upackets))) return -EFAULT; @@ -2194,17 +2193,21 @@ upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) return -EFAULT; - /* copy the packet_infos in */ + /* copy the infos structs in and queue the packets */ for(i = 0; i < upackets.n_packets; i++) { - if(__copy_from_user(&fi->iso_handle->infos[packet], - &upackets.infos[i], + struct raw1394_iso_packet_info info; + + if(__copy_from_user(&info, &upackets.infos[i], sizeof(struct raw1394_iso_packet_info))) return -EFAULT; - - packet = (packet + 1) % fi->iso_handle->buf_packets; + + rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset, + info.len, info.tag, info.sy); + if(rv) + return rv; } - return hpsb_iso_xmit_queue_packets(fi->iso_handle, upackets.n_packets); + return 0; } static void raw1394_iso_shutdown(struct file_info *fi) @@ -2289,6 +2292,8 @@ return -EFAULT; return hpsb_iso_xmit_start(fi->iso_handle, args[0], args[1]); } + case RAW1394_ISO_XMIT_SYNC: + return hpsb_iso_xmit_sync(fi->iso_handle); case RAW1394_ISO_STOP: hpsb_iso_stop(fi->iso_handle); return 0; Modified: trunk/raw1394.h ============================================================================== --- trunk/raw1394.h (original) +++ trunk/raw1394.h 2003-02-01 08:59:30.000000000 -0500 @@ -133,7 +133,8 @@ #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* */ - +#define RAW1394_ISO_XMIT_SYNC 16 + /* per-packet metadata embedded in the ringbuffer */ /* must be identical to hpsb_iso_packet_info in iso.h! */ struct raw1394_iso_packet_info { Modified: trunk/iso.c ============================================================================== --- trunk/iso.c (original) +++ trunk/iso.c 2003-02-01 08:59:30.000000000 -0500 @@ -80,11 +80,13 @@ iso->host = host; iso->hostdata = NULL; iso->callback = callback; + init_waitqueue_head(&iso->waitq); iso->channel = channel; iso->irq_interval = irq_interval; dma_region_init(&iso->data_buf); iso->buf_size = round_up_to_page(data_buf_size); iso->buf_packets = buf_packets; + iso->pkt_dma = 0; iso->first_packet = 0; spin_lock_init(&iso->lock); @@ -223,7 +225,9 @@ iso->xmit_cycle = cycle; - if(prebuffer < 1) + if(prebuffer < 0) + prebuffer = iso->buf_packets; + else if(prebuffer == 0) prebuffer = 1; if(prebuffer > iso->buf_packets) @@ -271,60 +275,148 @@ return retval; } -int hpsb_iso_xmit_queue_packets(struct hpsb_iso *iso, unsigned int n_packets) +/* check to make sure the user has not supplied bogus values of offset/len + that would cause the kernel to access memory outside the buffer */ + +static int hpsb_iso_check_offset_len(struct hpsb_iso *iso, + unsigned int offset, unsigned short len, + unsigned int *out_offset, unsigned short *out_len) { - int retval; + if(offset >= iso->buf_size) + return -EFAULT; + + /* make sure the packet does not go beyond the end of the buffer */ + if(offset + len > iso->buf_size) + return -EFAULT; + + /* check for wrap-around */ + if(offset + len < offset) + return -EFAULT; + + /* now we can trust 'offset' and 'length' */ + *out_offset = offset; + *out_len = len; + + return 0; +} + + +int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy) +{ + struct hpsb_iso_packet_info *info; + unsigned long flags; + int rv; if(iso->type != HPSB_ISO_XMIT) - return -1; + return -EINVAL; - retval = iso->host->driver->isoctl(iso, XMIT_QUEUE, n_packets); - if(retval) - return retval; + /* is there space in the buffer? */ + if(iso->n_ready_packets <= 0) { + return -EBUSY; + } + + info = &iso->infos[iso->first_packet]; + + /* check for bogus offset/length */ + if(hpsb_iso_check_offset_len(iso, offset, len, &info->offset, &info->len)) + return -EFAULT; + + info->tag = tag; + info->sy = sy; + + spin_lock_irqsave(&iso->lock, flags); + + rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long) info); + if(rv) + goto out; + + /* increment cursors */ + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + iso->xmit_cycle = (iso->xmit_cycle+1) % 8000; + iso->n_ready_packets--; if(iso->prebuffer != 0) { - iso->prebuffer -= n_packets; + iso->prebuffer--; if(iso->prebuffer <= 0) { iso->prebuffer = 0; - return do_iso_xmit_start(iso, - iso->start_cycle); + rv = do_iso_xmit_start(iso, iso->start_cycle); } } - return 0; +out: + spin_unlock_irqrestore(&iso->lock, flags); + return rv; } -int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) +int hpsb_iso_xmit_sync(struct hpsb_iso *iso) { - if(iso->type != HPSB_ISO_RECV) - return -1; + if(iso->type != HPSB_ISO_XMIT) + return -EINVAL; - return iso->host->driver->isoctl(iso, RECV_RELEASE, n_packets); + return wait_event_interruptible(iso->waitq, hpsb_iso_n_ready(iso) == iso->buf_packets); } -int hpsb_iso_check_offset_len(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info, - unsigned int *out_offset, unsigned short *out_len) +void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error) { - unsigned int offset, len; + unsigned long flags; + spin_lock_irqsave(&iso->lock, flags); - offset = info->offset; + /* predict the cycle of the next packet to be queued */ - if(offset >= iso->buf_size) - return -EFAULT; + /* jump ahead by the number of packets that are already buffered */ + cycle += iso->buf_packets - iso->n_ready_packets; + cycle %= 8000; - len = info->len; + iso->xmit_cycle = cycle; + iso->n_ready_packets++; + iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets; - /* make sure the packet does not go beyond the end of the buffer */ - if(offset + len > iso->buf_size) - return -EFAULT; + if(iso->n_ready_packets == iso->buf_packets || error != 0) { + /* the buffer has run empty! */ + atomic_inc(&iso->overflows); + } - /* check for wrap-around */ - if(offset + len < offset) - return -EFAULT; + spin_unlock_irqrestore(&iso->lock, flags); +} - /* now we can trust 'offset' and 'length' */ - *out_offset = offset; - *out_len = len; +void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, + u16 cycle, u8 channel, u8 tag, u8 sy) +{ + unsigned long flags; + spin_lock_irqsave(&iso->lock, flags); - return 0; + if(iso->n_ready_packets == iso->buf_packets) { + /* overflow! */ + atomic_inc(&iso->overflows); + return; + } else { + struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma]; + info->offset = offset; + info->len = len; + info->cycle = cycle; + info->channel = channel; + info->tag = tag; + info->sy = sy; + + iso->pkt_dma = (iso->pkt_dma+1) % iso->buf_packets; + iso->n_ready_packets++; + } + + spin_unlock_irqrestore(&iso->lock, flags); +} + +int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) +{ + if(iso->type != HPSB_ISO_RECV) + return -1; + + return iso->host->driver->isoctl(iso, RECV_RELEASE, n_packets); +} + +void hpsb_iso_wake(struct hpsb_iso *iso) +{ + wake_up_interruptible(&iso->waitq); + + if(iso->callback) + iso->callback(iso); } |