[Linux1394-cvslog] rev 561 - branches/rawiso
Brought to you by:
aeb,
bencollins
From: SVN U. <dm...@li...> - 2002-08-28 07:37:51
|
Author: dmaas Date: 2002-08-28 12:30:06 -0400 (Wed, 28 Aug 2002) New Revision: 561 Added: branches/rawiso/iso.c branches/rawiso/iso.h Modified: branches/rawiso/Makefile branches/rawiso/Makefile.in branches/rawiso/hosts.h branches/rawiso/ieee1394_core.c Log: added iso.c and iso.h (kernel ISO mid-layer) Added: branches/rawiso/iso.h ============================================================================== --- branches/rawiso/iso.h (original) +++ branches/rawiso/iso.h 2002-08-28 12:30:07.000000000 -0400 @@ -0,0 +1,131 @@ +/* + * IEEE 1394 for Linux + * + * kernel ISO transmission/reception + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#ifndef IEEE1394_ISO_H +#define IEEE1394_ISO_H + +#include "hosts.h" +#include "dma.h" + +/* high-level ISO interface */ + +/* per-packet data embedded in the ringbuffer */ +struct hpsb_iso_packet_info { + unsigned short len; + unsigned char channel; + unsigned char tag; + unsigned char tcode; + unsigned char sy; +}; + +enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 }; + +struct hpsb_iso { + enum hpsb_iso_type type; + + /* pointer to low-level driver and its private data */ + struct hpsb_host *host; + void *hostdata; + + /* pointer to a wait queue that will receive wakeups */ + wait_queue_head_t *waitq; + + int speed; /* SPEED_100, 200, or 400 */ + int channel; + + /* greatest # of packets between interrupts - controls + the maximum latency of the buffer */ + int irq_interval; + + /* the packet ringbuffer */ + struct dma_region buf; + + /* # of packets in the ringbuffer */ + unsigned int buf_packets; + + /* offset between successive packets - + you can assume that this is a power of 2, + and that packets will never cross a page boundary */ + int buf_stride; + + /* largest possible packet size, in bytes */ + unsigned int max_packet_size; + + /* offset relative to (buf.kvirt + pkt*buf_stride) at which + the data payload begins for each packet */ + int packet_data_offset; + + /* offset relative to beginning of packet at which a + struct hpsb_iso_packet_info is stored */ + int packet_info_offset; + + /* the index of the next packet that will be produced + or consumed by the user */ + int first_packet; + + /* number of packets owned by the low-level driver and + queued for transmission or reception. + this is related to the number of packets available + to the user process: n_ready = buf_packets - n_dma_packets */ + atomic_t n_dma_packets; + + /* how many times the buffer has overflowed or underflowed */ + atomic_t overflows; + + /* used for cycle matching */ + int first_packet_cycle; + + int driver_started; +}; + +/* functions available to high-level drivers (e.g. raw1394) */ + +/* allocate the buffer and DMA context - transmission will begin + at the first following call to xmit_produce() */ +struct hpsb_iso* hpsb_iso_xmit_start(struct hpsb_host *host, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int speed, + int irq_interval, + wait_queue_head_t *waitq); + +/* N packets have been written to the buffer and can be queued for transmission */ +int hpsb_iso_xmit_produce(struct hpsb_iso *xmit, unsigned int n_packets); + +/* halt transmission, deallocate buffer and DMA context */ +void hpsb_iso_xmit_stop(struct hpsb_iso *iso); + +/* allocate the buffer and DMA context, and start filling the buffer + with packets */ +struct hpsb_iso* hpsb_iso_recv_start(struct hpsb_host *host, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int irq_interval, + wait_queue_head_t *waitq); + +/* N packets have been read out of the buffer, re-use the buffer space */ +int hpsb_iso_recv_consume(struct hpsb_iso *recv, unsigned int n_packets); + +/* halt reception, deallocate buffer and DMA context */ +void hpsb_iso_recv_stop(struct hpsb_iso *iso); + +/* returns # of packets ready to send or receive */ +int hpsb_iso_n_ready(struct hpsb_iso *iso); + +/* returns a pointer to the payload of packet 'pkt' */ +unsigned char* hpsb_iso_packet_data(struct hpsb_iso *iso, unsigned int pkt); + +/* returns a pointer to the info struct of packet 'pkt' */ +struct hpsb_iso_packet_info* hpsb_iso_packet_info(struct hpsb_iso *iso, unsigned int pkt); + +#endif /* IEEE1394_ISO_H */ Modified: branches/rawiso/ieee1394_core.c ============================================================================== --- branches/rawiso/ieee1394_core.c (original) +++ branches/rawiso/ieee1394_core.c 2002-08-28 12:30:07.000000000 -0400 @@ -28,6 +28,7 @@ #include "hosts.h" #include "ieee1394_core.h" #include "highlevel.h" +#include "iso.h" #include "ieee1394_transactions.h" #include "csr.h" #include "nodemgr.h" @@ -1098,6 +1099,16 @@ EXPORT_SYMBOL(highlevel_remove_host); EXPORT_SYMBOL(highlevel_host_reset); +EXPORT_SYMBOL(hpsb_iso_xmit_start); +EXPORT_SYMBOL(hpsb_iso_xmit_produce); +EXPORT_SYMBOL(hpsb_iso_xmit_stop); +EXPORT_SYMBOL(hpsb_iso_recv_start); +EXPORT_SYMBOL(hpsb_iso_recv_consume); +EXPORT_SYMBOL(hpsb_iso_recv_stop); +EXPORT_SYMBOL(hpsb_iso_n_ready); +EXPORT_SYMBOL(hpsb_iso_packet_data); +EXPORT_SYMBOL(hpsb_iso_packet_info); + EXPORT_SYMBOL(hpsb_guid_get_entry); EXPORT_SYMBOL(hpsb_nodeid_get_entry); EXPORT_SYMBOL(hpsb_node_fill_packet); Modified: branches/rawiso/Makefile.in ============================================================================== --- branches/rawiso/Makefile.in (original) +++ branches/rawiso/Makefile.in 2002-08-28 12:30:07.000000000 -0400 @@ -4,7 +4,7 @@ expsyms(ieee1394_core.o ohci1394.o cmp.o dma.o) objlink(ieee1394.o ieee1394_core.o ieee1394_transactions.o hosts.o highlevel.o - csr.o nodemgr.o dma.o) + csr.o nodemgr.o dma.o iso.o) extra_cflags(sbp2.o $(src_includelist /drivers/scsi)) Modified: branches/rawiso/Makefile ============================================================================== --- branches/rawiso/Makefile (original) +++ branches/rawiso/Makefile 2002-08-28 12:30:07.000000000 -0400 @@ -8,7 +8,7 @@ list-multi := ieee1394.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ - highlevel.o csr.o nodemgr.o dma.o + highlevel.o csr.o nodemgr.o dma.o iso.o obj-$(CONFIG_IEEE1394) += ieee1394.o obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o Modified: branches/rawiso/hosts.h ============================================================================== --- branches/rawiso/hosts.h (original) +++ branches/rawiso/hosts.h 2002-08-28 12:30:07.000000000 -0400 @@ -9,8 +9,8 @@ #include "ieee1394_types.h" #include "csr.h" - struct hpsb_packet; +struct hpsb_iso; struct hpsb_host { struct list_head host_list; @@ -62,8 +62,6 @@ struct pci_dev *pdev; }; - - enum devctl_cmd { /* Host is requested to reset its bus and cancel all outstanding async * requests. If arg == 1, it shall also attempt to become root on the @@ -101,6 +99,18 @@ ISO_UNLISTEN_CHANNEL }; +enum isoctl_cmd { + /* see iso.h for the meanings of these commands */ + + XMIT_START, + XMIT_PRODUCE, + XMIT_STOP, + + RECV_START, + RECV_CONSUME, + RECV_STOP +}; + enum reset_types { /* 166 microsecond reset -- only type of reset available on non-1394a capable IEEE 1394 controllers */ @@ -138,6 +148,11 @@ */ int (*devctl) (struct hpsb_host *host, enum devctl_cmd command, int arg); + /* ISO transmission/reception functions. Return 0 on success, -1 on failure. + * If the low-level driver does not support the new ISO API, set isoctl to NULL. + */ + int (*isoctl) (struct hpsb_iso *iso, enum isoctl_cmd command, int arg); + /* This function is mainly to redirect local CSR reads/locks to the iso * management registers (bus manager id, bandwidth available, channels * available) to the hardware registers in OHCI. reg is 0,1,2,3 for bus Added: branches/rawiso/iso.c ============================================================================== --- branches/rawiso/iso.c (original) +++ branches/rawiso/iso.c 2002-08-28 12:30:07.000000000 -0400 @@ -0,0 +1,206 @@ +/* + * IEEE 1394 for Linux + * + * kernel ISO transmission/reception + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include "iso.h" + +static void hpsb_iso_common_stop(struct hpsb_iso *iso) +{ + if(iso->driver_started) { + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? XMIT_STOP : RECV_STOP, 0); + } + + dma_region_free(&iso->buf); + kfree(iso); +} + +static struct hpsb_iso* hpsb_iso_common_start(struct hpsb_host *host, enum hpsb_iso_type type, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int irq_interval, + wait_queue_head_t *waitq) +{ + struct hpsb_iso *iso; + unsigned int packet_plus_info; + int dma_direction; + + /* make sure driver supports the ISO API */ + if(!host->driver->isoctl) + return NULL; + + /* sanitize parameters */ + if(buf_packets < 2) + buf_packets = 2; + + if(irq_interval < 1 || irq_interval > buf_packets / 2) + irq_interval = buf_packets / 2; + + if(max_packet_size + sizeof(struct hpsb_iso_packet_info) > PAGE_SIZE) + return NULL; + + /* size of packet payload plus the per-packet info must be a power of 2 + and at most equal to the page size */ + + for(packet_plus_info = 256; packet_plus_info < PAGE_SIZE; packet_plus_info *= 2) { + if(packet_plus_info >= (max_packet_size + sizeof(struct hpsb_iso_packet_info))) { + break; + } + } + + /* allocate and write the struct hpsb_iso */ + + iso = kmalloc(sizeof(*iso), SLAB_KERNEL); + if(!iso) + return NULL; + + iso->type = type; + iso->host = host; + iso->hostdata = NULL; + iso->waitq = waitq; + iso->channel = channel; + iso->irq_interval = irq_interval; + dma_region_init(&iso->buf); + iso->buf_packets = buf_packets; + iso->buf_stride = packet_plus_info; + iso->max_packet_size = max_packet_size; + iso->packet_data_offset = 0; + iso->packet_info_offset = max_packet_size; + iso->first_packet = 0; + + if(iso->type == HPSB_ISO_XMIT) { + atomic_set(&iso->n_dma_packets, 0); + dma_direction = PCI_DMA_TODEVICE; + } else { + atomic_set(&iso->n_dma_packets, iso->buf_packets); + dma_direction = PCI_DMA_FROMDEVICE; + } + + atomic_set(&iso->overflows, 0); + iso->first_packet_cycle = 0; + iso->driver_started = 0; + + /* allocate the packet buffer */ + if(dma_region_alloc(&iso->buf, iso->buf_packets * iso->buf_stride, + host->pdev, dma_direction)) + goto err; + + return iso; + +err: + hpsb_iso_common_stop(iso); + return NULL; +} + +int hpsb_iso_n_ready(struct hpsb_iso* iso) +{ + return iso->buf_packets - atomic_read(&iso->n_dma_packets); +} + + +struct hpsb_iso* hpsb_iso_xmit_start(struct hpsb_host *host, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int speed, + int irq_interval, + wait_queue_head_t *waitq) +{ + struct hpsb_iso *iso = hpsb_iso_common_start(host, HPSB_ISO_XMIT, + buf_packets, max_packet_size, + channel, irq_interval, waitq); + if(!iso) + return NULL; + + iso->speed = speed; + + /* tell the driver to start working */ + if(host->driver->isoctl(iso, XMIT_START, 0)) + goto err; + + iso->driver_started = 1; + return iso; + +err: + hpsb_iso_common_stop(iso); + return NULL; +} + +struct hpsb_iso* hpsb_iso_recv_start(struct hpsb_host *host, + unsigned int buf_packets, + unsigned int max_packet_size, + int channel, + int irq_interval, + wait_queue_head_t *waitq) +{ + struct hpsb_iso *iso = hpsb_iso_common_start(host, HPSB_ISO_RECV, + buf_packets, max_packet_size, + channel, irq_interval, waitq); + if(!iso) + return NULL; + + /* tell the driver to start working */ + if(host->driver->isoctl(iso, RECV_START, 0)) + goto err; + + iso->driver_started = 1; + return iso; + +err: + hpsb_iso_common_stop(iso); + return NULL; +} + +void hpsb_iso_xmit_stop(struct hpsb_iso *iso) +{ + hpsb_iso_common_stop(iso); +} + +void hpsb_iso_recv_stop(struct hpsb_iso *iso) +{ + hpsb_iso_common_stop(iso); +} + +int hpsb_iso_xmit_produce(struct hpsb_iso *iso, unsigned int n_packets) +{ + int i; + int pkt = iso->first_packet; + + /* check packet sizes for sanity */ + for(i = 0; i < n_packets; i++) { + struct hpsb_iso_packet_info *info = hpsb_iso_packet_info(iso, pkt); + if(info->len > iso->max_packet_size) { + printk(KERN_ERR "hpsb_iso_xmit_produce: packet too long (%u, max is %u)\n", + info->len, iso->max_packet_size); + return -EINVAL; + } + + pkt = (pkt+1) % iso->buf_packets; + } + + return iso->host->driver->isoctl(iso, XMIT_PRODUCE, n_packets); +} + +int hpsb_iso_recv_consume(struct hpsb_iso *iso, unsigned int n_packets) +{ + return iso->host->driver->isoctl(iso, RECV_CONSUME, n_packets); +} + +unsigned char* hpsb_iso_packet_data(struct hpsb_iso *iso, unsigned int pkt) +{ + return (iso->buf.kvirt + pkt * iso->buf_stride) + iso->packet_data_offset; +} + +struct hpsb_iso_packet_info* hpsb_iso_packet_info(struct hpsb_iso *iso, unsigned int pkt) +{ + return (struct hpsb_iso_packet_info*) (iso->buf.kvirt + + pkt * iso->buf_stride + + iso->packet_info_offset); +} |