linux1394-cvslog Mailing List for IEEE 1394 for Linux (Page 13)
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. <hog...@li...> - 2002-09-12 19:13:15
|
Author: hogsberg Date: 2002-09-13 00:01:18 -0400 (Fri, 13 Sep 2002) New Revision: 568 Modified: trunk/video1394.c Log: Fix typo in page align computation, reported by Kurt Konolige, Modified: trunk/video1394.c ============================================================================== --- trunk/video1394.c (original) +++ trunk/video1394.c 2002-09-13 00:01:19.000000000 -0400 @@ -237,7 +237,8 @@ DBGMSG(d->ohci->id, "Freeing dma_iso_ctx %d", d->ctx); ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet); + 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); @@ -277,8 +278,7 @@ struct dma_iso_ctx *d; int i; - d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx), - GFP_KERNEL); + d = kmalloc(sizeof(struct dma_iso_ctx), GFP_KERNEL); if (d == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_iso_ctx"); return NULL; @@ -291,7 +291,7 @@ d->channel = channel; d->num_desc = num_desc; d->frame_size = buf_size; - d->buf_size = (d->buf_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + d->buf_size = PAGE_ALIGN(buf_size); d->last_buffer = -1; d->buf = NULL; d->ir_prg = NULL; |
From: SVN U. <ben...@li...> - 2002-08-28 12:12:47
|
Author: bencollins Date: 2002-08-28 17:04:59 -0400 (Wed, 28 Aug 2002) New Revision: 567 Removed: tags/v2.5/2.5.31/ Log: Still no merge from Linus. Maybe we'll get 2.5.33 |
From: SVN U. <ben...@li...> - 2002-08-28 12:07:30
|
Author: bencollins Date: 2002-08-28 16:59:39 -0400 (Wed, 28 Aug 2002) New Revision: 566 Removed: branch-points/ Modified: branches/gasp/nodemgr.c branches/rawiso/ Log: We aren't using a branch-point directory anymore. We're using a "branch-point" property set on the branched directory. Like so: # svn copy trunk branches/mybranch (note rev copied from) # svn propset branch-point <rev> branches/mybranch # svn commit -m "Created 'mybranch'" Then you can query the branch-point using propget. Modified: branches/gasp/nodemgr.c ============================================================================== --- branches/gasp/nodemgr.c (original) +++ branches/gasp/nodemgr.c 2002-08-28 16:59:41.000000000 -0400 @@ -79,7 +79,7 @@ #define PUTF(fmt, args...) out += sprintf(out, fmt, ## args) -static int raw1394_read_proc(char *page, char **start, off_t off, +static int hpsb_devices_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { struct list_head *lh; @@ -178,7 +178,32 @@ return len; } +static int hpsb_devices_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct list_head *lh; + struct node_entry *ne; + int len; + char *out = page; + + PUTF("Not implemented yet\n"); + + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + + *start = page + off; + + return len; +} + #undef PUTF + #endif /* CONFIG_PROC_FS */ static void nodemgr_process_config_rom(struct node_entry *ne, @@ -1424,14 +1449,15 @@ static struct hpsb_highlevel *hl; -#define PROC_ENTRY "devices" - void init_ieee1394_nodemgr(int disable_hotplug) { nodemgr_disable_hotplug = disable_hotplug; #ifdef CONFIG_PROC_FS - if (!create_proc_read_entry(PROC_ENTRY, 0444, ieee1394_procfs_entry, raw1394_read_proc, NULL)) - HPSB_ERR("Can't create devices procfs entry"); + if (!create_proc_read_entry("devices", 0444, ieee1394_procfs_entry, + hpsb_devices_read_proc, NULL) || + !create_proc_read_entry("channels", 0444, ieee1394_procfs_entry, + hpsb_channels_read_proc, NULL)) + HPSB_ERR("Can't create procfs entries"); #endif hl = hpsb_register_highlevel("Node manager", &nodemgr_ops); if (!hl) { @@ -1443,6 +1469,7 @@ { hpsb_unregister_highlevel(hl); #ifdef CONFIG_PROC_FS - remove_proc_entry(PROC_ENTRY, ieee1394_procfs_entry); + remove_proc_entry("devices", ieee1394_procfs_entry); + remove_proc_entry("channels", ieee1394_procfs_entry); #endif } |
From: SVN U. <dm...@li...> - 2002-08-28 08:01:26
|
Author: dmaas Date: 2002-08-28 12:53:42 -0400 (Wed, 28 Aug 2002) New Revision: 565 Modified: branches/rawiso/amdtp.c branches/rawiso/cmp.c branches/rawiso/cmp.h Log: cmp hacks to get MPEG transmission working... this really belongs in user space Modified: branches/rawiso/amdtp.c ============================================================================== --- branches/rawiso/amdtp.c (original) +++ branches/rawiso/amdtp.c 2002-08-28 12:53:43.000000000 -0400 @@ -972,7 +972,7 @@ switch(cmd) { case AMDTP_IOC_PLUG: s->opcr = cmp_register_opcr(s->host->host, cfg->u.plug, - /*payload*/ 12, plug_update, s); + /*payload*/ 12, SPEED_100, plug_update, s); if (s->opcr == NULL) return -EINVAL; s->iso_channel = s->opcr->channel; Modified: branches/rawiso/cmp.c ============================================================================== --- branches/rawiso/cmp.c (original) +++ branches/rawiso/cmp.c 2002-08-28 12:53:43.000000000 -0400 @@ -104,7 +104,8 @@ } struct cmp_pcr * -cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload, +cmp_register_opcr(struct hpsb_host *host, int opcr_number, + int payload, int speed, void (*update)(struct cmp_pcr *pcr, void *data), void *data) { @@ -121,6 +122,7 @@ plug->u.pcr.online = 1; plug->u.pcr.bcast_count = 0; plug->u.pcr.p2p_count = 0; + plug->u.pcr.speed = speed; plug->u.pcr.overhead = 0; plug->u.pcr.payload = payload; plug->update = update; @@ -135,9 +137,13 @@ struct plug *plug; ch = lookup_cmp_host(host); - plug = (struct plug *)opcr; - if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG(); + /* XXXDJM */ + //plug = (struct plug *)opcr; + //if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG(); + plug = &ch->opcr[0]; + /* XXXDJM */ + plug->u.pcr.online = 0; plug->update = NULL; } @@ -165,7 +171,7 @@ } memset(ch, 0, sizeof *ch); ch->host = host; - ch->u.ompr.rate = SPEED_100; + ch->u.ompr.rate = SPEED_200; ch->u.ompr.bcast_channel_base = 63; ch->u.ompr.nplugs = 2; reset_plugs(ch); @@ -173,6 +179,15 @@ spin_lock_irq(&host_list_lock); list_add_tail(&ch->link, &host_list); spin_unlock_irq(&host_list_lock); + + /* XXXDJM */ + { + struct cmp_pcr *opcr = cmp_register_opcr(host, 0, 146, SPEED_200, NULL, NULL); + if(opcr) { + printk("register opcr: channel %d\n", opcr->channel); + } + } + /* XXXDJM */ } static void cmp_host_reset(struct hpsb_host *host) @@ -188,6 +203,11 @@ { struct cmp_host *ch; + /* XXXDJM */ + printk("unregister opcr\n"); + cmp_unregister_opcr(host, NULL); + /* XXXDJM */ + ch = lookup_cmp_host(host); if (ch == NULL) BUG(); Modified: branches/rawiso/cmp.h ============================================================================== --- branches/rawiso/cmp.h (original) +++ branches/rawiso/cmp.h 2002-08-28 12:53:43.000000000 -0400 @@ -22,7 +22,7 @@ } __attribute__((packed)); struct cmp_pcr *cmp_register_opcr(struct hpsb_host *host, int plug, - int payload, + int payload, int speed, void (*update)(struct cmp_pcr *plug, void *data), void *data); |
From: SVN U. <dm...@li...> - 2002-08-28 07:54:19
|
Author: dmaas Date: 2002-08-28 12:46:35 -0400 (Wed, 28 Aug 2002) New Revision: 564 Added: branches/rawiso/_libraw1394_patch Log: include the libraw1394 patch to expose the new ISO API Added: branches/rawiso/_libraw1394_patch ============================================================================== --- branches/rawiso/_libraw1394_patch (original) +++ branches/rawiso/_libraw1394_patch 2002-08-28 12:46:36.000000000 -0400 @@ -0,0 +1,413 @@ +diff -ru libraw1394/src/eventloop.c libraw1394-iso/src/eventloop.c +--- libraw1394/src/eventloop.c Sun May 13 21:02:10 2001 ++++ libraw1394-iso/src/eventloop.c Mon Aug 26 13:21:07 2002 +@@ -11,16 +11,58 @@ + #include <config.h> + #include <unistd.h> + #include <byteswap.h> ++#include <sys/poll.h> + + #include "raw1394.h" + #include "kernel-raw1394.h" + #include "raw1394_private.h" + ++/* ++ This is a bit complicated because the read/write interface and the ISO ++ interface are essentially two independent streams of input. ++ ++ poll() will return POLLIN or POLLOUT for pending read activity, and ++ POLLPRI for pending ISO activity. ++ ++ do_poll() returns 1 if there are pending events to read(), ++ 0 if there are no events, and -1 on error. ++*/ ++ ++static int do_poll(struct raw1394_handle *handle) ++{ ++ struct pollfd pfd[1]; ++ ++ pfd[0].fd = handle->fd; ++ pfd[0].events = POLLIN | POLLOUT | POLLPRI; ++ pfd[0].revents = 0; ++ ++ while(1) { ++ int ret = poll(pfd, 1, -1); ++ if(ret > 0) { ++ break; ++ } else if(ret < 0) { ++ return -1; ++ } ++ } ++ ++ if(pfd[0].revents & (POLLIN | POLLOUT)) { ++ return 1; ++ } ++ ++ return 0; ++} + + int raw1394_loop_iterate(struct raw1394_handle *handle) + { + struct raw1394_request *req = &handle->req; + int retval = 0, channel; ++ ++ int read_events = do_poll(handle); ++ if(read_events < 0) ++ return -1; ++ ++ if(read_events == 0) ++ return 0; + + if (read(handle->fd, req, sizeof(*req)) < 0) { + return -1; +diff -ru libraw1394/src/iso.c libraw1394-iso/src/iso.c +--- libraw1394/src/iso.c Sun Sep 10 18:18:49 2000 ++++ libraw1394-iso/src/iso.c Wed Aug 28 01:08:10 2002 +@@ -11,11 +11,15 @@ + #include <config.h> + #include <errno.h> + #include <unistd.h> ++#include <string.h> ++#include <sys/ioctl.h> ++#include <sys/mman.h> + + #include "raw1394.h" + #include "kernel-raw1394.h" + #include "raw1394_private.h" + ++/* old ISO API */ + + static int do_iso_listen(struct raw1394_handle *handle, int channel) + { +@@ -72,3 +76,104 @@ + + return do_iso_listen(handle, ~channel); + } ++ ++ ++ ++/* new ISO API */ ++ ++static int do_iso_start(raw1394handle_t handle, struct raw1394_iso_config *config, int xmit) ++{ ++ struct raw1394_kernel_iso_status kstat; ++ size_t pgsize; ++ ++ kstat.config.buf_packets = config->buf_packets; ++ kstat.config.max_packet_size = config->max_packet_size; ++ kstat.config.channel = config->channel; ++ kstat.config.speed = config->speed; ++ kstat.config.irq_interval = config->irq_interval; ++ ++ if(ioctl(handle->fd, xmit ? RAW1394_ISO_START_XMIT : RAW1394_ISO_START_RECV, &kstat.config)) ++ return -1; ++ ++ if(ioctl(handle->fd, RAW1394_ISO_GET_STATUS, &kstat)) ++ return -1; ++ ++ handle->iso_buffer_bytes = kstat.config.buf_packets * kstat.buf_stride; ++ ++ /* make sure buffer is a multiple of the page size */ ++ pgsize = getpagesize(); ++ if(handle->iso_buffer_bytes % pgsize) ++ handle->iso_buffer_bytes += pgsize - (handle->iso_buffer_bytes % pgsize); ++ ++ handle->iso_buffer = mmap(NULL, handle->iso_buffer_bytes, PROT_READ | PROT_WRITE, ++ MAP_SHARED, handle->fd, 0); ++ ++ if(handle->iso_buffer == (unsigned char*) MAP_FAILED) { ++ handle->iso_buffer = NULL; ++ raw1394_iso_stop(handle); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++void raw1394_iso_stop(raw1394handle_t handle) ++{ ++ if(handle->iso_buffer) { ++ munmap(handle->iso_buffer, handle->iso_buffer_bytes); ++ handle->iso_buffer = NULL; ++ } ++ ++ ioctl(handle->fd, RAW1394_ISO_STOP, 0); ++} ++ ++int raw1394_iso_xmit_start(raw1394handle_t handle, struct raw1394_iso_config *config) ++{ ++ return do_iso_start(handle, config, 1); ++} ++ ++int raw1394_iso_recv_start(raw1394handle_t handle, struct raw1394_iso_config *config) ++{ ++ return do_iso_start(handle, config, 0); ++} ++ ++int raw1394_iso_get_status(raw1394handle_t handle, struct raw1394_iso_status *stat) ++{ ++ struct raw1394_kernel_iso_status kstat; ++ int err; ++ ++ err = ioctl(handle->fd, RAW1394_ISO_GET_STATUS, &kstat); ++ if(err != 0) ++ return err; ++ ++ /* mediate between user and kernel versions of the structure */ ++ stat->config.buf_packets = kstat.config.buf_packets; ++ stat->config.max_packet_size = kstat.config.max_packet_size; ++ stat->config.channel = kstat.config.channel; ++ stat->config.speed = kstat.config.speed; ++ stat->config.irq_interval = kstat.config.irq_interval; ++ ++ stat->buf = handle->iso_buffer; ++ stat->buf_stride = kstat.buf_stride; ++ stat->packet_data_offset = kstat.packet_data_offset; ++ stat->packet_info_offset = kstat.packet_info_offset; ++ stat->first_packet = kstat.first_packet; ++ stat->n_packets = kstat.n_packets; ++ stat->overflows = kstat.overflows; ++ stat->first_packet_cycle = kstat.first_packet_cycle; ++ ++ return 0; ++} ++ ++int raw1394_iso_xmit_produce(raw1394handle_t handle, unsigned int n_packets) ++{ ++ if(!n_packets) return 0; ++ return ioctl(handle->fd, RAW1394_ISO_PRODUCE_CONSUME, n_packets); ++} ++ ++int raw1394_iso_recv_consume(raw1394handle_t handle, unsigned int n_packets) ++{ ++ if(!n_packets) return 0; ++ return ioctl(handle->fd, RAW1394_ISO_PRODUCE_CONSUME, n_packets); ++} ++ +diff -ru libraw1394/src/kernel-raw1394.h libraw1394-iso/src/kernel-raw1394.h +--- libraw1394/src/kernel-raw1394.h Mon Aug 7 20:29:08 2000 ++++ libraw1394-iso/src/kernel-raw1394.h Wed Aug 28 03:50:43 2002 +@@ -69,6 +69,57 @@ + __u8 name[32]; + }; + ++/* new ISO API */ ++ ++/* ioctls */ ++#define RAW1394_ISO_START_XMIT 1 ++#define RAW1394_ISO_START_RECV 2 ++#define RAW1394_ISO_GET_STATUS 3 ++#define RAW1394_ISO_STOP 4 ++#define RAW1394_ISO_PRODUCE_CONSUME 5 ++ ++/* argument to RAW1394_ISO_START_RECV, XMIT */ ++struct raw1394_kernel_iso_config { ++ unsigned int buf_packets; ++ unsigned int max_packet_size; ++ int channel; ++ int speed; /* xmit only */ ++ int irq_interval; ++}; ++ ++struct raw1394_kernel_iso_status { ++ /* current settings */ ++ struct raw1394_kernel_iso_config config; ++ ++ /* byte offset between successive packets in the buffer */ ++ int buf_stride; ++ ++ /* byte offset of data payload within each packet */ ++ int packet_data_offset; ++ ++ /* byte offset of struct iso_packet_info within each packet */ ++ int packet_info_offset; ++ ++ /* index of next packet to fill with data (ISO transmission) ++ or next packet containing data recieved (ISO reception) */ ++ unsigned int first_packet; ++ ++ /* number of packets waiting to be filled with data (ISO transmission) ++ or containing data received (ISO reception) */ ++ unsigned int n_packets; ++ ++ /* approximate number of packets dropped due to overflow or ++ underflow of the packet buffer (a value of zero guarantees ++ that no packets have been dropped) */ ++ unsigned int overflows; ++ ++ /* the value the ISO CYCLE_COUNT register will have when the first_packet ++ is sent (ISO transmission) or received (ISO reception). ++ set to -1 if you don't care about cycle matching. ++ */ ++ int first_packet_cycle; ++}; ++ + #ifdef __KERNEL__ + + struct iso_block_store { +@@ -77,6 +128,10 @@ + quadlet_t data[0]; + }; + ++enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0, ++ RAW1394_ISO_RECV = 1, ++ RAW1394_ISO_XMIT = 2 }; ++ + struct file_info { + struct list_head list; + +@@ -93,9 +148,14 @@ + + u8 *fcp_buffer; + ++ /* old ISO API */ + u64 listen_channels; + quadlet_t *iso_buffer; + size_t iso_buffer_length; ++ ++ /* new ISO API */ ++ enum raw1394_iso_state iso_state; ++ struct hpsb_iso *iso_handle; + }; + + struct pending_request { +diff -ru libraw1394/src/main.c libraw1394-iso/src/main.c +--- libraw1394/src/main.c Sun May 13 21:02:10 2001 ++++ libraw1394-iso/src/main.c Mon Aug 26 01:23:02 2002 +@@ -104,12 +104,18 @@ + handle->bus_reset_handler = bus_reset_default; + handle->tag_handler = tag_handler_default; + memset(handle->iso_handler, 0, sizeof(handle->iso_handler)); ++ handle->iso_buffer = NULL; ++ handle->iso_buffer_bytes = 0; ++ + return handle; + } + + void raw1394_destroy_handle(struct raw1394_handle *handle) + { + if (handle) { ++ if(handle->iso_buffer) { ++ raw1394_iso_stop(handle); ++ } + close(handle->fd); + free(handle); + } +diff -ru libraw1394/src/raw1394.h libraw1394-iso/src/raw1394.h +--- libraw1394/src/raw1394.h Sun May 13 21:02:10 2001 ++++ libraw1394-iso/src/raw1394.h Wed Aug 28 01:14:57 2002 +@@ -212,6 +212,101 @@ + */ + const char *raw1394_get_libversion(void); + ++ ++enum raw1394_iso_speed { ++ RAW1394_ISO_SPEED_100 = 0, ++ RAW1394_ISO_SPEED_200 = 1, ++ RAW1394_ISO_SPEED_400 = 2, ++}; ++ ++ ++struct raw1394_iso_config { ++ /* total number of packets in the buffer */ ++ unsigned int buf_packets; ++ ++ /* largest possible packet, in bytes */ ++ unsigned int max_packet_size; ++ ++ /* ISO channel */ ++ int channel; ++ ++ /* speed (transmission only) */ ++ enum raw1394_iso_speed speed; ++ ++ /* max latency of buffer, # of packets (-1 to get a default) */ ++ int irq_interval; ++}; ++ ++struct raw1394_iso_status { ++ /* current settings */ ++ struct raw1394_iso_config config; ++ ++ /* address of the packet buffer (first byte of first packet) */ ++ unsigned char *buf; ++ ++ /* byte offset between successive packets in the buffer */ ++ unsigned int buf_stride; ++ ++ /* byte offset of payload data within each packet */ ++ unsigned int packet_data_offset; ++ ++ /* byte offset of packet length within each packet */ ++ unsigned int packet_info_offset; ++ ++ /* index of next packet to fill with data (ISO transmission) ++ or next packet containing data recieved (ISO reception) */ ++ unsigned int first_packet; ++ ++ /* number of packets waiting to be filled with data (ISO transmission) ++ or containing data received (ISO reception) */ ++ unsigned int n_packets; ++ ++ /* approximate number of packets dropped due to overflow or ++ underflow of the packet buffer (a value of zero guarantees ++ that no packets have been dropped) */ ++ unsigned int overflows; ++ ++ /* the value the ISO CYCLE_COUNT register will have when the first_packet ++ is sent (ISO transmission) or received (ISO reception). ++ set to -1 if you don't care about cycle matching. ++ */ ++ int first_packet_cycle; ++}; ++ ++/* per-packet info embedded in the packet buffer */ ++struct raw1394_iso_packet_info { ++ unsigned short len; ++ unsigned char channel; /* receive only */ ++ unsigned char tag; ++ unsigned char tcode; /* receive only */ ++ unsigned char sy; ++}; ++ ++static inline struct raw1394_iso_packet_info* ++raw1394_iso_packet_info(struct raw1394_iso_status *stat, unsigned int index) ++{ ++ /* XXX make internal */ ++ return (struct raw1394_iso_packet_info*) (stat->buf + index * stat->buf_stride ++ + stat->packet_info_offset); ++} ++ ++static inline unsigned char* ++raw1394_iso_packet_data(struct raw1394_iso_status *stat, unsigned int index) ++{ ++ /* XXX make internal */ ++ return (stat->buf + index * stat->buf_stride + stat->packet_data_offset); ++} ++ ++int raw1394_iso_xmit_start(raw1394handle_t handle, struct raw1394_iso_config *config); ++int raw1394_iso_recv_start(raw1394handle_t handle, struct raw1394_iso_config *config); ++ ++int raw1394_iso_get_status(raw1394handle_t handle, struct raw1394_iso_status *status); ++ ++int raw1394_iso_xmit_produce(raw1394handle_t handle, unsigned int n_packets); ++int raw1394_iso_recv_consume(raw1394handle_t handle, unsigned int n_packets); ++ ++void raw1394_iso_stop(raw1394handle_t handle); ++ + #ifdef __cplusplus + } + #endif +diff -ru libraw1394/src/raw1394_private.h libraw1394-iso/src/raw1394_private.h +--- libraw1394/src/raw1394_private.h Thu Jan 18 20:08:19 2001 ++++ libraw1394-iso/src/raw1394_private.h Mon Aug 26 01:21:55 2002 +@@ -19,6 +19,9 @@ + fcp_handler_t fcp_handler; + iso_handler_t iso_handler[64]; + ++ unsigned char *iso_buffer; ++ unsigned long iso_buffer_bytes; ++ + struct raw1394_request req; + quadlet_t buffer[2048]; + }; |
From: SVN U. <dm...@li...> - 2002-08-28 07:46:30
|
Author: dmaas Date: 2002-08-28 12:38:46 -0400 (Wed, 28 Aug 2002) New Revision: 563 Modified: branches/rawiso/raw1394.c branches/rawiso/raw1394.h Log: expose new ISO API through raw1394 Modified: branches/rawiso/raw1394.c ============================================================================== --- branches/rawiso/raw1394.c (original) +++ branches/rawiso/raw1394.c 2002-08-28 12:38:47.000000000 -0400 @@ -28,6 +28,7 @@ #include "ieee1394_core.h" #include "hosts.h" #include "highlevel.h" +#include "iso.h" #include "ieee1394_transactions.h" #include "raw1394.h" @@ -892,19 +893,168 @@ return retval; } +/* ISO operations */ + +static int raw1394_iso_start_xmit(struct file_info *fi, void *uaddr) +{ + struct raw1394_kernel_iso_config config; + + if(copy_from_user(&config, uaddr, sizeof(config))) + return -EFAULT; + + fi->iso_handle = hpsb_iso_xmit_start(fi->host, + config.buf_packets, + config.max_packet_size, + config.channel, + config.speed, + config.irq_interval, + &fi->poll_wait_complete); + if(!fi->iso_handle) + return -ENOMEM; + + fi->iso_state = RAW1394_ISO_XMIT; + return 0; +} + +static int raw1394_iso_start_recv(struct file_info *fi, void *uaddr) +{ + struct raw1394_kernel_iso_config config; + + if(copy_from_user(&config, uaddr, sizeof(config))) + return -EFAULT; + + fi->iso_handle = hpsb_iso_recv_start(fi->host, + config.buf_packets, + config.max_packet_size, + config.channel, + config.irq_interval, + &fi->poll_wait_complete); + if(!fi->iso_handle) + return -ENOMEM; + + fi->iso_state = RAW1394_ISO_RECV; + return 0; +} + +static int raw1394_iso_get_status(struct file_info *fi, void *uaddr) +{ + struct raw1394_kernel_iso_status stat; + struct hpsb_iso *iso = fi->iso_handle; + + stat.config.buf_packets = iso->buf_packets; + stat.config.max_packet_size = iso->max_packet_size; + stat.config.channel = iso->channel; + stat.config.speed = iso->speed; + stat.config.irq_interval = iso->irq_interval; + + stat.buf_stride = iso->buf_stride; + stat.packet_data_offset = iso->packet_data_offset; + stat.packet_info_offset = iso->packet_info_offset; + stat.first_packet = iso->first_packet; + stat.n_packets = hpsb_iso_n_ready(iso); + stat.overflows = atomic_read(&iso->overflows); + stat.first_packet_cycle = iso->first_packet_cycle; + + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; + + /* reset overflow counter */ + atomic_set(&iso->overflows, 0); + + return 0; +} + +static void raw1394_iso_stop(struct file_info *fi) +{ + if(fi->iso_state == RAW1394_ISO_RECV) + hpsb_iso_recv_stop(fi->iso_handle); + else + hpsb_iso_xmit_stop(fi->iso_handle); + + fi->iso_handle = NULL; + + fi->iso_state = RAW1394_ISO_INACTIVE; +} + +/* mmap the ISO xmit/recv buffer */ +static int raw1394_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct file_info *fi = file->private_data; + + if(fi->iso_state == RAW1394_ISO_INACTIVE) + return -EINVAL; + + return dma_region_mmap(&fi->iso_handle->buf, file, vma); +} + +static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct file_info *fi = file->private_data; + + /* ioctl is only used for ISO operations */ + + switch(fi->iso_state) { + case RAW1394_ISO_INACTIVE: + switch(cmd) { + case RAW1394_ISO_START_XMIT: + return raw1394_iso_start_xmit(fi, (void*) arg); + case RAW1394_ISO_START_RECV: + return raw1394_iso_start_recv(fi, (void*) arg); + default: + break; + } + break; + case RAW1394_ISO_RECV: + switch(cmd) { + case RAW1394_ISO_GET_STATUS: + return raw1394_iso_get_status(fi, (void*) arg); + case RAW1394_ISO_PRODUCE_CONSUME: + return hpsb_iso_recv_consume(fi->iso_handle, arg); + case RAW1394_ISO_STOP: + raw1394_iso_stop(fi); + return 0; + } + break; + case RAW1394_ISO_XMIT: + switch(cmd) { + case RAW1394_ISO_GET_STATUS: + return raw1394_iso_get_status(fi, (void*) arg); + case RAW1394_ISO_PRODUCE_CONSUME: + return hpsb_iso_xmit_produce(fi->iso_handle, arg); + case RAW1394_ISO_STOP: + raw1394_iso_stop(fi); + return 0; + } + break; + default: + break; + } + + return -EINVAL; +} + +/* + POLLIN/OUT is for read/write requests + POLLPRI is for ISO transmission and reception + */ static unsigned int raw1394_poll(struct file *file, poll_table *pt) { struct file_info *fi = file->private_data; - unsigned int mask = POLLOUT | POLLWRNORM; + unsigned int mask = 0; poll_wait(file, &fi->poll_wait_complete, pt); - - spin_lock_irq(&fi->reqlists_lock); + + spin_lock_irq(&fi->reqlists_lock); if (!list_empty(&fi->req_complete)) { mask |= POLLIN | POLLRDNORM; } spin_unlock_irq(&fi->reqlists_lock); + if(fi->iso_state != RAW1394_ISO_INACTIVE) { + if(hpsb_iso_n_ready(fi->iso_handle) > 0) + mask |= POLLPRI; + } + return mask; } @@ -929,7 +1079,7 @@ sema_init(&fi->complete_sem, 0); spin_lock_init(&fi->reqlists_lock); init_waitqueue_head(&fi->poll_wait_complete); - + file->private_data = fi; return 0; @@ -942,6 +1092,9 @@ struct pending_request *req; int done = 0, i; + if(fi->iso_state != RAW1394_ISO_INACTIVE) + raw1394_iso_stop(fi); + for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { hpsb_unlisten_channel(hl_handle, fi->host, i); @@ -995,7 +1148,9 @@ static struct file_operations file_ops = { .owner = THIS_MODULE, .read = raw1394_read, - .write = raw1394_write, + .write = raw1394_write, + .mmap = raw1394_mmap, + .ioctl = raw1394_ioctl, .poll = raw1394_poll, .open = raw1394_open, .release = raw1394_release, Modified: branches/rawiso/raw1394.h ============================================================================== --- branches/rawiso/raw1394.h (original) +++ branches/rawiso/raw1394.h 2002-08-28 12:38:47.000000000 -0400 @@ -69,6 +69,57 @@ __u8 name[32]; }; +/* new ISO API */ + +/* ioctls */ +#define RAW1394_ISO_START_XMIT 1 +#define RAW1394_ISO_START_RECV 2 +#define RAW1394_ISO_GET_STATUS 3 +#define RAW1394_ISO_STOP 4 +#define RAW1394_ISO_PRODUCE_CONSUME 5 + +/* argument to RAW1394_ISO_START_RECV, XMIT */ +struct raw1394_kernel_iso_config { + unsigned int buf_packets; + unsigned int max_packet_size; + int channel; + int speed; /* xmit only */ + int irq_interval; +}; + +struct raw1394_kernel_iso_status { + /* current settings */ + struct raw1394_kernel_iso_config config; + + /* byte offset between successive packets in the buffer */ + int buf_stride; + + /* byte offset of data payload within each packet */ + int packet_data_offset; + + /* byte offset of struct iso_packet_info within each packet */ + int packet_info_offset; + + /* index of next packet to fill with data (ISO transmission) + or next packet containing data recieved (ISO reception) */ + unsigned int first_packet; + + /* number of packets waiting to be filled with data (ISO transmission) + or containing data received (ISO reception) */ + unsigned int n_packets; + + /* approximate number of packets dropped due to overflow or + underflow of the packet buffer (a value of zero guarantees + that no packets have been dropped) */ + unsigned int overflows; + + /* the value the ISO CYCLE_COUNT register will have when the first_packet + is sent (ISO transmission) or received (ISO reception). + set to -1 if you don't care about cycle matching. + */ + int first_packet_cycle; +}; + #ifdef __KERNEL__ struct iso_block_store { @@ -77,6 +128,10 @@ quadlet_t data[0]; }; +enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0, + RAW1394_ISO_RECV = 1, + RAW1394_ISO_XMIT = 2 }; + struct file_info { struct list_head list; @@ -93,9 +148,14 @@ u8 *fcp_buffer; + /* old ISO API */ u64 listen_channels; quadlet_t *iso_buffer; size_t iso_buffer_length; + + /* new ISO API */ + enum raw1394_iso_state iso_state; + struct hpsb_iso *iso_handle; }; struct pending_request { |
From: SVN U. <dm...@li...> - 2002-08-28 07:40:45
|
Author: dmaas Date: 2002-08-28 12:33:01 -0400 (Wed, 28 Aug 2002) New Revision: 562 Modified: branches/rawiso/ohci1394.c Log: ohci1394 implementation of new kernel ISO API Modified: branches/rawiso/ohci1394.c ============================================================================== --- branches/rawiso/ohci1394.c (original) +++ branches/rawiso/ohci1394.c 2002-08-28 12:33:02.000000000 -0400 @@ -113,6 +113,8 @@ #include "ieee1394.h" #include "ieee1394_types.h" #include "hosts.h" +#include "dma.h" +#include "iso.h" #include "ieee1394_core.h" #include "highlevel.h" #include "ohci1394.h" @@ -975,6 +977,677 @@ return retval; } + +/*********************************** + * ISO reception * + ***********************************/ + +struct ohci_iso_recv { + struct ti_ohci *ohci; + + /* memory and PCI mapping for the DMA descriptors */ + struct dma_prog_region prog; + + struct ohci1394_iso_tasklet task; + int task_active; + + /* index of next packet to arrive */ + int pkt_dma; + + u32 ContextControlSet; + u32 ContextControlClear; + u32 CommandPtr; + u32 ContextMatch; +}; + +static void ohci_iso_recv_task(unsigned long data); +static void ohci_iso_recv_stop(struct hpsb_iso *iso); +static void ohci_iso_recv_program(struct hpsb_iso *iso); +static int ohci_iso_recv_start_dma(struct hpsb_iso *iso); + + +static int ohci_iso_recv_start(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv; + unsigned int prog_size; + int ctx; + int ret = -ENOMEM; + + recv = kmalloc(sizeof(*recv), SLAB_KERNEL); + if(!recv) + return -ENOMEM; + + iso->hostdata = recv; + recv->ohci = iso->host->hostdata; + recv->task_active = 0; + recv->pkt_dma = iso->first_packet; + + dma_prog_region_init(&recv->prog); + + /* size of DMA program = one INPUT_LAST per packet in the buffer */ + prog_size = sizeof(struct dma_cmd) * iso->buf_packets; + + if(dma_prog_region_alloc(&recv->prog, prog_size, recv->ohci->dev)) + goto err; + + ohci1394_init_iso_tasklet(&recv->task, OHCI_ISO_RECEIVE, + ohci_iso_recv_task, (unsigned long) iso); + + if(ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) + goto err; + + recv->task_active = 1; + + /* recv context registers are spaced 32 bytes apart */ + ctx = recv->task.context; + recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx; + recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx; + recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx; + recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx; + + /* enable interrupts */ + reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << ctx); + + /* write the DMA program */ + ohci_iso_recv_program(iso); + + /* go! */ + if(ohci_iso_recv_start_dma(iso)) + goto err; + + return 0; + +err: + ohci_iso_recv_stop(iso); + return ret; +} + + +static void ohci_iso_recv_stop(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + + if(recv->task_active) { + /* halt DMA */ + ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL); + + /* disable interrupts */ + reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context); + + ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task); + recv->task_active = 0; + } + + dma_prog_region_free(&recv->prog); + kfree(recv); + iso->hostdata = NULL; +} + +static void ohci_iso_recv_program(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + + /* address of 'branch' field in previous DMA descriptor */ + u32 *prev_branch = NULL; + + /* start at pkt_dma and go around the whole buffer */ + int pkt = recv->pkt_dma; + int i; + + for(i = 0; i < iso->buf_packets; i++) { + + /* pointer to the DMA descriptor */ + struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + pkt; + + /* offset of the DMA descriptor relative to the DMA prog buffer */ + unsigned long prog_offset = pkt * sizeof(struct dma_cmd); + + /* offset of this bus_cycle within the DMA buffer */ + unsigned long buf_offset = hpsb_iso_packet_data(iso, pkt) - iso->buf.kvirt; + + int want_interrupt; + unsigned int data_size = iso->max_packet_size; + + /* ask for an interrupt every now and then, and + always interrupt on the final descriptor */ + + if( ((i % iso->irq_interval) == 0) || + (i == (iso->buf_packets - 1)) ) { + want_interrupt = 1; + } else { + want_interrupt = 0; + } + + /* write the DMA descriptor */ + + il->control = 3 << 28; /* INPUT_LAST */ + il->control |= 8 << 24; /* s = 1, update xferStatus and resCount */ + if(want_interrupt) + il->control |= 3 << 20; + il->control |= 0xC << 16; /* enable branch to address */ + il->control |= data_size; + + il->address = dma_region_offset_to_bus(&iso->buf, buf_offset); + il->branchAddress = 0; /* filled in on next loop */ + il->status = data_size; + + /* link the previous descriptor to this one */ + if(prev_branch) { + *prev_branch = dma_prog_region_offset_to_bus(&recv->prog, prog_offset); + *prev_branch |= 1; /* set Z=1 */ + } + + prev_branch = &il->branchAddress; + + pkt = (pkt + 1) % iso->buf_packets; + } + + /* the final descriptor's branch address and Z should be left at 0 */ +} + +static int ohci_iso_recv_start_dma(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + u32 command; + + reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF); + wmb(); + + /* use packet-per-buffer mode, and do not keep ISO headers */ + reg_write(recv->ohci, recv->ContextControlSet, 0x00000000); + + /* match on all tags, listen on channel */ + reg_write(recv->ohci, recv->ContextMatch, 0xF0000000 | iso->channel); + + /* address of first descriptor block */ + command = dma_prog_region_offset_to_bus(&recv->prog, recv->pkt_dma * sizeof(struct dma_cmd)); + command |= 1; /* Z=1 */ + + reg_write(recv->ohci, recv->CommandPtr, command); + wmb(); + + /* run */ + reg_write(recv->ohci, recv->ContextControlSet, 0x8000); + + /* issue a dummy read of the cycle timer register to force + all PCI writes to be posted immediately */ + mb(); + reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); + + /* check RUN */ + if(!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) { + PRINT(KERN_ERR, recv->ohci->id, "Error starting ISO DMA reception (ContextControl 0x%08x)\n", + reg_read(recv->ohci, recv->ContextControlSet)); + return -1; + } + + return 0; +} + +static void ohci_iso_recv_consume_one(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + + /* re-use the DMA descriptor for first_packet */ + /* by linking the previous descriptor to it */ + + int next_i = iso->first_packet; + int prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1); + + struct dma_cmd *next = dma_region_i(&recv->prog, struct dma_cmd, next_i); + struct dma_cmd *prev = dma_region_i(&recv->prog, struct dma_cmd, prev_i); + + /* 'next' becomes the new end of the DMA chain */ + next->control |= 3 << 20; /* enable interrupt */ + next->branchAddress = 0; /* disable branch */ + + /* link prev to next */ + if(prev_i % iso->irq_interval) { + prev->control &= ~(3 << 20); /* no interrupt */ + } else { + prev->control |= 3 << 20; /* enable interrupt */ + } + prev->branchAddress = dma_prog_region_offset_to_bus(&recv->prog, + sizeof(struct dma_cmd) * next_i) | 1; + wmb(); + + /* wake up DMA in case it fell asleep */ + reg_write(recv->ohci, recv->ContextControlSet, (1 << 12)); + + /* advance packet cursors */ + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + atomic_inc(&iso->n_dma_packets); +} + +static void ohci_iso_recv_consume(struct hpsb_iso *iso, int n_packets) +{ + int i; + for(i = 0; i < n_packets; i++) + ohci_iso_recv_consume_one(iso); +} + +static void ohci_iso_recv_task(unsigned long data) +{ + struct hpsb_iso *iso = (struct hpsb_iso*) data; + struct ohci_iso_recv *recv = iso->hostdata; + + int count; + int wake = 0; + int good_packets = 0; + int bad_packets = 0; + + /* loop over the entire buffer */ + for(count = 0; count < iso->buf_packets; count++) { + u32 packet_len = 0; + struct hpsb_iso_packet_info *info; + + /* pointer to the DMA descriptor */ + struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + recv->pkt_dma; + + /* check the DMA descriptor for new writes to xferStatus */ + u16 xferstatus = il->status >> 16; + u16 rescount = il->status & 0xFFFF; + + unsigned char event = xferstatus & 0x1F; + + if(event == 0x11) { + /* packet received successfully! */ + good_packets++; + + /* rescount is the number of bytes *remaining* in the packet buffer, + after the packet was written */ + packet_len = iso->max_packet_size - rescount; + + } else if(event == 0x02) { + PRINT(KERN_ERR, recv->ohci->id, + "ISO DMA reception error - packet too long for buffer\n"); + bad_packets++; + } else if(event) { + PRINT(KERN_ERR, recv->ohci->id, + "ISO DMA reception error - OHCI error code 0x%02x\n", event); + bad_packets++; + } + + if(!event) { + /* this packet hasn't come in yet; we are done for now */ + goto out; + } + + /* sync our view of the buffer */ + dma_region_sync(&iso->buf); + + /* record the per-packet info */ + info = hpsb_iso_packet_info(iso, recv->pkt_dma); + info->len = packet_len; + + /* at least one packet came in, so wake up the reader */ + wake = 1; + + /* reset the DMA descriptor */ + il->status = iso->max_packet_size; + + /* advance DMA packet cursor */ + recv->pkt_dma = (recv->pkt_dma + 1) % iso->buf_packets; + + /* one more packet for the user, one less for us */ + if(atomic_dec_and_test(&iso->n_dma_packets)) { + /* if n_dma_packets reaches zero, we have an overflow */ + atomic_inc(&iso->overflows); + } + + } + +out: + if(wake && iso->waitq) { + wake_up_interruptible(iso->waitq); + } +} + + +/*********************************** + * ISO transmission * + ***********************************/ + +struct ohci_iso_xmit { + struct ti_ohci *ohci; + struct dma_prog_region prog; + struct ohci1394_iso_tasklet task; + int task_active; + int pkt_dma; + + u32 ContextControlSet; + u32 ContextControlClear; + u32 CommandPtr; +}; + +/* transmission DMA program: + one OUTPUT_MORE_IMMEDIATE for the IT header + one OUTPUT_LAST for the buffer data */ + +struct iso_xmit_cmd { + struct dma_cmd output_more_immediate; + u8 iso_hdr[8]; + u32 unused[2]; + struct dma_cmd output_last; +}; + +static int ohci_iso_xmit_start(struct hpsb_iso *iso); +static int ohci_iso_xmit_start_dma(struct hpsb_iso *iso, int cycle); +static void ohci_iso_xmit_stop(struct hpsb_iso *iso); +static void ohci_iso_xmit_task(unsigned long data); + +static int ohci_iso_xmit_suggest_start_cycle(struct ti_ohci *ohci) +{ + u32 cycleTimer, sec, cyc, off; + + cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + sec = cycleTimer >> 25; + cyc = (cycleTimer >> 12) & 0x1FFF; + off = cycleTimer & 0xFFF; + + /* go ahead 500 cycles - if the user doesn't xmit_produce() a + packet within this time, we will end up waiting until the + 4-bit second counter wraps around to start transmission... + is there a better way? */ + + cyc += 500; + + sec += cyc/8000; + cyc %= 8000; + + return ((sec & 0x3) << 13) | cyc; +} + +static int ohci_iso_xmit_start(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit; + unsigned int prog_size; + int ctx; + int ret = -ENOMEM; + + xmit = kmalloc(sizeof(*xmit), SLAB_KERNEL); + if(!xmit) + return -ENOMEM; + + iso->hostdata = xmit; + xmit->ohci = iso->host->hostdata; + xmit->task_active = 0; + xmit->pkt_dma = iso->first_packet; + + dma_prog_region_init(&xmit->prog); + + prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets; + + if(dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev)) + goto err; + + ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT, + ohci_iso_xmit_task, (unsigned long) iso); + + if(ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) + goto err; + + xmit->task_active = 1; + + /* xmit context registers are spaced 16 bytes apart */ + ctx = xmit->task.context; + xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx; + xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx; + xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx; + + reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF); + + /* enable interrupts */ + reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << ctx); + + /* suggest a starting cycle */ + iso->first_packet_cycle = ohci_iso_xmit_suggest_start_cycle(xmit->ohci); + + return 0; + +err: + ohci_iso_xmit_stop(iso); + return ret; +} + +static void ohci_iso_xmit_stop(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + + if(xmit->task_active) { + /* halt DMA */ + ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL); + + /* disable interrupts */ + reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context); + + ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task); + xmit->task_active = 0; + } + + dma_prog_region_free(&xmit->prog); + kfree(xmit); + iso->hostdata = NULL; +} + +static void ohci_iso_xmit_task(unsigned long data) +{ + struct hpsb_iso *iso = (struct hpsb_iso*) data; + struct ohci_iso_xmit *xmit = iso->hostdata; + int wake = 0; + unsigned int good_packets = 0; + unsigned int bad_packets = 0; + int count; + + /* check the whole buffer if necessary, starting at pkt_dma*/ + for(count = 0; count < iso->buf_packets; count++) { + struct iso_xmit_cmd *cmd = + dma_region_i(&xmit->prog, struct iso_xmit_cmd, xmit->pkt_dma); + + /* check for new writes to xferStatus */ + u16 xferstatus = cmd->output_last.status >> 16; + unsigned char event = xferstatus & 0x1F; + + if(event == 0x11) { + /* packet sent successfully */ + good_packets++; + } else if(event) { + PRINT(KERN_ERR, xmit->ohci->id, + "ISO DMA transmission error - OHCI error code 0x%02x\n", event); + bad_packets++; + } + + if(!event) { + /* packet hasn't been sent yet; we are done for now */ + goto out; + } + + /* at least one packet came in, so wake up the writer */ + wake = 1; + + /* reset the DMA descriptor for next time */ + cmd->output_last.status = 0; + + /* advance packet cursor */ + xmit->pkt_dma = (xmit->pkt_dma + 1) % iso->buf_packets; + + /* one less packet for us */ + if(atomic_dec_and_test(&iso->n_dma_packets)) { + /* underflow */ + atomic_inc(&iso->overflows); + } + } + +out: + if(wake && iso->waitq) { + wake_up_interruptible(iso->waitq); + } +} + +static void ohci_iso_xmit_produce_one(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + struct hpsb_iso_packet_info *info; + int next_i, prev_i; + struct iso_xmit_cmd *next, *prev; + + /* sync up the card's view of the buffer */ + dma_region_sync(&iso->buf); + + /* append first_packet to the DMA chain */ + /* by linking the previous descriptor to it */ + /* (next will become the new end of the DMA chain) */ + + next_i = iso->first_packet; + prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1); + + next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i); + prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i); + + /* retrieve the packet info stashed in the buffer */ + info = hpsb_iso_packet_info(iso, iso->first_packet); + + /* set up the OUTPUT_MORE_IMMEDIATE */ + memset(next, 0, sizeof(struct iso_xmit_cmd)); + next->output_more_immediate.control = 0x02000008; + + /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */ + + /* tcode = 0xA, and sy */ + next->iso_hdr[0] = 0xA0 | (info->sy & 0xF); + + /* tag and channel number */ + next->iso_hdr[1] = (info->tag << 6) | (iso->channel & 0x3F); + + /* transmission speed */ + next->iso_hdr[2] = iso->speed & 0x7; + + /* payload size */ + next->iso_hdr[6] = info->len & 0xFF; + next->iso_hdr[7] = info->len >> 8; + + /* set up the OUTPUT_LAST */ + next->output_last.control = 1 << 28; + next->output_last.control |= 1 << 27; /* update timeStamp */ + next->output_last.control |= 3 << 20; /* want interrupt */ + next->output_last.control |= 3 << 18; /* enable branch */ + next->output_last.control |= info->len; + + /* payload bus address */ + next->output_last.address = dma_region_offset_to_bus(&iso->buf, + hpsb_iso_packet_data(iso, iso->first_packet) - iso->buf.kvirt); + + /* leave branchAddress at zero for now */ + + /* re-write the previous DMA descriptor to chain to this one */ + + /* set prev branch address to point to next (Z=3) */ + prev->output_last.branchAddress = + dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3; + + /* disable interrupt, unless required by the IRQ interval */ + if(prev_i % iso->irq_interval) { + prev->output_last.control &= ~(3 << 20); /* no interrupt */ + } else { + prev->output_last.control |= 3 << 20; /* enable interrupt */ + } + + wmb(); + + /* wake DMA in case it is sleeping */ + reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12); + + /* issue a dummy read of the cycle timer to force all PCI + writes to be posted immediately */ + mb(); + reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer); + + /* increment cursors */ + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + iso->first_packet_cycle = (iso->first_packet_cycle+1) % iso->buf_packets; + + atomic_inc(&iso->n_dma_packets); +} + +static void ohci_iso_xmit_produce(struct hpsb_iso *iso, int n_packets) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + int i; + + /* record the starting cycle here, since produce_one() bumps first_packet_cycle */ + int starting_cycle = iso->first_packet_cycle; + + for(i = 0; i < n_packets; i++) + ohci_iso_xmit_produce_one(iso); + + /* if DMA is not running, start it up */ + if(!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) + ohci_iso_xmit_start_dma(iso, starting_cycle); +} + +static int ohci_iso_xmit_start_dma(struct hpsb_iso *iso, int cycle) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + + /* clear out the control register */ + reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF); + wmb(); + + /* address and length of first descriptor block (Z=3) */ + reg_write(xmit->ohci, xmit->CommandPtr, + dma_prog_region_offset_to_bus(&xmit->prog, xmit->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3); + + /* cycle match */ + if(cycle >= 0) { + reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (cycle << 16)); + } + + /* run */ + reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000); + mb(); + + /* wait 100 usec to give the card time to go active */ + udelay(100); + + /* check the RUN bit */ + if(!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) { + PRINT(KERN_ERR, xmit->ohci->id, "Error starting ISO DMA transmission (ContextControl 0x%08x)\n", + reg_read(xmit->ohci, xmit->ContextControlSet)); + return -1; + } + + return 0; +} + + +static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, int arg) +{ + + switch(cmd) { + case XMIT_START: + return ohci_iso_xmit_start(iso); + case XMIT_PRODUCE: + ohci_iso_xmit_produce(iso, arg); + return 0; + case XMIT_STOP: + ohci_iso_xmit_stop(iso); + return 0; + case RECV_START: + return ohci_iso_recv_start(iso); + case RECV_CONSUME: + ohci_iso_recv_consume(iso, arg); + return 0; + case RECV_STOP: + ohci_iso_recv_stop(iso); + return 0; + default: + PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet", + cmd); + break; + } + return -EINVAL; +} + /*************************************** * IEEE-1394 functionality section END * ***************************************/ @@ -1939,6 +2612,7 @@ .get_rom = ohci_get_rom, .transmit_packet = ohci_transmit, .devctl = ohci_devctl, + .isoctl = ohci_isoctl, .hw_csr_reg = ohci_hw_csr_reg, }; |
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); +} |
From: SVN U. <dm...@li...> - 2002-08-28 07:27:53
|
Author: dmaas Date: 2002-08-28 12:20:08 -0400 (Wed, 28 Aug 2002) New Revision: 560 Added: branches/rawiso/dma.c branches/rawiso/dma.h Modified: branches/rawiso/Makefile branches/rawiso/Makefile.in Log: added dma.c and dma.h (DMA region bookkeeping routines) Modified: branches/rawiso/Makefile.in ============================================================================== --- branches/rawiso/Makefile.in (original) +++ branches/rawiso/Makefile.in 2002-08-28 12:20:09.000000000 -0400 @@ -1,10 +1,10 @@ # # Makefile for the Linux IEEE 1394 implementation -expsyms(ieee1394_core.o ohci1394.o cmp.o) +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) + csr.o nodemgr.o dma.o) extra_cflags(sbp2.o $(src_includelist /drivers/scsi)) Modified: branches/rawiso/Makefile ============================================================================== --- branches/rawiso/Makefile (original) +++ branches/rawiso/Makefile 2002-08-28 12:20:09.000000000 -0400 @@ -4,11 +4,11 @@ O_TARGET := ieee1394drv.o -export-objs := ieee1394_core.o ohci1394.o cmp.o +export-objs := ieee1394_core.o ohci1394.o cmp.o dma.o list-multi := ieee1394.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ - highlevel.o csr.o nodemgr.o + highlevel.o csr.o nodemgr.o dma.o obj-$(CONFIG_IEEE1394) += ieee1394.o obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o Added: branches/rawiso/dma.c ============================================================================== --- branches/rawiso/dma.c (original) +++ branches/rawiso/dma.c 2002-08-28 12:20:09.000000000 -0400 @@ -0,0 +1,203 @@ +/* + * DMA region bookkeeping routines + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include <linux/module.h> +#include "dma.h" + +void dma_prog_region_init(struct dma_prog_region *prog) +{ + prog->kvirt = NULL; + prog->dev = NULL; + prog->n_pages = 0; + prog->bus_addr = 0; +} + +int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev) +{ + /* round up to page size */ + if(n_bytes % PAGE_SIZE) + n_bytes += PAGE_SIZE - (n_bytes & PAGE_SIZE); + + prog->n_pages = n_bytes / PAGE_SIZE; + + prog->kvirt = pci_alloc_consistent(dev, prog->n_pages * PAGE_SIZE, &prog->bus_addr); + if(!prog->kvirt) { + printk(KERN_ERR "dma_prog_region_alloc: pci_alloc_consistent() failed\n"); + dma_prog_region_free(prog); + return -ENOMEM; + } + + prog->dev = dev; + + return 0; +} + +void dma_prog_region_free(struct dma_prog_region *prog) +{ + if(prog->kvirt) { + pci_free_consistent(prog->dev, prog->n_pages * PAGE_SIZE, prog->kvirt, prog->bus_addr); + } + + prog->kvirt = NULL; + prog->dev = NULL; + prog->n_pages = 0; + prog->bus_addr = 0; +} + + + + +void dma_region_init(struct dma_region *dma) +{ + dma->kvirt = NULL; + dma->dev = NULL; + dma->n_pages = 0; + dma->n_dma_pages = 0; + dma->sglist = NULL; +} + +int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction) +{ + unsigned int i, n_pages; + + /* round up to page size */ + if(n_bytes % PAGE_SIZE) + n_bytes += PAGE_SIZE - (n_bytes & PAGE_SIZE); + + n_pages = n_bytes / PAGE_SIZE; + + dma->kvirt = vmalloc_32(n_pages * PAGE_SIZE); + if(!dma->kvirt) { + printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n"); + goto err; + } + + dma->n_pages = n_pages; + + /* Clear the ram out, no junk to the user */ + memset(dma->kvirt, 0, n_pages * PAGE_SIZE); + + dma->sglist = kmalloc(dma->n_pages * sizeof(struct scatterlist), GFP_KERNEL); + if(!dma->sglist) { + printk(KERN_ERR "dma_region_alloc: kmalloc(sglist) failed\n"); + goto err; + } + + /* just to be safe - this will become unnecessary once sglist->address goes away */ + memset(dma->sglist, 0, dma->n_pages * sizeof(struct scatterlist)); + + for(i = 0; i < dma->n_pages; i++) { + unsigned long va = (unsigned long) dma->kvirt + i * PAGE_SIZE; + + dma->sglist[i].page = vmalloc_to_page((void *)va); + dma->sglist[i].length = PAGE_SIZE; + } + + dma->n_dma_pages = pci_map_sg(dev, &dma->sglist[0], dma->n_pages, direction); + + if(dma->n_dma_pages == 0) { + printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n"); + goto err; + } + + dma->dev = dev; + dma->direction = direction; + + return 0; + +err: + dma_region_free(dma); + return -ENOMEM; +} + +void dma_region_free(struct dma_region *dma) +{ + if(dma->n_dma_pages) { + pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages, dma->direction); + dma->n_dma_pages = 0; + dma->dev = NULL; + } + + if(dma->sglist) { + kfree(dma->sglist); + dma->sglist = NULL; + } + + if(dma->kvirt) { + vfree(dma->kvirt); + dma->kvirt = NULL; + dma->n_pages = 0; + } +} + +void dma_region_sync(struct dma_region *dma) +{ + pci_dma_sync_sg(dma->dev, &dma->sglist[0], dma->n_dma_pages, dma->direction); +} + +static struct page* +dma_region_pagefault(struct vm_area_struct *area, unsigned long address, int write_access) +{ + unsigned long offset; + unsigned long kernel_virt_addr; + struct page *ret = NOPAGE_SIGBUS; + + struct dma_region *dma = (struct dma_region*) area->vm_private_data; + + if(!dma->kvirt) + goto out; + + if( (address < (unsigned long) area->vm_start) || + (address > (unsigned long) area->vm_start + (PAGE_SIZE * dma->n_pages)) ) + goto out; + + offset = address - area->vm_start; + kernel_virt_addr = (unsigned long) dma->kvirt + offset; + ret = vmalloc_to_page((void*) kernel_virt_addr); + get_page(ret); +out: + return ret; +} + +static struct vm_operations_struct dma_region_vm_ops = { + nopage: dma_region_pagefault, +}; + +int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma) +{ + unsigned long size; + + if(!dma->kvirt) + return -EINVAL; + + /* must be page-aligned */ + if(vma->vm_pgoff != 0) + return -EINVAL; + + /* check the length */ + size = vma->vm_end - vma->vm_start; + if(size > (PAGE_SIZE * dma->n_pages)) + return -EINVAL; + + vma->vm_ops = &dma_region_vm_ops; + vma->vm_private_data = dma; + vma->vm_file = file; + vma->vm_flags |= VM_RESERVED; + + return 0; +} + +EXPORT_SYMBOL(dma_prog_region_init); +EXPORT_SYMBOL(dma_prog_region_alloc); +EXPORT_SYMBOL(dma_prog_region_free); +EXPORT_SYMBOL(dma_region_init); +EXPORT_SYMBOL(dma_region_alloc); +EXPORT_SYMBOL(dma_region_free); +EXPORT_SYMBOL(dma_region_sync); +EXPORT_SYMBOL(dma_region_mmap); Added: branches/rawiso/dma.h ============================================================================== --- branches/rawiso/dma.h (original) +++ branches/rawiso/dma.h 2002-08-28 12:20:09.000000000 -0400 @@ -0,0 +1,86 @@ +/* + * DMA region bookkeeping routines + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#ifndef IEEE1394_DMA_H +#define IEEE1394_DMA_H + +#include <linux/pci.h> +#include <asm/scatterlist.h> + +/* structure for bookkeeping of a small, physically-contiguous DMA buffer + with random-access, synchronous usage characteristics */ + +struct dma_prog_region { + unsigned char *kvirt; /* kernel virtual address */ + struct pci_dev *dev; /* PCI device */ + unsigned int n_pages; /* # of kernel pages */ + dma_addr_t bus_addr; /* base bus address */ +}; + +/* clear out all fields but do not allocate any memory */ +void dma_prog_region_init(struct dma_prog_region *prog); +int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev); +void dma_prog_region_free(struct dma_prog_region *prog); + +static inline dma_addr_t dma_prog_region_offset_to_bus(struct dma_prog_region *prog, unsigned long offset) +{ + return prog->bus_addr + offset; +} + + + +/* structure for bookkeeping of a large, non-physically-contiguous DMA buffer + with streaming, asynchronous usage characteristics */ + +struct dma_region { + unsigned char *kvirt; /* kernel virtual address */ + struct pci_dev *dev; /* PCI device */ + unsigned int n_pages; /* # of kernel pages */ + unsigned int n_dma_pages; /* # of IOMMU pages */ + struct scatterlist *sglist; + int direction; /* PCI_DMA_TODEVICE, etc */ +}; + +/* clear out all fields but do not allocate anything */ +void dma_region_init(struct dma_region *dma); + +/* allocate the buffer and map it to the IOMMU */ +int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction); + +/* unmap and free the buffer */ +void dma_region_free(struct dma_region *dma); + +/* sync the IO bus' view of the buffer with the CPU's view */ +/* XXXDJM add addr, len arguments */ +void dma_region_sync(struct dma_region *dma); + +/* map the buffer into a user space process */ +int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma); + +/* macro to index into a DMA region */ +#define dma_region_i(_dma, _type, _index) ( ((_type*) ((_dma)->kvirt)) + (_index) ) + +/* return the DMA bus address of the byte with the given offset + relative to the beginning of the dma_region */ + +static inline dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset) +{ + int i; + struct scatterlist *sg; + + for(i = 0, sg = &dma->sglist[0]; i < dma->n_dma_pages; i++, sg++) { + if(offset < sg_dma_len(sg)) { + return sg_dma_address(sg) + offset; + } + offset -= sg_dma_len(sg); + } + return 0; +} + +#endif /* IEEE1394_DMA_H */ |
From: SVN U. <dm...@li...> - 2002-08-28 07:17:44
|
Author: dmaas Date: 2002-08-28 12:10:01 -0400 (Wed, 28 Aug 2002) New Revision: 559 Added: branches/rawiso/ Log: create rawiso branch (new isochronous API work) Copied: rawiso (from rev 558, branch-points/rawiso) |
From: SVN U. <dm...@li...> - 2002-08-28 07:16:48
|
Author: dmaas Date: 2002-08-28 12:09:05 -0400 (Wed, 28 Aug 2002) New Revision: 558 Added: branch-points/rawiso/ Log: mark branch point for rawiso Copied: rawiso (from rev 557, trunk) |
From: SVN U. <dm...@li...> - 2002-08-28 07:16:33
|
Author: dmaas Date: 2002-08-28 12:08:44 -0400 (Wed, 28 Aug 2002) New Revision: 557 Added: branch-points/ Log: create branch-points directory |
From: SVN U. <ben...@li...> - 2002-08-28 01:28:23
|
Author: bencollins Date: 2002-08-28 06:20:39 -0400 (Wed, 28 Aug 2002) New Revision: 556 Modified: trunk/ieee1394_core.c Log: Remove inclusion of smplock.h. Change merged from 2.5.32. Maybe Linus will one day apply my patches to his tree Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2002-08-28 06:20:39.000000000 -0400 @@ -22,7 +22,6 @@ #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/semaphore.h> -#include <asm/smplock.h> #include "ieee1394_types.h" #include "ieee1394.h" |
From: SVN U. <hog...@li...> - 2002-08-27 22:22:32
|
Author: hogsberg Date: 2002-08-28 03:14:44 -0400 (Wed, 28 Aug 2002) New Revision: 555 Modified: trunk/amdtp.c trunk/dv1394-private.h trunk/dv1394.c trunk/ohci1394.c trunk/ohci1394.h trunk/video1394.c Log: Introduce ohci1394_iso_tasklet interface to the dma contexts of the ohci controller. Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-08-28 03:14:46.000000000 -0400 @@ -170,10 +170,6 @@ static void ohci1394_pci_remove(struct pci_dev *pdev); -static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci, - quadlet_t isoRecvEvent, - quadlet_t isoXmitEvent); - #ifndef __LITTLE_ENDIAN /* Swap a series of quads inplace. */ static __inline__ void block_swab32(quadlet_t *data, size_t size) { @@ -475,34 +471,6 @@ { quadlet_t buf; - /* Start off with a soft reset, to clear everything to a sane - * state. */ - ohci_soft_reset(ohci); - - /* Now enable LPS, which we need in order to start accessing - * most of the registers. In fact, on some cards (ALI M5251), - * accessing registers in the SClk domain without LPS enabled - * will lock up the machine. Wait 50msec to make sure we have - * full link enabled. */ - reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); - mdelay(50); - - /* Determine the number of available IR and IT contexts. */ - ohci->nb_iso_rcv_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); - DBGMSG(ohci->id, "%d iso receive contexts available", - ohci->nb_iso_rcv_ctx); - - ohci->nb_iso_xmit_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); - DBGMSG(ohci->id, "%d iso transmit contexts available", - ohci->nb_iso_xmit_ctx); - - /* Set the usage bits for non-existent contexts so they can't - * be allocated */ - ohci->ir_ctx_usage |= ~0 << ohci->nb_iso_rcv_ctx; - ohci->it_ctx_usage |= ~0 << ohci->nb_iso_xmit_ctx; - spin_lock_init(&ohci->phy_reg_lock); spin_lock_init(&ohci->event_lock); @@ -1052,6 +1020,30 @@ } } +static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci, + quadlet_t rx_event, + quadlet_t tx_event) +{ + struct list_head *lh; + struct ohci1394_iso_tasklet *t; + unsigned long mask; + + spin_lock(&ohci->iso_tasklet_list_lock); + + list_for_each(lh, &ohci->iso_tasklet_list) { + t = list_entry(lh, struct ohci1394_iso_tasklet, link); + mask = 1 << t->context; + + if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask) + tasklet_schedule(&t->tasklet); + if (t->type == OHCI_ISO_RECEIVE && rx_event & mask) + tasklet_schedule(&t->tasklet); + } + + spin_unlock(&ohci->iso_tasklet_list_lock); + +} + static void ohci_irq_handler(int irq, void *dev_id, struct pt_regs *regs_are_unused) { @@ -1162,46 +1154,19 @@ event &= ~OHCI1394_RSPkt; } if (event & OHCI1394_isochRx) { - quadlet_t isoRecvIntEvent; - struct dma_rcv_ctx *d = &ohci->ir_context; - isoRecvIntEvent = - reg_read(ohci, OHCI1394_IsoRecvIntEventSet); - reg_write(ohci, OHCI1394_IsoRecvIntEventClear, - isoRecvIntEvent); - DBGMSG(ohci->id, "Got isochRx interrupt " - "status=0x%08X isoRecvIntEvent=%08x", - reg_read(ohci, d->ctrlSet), isoRecvIntEvent); - if (isoRecvIntEvent & 0x1) { - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, - "isochRx"); - else - tasklet_schedule(&d->task); - } - - ohci1394_run_irq_hooks(ohci, isoRecvIntEvent, 0); + quadlet_t rx_event; + rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event); + ohci_schedule_iso_tasklets(ohci, rx_event, 0); event &= ~OHCI1394_isochRx; } if (event & OHCI1394_isochTx) { - quadlet_t isoXmitIntEvent; - struct dma_trm_ctx *d = &ohci->it_context; - isoXmitIntEvent = - reg_read(ohci, OHCI1394_IsoXmitIntEventSet); - reg_write(ohci, OHCI1394_IsoXmitIntEventClear, - isoXmitIntEvent); - DBGMSG(ohci->id, "Got isochTx interrupt " - "status=0x%08x isoXmitIntEvent=%08x", - reg_read(ohci, d->ctrlSet), isoXmitIntEvent); + quadlet_t tx_event; - ohci1394_run_irq_hooks(ohci, 0, isoXmitIntEvent); - - if (isoXmitIntEvent & 0x1) { - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, "isochTx"); - else - tasklet_schedule(&d->task); - } + tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event); + ohci_schedule_iso_tasklets(ohci, 0, tx_event); event &= ~OHCI1394_isochTx; } if (event & OHCI1394_selfIDComplete) { @@ -1566,21 +1531,24 @@ static void free_dma_rcv_ctx(struct dma_rcv_ctx *d) { int i; - struct ti_ohci *ohci; - ohci = d->ohci; + if (d->ohci == NULL) + return; - DBGMSG(ohci->id, "Freeing dma_rcv_ctx %d", d->ctx); + DBGMSG(d->ohci->id, "Freeing dma_rcv_ctx %d", d->ctx); - ohci1394_stop_context(ohci, d->ctrlClear, NULL); + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - tasklet_kill(&d->task); + if (d->type == DMA_CTX_ISO) + ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_tasklet); + else + tasklet_kill(&d->task); if (d->buf_cpu) { for (i=0; i<d->num_desc; i++) if (d->buf_cpu[i] && d->buf_bus[i]) { pci_free_consistent( - ohci->dev, d->buf_size, + d->ohci->dev, d->buf_size, d->buf_cpu[i], d->buf_bus[i]); OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i); } @@ -1591,7 +1559,7 @@ for (i=0; i<d->num_desc; i++) if (d->prg_cpu[i] && d->prg_bus[i]) { pci_free_consistent( - ohci->dev, sizeof(struct dma_cmd), + d->ohci->dev, sizeof(struct dma_cmd), d->prg_cpu[i], d->prg_bus[i]); OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i); } @@ -1600,9 +1568,8 @@ } if (d->spb) kfree(d->spb); - /* clear ISO context usage bit */ - if (d->type == DMA_CTX_ISO) - clear_bit(d->ctx, &ohci->ir_ctx_usage); + /* Mark this context as freed. */ + d->ohci = NULL; } static int @@ -1612,14 +1579,6 @@ { int i; - if (type == DMA_CTX_ISO) { - /* try to claim the ISO context usage bit */ - if (test_and_set_bit(ctx, &ohci->ir_ctx_usage)) { - PRINT(KERN_ERR, ohci->id, "IR DMA context %d is not available", ctx); - return -EBUSY; - } - } - d->ohci = ohci; d->type = type; d->ctx = ctx; @@ -1696,30 +1655,43 @@ spin_lock_init(&d->lock); - /* initialize tasklet */ - tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long)d); + if (type == DMA_CTX_ISO) { + ohci1394_init_iso_tasklet(&ohci->ir_tasklet, OHCI_ISO_RECEIVE, + dma_rcv_tasklet, (unsigned long) d); + if (ohci1394_register_iso_tasklet(ohci, + &ohci->ir_tasklet) < 0) { + PRINT(KERN_ERR, ohci->id, "No IR DMA context available"); + free_dma_rcv_ctx(d); + return -EBUSY; + } + } + else + tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long) d); return 0; } static void free_dma_trm_ctx(struct dma_trm_ctx *d) { - struct ti_ohci *ohci; int i; - ohci = d->ohci; + if (d->ohci == NULL) + return; - DBGMSG(ohci->id, "Freeing dma_trm_ctx %d", d->ctx); + DBGMSG(d->ohci->id, "Freeing dma_trm_ctx %d", d->ctx); - ohci1394_stop_context(ohci, d->ctrlClear, NULL); + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - tasklet_kill(&d->task); + if (d->type == DMA_CTX_ISO) + ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->it_tasklet); + else + tasklet_kill(&d->task); if (d->prg_cpu) { for (i=0; i<d->num_desc; i++) if (d->prg_cpu[i] && d->prg_bus[i]) { pci_free_consistent( - ohci->dev, sizeof(struct at_dma_prg), + d->ohci->dev, sizeof(struct at_dma_prg), d->prg_cpu[i], d->prg_bus[i]); OHCI_DMA_FREE("consistent dma_trm prg[%d]", i); } @@ -1727,9 +1699,8 @@ kfree(d->prg_bus); } - /* clear the ISO context usage bit */ - if (d->type == DMA_CTX_ISO) - clear_bit(d->ctx, &ohci->it_ctx_usage); + /* Mark this context as freed. */ + d->ohci = NULL; } static int @@ -1739,14 +1710,6 @@ { int i; - if (type == DMA_CTX_ISO) { - /* try to claim the ISO context usage bit */ - if (test_and_set_bit(ctx, &ohci->it_ctx_usage)) { - PRINT(KERN_ERR, ohci->id, "IT DMA context %d is not available", ctx); - return -EBUSY; - } - } - d->ohci = ohci; d->type = type; d->ctx = ctx; @@ -1785,8 +1748,19 @@ spin_lock_init(&d->lock); - /* initialize bottom handler */ - tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d); + /* initialize tasklet */ + if (type == DMA_CTX_ISO) { + ohci1394_init_iso_tasklet(&ohci->it_tasklet, OHCI_ISO_TRANSMIT, + dma_rcv_tasklet, (unsigned long) d); + if (ohci1394_register_iso_tasklet(ohci, + &ohci->it_tasklet) < 0) { + PRINT(KERN_ERR, ohci->id, "No IT DMA context available"); + free_dma_trm_ctx(d); + return -EBUSY; + } + } + else + tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d); return 0; } @@ -1990,7 +1964,6 @@ struct hpsb_host *host; struct ti_ohci *ohci; /* shortcut to currently handled device */ unsigned long ohci_base; - int i; if (version_printed++ == 0) PRINT_G(KERN_INFO, "%s", version); @@ -2107,9 +2080,39 @@ OHCI1394_AsRspTrContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate AT Resp context"); - ohci->ir_ctx_usage = 0; - ohci->it_ctx_usage = 0; - + /* Start off with a soft reset, to clear everything to a sane + * state. */ + ohci_soft_reset(ohci); + + /* Now enable LPS, which we need in order to start accessing + * most of the registers. In fact, on some cards (ALI M5251), + * accessing registers in the SClk domain without LPS enabled + * will lock up the machine. Wait 50msec to make sure we have + * full link enabled. */ + reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); + mdelay(50); + + /* Determine the number of available IR and IT contexts. */ + ohci->nb_iso_rcv_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); + DBGMSG(ohci->id, "%d iso receive contexts available", + ohci->nb_iso_rcv_ctx); + + ohci->nb_iso_xmit_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); + DBGMSG(ohci->id, "%d iso transmit contexts available", + ohci->nb_iso_xmit_ctx); + + /* Set the usage bits for non-existent contexts so they can't + * be allocated */ + ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx; + ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx; + + INIT_LIST_HEAD(&ohci->iso_tasklet_list); + spin_lock_init(&ohci->iso_tasklet_list_lock); + ohci->ISO_channel_usage = 0; + spin_lock_init(&ohci->IR_channel_lock); + /* IR DMA context */ if (alloc_dma_rcv_ctx(ohci, &ohci->ir_context, DMA_CTX_ISO, 0, IR_NUM_DESC, @@ -2124,15 +2127,6 @@ OHCI1394_IsoXmitContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate IT context"); - ohci->ISO_channel_usage = 0; - spin_lock_init(&ohci->IR_channel_lock); - - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - ohci->irq_hooks[i].irq_handler = NULL; - ohci->irq_hooks[i].data = NULL; - } - spin_lock_init(&ohci->irq_hooks_lock); - if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); @@ -2275,81 +2269,69 @@ if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg); } -static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci, - quadlet_t isoRecvEvent, - quadlet_t isoXmitEvent) +void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type, + void (*func)(unsigned long), unsigned long data) { - int i; - - spin_lock(&ohci->irq_hooks_lock); - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - if(ohci->irq_hooks[i].irq_handler != NULL) { - ohci->irq_hooks[i].irq_handler(ohci->id, isoRecvEvent, isoXmitEvent, - ohci->irq_hooks[i].data); - } - } - spin_unlock(&ohci->irq_hooks_lock); + tasklet_init(&tasklet->tasklet, func, data); + tasklet->type = type; + /* We init the tasklet->link field, so we can list_del() it + * without worrying wether it was added to the list or not. */ + INIT_LIST_HEAD(&tasklet->link); } -int ohci1394_hook_irq(struct ti_ohci *ohci, - void (*irq_handler) (int, quadlet_t, quadlet_t, void *), - void *data) +int ohci1394_register_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet) { - int i; - int ret = -EBUSY; - unsigned long flags; - - spin_lock_irqsave(&ohci->irq_hooks_lock, flags); - - /* find a free slot */ - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - if(ohci->irq_hooks[i].irq_handler == NULL) - break; - } + unsigned long flags, *usage; + int n, i, r = -EBUSY; - if(i >= OHCI1394_MAX_IRQ_HOOKS) - goto out; + if (tasklet->type == OHCI_ISO_TRANSMIT) { + n = ohci->nb_iso_xmit_ctx; + usage = &ohci->it_ctx_usage; + } + else { + n = ohci->nb_iso_rcv_ctx; + usage = &ohci->ir_ctx_usage; + } - ohci->irq_hooks[i].irq_handler = irq_handler; - ohci->irq_hooks[i].data = data; + spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); - ret = 0; + for (i = 0; i < n; i++) + if (!test_and_set_bit(i, usage)) { + tasklet->context = i; + list_add_tail(&tasklet->link, &ohci->iso_tasklet_list); + r = 0; + break; + } -out: - spin_unlock_irqrestore(&ohci->irq_hooks_lock, flags); - return ret; + spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); - /* ohci1394 will never be unloaded while an IRQ hook is - in use, because the user must reference this symbol */ + return r; } -void ohci1394_unhook_irq(struct ti_ohci *ohci, - void (*irq_handler) (int, quadlet_t, quadlet_t, void *), - void *data) +void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet) { - int i; unsigned long flags; - - spin_lock_irqsave(&ohci->irq_hooks_lock, flags); - - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - if( (ohci->irq_hooks[i].irq_handler == irq_handler) && - (ohci->irq_hooks[i].data == data) ) - break; - } - - if(i < OHCI1394_MAX_IRQ_HOOKS) { - ohci->irq_hooks[i].irq_handler = NULL; - ohci->irq_hooks[i].data = NULL; - } - spin_unlock_irqrestore(&ohci->irq_hooks_lock, flags); + tasklet_kill(&tasklet->tasklet); + + spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); + + if (tasklet->type == OHCI_ISO_TRANSMIT) + clear_bit(tasklet->context, &ohci->it_ctx_usage); + else + clear_bit(tasklet->context, &ohci->ir_ctx_usage); + + list_del(&tasklet->link); + + spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); } EXPORT_SYMBOL(ohci1394_stop_context); -EXPORT_SYMBOL(ohci1394_hook_irq); -EXPORT_SYMBOL(ohci1394_unhook_irq); - +EXPORT_SYMBOL(ohci1394_init_iso_tasklet); +EXPORT_SYMBOL(ohci1394_register_iso_tasklet); +EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet); /*********************************** Modified: trunk/amdtp.c ============================================================================== --- trunk/amdtp.c (original) +++ trunk/amdtp.c 2002-08-28 03:14:46.000000000 -0400 @@ -251,7 +251,7 @@ struct list_head free_packet_lists; wait_queue_head_t packet_list_wait; spinlock_t packet_list_lock; - int iso_context; + struct ohci1394_iso_tasklet iso_tasklet; struct pci_pool *descriptor_pool, *packet_pool; /* Streams at a host controller are chained through this field. */ @@ -279,23 +279,6 @@ #define OHCI1394_CONTEXT_DEAD 0x00000800 #define OHCI1394_CONTEXT_ACTIVE 0x00000400 -static inline int ohci1394_alloc_it_ctx(struct ti_ohci *ohci) -{ - int i; - - for (i = 0; i < ohci->nb_iso_xmit_ctx; i++) - if (!test_and_set_bit(i, &ohci->it_ctx_usage)) - return i; - - return -EBUSY; -} - -static inline void ohci1394_free_it_ctx(struct ti_ohci *ohci, int ctx) -{ - clear_bit(ctx, &ohci->it_ctx_usage); -} - - void ohci1394_start_it_ctx(struct ti_ohci *ohci, int ctx, dma_addr_t first_cmd, int z, int cycle_match) { @@ -374,7 +357,7 @@ if ((start_cycle & 0x1fff) >= 8000) start_cycle = start_cycle - 8000 + 0x2000; - ohci1394_start_it_ctx(s->host->ohci, s->iso_context, + ohci1394_start_it_ctx(s->host->ohci, s->iso_tasklet.context, pl->packets[0].db_bus, 3, start_cycle & 0x7fff); } @@ -398,14 +381,15 @@ struct packet *last = &prev->packets[PACKET_LIST_SIZE - 1]; last->db->payload_desc.branch = pl->packets[0].db_bus | 3; last->db->header_desc.skip = pl->packets[0].db_bus | 3; - ohci1394_wake_it_ctx(s->host->ohci, s->iso_context); + ohci1394_wake_it_ctx(s->host->ohci, s->iso_tasklet.context); } else stream_start_dma(s, pl); } -static void stream_shift_packet_lists(struct stream *s) +static void stream_shift_packet_lists(unsigned long l) { + struct stream *s = (struct stream *) l; struct packet_list *pl; struct packet *last; int diff; @@ -539,25 +523,6 @@ return frac->integer + (frac->numerator > 0 ? 1 : 0); } -static void amdtp_irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data) -{ - struct amdtp_host *host = data; - struct list_head *lh; - struct stream *s = NULL; - - spin_lock(&host->stream_list_lock); - list_for_each(lh, &host->stream_list) { - s = list_entry(lh, struct stream, link); - if (isoXmitIntEvent & (1 << s->iso_context)) - break; - } - spin_unlock(&host->stream_list_lock); - - if (s != NULL) - stream_shift_packet_lists(s); -} - void packet_initialize(struct packet *p, struct packet *next) { /* Here we initialize the dma descriptor block for @@ -918,7 +883,7 @@ stream_start_dma(s, pl); } else { - ohci1394_stop_it_ctx(s->host->ohci, s->iso_context, 0); + ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 0); } } @@ -1068,8 +1033,11 @@ init_waitqueue_head(&s->packet_list_wait); spin_lock_init(&s->packet_list_lock); - s->iso_context = ohci1394_alloc_it_ctx(host->ohci); - if (s->iso_context < 0) { + ohci1394_init_iso_tasklet(&s->iso_tasklet, OHCI_ISO_TRANSMIT, + stream_shift_packet_lists, + (unsigned long) s); + + if (ohci1394_register_iso_tasklet(host->ohci, &s->iso_tasklet) < 0) { pci_pool_destroy(s->descriptor_pool); kfree(s->input); kfree(s); @@ -1096,8 +1064,8 @@ wait_event_interruptible(s->packet_list_wait, list_empty(&s->dma_packet_lists)); - ohci1394_stop_it_ctx(s->host->ohci, s->iso_context, 1); - ohci1394_free_it_ctx(s->host->ohci, s->iso_context); + ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 1); + ohci1394_unregister_iso_tasklet(s->host->ohci, &s->iso_tasklet); if (s->opcr != NULL) cmp_unregister_opcr(s->host->host, s->opcr); @@ -1250,8 +1218,6 @@ spin_lock_irq(&host_list_lock); list_add_tail(&ah->link, &host_list); spin_unlock_irq(&host_list_lock); - - ohci1394_hook_irq(ah->ohci, amdtp_irq_handler, ah); } static void amdtp_remove_host(struct hpsb_host *host) @@ -1270,7 +1236,6 @@ if (lh != &host_list) { ah = list_entry(lh, struct amdtp_host, link); - ohci1394_unhook_irq(ah->ohci, amdtp_irq_handler, ah); kfree(ah); } else Modified: trunk/dv1394-private.h ============================================================================== --- trunk/dv1394-private.h (original) +++ trunk/dv1394-private.h 2002-08-28 03:14:46.000000000 -0400 @@ -27,6 +27,7 @@ #define _DV_1394_PRIVATE_H #include "ieee1394.h" +#include "ohci1394.h" #include <linux/pci.h> #include <asm/scatterlist.h> @@ -435,6 +436,7 @@ /* OHCI card IT DMA context number, -1 if not in use */ int ohci_it_ctx; + struct ohci1394_iso_tasklet it_tasklet; /* register offsets for current IT DMA context, 0 if not in use */ u32 ohci_IsoXmitContextControlSet; @@ -442,6 +444,7 @@ u32 ohci_IsoXmitCommandPtr; /* OHCI card IR DMA context number, -1 if not in use */ + struct ohci1394_iso_tasklet ir_tasklet; int ohci_ir_ctx; /* register offsets for current IR DMA context, 0 if not in use */ Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2002-08-28 03:14:46.000000000 -0400 @@ -139,6 +139,13 @@ int cmdPtr; }; +struct ohci1394_iso_tasklet { + struct tasklet_struct tasklet; + struct list_head link; + int context; + enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE } type; +}; + struct ti_ohci { int id; /* sequential card number */ @@ -179,12 +186,14 @@ /* iso receive */ struct dma_rcv_ctx ir_context; + struct ohci1394_iso_tasklet ir_tasklet; spinlock_t IR_channel_lock; int nb_iso_rcv_ctx; unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ /* 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 */ @@ -200,17 +209,11 @@ int self_id_errors; - /* IRQ hooks, for video1394 and dv1394 */ + /* Tasklets for iso receive and transmit, used by video1394, + * amdtp and dv1394 */ -#define OHCI1394_MAX_IRQ_HOOKS 16 - - struct ohci1394_irq_hook { - void (*irq_handler) (int card, quadlet_t isoRecvEvent, - quadlet_t isoXmitEvent, void *data); - void *data; - } irq_hooks[OHCI1394_MAX_IRQ_HOOKS]; - - spinlock_t irq_hooks_lock; + struct list_head iso_tasklet_list; + spinlock_t iso_tasklet_list_lock; /* Swap the selfid buffer? */ unsigned int selfid_swap:1; @@ -399,15 +402,17 @@ #define OHCI1394_TCODE_PHY 0xE -void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg); +void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, + int type, + void (*func)(unsigned long), + unsigned long data); +int ohci1394_register_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet); +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); struct ti_ohci *ohci1394_get_struct(int card_num); -int ohci1394_hook_irq(struct ti_ohci *ohci, - void (*irq_handler) (int, quadlet_t, quadlet_t, void *), - void *data); - -void ohci1394_unhook_irq(struct ti_ohci *ohci, - void (*irq_handler) (int, quadlet_t, quadlet_t, void *), - void *data); #endif Modified: trunk/video1394.c ============================================================================== --- trunk/video1394.c (original) +++ trunk/video1394.c 2002-08-28 03:14:46.000000000 -0400 @@ -56,8 +56,6 @@ #include "ohci1394.h" #define ISO_CHANNELS 64 -#define ISO_RECEIVE 0 -#define ISO_TRANSMIT 1 #ifndef virt_to_page #define virt_to_page(x) MAP_NR(x) @@ -84,9 +82,10 @@ struct dma_iso_ctx { struct ti_ohci *ohci; - int type; /* ISO_TRANSMIT or ISO_RECEIVE */ - int ctx; + int type; /* OHCI_ISO_TRANSMIT or OHCI_ISO_RECEIVE */ + struct ohci1394_iso_tasklet iso_tasklet; int channel; + int ctx; int last_buffer; int * next_buffer; /* For ISO Transmit of video packets to write the correct SYT field @@ -153,8 +152,8 @@ #define PRINT(level, card, fmt, args...) \ printk(level "video1394_%d: " fmt "\n" , card , ## args) -static void irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data); +void wakeup_dma_ir_ctx(unsigned long l); +void wakeup_dma_it_ctx(unsigned long l); static LIST_HEAD(video1394_cards); static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED; @@ -234,12 +233,11 @@ static int free_dma_iso_ctx(struct dma_iso_ctx *d) { int i; - unsigned long *usage; DBGMSG(d->ohci->id, "Freeing dma_iso_ctx %d", d->ctx); ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - ohci1394_unhook_irq(d->ohci, irq_handler, d); + ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet); if (d->buf) rvfree((void *)d->buf, d->num_desc * d->buf_size); @@ -265,11 +263,6 @@ if (d->next_buffer) kfree(d->next_buffer); - usage = (d->type == ISO_RECEIVE) ? &d->ohci->ir_ctx_usage : - &d->ohci->it_ctx_usage; - - /* clear the ISO context usage bit */ - clear_bit(d->ctx, usage); list_del(&d->link); kfree(d); @@ -281,55 +274,29 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, int buf_size, int channel, unsigned int packet_size) { - struct dma_iso_ctx *d=NULL; + struct dma_iso_ctx *d; int i; - unsigned long *usage = (type == ISO_RECEIVE) ? &ohci->ir_ctx_usage : - &ohci->it_ctx_usage; - - /* try to claim the ISO context usage bit */ - for (i = 0; i < ohci->nb_iso_rcv_ctx; i++) { - if (!test_and_set_bit(i, usage)) { - PRINT(KERN_ERR, ohci->id, "Free iso ctx %d found", i); - break; - } - } - - if (i == ohci->nb_iso_rcv_ctx) { - PRINT(KERN_ERR, ohci->id, "No DMA contexts available"); - return NULL; - } - d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx), GFP_KERNEL); - if (d==NULL) { + if (d == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_iso_ctx"); return NULL; } - memset(d, 0, sizeof(struct dma_iso_ctx)); + memset(d, 0, sizeof *d); - d->ohci = (void *)ohci; + d->ohci = ohci; d->type = type; - d->ctx = i; d->channel = channel; d->num_desc = num_desc; d->frame_size = buf_size; - if (buf_size%PAGE_SIZE) - d->buf_size = buf_size + PAGE_SIZE - (buf_size%PAGE_SIZE); - else - d->buf_size = buf_size; + d->buf_size = (d->buf_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); d->last_buffer = -1; d->buf = NULL; d->ir_prg = NULL; init_waitqueue_head(&d->waitq); - if (ohci1394_hook_irq(ohci, irq_handler, d) != 0) { - PRINT(KERN_ERR, ohci->id, "ohci1394_hook_irq() failed"); - free_dma_iso_ctx(d); - return NULL; - } - d->buf = rvmalloc(d->num_desc * d->buf_size); if (d->buf == NULL) { @@ -339,7 +306,24 @@ } memset(d->buf, 0, d->num_desc * d->buf_size); - if (type == ISO_RECEIVE) { + if (type == OHCI_ISO_RECEIVE) + ohci1394_init_iso_tasklet(&d->iso_tasklet, type, + wakeup_dma_ir_ctx, + (unsigned long) d); + else + ohci1394_init_iso_tasklet(&d->iso_tasklet, type, + wakeup_dma_it_ctx, + (unsigned long) d); + + if (ohci1394_register_iso_tasklet(ohci, &d->iso_tasklet) < 0) { + PRINT(KERN_ERR, ohci->id, "no free iso %s contexts", + type == OHCI_ISO_RECEIVE ? "receive" : "transmit"); + free_dma_iso_ctx(d); + return NULL; + } + d->ctx = d->iso_tasklet.context; + + if (type == OHCI_ISO_RECEIVE) { d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx; d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx; d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx; @@ -359,7 +343,7 @@ d->nb_cmd = d->buf_size / PAGE_SIZE + 1; d->left_size = (d->frame_size % PAGE_SIZE) ? d->frame_size % PAGE_SIZE : PAGE_SIZE; - + for (i=0;i<d->num_desc;i++) { d->ir_prg[i] = kmalloc(d->nb_cmd * sizeof(struct dma_cmd), @@ -371,8 +355,9 @@ return NULL; } } + } - else { /* 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; @@ -458,7 +443,7 @@ PRINT(KERN_INFO, ohci->id, "Iso %s DMA: %d buffers " "of size %d allocated for a frame size %d, each with %d prgs", - (type==ISO_RECEIVE) ? "receive" : "transmit", + (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit", d->num_desc, d->buf_size, d->frame_size, d->nb_cmd); return d; @@ -563,18 +548,14 @@ return NULL; } -int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) +void wakeup_dma_ir_ctx(unsigned long l) { + struct dma_iso_ctx *d = (struct dma_iso_ctx *) l; int i; - if (d==NULL) { - PRINT(KERN_ERR, ohci->id, "Iso receive event received but " - "context not allocated"); - return -EFAULT; - } - spin_lock(&d->lock); - for (i=0;i<d->num_desc;i++) { + + for (i = 0; i < d->num_desc; i++) { if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) { reset_ir_status(d, i); d->buffer_status[i] = VIDEO1394_BUFFER_READY; @@ -585,9 +566,11 @@ #endif } } + spin_unlock(&d->lock); - if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq); - return 0; + + if (waitqueue_active(&d->waitq)) + wake_up_interruptible(&d->waitq); } static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d, @@ -642,29 +625,28 @@ #endif } -int wakeup_dma_it_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) +void wakeup_dma_it_ctx(unsigned long l) { + struct dma_iso_ctx *d = (struct dma_iso_ctx *) l; + struct ti_ohci *ohci = d->ohci; int i; - if (d==NULL) { - PRINT(KERN_ERR, ohci->id, "Iso transmit event received but " - "context not allocated"); - return -EFAULT; - } - spin_lock(&d->lock); - for (i=0;i<d->num_desc;i++) { - if (d->it_prg[i][d->last_used_cmd[i]].end.status& - cpu_to_le32(0xFFFF0000)) { + + for (i = 0; i < d->num_desc; i++) { + if (d->it_prg[i][d->last_used_cmd[i]].end.status & + cpu_to_le32(0xFFFF0000)) { int next = d->next_buffer[i]; put_timestamp(ohci, d, next); d->it_prg[i][d->last_used_cmd[i]].end.status = 0; d->buffer_status[i] = VIDEO1394_BUFFER_READY; } } + spin_unlock(&d->lock); - if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq); - return 0; + + if (waitqueue_active(&d->waitq)) + wake_up_interruptible(&d->waitq); } static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) @@ -891,7 +873,7 @@ } if (cmd == VIDEO1394_LISTEN_CHANNEL) { - d = alloc_dma_iso_ctx(ohci, ISO_RECEIVE, + d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE, v.nb_buffers, v.buf_size, v.channel, 0); @@ -912,7 +894,7 @@ d->ctx, v.channel); } else { - d = alloc_dma_iso_ctx(ohci, ISO_TRANSMIT, + d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT, v.nb_buffers, v.buf_size, v.channel, v.packet_size); @@ -966,9 +948,9 @@ ohci->ISO_channel_usage &= ~mask; if (cmd == VIDEO1394_UNLISTEN_CHANNEL) - d = find_ctx(&ctx->context_list, ISO_RECEIVE, channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel); else - d = find_ctx(&ctx->context_list, ISO_TRANSMIT, channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel); if (d == NULL) return -EFAULT; PRINT(KERN_INFO, ohci->id, "Iso context %d " @@ -985,7 +967,7 @@ if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1047,7 +1029,7 @@ if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1128,7 +1110,7 @@ if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1217,7 +1199,7 @@ if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; - d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel); + d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, @@ -1340,7 +1322,7 @@ ohci->ISO_channel_usage &= ~mask; PRINT(KERN_INFO, ohci->id, "On release: Iso %s context " "%d stop listening on channel %d", - d->type == ISO_RECEIVE ? "receive" : "transmit", + d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit", d->ctx, d->channel); free_dma_iso_ctx(d); } @@ -1352,20 +1334,6 @@ return 0; } -static void irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data) -{ - struct dma_iso_ctx *d = (struct dma_iso_ctx *) data; - - DBGMSG(card, "Iso event Recv: %08x Xmit: %08x", - isoRecvIntEvent, isoXmitIntEvent); - - if (d->type == ISO_RECEIVE && isoRecvIntEvent & (1 << d->ctx)) - wakeup_dma_ir_ctx(d->ohci, d); - if (d->type == ISO_TRANSMIT && isoXmitIntEvent & (1 << d->ctx)) - wakeup_dma_it_ctx(d->ohci, d); -} - static struct file_operations video1394_fops= { .owner = THIS_MODULE, Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2002-08-28 03:14:46.000000000 -0400 @@ -159,9 +159,8 @@ reg_read(ohci, OHCI1394_IsochronousCycleTimer); } -static void irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data); - +static void it_tasklet_func(unsigned long data); +static void ir_tasklet_func(unsigned long data); /* GLOBAL DATA */ @@ -1036,39 +1035,34 @@ to clean up the init/shutdown process first.*/ if(video->ohci_it_ctx == -1) { + ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT, + it_tasklet_func, (unsigned long) video); - for(i = 0; i < video->ohci->nb_iso_xmit_ctx; i++) { - - if(! test_and_set_bit(i, &video->ohci->it_ctx_usage)) { - video->ohci_it_ctx = i; - debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); - break; - } - } - - if(i == video->ohci->nb_iso_xmit_ctx) { + if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) { printk(KERN_ERR "dv1394: could not find an available IT DMA context\n"); retval = -EBUSY; goto err_ctx; } + else { + video->ohci_it_ctx = video->it_tasklet.context; + debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); + } } if(video->ohci_ir_ctx == -1) { - for(i = 0; i < video->ohci->nb_iso_rcv_ctx; i++) { + ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE, + ir_tasklet_func, (unsigned long) video); - if(! test_and_set_bit(i, &video->ohci->ir_ctx_usage)) { - video->ohci_ir_ctx = i; - debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); - break; - } - } - - if(i == video->ohci->nb_iso_rcv_ctx) { + if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) { printk(KERN_ERR "dv1394: could not find an available IR DMA context\n"); retval = -EBUSY; goto err_ctx; } + else { + video->ohci_ir_ctx = video->ir_tasklet.context; + debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); + } } @@ -1222,11 +1216,11 @@ err_ctx: if(video->ohci_it_ctx != -1) { - clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage); + ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet); video->ohci_it_ctx = -1; } if(video->ohci_ir_ctx != -1) { - clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage); + ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet); video->ohci_ir_ctx = -1; } @@ -2318,8 +2312,7 @@ /*** DEVICE DRIVER HANDLERS ************************************************/ -static void irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data) +static void it_tasklet_func(unsigned long data) { int wake = 0; struct video_card *video = (struct video_card*) data; @@ -2335,7 +2328,6 @@ if( (video->ohci_it_ctx != -1) && - (isoXmitIntEvent & (1 << video->ohci_it_ctx)) && (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) { struct frame *f; @@ -2453,14 +2445,25 @@ } /* for(each frame) */ + } - } /* end XMIT portion */ + spin_unlock(&video->spinlock); - /***** RECEIVE INTERRUPT and DMA ACTIVE *****/ + if(wake) { + kill_fasync(&video->fasync, SIGIO, POLL_OUT); + + /* wake readers/writers/ioctl'ers */ + wake_up_interruptible(&video->waitq); + } +} - else if( (video->ohci_ir_ctx != -1) && - (isoRecvIntEvent & (1 << video->ohci_ir_ctx)) && - (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { +static void ir_tasklet_func(unsigned long data) +{ + int wake = 0; + struct video_card *video = (struct video_card*) data; + + if( (video->ohci_ir_ctx != -1) && + (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { int sof=0; /* start-of-frame flag */ struct frame *f; @@ -2538,15 +2541,8 @@ spin_unlock(&video->spinlock); if(wake) { - - /* send SIGIO */ - - if(isoRecvIntEvent & (1)) - kill_fasync(&video->fasync, SIGIO, POLL_IN); - - if(isoXmitIntEvent & (1)) - kill_fasync(&video->fasync, SIGIO, POLL_OUT); - + kill_fasync(&video->fasync, SIGIO, POLL_IN); + /* wake readers/writers/ioctl'ers */ wake_up_interruptible(&video->waitq); } @@ -2714,12 +2710,6 @@ memset(video, 0, sizeof(struct video_card)); - if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) { - printk(KERN_ERR "dv1394: ohci1394_hook_irq() failed\n"); - goto err_free; - } - - video->ohci = ohci; /* lower 2 bits of id indicate which of four "plugs" per host */ @@ -2795,7 +2785,6 @@ /* obviously nobody has the driver open at this point */ do_dv1394_shutdown(video, 1); - ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video); snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2), (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), (video->mode == MODE_RECEIVE ? "in" : "out") |
From: SVN U. <hog...@li...> - 2002-08-25 18:50:28
|
Author: hogsberg Date: 2002-08-25 23:43:23 -0400 (Sun, 25 Aug 2002) New Revision: 554 Modified: trunk/amdtp.c Log: Implemented poll and tried to make DMA continue over bus resets. Modified: trunk/amdtp.c ============================================================================== --- trunk/amdtp.c (original) +++ trunk/amdtp.c 2002-08-25 23:43:24.000000000 -0400 @@ -46,8 +46,6 @@ * * - Fix DMA stop after bus reset! * - * - Implement poll. - * * - Clean up iso context handling in ohci1394. * * @@ -75,6 +73,7 @@ #include <linux/wait.h> #include <linux/pci.h> #include <linux/interrupt.h> +#include <linux/poll.h> #include <asm/uaccess.h> #include <asm/atomic.h> @@ -398,6 +397,7 @@ if (pl->link.prev != &s->dma_packet_lists) { struct packet *last = &prev->packets[PACKET_LIST_SIZE - 1]; last->db->payload_desc.branch = pl->packets[0].db_bus | 3; + last->db->header_desc.skip = pl->packets[0].db_bus | 3; ohci1394_wake_it_ctx(s->host->ohci, s->iso_context); } else @@ -569,18 +569,19 @@ p->db->header_desc.control = DMA_CTL_OUTPUT_MORE | DMA_CTL_IMMEDIATE | 8; - p->db->header_desc.skip = 0; if (next) { p->db->payload_desc.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH; p->db->payload_desc.branch = next->db_bus | 3; + p->db->header_desc.skip = next->db_bus | 3; } else { p->db->payload_desc.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH | DMA_CTL_UPDATE | DMA_CTL_IRQ; p->db->payload_desc.branch = 0; + p->db->header_desc.skip = 0; } p->db->payload_desc.data_address = p->payload_bus; p->db->payload_desc.status = 0; @@ -1144,8 +1145,13 @@ stream_flush(s); - if (s->current_packet_list == NULL && - wait_event_interruptible(s->packet_list_wait, + if (s->current_packet_list != NULL) + continue; + + if (file->f_flags & O_NONBLOCK) + return i + length > 0 ? i + length : -EAGAIN; + + if (wait_event_interruptible(s->packet_list_wait, !list_empty(&s->free_packet_lists))) return -EINTR; } @@ -1158,7 +1164,6 @@ { struct stream *s = file->private_data; struct amdtp_ioctl cfg; - int new; switch(cmd) { @@ -1169,23 +1174,23 @@ else return stream_configure(s, cmd, &cfg); - case AMDTP_IOC_PING: - HPSB_INFO("ping: offsetting timpestamps %ld ticks", arg); - new = s->cycle_offset.integer + arg; - s->cycle_offset.integer = new % 3072; - atomic_add(new / 3072, &s->cycle_count); - return 0; - - case AMDTP_IOC_ZAP: - while (MOD_IN_USE) - MOD_DEC_USE_COUNT; - return 0; - default: return -EINVAL; } } +static unsigned int amdtp_poll(struct file *file, poll_table *pt) +{ + struct stream *s = file->private_data; + + poll_wait(file, &s->packet_list_wait, pt); + + if (!list_empty(&s->free_packet_lists)) + return POLLOUT | POLLWRNORM; + else + return 0; +} + static int amdtp_open(struct inode *inode, struct file *file) { struct amdtp_host *host; @@ -1221,6 +1226,7 @@ { .owner = THIS_MODULE, .write = amdtp_write, + .poll = amdtp_poll, .ioctl = amdtp_ioctl, .open = amdtp_open, .release = amdtp_release @@ -1232,7 +1238,8 @@ { struct amdtp_host *ah; - /* FIXME: check it's an ohci host. */ + if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME) != 0) + return; ah = kmalloc(sizeof *ah, SLAB_KERNEL); ah->host = host; |
From: SVN U. <hog...@li...> - 2002-08-25 17:50:59
|
Author: hogsberg Date: 2002-08-25 22:43:53 -0400 (Sun, 25 Aug 2002) New Revision: 553 Modified: trunk/ohci1394.c trunk/ohci1394.h Log: Minor cleanup: embed dma_rcv_ctx and dma_trm_ctx structs in struct ti_ohci - fewer kmallocs, fewer null-checks, less fragmentation. Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-08-25 22:43:54.000000000 -0400 @@ -569,18 +569,18 @@ reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); /* Initialize AR dma */ - initialize_dma_rcv_ctx(ohci->ar_req_context, 0); - initialize_dma_rcv_ctx(ohci->ar_resp_context, 0); + initialize_dma_rcv_ctx(&ohci->ar_req_context, 0); + initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0); /* Initialize AT dma */ - initialize_dma_trm_ctx(ohci->at_req_context); - initialize_dma_trm_ctx(ohci->at_resp_context); + initialize_dma_trm_ctx(&ohci->at_req_context); + initialize_dma_trm_ctx(&ohci->at_resp_context); /* Initialize IR dma */ - initialize_dma_rcv_ctx(ohci->ir_context, 1); + initialize_dma_rcv_ctx(&ohci->ir_context, 1); /* Initialize IT dma */ - initialize_dma_trm_ctx(ohci->it_context); + initialize_dma_trm_ctx(&ohci->it_context); /* Set up isoRecvIntMask to generate interrupts for context 0 (thanks to Michael Greger for seeing that I forgot this) */ @@ -854,9 +854,9 @@ /* Decide wether we have an iso, a request, or a response packet */ tcode = (packet->header[0]>>4)&0xf; - if (tcode == TCODE_ISO_DATA) d = ohci->it_context; - else if (tcode & 0x02) d = ohci->at_resp_context; - else d = ohci->at_req_context; + if (tcode == TCODE_ISO_DATA) d = &ohci->it_context; + else if (tcode & 0x02) d = &ohci->at_resp_context; + else d = &ohci->at_req_context; spin_lock_irqsave(&d->lock,flags); @@ -914,8 +914,8 @@ case CANCEL_REQUESTS: DBGMSG(ohci->id, "Cancel request received"); - dma_trm_reset(ohci->at_req_context); - dma_trm_reset(ohci->at_resp_context); + dma_trm_reset(&ohci->at_req_context); + dma_trm_reset(&ohci->at_resp_context); break; case MODIFY_USAGE: @@ -1120,7 +1120,7 @@ * we get sent acks before response packets. This sucks mainly * because it halts the interrupt handler. */ if (event & OHCI1394_reqTxComplete) { - struct dma_trm_ctx *d = ohci->at_req_context; + struct dma_trm_ctx *d = &ohci->at_req_context; DBGMSG(ohci->id, "Got reqTxComplete interrupt " "status=0x%08X", reg_read(ohci, d->ctrlSet)); if (reg_read(ohci, d->ctrlSet) & 0x800) @@ -1131,7 +1131,7 @@ event &= ~OHCI1394_reqTxComplete; } if (event & OHCI1394_respTxComplete) { - struct dma_trm_ctx *d = ohci->at_resp_context; + struct dma_trm_ctx *d = &ohci->at_resp_context; DBGMSG(ohci->id, "Got respTxComplete interrupt " "status=0x%08X", reg_read(ohci, d->ctrlSet)); if (reg_read(ohci, d->ctrlSet) & 0x800) @@ -1142,7 +1142,7 @@ event &= ~OHCI1394_respTxComplete; } if (event & OHCI1394_RQPkt) { - struct dma_rcv_ctx *d = ohci->ar_req_context; + struct dma_rcv_ctx *d = &ohci->ar_req_context; DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X", reg_read(ohci, d->ctrlSet)); if (reg_read(ohci, d->ctrlSet) & 0x800) @@ -1152,7 +1152,7 @@ event &= ~OHCI1394_RQPkt; } if (event & OHCI1394_RSPkt) { - struct dma_rcv_ctx *d = ohci->ar_resp_context; + struct dma_rcv_ctx *d = &ohci->ar_resp_context; DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X", reg_read(ohci, d->ctrlSet)); if (reg_read(ohci, d->ctrlSet) & 0x800) @@ -1163,7 +1163,7 @@ } if (event & OHCI1394_isochRx) { quadlet_t isoRecvIntEvent; - struct dma_rcv_ctx *d = ohci->ir_context; + struct dma_rcv_ctx *d = &ohci->ir_context; isoRecvIntEvent = reg_read(ohci, OHCI1394_IsoRecvIntEventSet); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, @@ -1185,7 +1185,7 @@ } if (event & OHCI1394_isochTx) { quadlet_t isoXmitIntEvent; - struct dma_trm_ctx *d = ohci->it_context; + struct dma_trm_ctx *d = &ohci->it_context; isoXmitIntEvent = reg_read(ohci, OHCI1394_IsoXmitIntEventSet); reg_write(ohci, OHCI1394_IsoXmitIntEventClear, @@ -1563,80 +1563,63 @@ spin_unlock_irqrestore(&d->lock, flags); } -static int free_dma_rcv_ctx(struct dma_rcv_ctx **d) +static void free_dma_rcv_ctx(struct dma_rcv_ctx *d) { int i; struct ti_ohci *ohci; - if (*d==NULL) return -1; + ohci = d->ohci; - ohci = (struct ti_ohci *)(*d)->ohci; - - DBGMSG(ohci->id, "Freeing dma_rcv_ctx %d",(*d)->ctx); + DBGMSG(ohci->id, "Freeing dma_rcv_ctx %d", d->ctx); - ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL); + ohci1394_stop_context(ohci, d->ctrlClear, NULL); - tasklet_kill(&(*d)->task); + tasklet_kill(&d->task); - if ((*d)->buf_cpu) { - for (i=0; i<(*d)->num_desc; i++) - if ((*d)->buf_cpu[i] && (*d)->buf_bus[i]) { + if (d->buf_cpu) { + for (i=0; i<d->num_desc; i++) + if (d->buf_cpu[i] && d->buf_bus[i]) { pci_free_consistent( - ohci->dev, (*d)->buf_size, - (*d)->buf_cpu[i], (*d)->buf_bus[i]); + ohci->dev, d->buf_size, + d->buf_cpu[i], d->buf_bus[i]); OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i); } - kfree((*d)->buf_cpu); - kfree((*d)->buf_bus); + kfree(d->buf_cpu); + kfree(d->buf_bus); } - if ((*d)->prg_cpu) { - for (i=0; i<(*d)->num_desc; i++) - if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) { + if (d->prg_cpu) { + for (i=0; i<d->num_desc; i++) + if (d->prg_cpu[i] && d->prg_bus[i]) { pci_free_consistent( ohci->dev, sizeof(struct dma_cmd), - (*d)->prg_cpu[i], (*d)->prg_bus[i]); + d->prg_cpu[i], d->prg_bus[i]); OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i); } - kfree((*d)->prg_cpu); - kfree((*d)->prg_bus); + kfree(d->prg_cpu); + kfree(d->prg_bus); } - if ((*d)->spb) kfree((*d)->spb); + if (d->spb) kfree(d->spb); /* clear ISO context usage bit */ - if ((*d)->type == DMA_CTX_ISO) { - clear_bit((*d)->ctx, &ohci->ir_ctx_usage); - } - - kfree(*d); - *d = NULL; - - return 0; + if (d->type == DMA_CTX_ISO) + clear_bit(d->ctx, &ohci->ir_ctx_usage); } -static struct dma_rcv_ctx * -alloc_dma_rcv_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc, +static int +alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, + enum context_type type, int ctx, int num_desc, int buf_size, int split_buf_size, int context_base) { - struct dma_rcv_ctx *d; int i; if (type == DMA_CTX_ISO) { /* try to claim the ISO context usage bit */ if (test_and_set_bit(ctx, &ohci->ir_ctx_usage)) { PRINT(KERN_ERR, ohci->id, "IR DMA context %d is not available", ctx); - return NULL; + return -EBUSY; } } - d = kmalloc(sizeof(struct dma_rcv_ctx), GFP_KERNEL); - - if (d == NULL) { - PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_rcv_ctx"); - return NULL; - } - - memset (d, 0, sizeof (struct dma_rcv_ctx)); - d->ohci = ohci; d->type = type; d->ctx = ctx; @@ -1654,8 +1637,8 @@ if (d->buf_cpu == NULL || d->buf_bus == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); - free_dma_rcv_ctx(&d); - return NULL; + free_dma_rcv_ctx(d); + return -ENOMEM; } memset(d->buf_cpu, 0, d->num_desc * sizeof(quadlet_t*)); memset(d->buf_bus, 0, d->num_desc * sizeof(dma_addr_t)); @@ -1666,8 +1649,8 @@ if (d->prg_cpu == NULL || d->prg_bus == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma prg"); - free_dma_rcv_ctx(&d); - return NULL; + free_dma_rcv_ctx(d); + return -ENOMEM; } memset(d->prg_cpu, 0, d->num_desc * sizeof(struct dma_cmd*)); memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t)); @@ -1676,8 +1659,8 @@ if (d->spb == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate split buffer"); - free_dma_rcv_ctx(&d); - return NULL; + free_dma_rcv_ctx(d); + return -ENOMEM; } for (i=0; i<d->num_desc; i++) { @@ -1691,8 +1674,8 @@ } else { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); - free_dma_rcv_ctx(&d); - return NULL; + free_dma_rcv_ctx(d); + return -ENOMEM; } @@ -1706,8 +1689,8 @@ } else { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma prg"); - free_dma_rcv_ctx(&d); - return NULL; + free_dma_rcv_ctx(d); + return -ENOMEM; } } @@ -1716,70 +1699,54 @@ /* initialize tasklet */ tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long)d); - return d; + return 0; } -static int free_dma_trm_ctx(struct dma_trm_ctx **d) +static void free_dma_trm_ctx(struct dma_trm_ctx *d) { struct ti_ohci *ohci; int i; - if (*d==NULL) return -1; - - ohci = (struct ti_ohci *)(*d)->ohci; + ohci = d->ohci; - DBGMSG(ohci->id, "Freeing dma_trm_ctx %d",(*d)->ctx); + DBGMSG(ohci->id, "Freeing dma_trm_ctx %d", d->ctx); - ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL); + ohci1394_stop_context(ohci, d->ctrlClear, NULL); - tasklet_kill(&(*d)->task); + tasklet_kill(&d->task); - if ((*d)->prg_cpu) { - for (i=0; i<(*d)->num_desc; i++) - if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) { + if (d->prg_cpu) { + for (i=0; i<d->num_desc; i++) + if (d->prg_cpu[i] && d->prg_bus[i]) { pci_free_consistent( ohci->dev, sizeof(struct at_dma_prg), - (*d)->prg_cpu[i], (*d)->prg_bus[i]); + d->prg_cpu[i], d->prg_bus[i]); OHCI_DMA_FREE("consistent dma_trm prg[%d]", i); } - kfree((*d)->prg_cpu); - kfree((*d)->prg_bus); + kfree(d->prg_cpu); + kfree(d->prg_bus); } /* clear the ISO context usage bit */ - if ((*d)->type == DMA_CTX_ISO) { - clear_bit((*d)->ctx, &ohci->it_ctx_usage); - } - - kfree(*d); - *d = NULL; - return 0; + if (d->type == DMA_CTX_ISO) + clear_bit(d->ctx, &ohci->it_ctx_usage); } -static struct dma_trm_ctx * -alloc_dma_trm_ctx(struct ti_ohci *ohci, enum context_type type, int ctx, int num_desc, +static int +alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, + enum context_type type, int ctx, int num_desc, int context_base) { - struct dma_trm_ctx *d; int i; if (type == DMA_CTX_ISO) { /* try to claim the ISO context usage bit */ if (test_and_set_bit(ctx, &ohci->it_ctx_usage)) { PRINT(KERN_ERR, ohci->id, "IT DMA context %d is not available", ctx); - return NULL; + return -EBUSY; } } - d = kmalloc(sizeof(struct dma_trm_ctx), GFP_KERNEL); - - if (d == NULL) { - PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_trm_ctx"); - return NULL; - } - - memset (d, 0, sizeof (struct dma_trm_ctx)); - d->ohci = ohci; d->type = type; d->ctx = ctx; @@ -1794,8 +1761,8 @@ if (d->prg_cpu == NULL || d->prg_bus == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate at dma prg"); - free_dma_trm_ctx(&d); - return NULL; + free_dma_trm_ctx(d); + return -ENOMEM; } memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*)); memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t)); @@ -1811,8 +1778,8 @@ } else { PRINT(KERN_ERR, ohci->id, "Failed to allocate at dma prg"); - free_dma_trm_ctx(&d); - return NULL; + free_dma_trm_ctx(d); + return -ENOMEM; } } @@ -1821,7 +1788,7 @@ /* initialize bottom handler */ tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d); - return d; + return 0; } static u16 ohci_crc16 (u32 *ptr, int length) @@ -2115,58 +2082,46 @@ ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE; /* AR DMA request context allocation */ - ohci->ar_req_context = - alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC, - AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE, - OHCI1394_AsReqRcvContextBase); - - if (ohci->ar_req_context == NULL) + if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context, + DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC, + AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE, + OHCI1394_AsReqRcvContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate AR Req context"); /* AR DMA response context allocation */ - ohci->ar_resp_context = - alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC, - AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE, - OHCI1394_AsRspRcvContextBase); - - if (ohci->ar_resp_context == NULL) + if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context, + DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC, + AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE, + OHCI1394_AsRspRcvContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate AR Resp context"); /* AT DMA request context */ - ohci->at_req_context = - alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC, - OHCI1394_AsReqTrContextBase); - - if (ohci->at_req_context == NULL) + if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context, + DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC, + OHCI1394_AsReqTrContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate AT Req context"); /* AT DMA response context */ - ohci->at_resp_context = - alloc_dma_trm_ctx(ohci, DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC, - OHCI1394_AsRspTrContextBase); - - if (ohci->at_resp_context == NULL) + if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context, + DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC, + OHCI1394_AsRspTrContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate AT Resp context"); ohci->ir_ctx_usage = 0; ohci->it_ctx_usage = 0; /* IR DMA context */ - ohci->ir_context = - alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC, - IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, - OHCI1394_IsoRcvContextBase); - - if (ohci->ir_context == NULL) + if (alloc_dma_rcv_ctx(ohci, &ohci->ir_context, + DMA_CTX_ISO, 0, IR_NUM_DESC, + IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, + OHCI1394_IsoRcvContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate IR context"); /* IT DMA context allocation */ - ohci->it_context = - alloc_dma_trm_ctx(ohci, DMA_CTX_ISO, 0, IT_NUM_DESC, - OHCI1394_IsoXmitContextBase); - - if (ohci->it_context == NULL) + if (alloc_dma_trm_ctx(ohci, &ohci->it_context, + DMA_CTX_ISO, 0, IT_NUM_DESC, + OHCI1394_IsoXmitContextBase) < 0) FAIL(-ENOMEM, "Failed to allocate IT context"); ohci->ISO_channel_usage = 0; Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2002-08-25 22:43:54.000000000 -0400 @@ -170,21 +170,21 @@ unsigned int max_packet_size; /* async receive */ - struct dma_rcv_ctx *ar_resp_context; - struct dma_rcv_ctx *ar_req_context; + struct dma_rcv_ctx ar_resp_context; + struct dma_rcv_ctx ar_req_context; /* async transmit */ - struct dma_trm_ctx *at_resp_context; - struct dma_trm_ctx *at_req_context; + struct dma_trm_ctx at_resp_context; + struct dma_trm_ctx at_req_context; /* iso receive */ - struct dma_rcv_ctx *ir_context; + struct dma_rcv_ctx ir_context; spinlock_t IR_channel_lock; int nb_iso_rcv_ctx; unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ /* iso transmit */ - struct dma_trm_ctx *it_context; + struct dma_trm_ctx it_context; int nb_iso_xmit_ctx; unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */ |
From: SVN U. <hog...@li...> - 2002-08-25 16:02:44
|
Author: hogsberg Date: 2002-08-25 20:55:33 -0400 (Sun, 25 Aug 2002) New Revision: 552 Modified: trunk/ieee1394_core.h trunk/ohci1394.c trunk/ohci1394.h trunk/pcilynx.c trunk/pcilynx.h Log: Minor cleanup: use linux/list.h for driver-internal packet queueing Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-08-25 20:55:34.000000000 -0400 @@ -443,10 +443,8 @@ d->sent_ind = 0; d->free_prgs = d->num_desc; d->branchAddrPtr = NULL; - d->fifo_first = NULL; - d->fifo_last = NULL; - d->pending_first = NULL; - d->pending_last = NULL; + INIT_LIST_HEAD(&d->fifo_list); + INIT_LIST_HEAD(&d->pending_list); DBGMSG(ohci->id, "Transmit DMA ctx=%d initialized", d->ctx); } @@ -789,13 +787,7 @@ d->free_prgs--; /* queue the packet in the appropriate context queue */ - if (d->fifo_last) { - d->fifo_last->xnext = packet; - d->fifo_last = packet; - } else { - d->fifo_first = packet; - d->fifo_last = packet; - } + list_add_tail(&packet->driver_list, &d->fifo_list); d->prg_ind = (d->prg_ind+1)%d->num_desc; } @@ -807,22 +799,24 @@ */ static int dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d) { + struct hpsb_packet *p; int idx,z; - if (d->pending_first == NULL || d->free_prgs == 0) + if (list_empty(&d->pending_list) || d->free_prgs == 0) return 0; + p = driver_packet(d->pending_list.next); idx = d->prg_ind; - z = (d->pending_first->data_size) ? 3 : 2; + z = (p->data_size) ? 3 : 2; /* insert the packets into the at dma fifo */ - while (d->free_prgs>0 && d->pending_first) { - insert_packet(ohci, d, d->pending_first); - d->pending_first = d->pending_first->xnext; - } - if (d->pending_first == NULL) - d->pending_last = NULL; - else + while (d->free_prgs > 0 && !list_empty(&d->pending_list)) { + struct hpsb_packet *p = driver_packet(d->pending_list.next); + list_del(&p->driver_list); + insert_packet(ohci, d, p); + } + + if (d->free_prgs == 0) PRINT(KERN_INFO, ohci->id, "Transmit DMA FIFO ctx=%d is full... waiting",d->ctx); @@ -857,7 +851,6 @@ packet->data_size); return 0; } - packet->xnext = NULL; /* Decide wether we have an iso, a request, or a response packet */ tcode = (packet->header[0]>>4)&0xf; @@ -867,15 +860,7 @@ spin_lock_irqsave(&d->lock,flags); - /* queue the packet for later insertion into the dma fifo */ - if (d->pending_last) { - d->pending_last->xnext = packet; - d->pending_last = packet; - } - else { - d->pending_first = packet; - d->pending_last = packet; - } + list_add_tail(&packet->driver_list, &d->pending_list); dma_trm_flush(ohci, d); @@ -1033,46 +1018,38 @@ static void dma_trm_reset(struct dma_trm_ctx *d) { - struct ti_ohci *ohci; unsigned long flags; - struct hpsb_packet *nextpacket; + LIST_HEAD(packet_list); - if (d==NULL) { - PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg"); - return; - } - ohci = (struct ti_ohci *)(d->ohci); - ohci1394_stop_context(ohci, d->ctrlClear, NULL); + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - spin_lock_irqsave(&d->lock,flags); + /* Lock the context, reset it and release it. Move the packets + * that were pending in the context to packet_list and free + * them after releasing the lock. */ - /* Is there still any packet pending in the fifo ? */ - while(d->fifo_first) { - PRINT(KERN_INFO, ohci->id, - "AT dma reset ctx=%d, aborting transmission", - d->ctx); - nextpacket = d->fifo_first->xnext; - hpsb_packet_sent(ohci->host, d->fifo_first, ACKX_ABORTED); - d->fifo_first = nextpacket; - } - d->fifo_first = d->fifo_last = NULL; + spin_lock_irqsave(&d->lock, flags); - /* is there still any packet pending ? */ - while(d->pending_first) { - PRINT(KERN_INFO, ohci->id, - "AT dma reset ctx=%d, aborting transmission", - d->ctx); - nextpacket = d->pending_first->xnext; - hpsb_packet_sent(ohci->host, d->pending_first, - ACKX_ABORTED); - d->pending_first = nextpacket; - } - d->pending_first = d->pending_last = NULL; - - d->branchAddrPtr=NULL; + list_splice(&d->fifo_list, &packet_list); + list_splice(&d->pending_list, &packet_list); + INIT_LIST_HEAD(&d->fifo_list); + INIT_LIST_HEAD(&d->pending_list); + + d->branchAddrPtr = NULL; d->sent_ind = d->prg_ind; d->free_prgs = d->num_desc; - spin_unlock_irqrestore(&d->lock,flags); + + spin_unlock_irqrestore(&d->lock, flags); + + /* Now process subsystem callbacks for the packets from the + * context. */ + + while (!list_empty(&packet_list)) { + struct hpsb_packet *p = driver_packet(packet_list.next); + PRINT(KERN_INFO, d->ohci->id, + "AT dma reset ctx=%d, aborting transmission", d->ctx); + list_del(&p->driver_list); + hpsb_packet_sent(d->ohci->host, p, ACKX_ABORTED); + } } static void ohci_irq_handler(int irq, void *dev_id, @@ -1507,25 +1484,16 @@ { struct dma_trm_ctx *d = (struct dma_trm_ctx*)data; struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); - struct hpsb_packet *packet, *nextpacket; + struct hpsb_packet *packet; unsigned long flags; u32 ack; size_t datasize; spin_lock_irqsave(&d->lock, flags); - if (d->fifo_first == NULL) { -#if 0 - ohci1394_stop_context(ohci, d->ctrlClear, - "Packet sent ack received but queue is empty"); -#endif - spin_unlock_irqrestore(&d->lock, flags); - return; - } - - while (d->fifo_first) { - packet = d->fifo_first; - datasize = d->fifo_first->data_size; + while (!list_empty(&d->fifo_list)) { + packet = driver_packet(d->fifo_list.next); + datasize = packet->data_size; if (datasize && packet->type != hpsb_raw) ack = le32_to_cpu( d->prg_cpu[d->sent_ind]->end.status) >> 16; @@ -1576,7 +1544,7 @@ d->ctx); #endif - nextpacket = packet->xnext; + list_del(&packet->driver_list); hpsb_packet_sent(ohci->host, packet, ack & 0xf); if (datasize) { @@ -1588,10 +1556,7 @@ d->sent_ind = (d->sent_ind+1)%d->num_desc; d->free_prgs++; - d->fifo_first = nextpacket; } - if (d->fifo_first == NULL) - d->fifo_last = NULL; dma_trm_flush(ohci, d); Modified: trunk/ieee1394_core.h ============================================================================== --- trunk/ieee1394_core.h (original) +++ trunk/ieee1394_core.h 2002-08-25 20:55:34.000000000 -0400 @@ -16,7 +16,7 @@ struct list_head list; /* This can be used for host driver internal linking. */ - struct hpsb_packet *xnext; + struct list_head driver_list; nodeid_t node_id; @@ -77,6 +77,10 @@ quadlet_t embedded_header[5]; }; +static inline struct hpsb_packet *driver_packet(struct list_head *l) +{ + return list_entry(l, struct hpsb_packet, driver_list); +} void abort_timedouts(struct hpsb_host *host); void abort_requests(struct hpsb_host *host); Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2002-08-25 20:55:34.000000000 -0400 @@ -127,12 +127,10 @@ quadlet_t *branchAddrPtr; /* list of packets inserted in the AT FIFO */ - struct hpsb_packet *fifo_first; - struct hpsb_packet *fifo_last; + struct list_head fifo_list; /* list of pending packets to be inserted in the AT FIFO */ - struct hpsb_packet *pending_first; - struct hpsb_packet *pending_last; + struct list_head pending_list; spinlock_t lock; struct tasklet_struct task; Modified: trunk/pcilynx.c ============================================================================== --- trunk/pcilynx.c (original) +++ trunk/pcilynx.c 2002-08-25 20:55:34.000000000 -0400 @@ -466,7 +466,7 @@ struct hpsb_packet *packet; d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async); - packet = d->queue; + packet = driver_packet(d->queue.next); d->header_dma = pci_map_single(lynx->dev, packet->header, packet->header_size, PCI_DMA_TODEVICE); @@ -538,7 +538,6 @@ return 0; } - packet->xnext = NULL; if (packet->tcode == TCODE_WRITEQ || packet->tcode == TCODE_READQ_RESPONSE) { cpu_to_be32s(&packet->header[3]); @@ -546,14 +545,9 @@ spin_lock_irqsave(&d->queue_lock, flags); - if (d->queue == NULL) { - d->queue = packet; - d->queue_last = packet; + list_add_tail(&packet->driver_list, &d->queue); + if (d->queue.next == &packet->driver_list) send_next(lynx, packet->type); - } else { - d->queue_last->xnext = packet; - d->queue_last = packet; - } spin_unlock_irqrestore(&d->queue_lock, flags); @@ -566,7 +560,8 @@ { struct ti_lynx *lynx = host->hostdata; int retval = 0; - struct hpsb_packet *packet, *lastpacket; + struct hpsb_packet *packet; + LIST_HEAD(packet_list); unsigned long flags; switch (cmd) { @@ -620,16 +615,16 @@ spin_lock_irqsave(&lynx->async.queue_lock, flags); reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0); - packet = lynx->async.queue; - lynx->async.queue = NULL; + list_splice(&lynx->async.queue, &packet_list); + INIT_LIST_HEAD(&lynx->async.queue); spin_unlock_irqrestore(&lynx->async.queue_lock, flags); - while (packet != NULL) { - lastpacket = packet; - packet = packet->xnext; - hpsb_packet_sent(host, lastpacket, ACKX_ABORTED); - } + while (!list_empty(&packet_list)) { + packet = driver_packet(packet_list.next); + list_del(&packet->driver_list); + hpsb_packet_sent(host, packet, ACKX_ABORTED); + } break; @@ -1122,8 +1117,9 @@ spin_lock(&lynx->async.queue_lock); ack = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_SEND)); - packet = lynx->async.queue; - lynx->async.queue = packet->xnext; + + 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); @@ -1132,7 +1128,7 @@ packet->data_size, PCI_DMA_TODEVICE); } - if (lynx->async.queue != NULL) { + if (!list_empty(&lynx->async.queue)) { send_next(lynx, hpsb_async); } @@ -1154,8 +1150,8 @@ spin_lock(&lynx->iso_send.queue_lock); - packet = lynx->iso_send.queue; - lynx->iso_send.queue = packet->xnext; + packet = driver_packet(lynx->iso_send.queue.next); + list_del(&packet->driver_list); pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, packet->header_size, PCI_DMA_TODEVICE); @@ -1164,7 +1160,7 @@ packet->data_size, PCI_DMA_TODEVICE); } - if (lynx->iso_send.queue != NULL) { + if (!list_empty(&lynx->iso_send.queue)) { send_next(lynx, hpsb_iso); } @@ -1471,7 +1467,8 @@ lynx->selfid_size = -1; lynx->phy_reg0 = -1; - lynx->async.queue = NULL; + INIT_LIST_HEAD(&lynx->async.queue); + INIT_LIST_HEAD(&lynx->iso_send.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-08-25 20:55:34.000000000 -0400 @@ -94,7 +94,7 @@ struct lynx_send_data { pcl_t pcl_start, pcl; - struct hpsb_packet *queue, *queue_last; + struct list_head queue; spinlock_t queue_lock; dma_addr_t header_dma, data_dma; int channel; |
From: SVN U. <dm...@li...> - 2002-08-14 01:14:56
|
Author: dmaas Date: 2002-08-14 05:58:04 -0400 (Wed, 14 Aug 2002) New Revision: 551 Modified: trunk/dv1394-private.h trunk/dv1394.c trunk/ohci1394.c trunk/ohci1394.h Log: - dv1394: expand the spinlock to include video->ohci_i*_ctx (Drew Perttula reported race conditions between irq_handler and do_dv1394_shutdown) - ohci1394: add a spinlock to cover hooking/unhooking IRQ handlers Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-08-14 05:58:05.000000000 -0400 @@ -2211,6 +2211,7 @@ ohci->irq_hooks[i].irq_handler = NULL; ohci->irq_hooks[i].data = NULL; } + spin_lock_init(&ohci->irq_hooks_lock); if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) @@ -2359,12 +2360,15 @@ quadlet_t isoXmitEvent) { int i; + + spin_lock(&ohci->irq_hooks_lock); for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { if(ohci->irq_hooks[i].irq_handler != NULL) { ohci->irq_hooks[i].irq_handler(ohci->id, isoRecvEvent, isoXmitEvent, ohci->irq_hooks[i].data); } } + spin_unlock(&ohci->irq_hooks_lock); } int ohci1394_hook_irq(struct ti_ohci *ohci, @@ -2372,6 +2376,10 @@ void *data) { int i; + int ret = -EBUSY; + unsigned long flags; + + spin_lock_irqsave(&ohci->irq_hooks_lock, flags); /* find a free slot */ for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { @@ -2380,15 +2388,19 @@ } if(i >= OHCI1394_MAX_IRQ_HOOKS) - return -EBUSY; + goto out; ohci->irq_hooks[i].irq_handler = irq_handler; ohci->irq_hooks[i].data = data; + ret = 0; + +out: + spin_unlock_irqrestore(&ohci->irq_hooks_lock, flags); + return ret; + /* ohci1394 will never be unloaded while an IRQ hook is in use, because the user must reference this symbol */ - - return 0; } void ohci1394_unhook_irq(struct ti_ohci *ohci, @@ -2396,6 +2408,9 @@ void *data) { int i; + unsigned long flags; + + spin_lock_irqsave(&ohci->irq_hooks_lock, flags); for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { if( (ohci->irq_hooks[i].irq_handler == irq_handler) && @@ -2407,6 +2422,8 @@ ohci->irq_hooks[i].irq_handler = NULL; ohci->irq_hooks[i].data = NULL; } + + spin_unlock_irqrestore(&ohci->irq_hooks_lock, flags); } EXPORT_SYMBOL(ohci1394_stop_context); Modified: trunk/dv1394-private.h ============================================================================== --- trunk/dv1394-private.h (original) +++ trunk/dv1394-private.h 2002-08-14 05:58:05.000000000 -0400 @@ -477,6 +477,9 @@ immediately. This is safe because the interrupt handler will never advance active_frame onto a frame that is not READY (and the spinlock must be held while marking a frame READY). + + spinlock is also used to protect ohci_it_ctx and ohci_ir_ctx, + which can be accessed from both process and interrupt context */ spinlock_t spinlock; Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2002-08-14 05:58:05.000000000 -0400 @@ -212,6 +212,8 @@ void *data; } irq_hooks[OHCI1394_MAX_IRQ_HOOKS]; + spinlock_t irq_hooks_lock; + /* Swap the selfid buffer? */ unsigned int selfid_swap:1; /* Some Apple chipset seem to swap incoming headers for us */ Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2002-08-14 05:58:05.000000000 -0400 @@ -982,6 +982,7 @@ do_dv1394_shutdown(video, 0); + /* try to claim the ISO channel */ spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); if(video->ohci->ISO_channel_usage & chan_mask) { @@ -994,9 +995,46 @@ video->channel = init->channel; + /* initialize misc. fields of video */ + video->n_frames = init->n_frames; + video->pal_or_ntsc = init->format; + + + video->cip_accum = 0; + video->continuity_counter = 0; + + video->active_frame = -1; + video->first_clear_frame = 0; + video->n_clear_frames = video->n_frames; + video->dropped_frames = 0; + + video->write_off = 0; + + video->first_run = 1; + video->current_packet = -1; + video->first_frame = 0; + + + if(video->pal_or_ntsc == DV1394_NTSC) { + video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC; + video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC; + video->frame_size = DV1394_NTSC_FRAME_SIZE; + } else { + video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL; + video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL; + video->frame_size = DV1394_PAL_FRAME_SIZE; + } + + video->syt_offset = init->syt_offset; - /* find and claim DMA contexts on the OHCI card */ + /* find and claim DMA contexts on the OHCI card */ + + /* XXX this should be the last step of initialization, since the interrupt + handler uses ohci_i*_ctx to indicate whether or not it is safe to touch + frames. I'm not making this change quite yet, since it would be better + to clean up the init/shutdown process first.*/ + if(video->ohci_it_ctx == -1) { for(i = 0; i < video->ohci->nb_iso_xmit_ctx; i++) { @@ -1045,38 +1083,8 @@ } } - /* initialize misc. fields of video */ - video->n_frames = init->n_frames; - video->pal_or_ntsc = init->format; - video->cip_accum = 0; - video->continuity_counter = 0; - - video->active_frame = -1; - video->first_clear_frame = 0; - video->n_clear_frames = video->n_frames; - video->dropped_frames = 0; - - video->write_off = 0; - - video->first_run = 1; - video->current_packet = -1; - video->first_frame = 0; - - - if(video->pal_or_ntsc == DV1394_NTSC) { - video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC; - video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC; - video->frame_size = DV1394_NTSC_FRAME_SIZE; - } else { - video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL; - video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL; - video->frame_size = DV1394_PAL_FRAME_SIZE; - } - - video->syt_offset = init->syt_offset; - if(video->user_buf == NULL) { unsigned int i; @@ -1303,25 +1311,14 @@ static int do_dv1394_shutdown(struct video_card *video, int free_user_buf) { int i; - + unsigned long flags; + debug_printk("dv1394: shutdown...\n"); /* stop DMA if in progress */ stop_dma(video); - /* release the ISO channel */ - if(video->channel != -1) { - u64 chan_mask; - unsigned long flags; - - chan_mask = (u64)1 << video->channel; - - spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); - video->ohci->ISO_channel_usage &= ~(chan_mask); - spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); - - video->channel = -1; - } + spin_lock_irqsave(&video->spinlock, flags); /* release the DMA contexts */ if(video->ohci_it_ctx != -1) { @@ -1351,6 +1348,22 @@ video->ohci_ir_ctx = -1; } + spin_unlock_irqrestore(&video->spinlock, flags); + + /* release the ISO channel */ + if(video->channel != -1) { + u64 chan_mask; + unsigned long flags; + + chan_mask = (u64)1 << video->channel; + + spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); + video->ohci->ISO_channel_usage &= ~(chan_mask); + spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); + + video->channel = -1; + } + /* free the frame structs */ for(i = 0; i < DV1394_MAX_FRAMES; i++) { if(video->frames[i]) @@ -2311,6 +2324,8 @@ int wake = 0; struct video_card *video = (struct video_card*) data; + spin_lock(&video->spinlock); + irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n", (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent); irq_printk("ContextControl = %08x, CommandPtr = %08x\n", @@ -2326,7 +2341,7 @@ struct frame *f; unsigned int frame, i; - spin_lock(&video->spinlock); + if(video->active_frame == -1) frame = 0; else @@ -2439,8 +2454,6 @@ } /* for(each frame) */ - spin_unlock(&video->spinlock); - } /* end XMIT portion */ /***** RECEIVE INTERRUPT and DMA ACTIVE *****/ @@ -2452,8 +2465,6 @@ int sof=0; /* start-of-frame flag */ struct frame *f; u16 packet_length, packet_time; - - spin_lock(&video->spinlock); packet_length = le16_to_cpu(video->packet_buffer[video->current_packet].data_length); packet_time = le16_to_cpu(video->packet_buffer[video->current_packet].timestamp); @@ -2520,12 +2531,12 @@ /* advance packet_buffer cursor */ video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER; - spin_unlock(&video->spinlock); - wake = 1; /* why the hell not? */ } /* receive interrupt */ + spin_unlock(&video->spinlock); + if(wake) { /* send SIGIO */ @@ -2922,12 +2933,13 @@ if(!video) return; + + spin_lock_irqsave(&video->spinlock, flags); + /* check IT context */ if(video->ohci_it_ctx != -1) { u32 ctx; - spin_lock_irqsave(&video->spinlock, flags); - ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet); /* if(RUN but not ACTIVE) */ @@ -2958,16 +2970,12 @@ reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)); } - - spin_unlock_irqrestore(&video->spinlock, flags); } /* check IR context */ if(video->ohci_ir_ctx != -1) { u32 ctx; - spin_lock_irqsave(&video->spinlock, flags); - ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet); /* if(RUN but not ACTIVE) */ @@ -2999,10 +3007,10 @@ reg_read(video->ohci, video->ohci_IsoRcvContextControlSet), reg_read(video->ohci, video->ohci_IsoRcvCommandPtr)); } - - spin_unlock_irqrestore(&video->spinlock, flags); } - + + spin_unlock_irqrestore(&video->spinlock, flags); + /* wake readers/writers/ioctl'ers */ wake_up_interruptible(&video->waitq); } |
From: SVN U. <ben...@li...> - 2002-08-11 05:32:22
|
Author: bencollins Date: 2002-08-11 10:17:59 -0400 (Sun, 11 Aug 2002) New Revision: 550 Added: tags/v2.5/2.5.31/ Removed: tags/v2.5/2.5.29/ Log: sigh...maybe Linus will actually commit this one day Copied: 2.5.31 (from rev 549, tags/v2.5/2.5.29) |
From: SVN U. <ben...@li...> - 2002-08-09 05:11:20
|
Author: bencollins Date: 2002-08-09 09:58:52 -0400 (Fri, 09 Aug 2002) New Revision: 549 Modified: branches/gasp/amdtp.c branches/gasp/csr.c branches/gasp/csr.h branches/gasp/dv1394.c branches/gasp/eth1394.c branches/gasp/eth1394.h branches/gasp/highlevel.c branches/gasp/highlevel.h branches/gasp/hosts.c branches/gasp/hosts.h branches/gasp/ieee1394.h branches/gasp/ieee1394_core.c branches/gasp/ieee1394_transactions.c branches/gasp/ieee1394_transactions.h branches/gasp/nodemgr.c branches/gasp/ohci1394.c branches/gasp/ohci1394.h branches/gasp/raw1394.c branches/gasp/video1394.c Log: Apply GASP patch from Steve Kinneberg Modified: branches/gasp/ieee1394_core.c ============================================================================== --- branches/gasp/ieee1394_core.c (original) +++ branches/gasp/ieee1394_core.c 2002-08-09 09:58:55.000000000 -0400 @@ -160,6 +160,8 @@ abort_requests(host); host->in_bus_reset = 1; + host->is_irm = 0; + host->is_busmgr = 0; host->irm_id = -1; host->busmgr_id = -1; host->node_count = 0; @@ -349,9 +351,6 @@ /* irm_id is kept up to date by check_selfids() */ if (host->irm_id == host->node_id) { host->is_irm = 1; - host->is_busmgr = 1; - host->busmgr_id = host->node_id; - host->csr.bus_manager_id = host->node_id; } host->reset_retries = 0; @@ -419,7 +418,8 @@ packet->state = hpsb_queued; - if (packet->type == hpsb_async && packet->node_id != ALL_NODES) { + if (packet->type == hpsb_async && packet->tcode != TCODE_STREAM_DATA && + packet->node_id != ALL_NODES) { packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64 + (packet->node_id & NODE_MASK)]; @@ -1074,23 +1074,27 @@ EXPORT_SYMBOL(fill_async_lock_resp); EXPORT_SYMBOL(fill_iso_packet); EXPORT_SYMBOL(fill_phy_packet); +EXPORT_SYMBOL(fill_async_stream_packet); EXPORT_SYMBOL(hpsb_make_readqpacket); EXPORT_SYMBOL(hpsb_make_readbpacket); EXPORT_SYMBOL(hpsb_make_writeqpacket); EXPORT_SYMBOL(hpsb_make_writebpacket); EXPORT_SYMBOL(hpsb_make_lockpacket); +EXPORT_SYMBOL(hpsb_make_lock64packet); EXPORT_SYMBOL(hpsb_make_phypacket); EXPORT_SYMBOL(hpsb_packet_success); EXPORT_SYMBOL(hpsb_make_packet); EXPORT_SYMBOL(hpsb_read); EXPORT_SYMBOL(hpsb_write); EXPORT_SYMBOL(hpsb_lock); +EXPORT_SYMBOL(hpsb_lock64); +EXPORT_SYMBOL(hpsb_send_gasp); EXPORT_SYMBOL(hpsb_register_highlevel); EXPORT_SYMBOL(hpsb_unregister_highlevel); EXPORT_SYMBOL(hpsb_register_addrspace); -EXPORT_SYMBOL(hpsb_listen_channel); -EXPORT_SYMBOL(hpsb_unlisten_channel); +EXPORT_SYMBOL(highlevel_channel_open); +EXPORT_SYMBOL(highlevel_channel_close); EXPORT_SYMBOL(highlevel_read); EXPORT_SYMBOL(highlevel_write); EXPORT_SYMBOL(highlevel_lock); Modified: branches/gasp/ohci1394.c ============================================================================== --- branches/gasp/ohci1394.c (original) +++ branches/gasp/ohci1394.c 2002-08-09 09:58:55.000000000 -0400 @@ -31,9 +31,9 @@ * * Things implemented, but still in test phase: * . Iso Transmit + * . Async Stream Packets * * Things not implemented: - * . Async Stream Packets * . DMA error recovery * * Known bugs: @@ -170,6 +170,13 @@ static void ohci1394_pci_remove(struct pci_dev *pdev); +static struct dma_rcv_ctx *alloc_dma_rcv_ctx(struct ti_ohci *ohci, + enum context_type type, + int ctx, int num_desc, + int buf_size, int split_buf_size, + int context_base); +static int free_dma_rcv_ctx(struct dma_rcv_ctx **d); + static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci, quadlet_t isoRecvEvent, quadlet_t isoXmitEvent); @@ -198,7 +205,7 @@ }; /* Swap headers */ -static inline void packet_swab(quadlet_t *data, int tcode, int len) +static inline void packet_swab(quadlet_t *data, int tcode) { if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0) return; @@ -206,7 +213,7 @@ } #else /* Don't waste cycles on same sex byte swaps */ -#define packet_swab(w,x,y) +#define packet_swab(w,x) #define block_swab32(x,y) #endif /* !LITTLE_ENDIAN */ @@ -422,15 +429,56 @@ d->buf_ind = 0; d->buf_offset = 0; - /* Tell the controller where the first AR program is */ + /* Tell the controller where the first dma receive program is */ + reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1); + + /* Run dma receive context */ + reg_write(ohci, d->ctrlSet, 0x00008000); + + DBGMSG(ohci->id, "Receive DMA ctx=%d initialized", d->ctx); +} + +/* ISO packet-per-buffer mode needs different settings */ +static void initialize_dma_rcv_ppb_ctx(struct dma_rcv_ctx *d) +{ + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + int i; + + ohci1394_stop_context(ohci, d->ctrlClear, NULL); + + for (i=0; i<d->num_desc; i++) { + u32 c; + + c = DMA_CTL_INPUT_LAST | DMA_CTL_UPDATE | DMA_CTL_BRANCH | DMA_CTL_IRQ; + + d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size); + + /* End of descriptor list? */ + if (i + 1 < d->num_desc) { + d->prg_cpu[i]->branchAddress = + cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 1); + } else { + d->prg_cpu[i]->branchAddress = + cpu_to_le32((d->prg_bus[0] & 0xfffffff0) | 1); + } + + d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]); + d->prg_cpu[i]->status = cpu_to_le32(d->buf_size); + } + + d->buf_ind = 0; + d->buf_offset = 4; /* packet-per-buffer does things differently :P */ + + /* Tell the controller where the first dma receive program is */ reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1); - /* Run AR context */ + /* Run dma receive context */ reg_write(ohci, d->ctrlSet, 0x00008000); DBGMSG(ohci->id, "Receive DMA ctx=%d initialized", d->ctx); } + /* Initialize the dma transmit context */ static void initialize_dma_trm_ctx(struct dma_trm_ctx *d) { @@ -579,7 +627,7 @@ initialize_dma_trm_ctx(ohci->at_resp_context); /* Initialize IR dma */ - initialize_dma_rcv_ctx(ohci->ir_context, 1); + initialize_dma_rcv_ctx(ohci->ir_context[0], 1); /* Initialize IT dma */ initialize_dma_trm_ctx(ohci->it_context); @@ -610,6 +658,7 @@ /* Enable interrupts */ reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_masterIntEnable | + OHCI1394_unrecoverableError | OHCI1394_busReset | OHCI1394_selfIDComplete | OHCI1394_RSPkt | @@ -676,19 +725,31 @@ } else { d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | (packet->header[0] & 0xFFFF); - d->prg_cpu[idx]->data[1] = - (packet->header[1] & 0xFFFF) | - (packet->header[0] & 0xFFFF0000); - d->prg_cpu[idx]->data[2] = packet->header[2]; - d->prg_cpu[idx]->data[3] = packet->header[3]; - packet_swab(d->prg_cpu[idx]->data, packet->tcode, - packet->header_size>>2); + + if(packet->tcode == TCODE_STREAM_DATA){ + /* Sending an asynchronous stream packet */ + d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; + } else { + /* Sending a normal asynchronous request or response packet */ + d->prg_cpu[idx]->data[1] = + (packet->header[1] & 0xFFFF) | + (packet->header[0] & 0xFFFF0000); + d->prg_cpu[idx]->data[2] = packet->header[2]; + d->prg_cpu[idx]->data[3] = packet->header[3]; + } + packet_swab(d->prg_cpu[idx]->data, packet->tcode); } if (packet->data_size) { /* block transmit */ - d->prg_cpu[idx]->begin.control = - cpu_to_le32(DMA_CTL_OUTPUT_MORE | - DMA_CTL_IMMEDIATE | 0x10); + if(packet->tcode == TCODE_STREAM_DATA){ + d->prg_cpu[idx]->begin.control = + cpu_to_le32(DMA_CTL_OUTPUT_MORE | + DMA_CTL_IMMEDIATE | 0x8); + } else { + d->prg_cpu[idx]->begin.control = + cpu_to_le32(DMA_CTL_OUTPUT_MORE | + DMA_CTL_IMMEDIATE | 0x10); + } d->prg_cpu[idx]->end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_IRQ | @@ -747,7 +808,7 @@ d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | (packet->header[0] & 0xFFFF); d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; - packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2); + packet_swab(d->prg_cpu[idx]->data, packet->tcode); d->prg_cpu[idx]->begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE | @@ -861,7 +922,8 @@ /* Decide wether we have an iso, a request, or a response packet */ tcode = (packet->header[0]>>4)&0xf; - if (tcode == TCODE_ISO_DATA) d = ohci->it_context; + if ((tcode == TCODE_ISO_DATA) && (packet->type == hpsb_iso)) + d = ohci->it_context; else if (tcode & 0x02) d = ohci->at_resp_context; else d = ohci->at_req_context; @@ -892,9 +954,13 @@ switch (cmd) { case RESET_BUS: + /* should probably remove the attempt_root module parameter + * because proper operation of the 1394 bus doesn't need it */ DBGMSG(ohci->id, "devctl: Bus reset requested%s", - attempt_root ? " and attempting to become root" : ""); - set_phy_reg_mask (ohci, 1, 0x40 | (attempt_root ? 0x80 : 0)); + (arg == 1 || attempt_root) ? + " and attempting to become root" : ""); + set_phy_reg_mask (ohci, 1, 0x40 | ((arg = 1 || attempt_root) ? + 0x80 : 0)); break; case GET_CYCLE_COUNTER: @@ -944,71 +1010,103 @@ case ISO_LISTEN_CHANNEL: { - u64 mask; - - if (arg<0 || arg>63) { - PRINT(KERN_ERR, ohci->id, - "%s: IS0 listen channel %d is out of range", - __FUNCTION__, arg); - return -EFAULT; - } + int channel = arg & ISO_LISTEN_CHANNEL_MASK; + int context; - mask = (u64)0x1<<arg; - spin_lock_irqsave(&ohci->IR_channel_lock, flags); - if (ohci->ISO_channel_usage & mask) { - PRINT(KERN_ERR, ohci->id, - "%s: IS0 listen channel %d is already used", - __FUNCTION__, arg); - spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); - return -EFAULT; - } - - ohci->ISO_channel_usage |= mask; + if(ohci->ir_channel_to_ctx[channel] != OHCI1394_IR_CTX_UNALLOCED) { + if((ohci->ir_channel_to_ctx[channel] == 0) && + (arg & ISO_LISTEN_SINGLE_PACKET)) + PRINT(KERN_ERR, ohci->id, + "Attempting to listen to channel in packet-" + "per-buffer mode when channel already being " + "listened to in buffer-fill mode"); + /* already listening to requested channel, nothing to do */ + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + break; + } - if (arg>31) - reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, - 1<<(arg-32)); - else - reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, - 1<<arg); + if(arg & ISO_LISTEN_SINGLE_PACKET) { + if(ohci->ir_ctx_usage == ~0x0) { + PRINT(KERN_ERR, ohci->id, + "Cannot listen to ISO channel %d, " + "all contexts are in use", + channel); + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + return -EBUSY; /* all contexts in use */ + } + + context = ffz(ohci->ir_ctx_usage); + DBGMSG(ohci->id, "using context: %d", context); + + ohci->ir_context[context] = + alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, context, + IR_NUM_DESC, IR_BUF_SIZE, + IR_SPLIT_BUF_SIZE, + OHCI1394_IsoRcvContextBase + + (0x20 * context)); + if(ohci->ir_context[context] == NULL) { + PRINT(KERN_ERR, ohci->id, + "Cannot listen to ISO channel %d, " + "requested context %d not available", + channel, context); + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + return -EBUSY; + } + + /* Set packet-per-buffer, isochHeader, for IR context */ + reg_write(ohci, OHCI1394_IsoRcvContextControlSet + (0x20 * context), + 0x40000000); + + /* Set the context match register to match on all tags */ + reg_write(ohci, OHCI1394_IsoRcvContextMatch + (0x20 * context), + 0x8000001f); + + /* Initialize IR dma */ + initialize_dma_rcv_ppb_ctx(ohci->ir_context[context]); + + reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x1 << context); + } else { + context = 0; + if (channel>31) + reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, + 1<<(channel-32)); + else + reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, + 1<<channel); + } + ohci->ir_channel_to_ctx[channel] = context; spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); - DBGMSG(ohci->id, "Listening enabled on channel %d", arg); + DBGMSG(ohci->id, "Listening enabled on channel %d", channel); break; } case ISO_UNLISTEN_CHANNEL: { - u64 mask; - - if (arg<0 || arg>63) { - PRINT(KERN_ERR, ohci->id, - "%s: IS0 unlisten channel %d is out of range", - __FUNCTION__, arg); - return -EFAULT; - } + int context = ohci->ir_channel_to_ctx[arg]; - mask = (u64)0x1<<arg; - spin_lock_irqsave(&ohci->IR_channel_lock, flags); - if (!(ohci->ISO_channel_usage & mask)) { - PRINT(KERN_ERR, ohci->id, - "%s: IS0 unlisten channel %d is not used", - __FUNCTION__, arg); - spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); - return -EFAULT; - } - - ohci->ISO_channel_usage &= ~mask; + if(context == OHCI1394_IR_CTX_UNALLOCED) { + /* already not listening to requested channel, nothing to do */ + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + break; + } - if (arg>31) - reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, - 1<<(arg-32)); - else - reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, - 1<<arg); + if (context == 0) { + if (arg>31) + reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, + 1<<(arg-32)); + else + reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, + 1<<arg); + } else { + /* Free IR dma */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0x1 << context); + free_dma_rcv_ctx(&ohci->ir_context[context]); + ohci->ir_channel_to_ctx[arg] = OHCI1394_IR_CTX_UNALLOCED; + } spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); DBGMSG(ohci->id, "Listening disabled on channel %d", arg); @@ -1096,10 +1194,64 @@ DBGMSG(ohci->id, "IntEvent: %08x", event); - /* Die right here an now */ if (event & OHCI1394_unrecoverableError) { - PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!"); - return; + int ctx; + PRINT(KERN_ERR, ohci->id, "Unrecoverable error!"); + if(reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Req Tx Context died. "); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x", + reg_read(ohci, OHCI1394_AsReqTrContextControlSet), + reg_read(ohci, OHCI1394_AsReqTrCommandPtr)); + } + if(reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Rsp Tx Context died. "); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x", + reg_read(ohci, OHCI1394_AsRspTrContextControlSet), + reg_read(ohci, OHCI1394_AsRspTrCommandPtr)); + } + if(reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Req Rcv Context died. "); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x", + reg_read(ohci, OHCI1394_AsReqRcvContextControlSet), + reg_read(ohci, OHCI1394_AsReqRcvCommandPtr)); + } + if(reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Rsp Rcv Context died. "); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x", + reg_read(ohci, OHCI1394_AsRspRcvContextControlSet), + reg_read(ohci, OHCI1394_AsRspRcvCommandPtr)); + } + for(ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) { + if(reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Iso Xmit %d Context died. ", ctx); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x", + reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)), + reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx))); + } + } + for(ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) { + if(reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Iso Recv %d Context died. ", ctx); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x " + " match: %#010x", + reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)), + reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)), + reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx))); + } + } + event &= ~OHCI1394_unrecoverableError; } if (event & OHCI1394_cycleInconsistent) { @@ -1186,15 +1338,25 @@ } if (event & OHCI1394_isochRx) { quadlet_t isoRecvIntEvent; - struct dma_rcv_ctx *d = ohci->ir_context; + struct dma_rcv_ctx *d = ohci->ir_context[0]; + int i; + isoRecvIntEvent = reg_read(ohci, OHCI1394_IsoRecvIntEventSet); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, isoRecvIntEvent); - DBGMSG(ohci->id, "Got isochRx interrupt " - "status=0x%08X isoRecvIntEvent=%08x", - reg_read(ohci, d->ctrlSet), isoRecvIntEvent); - if (isoRecvIntEvent & 0x1) { + DBGMSG(ohci->id, "Got isochRx interrupt isoRecvIntEvent=%08x", + isoRecvIntEvent); + + for (i = 0; i < ohci->nb_iso_rcv_ctx; i++) { + if (!test_bit(i, &ohci->ir_ctx_usage) || + !test_bit(i, &isoRecvIntEvent)) { + continue; + } + d = ohci->ir_context[i]; + DBGMSG(ohci->id, " Handling context %d: status = %08x", + i, reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) ohci1394_stop_context(ohci, d->ctrlClear, "isochRx"); @@ -1375,9 +1537,16 @@ quadlet_t *buf_ptr; char *split_ptr; char msg[256]; + int ppb_mode; spin_lock_irqsave(&d->lock, flags); + /* ppb_mode is a hack to deal with the time stamp being at the + * begining of a receive packet in packet-per-buffer mode (gotta love + * inconsistancy) */ + ppb_mode = ((d->type == DMA_CTX_ISO) && + ((reg_read(ohci, d->cmdPtr) & (1 << 31)) != (1 << 31))); + idx = d->buf_ind; offset = d->buf_offset; buf_ptr = d->buf_cpu[idx] + offset/4; @@ -1450,17 +1619,22 @@ memcpy(split_ptr, buf_ptr, split_left); offset = split_left; buf_ptr += offset/4; + if(ppb_mode) + insert_dma_buffer(d, idx); } } else { DBGMSG(ohci->id,"Single packet rcv'd"); memcpy(d->spb, buf_ptr, length); offset += length; buf_ptr += length/4; - if (offset==d->buf_size) { + if (offset==d->buf_size || ppb_mode) { insert_dma_buffer(d, idx); idx = (idx+1) % d->num_desc; buf_ptr = d->buf_cpu[idx]; - offset=0; + if(ppb_mode) + offset=4; + else + offset=0; } } @@ -1468,7 +1642,7 @@ * bus reset. We always ignore it. */ if (tcode != OHCI1394_TCODE_PHY) { if (!ohci->no_swap_incoming) - packet_swab(d->spb, tcode, (length - 4) >> 2); + packet_swab(d->spb, tcode); DBGMSG(ohci->id, "Packet received from node" " %d ack=0x%02X spd=%d tcode=0x%X" " length=%d ctx=%d tlabel=%d", @@ -1547,33 +1721,46 @@ } #ifdef OHCI1394_DEBUG - if (datasize) + if (((le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >> 4) & 0xf) == TCODE_STREAM_DATA) { DBGMSG(ohci->id, - "Packet sent to node %d tcode=0x%X tLabel=" - "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d", - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) - >>16)&0x3f, + "Packet sent via Async stream tcode=0x%X " + "ack=0x%X spd=%d dataLength=%d ctx=%d", (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) >>4)&0xf, - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) - >>10)&0x3f, ack&0x1f, (ack>>5)&0x3, - le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]) + le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) >>16, d->ctx); - else - DBGMSG(ohci->id, - "Packet sent to node %d tcode=0x%X tLabel=" - "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d", - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) + } else { + if (datasize) + DBGMSG(ohci->id, + "Packet sent to node %d tcode=0x%X tLabel=" + "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d", + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) >>16)&0x3f, - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) >>4)&0xf, - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) >>10)&0x3f, - ack&0x1f, (ack>>5)&0x3, - le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]), - d->ctx); + ack&0x1f, (ack>>5)&0x3, + le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]) + >>16, + d->ctx); + else + DBGMSG(ohci->id, + "Packet sent to node %d tcode=0x%X tLabel=" + "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d", + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) + >>16)&0x3f, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >>4)&0xf, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >>10)&0x3f, + ack&0x1f, (ack>>5)&0x3, + le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]), + d->ctx); + } #endif nextpacket = packet->xnext; @@ -2187,12 +2374,12 @@ ohci->it_ctx_usage = 0; /* IR DMA context */ - ohci->ir_context = + ohci->ir_context[0] = alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC, IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, OHCI1394_IsoRcvContextBase); - if (ohci->ir_context == NULL) + if (ohci->ir_context[0] == NULL) FAIL(-ENOMEM, "Failed to allocate IR context"); @@ -2204,7 +2391,7 @@ if (ohci->it_context == NULL) FAIL(-ENOMEM, "Failed to allocate IT context"); - ohci->ISO_channel_usage = 0; + memset(ohci->ir_channel_to_ctx, OHCI1394_IR_CTX_UNALLOCED, sizeof(char) * 64); spin_lock_init(&ohci->IR_channel_lock); for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { @@ -2255,7 +2442,7 @@ free_dma_trm_ctx(&ohci->at_resp_context); /* Free IR dma */ - free_dma_rcv_ctx(&ohci->ir_context); + free_dma_rcv_ctx(&ohci->ir_context[0]); /* Free IT dma */ free_dma_trm_ctx(&ohci->it_context); Modified: branches/gasp/amdtp.c ============================================================================== --- branches/gasp/amdtp.c (original) +++ branches/gasp/amdtp.c 2002-08-09 09:58:55.000000000 -0400 @@ -924,6 +924,7 @@ static int stream_configure(struct stream *s, int cmd, struct amdtp_ioctl *cfg) { const int transfer_delay = 9000; + int oldchan; if (cfg->format <= AMDTP_FORMAT_IEC958_AC3) s->format = cfg->format; @@ -1003,6 +1004,7 @@ s->opcr = NULL; } + oldchan = s->iso_channel; switch(cmd) { case AMDTP_IOC_PLUG: s->opcr = cmp_register_opcr(s->host->host, cfg->u.plug, @@ -1019,6 +1021,10 @@ return -EINVAL; break; } + if (oldchan != s->iso_channel) { + highlevel_channel_close(s->host->host, oldchan); + highlevel_channel_open(s->host->host, s->iso_channel, ISOCH_RESERVE); + } /* The ioctl settings were all valid, so we realloc the packet * lists to make sure the packet size is big enough. Modified: branches/gasp/ohci1394.h ============================================================================== --- branches/gasp/ohci1394.h (original) +++ branches/gasp/ohci1394.h 2002-08-09 09:58:55.000000000 -0400 @@ -56,6 +56,8 @@ #define OHCI1394_SI_DMA_BUF_SIZE 8192 /* length of the selfid buffer */ +#define OHCI1394_IR_CTX_UNALLOCED (1 << 5) + /* PCI configuration space addresses */ #define OHCI1394_PCI_HCI_Control 0x40 @@ -180,18 +182,17 @@ struct dma_trm_ctx *at_req_context; /* iso receive */ - struct dma_rcv_ctx *ir_context; + struct dma_rcv_ctx *ir_context[32]; spinlock_t IR_channel_lock; int nb_iso_rcv_ctx; unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ + char ir_channel_to_ctx[64]; /* map channel number to context */ /* iso transmit */ struct dma_trm_ctx *it_context; 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 */ struct hpsb_host *host; @@ -289,6 +290,9 @@ #define OHCI1394_IsoRecvIntEventClear 0x0A4 #define OHCI1394_IsoRecvIntMaskSet 0x0A8 #define OHCI1394_IsoRecvIntMaskClear 0x0AC +#define OHCI1394_InitialBandwidthAvailable 0x0B0 +#define OHCI1394_InitialChannelsAvailableHi 0x0B4 +#define OHCI1394_InitialChannelsAvailableLo 0x0B8 #define OHCI1394_FairnessControl 0x0DC #define OHCI1394_LinkControlSet 0x0E0 #define OHCI1394_LinkControlClear 0x0E4 Modified: branches/gasp/raw1394.c ============================================================================== --- branches/gasp/raw1394.c (original) +++ branches/gasp/raw1394.c 2002-08-09 09:58:55.000000000 -0400 @@ -538,7 +538,7 @@ req->req.error = RAW1394_ERROR_ALREADY; } else { fi->listen_channels |= 1ULL << channel; - hpsb_listen_channel(hl_handle, fi->host, channel); + highlevel_channel_open(fi->host, channel, ISOCH_RDONLY); fi->iso_buffer = int2ptr(req->req.recvb); fi->iso_buffer_length = req->req.length; } @@ -547,7 +547,7 @@ channel = ~channel; if (fi->listen_channels & (1ULL << channel)) { - hpsb_unlisten_channel(hl_handle, fi->host, channel); + highlevel_channel_close(fi->host, channel); fi->listen_channels &= ~(1ULL << channel); } else { req->req.error = RAW1394_ERROR_INVALID_ARG; @@ -944,7 +944,7 @@ for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { - hpsb_unlisten_channel(hl_handle, fi->host, i); + highlevel_channel_close(fi->host, i); } } Modified: branches/gasp/ieee1394_transactions.c ============================================================================== --- branches/gasp/ieee1394_transactions.c (original) +++ branches/gasp/ieee1394_transactions.c 2002-08-09 09:58:55.000000000 -0400 @@ -146,6 +146,17 @@ packet->speed_code = SPEED_100; /* Force speed to be 100Mbps */ } +void fill_async_stream_packet(struct hpsb_packet *packet, int length, + int channel, int tag, int sync) +{ + packet->header[0] = (length << 16) | (tag << 14) | (channel << 8) + | (TCODE_STREAM_DATA << 4) | sync; + + packet->header_size = 4; + packet->data_size = length; + packet->type = hpsb_async; + packet->tcode = TCODE_ISO_DATA; +} /** * get_tlabel - allocate a transaction label @@ -400,6 +411,31 @@ return p; } +struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(16); + if (!p) return NULL; + + p->host = host; + p->tlabel = get_tlabel(host, node, 1); + p->node_id = node; + + switch (extcode) { + case EXTCODE_FETCH_ADD: + case EXTCODE_LITTLE_ADD: + fill_async_lock(p, addr, extcode, 8); + break; + default: + fill_async_lock(p, addr, extcode, 16); + break; + } + + return p; +} + struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data) { @@ -611,3 +647,129 @@ return retval; } + +int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, octlet_t *data, octlet_t arg) +{ + struct hpsb_packet *packet; + int retval = 0, length; + + if (host->node_id == node) { + switch(highlevel_lock64(host, node, data, addr, *data, arg, + extcode)) { + case RCODE_COMPLETE: + return 0; + case RCODE_TYPE_ERROR: + return -EACCES; + case RCODE_ADDRESS_ERROR: + default: + return -EINVAL; + } + } + + packet = alloc_hpsb_packet(16); + if (!packet) { + return -ENOMEM; + } + + packet->host = host; + packet->tlabel = get_tlabel(host, node, 1); + packet->node_id = node; + + switch (extcode) { + case EXTCODE_MASK_SWAP: + case EXTCODE_COMPARE_SWAP: + case EXTCODE_BOUNDED_ADD: + case EXTCODE_WRAP_ADD: + length = 16; + packet->data[0] = (quadlet_t)(arg >> 32); + packet->data[1] = (quadlet_t)(arg & 0xFFFFFFFFLL); + packet->data[2] = (quadlet_t)(*data >> 32); + packet->data[3] = (quadlet_t)(*data & 0xFFFFFFFFLL); + break; + case EXTCODE_FETCH_ADD: + case EXTCODE_LITTLE_ADD: + length = 8; + packet->data[0] = (quadlet_t)(*data >> 32); + packet->data[1] = (quadlet_t)(*data & 0xFFFFFFFFLL); + break; + default: + return -EINVAL; + } + fill_async_lock(packet, addr, extcode, length); + + packet->generation = generation; + if (!hpsb_send_packet(packet)) { + retval = -EINVAL; + goto hpsb_lock_fail; + } + down(&packet->state_change); + down(&packet->state_change); + retval = hpsb_packet_success(packet); + + if (retval == 0) { + *data = (u64)packet->data[1] << 32 | packet->data[0]; + } + +hpsb_lock_fail: + free_tlabel(host, node, packet->tlabel); + free_hpsb_packet(packet); + + return retval; +} + +int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, + quadlet_t *buffer, size_t length, u32 specifier_id, + unsigned int version) +{ +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + int i; +#endif + + struct hpsb_packet *packet; + int retval = 0; + u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8; + u8 specifier_id_lo = specifier_id & 0xff; + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG("Send GASP: channel = %d, length = %d", channel, length); +#endif + + length += 8; + + packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0)); + if (!packet) + return -ENOMEM; + + if (length % 4) { + packet->data[length / 4] = 0; + } + + packet->host = host; + fill_async_stream_packet(packet, length, channel, 3, 0); + + packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi); + packet->data[1] = cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff)); + + memcpy(&(packet->data[2]), buffer, length - 4); + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG("GASP: packet->header_size = %d", packet->header_size); + HPSB_DEBUG("GASP: packet->data_size = %d", packet->data_size); + + for(i=0; i<(packet->data_size/4); i++) + HPSB_DEBUG("GASP: data[%d]: 0x%08x", i*4, be32_to_cpu(packet->data[i])); +#endif + + packet->generation = generation; + + packet->no_waiter = 1; + + if (!hpsb_send_packet(packet)) { + free_hpsb_packet(packet); + retval = -EINVAL; + } + + return retval; +} + Modified: branches/gasp/ieee1394_transactions.h ============================================================================== --- branches/gasp/ieee1394_transactions.h (original) +++ branches/gasp/ieee1394_transactions.h 2002-08-09 09:58:55.000000000 -0400 @@ -23,6 +23,8 @@ void fill_iso_packet(struct hpsb_packet *packet, int length, int channel, int tag, int sync); void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data); +void fill_async_stream_packet(struct hpsb_packet *packet, int length, + int channel, int tag, int sync); /* * Get and free transaction labels. @@ -42,6 +44,8 @@ size_t length); struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode); +struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode); struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data) ; @@ -73,6 +77,11 @@ u64 addr, quadlet_t *buffer, size_t length); int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, int extcode, quadlet_t *data, quadlet_t arg); +int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, octlet_t *data, octlet_t arg); +int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, + quadlet_t *buffer, size_t length, u32 specifier_id, + unsigned int version); /* Generic packet creation. Used by hpsb_write. Also useful for protocol * drivers that want to implement their own hpsb_write replacement. */ Modified: branches/gasp/nodemgr.c ============================================================================== --- branches/gasp/nodemgr.c (original) +++ branches/gasp/nodemgr.c 2002-08-09 09:58:56.000000000 -0400 @@ -1159,6 +1159,51 @@ return; } + +/* Because we are a 1394a compliant IRM, we need to inform all the other nodes + * of the broadcast channel. (Really we're only setting the validity bit). */ +static void nodemgr_do_irm_duties(struct hpsb_host *host) +{ + quadlet_t bc; + + if (!host->is_irm) return; + + host->csr.broadcast_channel |= 0x40000000; /* set validity bit */ + + bc = cpu_to_be32(host->csr.broadcast_channel); + + hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host), + (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL), + &bc, + sizeof(quadlet_t)); +} + + +/* We need to ensure that if we are not the IRM, that the IRM node is capable of + * everything we can do, otherwise issue a bus reset and try to become the IRM + * ourselves. */ +static int nodemgr_check_root_capability(struct hpsb_host *host) +{ + quadlet_t bc; + int status; + + if (host->is_irm) return 0; + + status = hpsb_read(host, LOCAL_BUS | (host->irm_id), + get_hpsb_generation(host), + (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL), + &bc, sizeof(quadlet_t)); + + if(status < 0 || !(be32_to_cpu(bc) & 0x80000000)) { + /* The root node does not have a valid BROADCAST_CHANNEL + * register and we do, so reset the bus with force_root set */ + HPSB_INFO("remote root node does not have a valid BROADCAST_CHANNEL register, resetting..."); + hpsb_reset_bus(host, 1); + return 1; + } + return 0; +} + static int nodemgr_host_thread(void *__hi) { struct host_info *hi = (struct host_info *)__hi; @@ -1172,6 +1217,12 @@ * happens when we get a bus reset. */ while (!down_interruptible(&hi->reset_sem) && !down_interruptible(&nodemgr_serialize)) { + if(nodemgr_check_root_capability(hi->host)) { + up(&nodemgr_serialize); + continue; /* don't do anything else, we're resetting */ + } + nodemgr_do_irm_duties(hi->host); + nodemgr_node_probe(hi->host); up(&nodemgr_serialize); } Modified: branches/gasp/hosts.c ============================================================================== --- branches/gasp/hosts.c (original) +++ branches/gasp/hosts.c 2002-08-09 09:58:56.000000000 -0400 @@ -136,6 +136,8 @@ sema_init(&h->tlabel_count, 64); spin_lock_init(&h->tlabel_lock); + spin_lock_init(&h->channel_access_lock); + atomic_set(&h->generation, 0); INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h); Modified: branches/gasp/eth1394.c ============================================================================== --- branches/gasp/eth1394.c (original) +++ branches/gasp/eth1394.c 2002-08-09 09:58:56.000000000 -0400 @@ -74,7 +74,8 @@ printk(level ETHER1394_DRIVER_NAME": %s: " fmt, dev_name, ## args) #define DEBUG(fmt, args...) \ - printk(KERN_ERR fmt, ## args) + ETH1394_PRINT_G(KERN_ERR, "%s[%d]:"fmt"\n", __FUNCTION__, __LINE__, ## args) + static char version[] __devinitdata = "$Rev$ Ben Collins <bco...@de...>"; @@ -167,7 +168,7 @@ ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n", ((struct eth1394_priv *)(dev->priv))->host->driver->name); - highlevel_host_reset (((struct eth1394_priv *)(dev->priv))->host); + hpsb_reset_bus (((struct eth1394_priv *)(dev->priv))->host, 0); netif_wake_queue (dev); } @@ -178,7 +179,7 @@ * XXX: This is where we need to create a list of skb's for fragmented * packets. */ static inline void ether1394_encapsulate (struct sk_buff *skb, struct net_device *dev, - int proto) + int proto, struct packet_task *ptask) { union eth1394_hdr *hdr = (union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]); @@ -187,6 +188,16 @@ hdr->words.word1 = htons(hdr->words.word1); hdr->uf.ether_type = proto; + /* Set the transmission type for the packet. Right now only ARP + * packets are sent via GASP. IP broadcast and IP multicast are not + * yet supported properly, they too should use GASP. */ + switch(proto) { + case __constant_htons(ETH_P_ARP): + ptask->tx_type = ETH1394_GASP; + break; + default: + ptask->tx_type = ETH1394_WRREQ; + } return; } @@ -289,6 +300,8 @@ memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi)); memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo)); + priv->bc_state = ETHER1394_CHECK; + /* Register our limits now */ ether1394_register_limits (phy_id, (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf, priv->host->speed_map[(phy_id << 6) + phy_id], @@ -299,7 +312,8 @@ /* We'll use our max_rec as the default mtu */ if (set_mtu) - dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - sizeof (union eth1394_hdr); + dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - /* mtu = max_rec - */ + (sizeof (union eth1394_hdr) + 8); /* (hdr + GASP) */ /* Set our hardware address while we're at it */ *(nodeid_t *)dev->dev_addr = htons (priv->host->node_id); @@ -343,6 +357,8 @@ struct eth1394_priv *priv; static int version_printed = 0; + quadlet_t bc; + if (version_printed++ == 0) ETH1394_PRINT_G (KERN_INFO, "%s\n", version); @@ -382,6 +398,17 @@ list_add_tail (&hi->list, &host_info_list); spin_unlock_irq (&host_info_lock); + + highlevel_read(host, host->node_id, &bc, + CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL, + sizeof(quadlet_t)); + + /* Ignore validity in hopes that it will be set in the future. It'll + * check it on transmit. */ + priv->broadcast_channel = be32_to_cpu(bc) & 0x3f; + + highlevel_channel_open(host, priv->broadcast_channel, ISOCH_RDWR | ISOCH_SGL_PKT); + return; out: @@ -395,11 +422,14 @@ /* Remove a card from our list */ static void ether1394_remove_host (struct hpsb_host *host) { + struct eth1394_priv *priv; struct host_info *hi; spin_lock_irq (&host_info_lock); hi = find_host_info (host); if (hi != NULL) { + priv = (struct eth1394_priv *)hi->dev->priv; + priv->bc_state = ETHER1394_BC_CLOSED; unregister_netdev (hi->dev); kfree (hi->dev); list_del (&hi->list); @@ -590,6 +620,88 @@ return RCODE_COMPLETE; } +static void ether1394_iso_receive(struct hpsb_host *host, int channel, + quadlet_t *data, unsigned int length) +{ + struct sk_buff *skb; + char *buf = (char *)data + 12; + int flags; + struct net_device *dev = ether1394_find_dev (host); + struct eth1394_priv *priv; + unsigned int len = length - 12; + u32 specifier_id = (((be32_to_cpu(data[1]) & 0xffff) << 8) | + ((be32_to_cpu(data[2]) & 0xff000000) >> 24)); + u16 source_id = be32_to_cpu(data[1]) >> 16; + + if (dev == NULL) { + ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n", + host->driver->name); + return; + } + + priv = (struct eth1394_priv *)dev->priv; + + if (channel != priv->broadcast_channel || + specifier_id != ETHER1394_GASP_SPECIFIER_ID) { + /* This packet is not for us */ + return; + } + + /* A packet has been received by the ieee1394 bus. Build an skbuff + * around it so we can pass it to the high level network layer. */ + + skb = dev_alloc_skb (len + dev->hard_header_len + 15); + if (!skb) { + HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n"); + priv->stats.rx_dropped++; + return; + } + + skb_reserve(skb, (dev->hard_header_len + 15) & ~15); + + memcpy (skb_put (skb, len), buf, len); + + /* Write metadata, and then pass to the receive level */ + skb->dev = dev; + skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + + /* Parse the encapsulation header. This actually does the job of + * converting to an ethernet frame header, aswell as arp + * conversion if needed. ARP conversion is easier in this + * direction, since we are using ethernet as our backend. */ + skb->protocol = ether1394_parse_encap (skb, dev, source_id, + LOCAL_BUS | ALL_NODES); + + spin_lock_irqsave (&priv->lock, flags); + if (!skb->protocol) { + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + dev_kfree_skb_any(skb); + goto bad_proto; + } + + netif_stop_queue(dev); + if (netif_rx (skb) == NET_RX_DROP) { + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + goto bad_proto; + } + + /* Statistics */ + priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + +bad_proto: + netif_start_queue(dev); + spin_unlock_irqrestore (&priv->lock, flags); + + dev->last_rx = jiffies; + + return; +} + + + /* This function is our scheduled write */ static void hpsb_write_sched (void *__ptask) { @@ -598,12 +710,24 @@ struct net_device *dev = ptask->skb->dev; struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; unsigned long flags; + int status; + + if (ptask->tx_type == ETH1394_GASP) { + status = hpsb_send_gasp(priv->host, priv->broadcast_channel, + get_hpsb_generation(priv->host), + (quadlet_t *)skb->data, skb->len, + ETHER1394_GASP_SPECIFIER_ID, + ETHER1394_GASP_VERSION); + } else { + status = hpsb_write(priv->host, ptask->dest_node, + get_hpsb_generation(priv->host), + ptask->addr, (quadlet_t *)skb->data, + skb->len); + } /* Statistics */ spin_lock_irqsave (&priv->lock, flags); - if (!hpsb_write(priv->host, ptask->dest_node, - get_hpsb_generation(priv->host), - ptask->addr, (quadlet_t *)skb->data, skb->len)) { + if (!status) { priv->stats.tx_bytes += skb->len; priv->stats.tx_packets++; } else { @@ -635,6 +759,54 @@ struct packet_task *ptask = NULL; int ret = 0; + spin_lock_irqsave (&priv->lock, flags); + if(priv->bc_state == ETHER1394_BC_CLOSED) + ETH1394_PRINT(KERN_ERR, dev->name, + "Cannot send packet, no broadcast channel available."); + + /* First time sending? Need a broadcast channel for ARP and for + * listening on */ + if (priv->bc_state == ETHER1394_CHECK) { + quadlet_t bc; + + /* Get the local copy of the broadcast channel and check its + * validity (the IRM should validate it for us) */ + + highlevel_read(priv->host, priv->host->node_id, &bc, + CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL, + sizeof(quadlet_t)); + + bc = be32_to_cpu(bc); + if((bc & 0xc0000000) != 0xc0000000) { + /* broadcast channel not validated yet */ + ETH1394_PRINT(KERN_WARNING, dev->name, + "Error BROADCAST_CHANNEL register valid " + "bit not set, can't send IP traffic\n"); + highlevel_channel_close(priv->host, + priv->broadcast_channel); + priv->bc_state = ETHER1394_BC_CLOSED; + ret = -EAGAIN; + spin_unlock_irqrestore (&priv->lock, flags); + goto fail; + } + if(priv->broadcast_channel != (bc & 0x3f)) { + /* This really shouldn't be possible, but just in case + * the IEEE 1394 spec changes regarding broadcast + * channels in the future. */ + highlevel_channel_close(priv->host, + priv->broadcast_channel); + priv->broadcast_channel = bc & 0x3f; + ETH1394_PRINT(KERN_WARNING, dev->name, + "Changing to broadcast channel %d...\n", + priv->broadcast_channel); + highlevel_channel_open(priv->host, priv->broadcast_channel, + ISOCH_RDWR | ISOCH_SGL_PKT); + } + priv->bc_state = ETHER1394_OPENED; + } + spin_unlock_irqrestore (&priv->lock, flags); + + if ((skb = skb_share_check (skb, kmflags)) == NULL) { ret = -ENOMEM; goto fail; @@ -653,8 +825,14 @@ if (proto == __constant_htons (ETH_P_ARP)) ether1394_arp_to_1394arp (skb, dev); + ptask = kmem_cache_alloc(packet_task_cache, kmflags); + if (ptask == NULL) { + ret = -ENOMEM; + goto fail; + } + /* Now add our encapsulation header */ - ether1394_encapsulate (skb, dev, proto); + ether1394_encapsulate (skb, dev, proto, ptask); /* TODO: The above encapsulate function needs to recognize when a * packet needs to be split for a specified node. It should create @@ -673,12 +851,6 @@ if (!addr) addr = ETHER1394_REGION_ADDR; - ptask = kmem_cache_alloc(packet_task_cache, kmflags); - if (ptask == NULL) { - ret = -ENOMEM; - goto fail; - } - ptask->skb = skb; ptask->addr = addr; ptask->dest_node = dest_node; @@ -699,7 +871,7 @@ netif_wake_queue (dev); spin_unlock_irqrestore (&priv->lock, flags); - return ret; + return 0; /* returning non-zero causes serious problems */ } /* Function for incoming 1394 packets */ @@ -712,6 +884,7 @@ .add_host = ether1394_add_host, .remove_host = ether1394_remove_host, .host_reset = ether1394_host_reset, + .iso_receive = ether1394_iso_receive, }; static int __init ether1394_init_module (void) @@ -735,6 +908,21 @@ static void __exit ether1394_exit_module (void) { + struct list_head *lh; + struct host_info *hi; + struct eth1394_priv *priv; + + lh = host_info_list.next; + while (lh != &host_info_list) { + hi = list_entry (lh, struct host_info, list); + priv = (struct eth1394_priv*)hi->dev->priv; + if(priv->bc_state != ETHER1394_BC_CLOSED) { + highlevel_channel_close(hi->host, priv->broadcast_channel); + } + lh = lh->next; + } + + hpsb_unregister_highlevel (hl_handle); kmem_cache_destroy(packet_task_cache); } Modified: branches/gasp/hosts.h ============================================================================== --- branches/gasp/hosts.h (original) +++ branches/gasp/hosts.h 2002-08-09 09:58:56.000000000 -0400 @@ -12,6 +12,14 @@ struct hpsb_packet; +typedef enum { + HPSB_CHANNEL_UNUSED, + HPSB_CHANNEL_SHARED, + HPSB_CHANNEL_EXCLUSIVE, + HPSB_CHANNEL_RESERVED, +} __attribute__((packed)) hpsb_channel_alloc_t; + + struct hpsb_host { struct list_head host_list; @@ -32,7 +40,9 @@ spinlock_t tlabel_lock; u32 tlabel_current; - unsigned char iso_listen_count[64]; + spinlock_t channel_access_lock; + unsigned char iso_access_count[64]; + hpsb_channel_alloc_t iso_channel_usage[64]; int node_count; /* number of identified nodes on this bus */ int selfid_count; /* total number of SelfIDs received */ @@ -94,13 +104,19 @@ * fail. */ MODIFY_USAGE, - /* Start or stop receiving isochronous channel in arg. Return void. - * This acts as an optimization hint, hosts are not required not to - * listen on unrequested channels. */ + /* Start or stop receiving isochronous channel in arg. Do not use + * these directly, use the functions highlevel_channel_open() and + * highlevel_channel_close() instead. Returns an error code if there + * is a problem and 0 otherwise. The arg option + * ISO_LISTEN_SINGLE_PACKET may not be implemented for all + * controllers */ ISO_LISTEN_CHANNEL, ISO_UNLISTEN_CHANNEL }; +#define ISO_LISTEN_CHANNEL_MASK 0x3f +#define ISO_LISTEN_SINGLE_PACKET (1 << 6) + enum reset_types { /* 166 microsecond reset -- only type of reset available on non-1394a capable IEEE 1394 controllers */ Modified: branches/gasp/eth1394.h ============================================================================== --- branches/gasp/eth1394.h (original) +++ branches/gasp/eth1394.h 2002-08-09 09:58:56.000000000 -0400 @@ -30,9 +30,17 @@ #define ETHER1394_REGION_ADDR 0xfffff0200000ULL #define ETHER1394_REGION_ADDR_END (ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN) +/* GASP identifier numbers for IPv4 over IEEE 1394 */ +#define ETHER1394_GASP_SPECIFIER_ID 0x00005E +#define ETHER1394_GASP_VERSION 1 + + /* Node set == 64 */ #define NODE_SET (ALL_NODES + 1) +enum eth1394_bc_states { ETHER1394_BC_CLOSED, ETHER1394_OPENED, + ETHER1394_CHECK }; + /* Private structure for our ethernet driver */ struct eth1394_priv { struct net_device_stats stats; /* Device stats */ @@ -43,6 +51,8 @@ u32 fifo_lo[ALL_NODES]; /* 32bit lo fifo offset per node */ u64 eui[ALL_NODES]; /* EUI-64 per node */ spinlock_t lock; /* Private lock */ + int broadcast_channel; /* Async stream Broadcast Channel */ + enum eth1394_bc_states bc_state; /* broadcast channel state */ }; struct host_info { @@ -51,12 +61,15 @@ struct net_device *dev; }; +typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; + /* This is our task struct. It's used for the complete_tq callback. */ struct packet_task { struct sk_buff *skb; /* Socket buffer we are sending */ nodeid_t dest_node; /* Destination of the packet */ u64 addr; /* Address */ struct tq_struct tq; /* The task */ + eth1394_tx_type tx_type; /* Send data via GASP or Write Req. */ }; /* IP1394 headers */ Modified: branches/gasp/highlevel.c ============================================================================== --- branches/gasp/highlevel.c (original) +++ branches/gasp/highlevel.c 2002-08-09 09:58:56.000000000 -0400 @@ -130,31 +130,77 @@ } -void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, - unsigned int channel) +int highlevel_channel_open(struct hpsb_host *host, unsigned int channel, + unsigned int flags) { + int slflags; + int enable_listen = ((flags & (ISOCH_RDONLY | ISOCH_RDWR)) != 0); + int enable_sgl_pkt = ((flags & ISOCH_SGL_PKT) != 0); + int retval = 0; + if (channel > 63) { - HPSB_ERR("%s called with invalid channel", __FUNCTION__); - return; + HPSB_ERR("%s called with invalid channel: %d", __FUNCTION__, channel); + return -EINVAL; } - if (host->iso_listen_count[channel]++ == 0) { - host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel); - } + spin_lock_irqsave(&host->channel_access_lock, slflags); + + if (host->iso_channel_usage[channel] == HPSB_CHANNEL_UNUSED) { + if (flags & ISOCH_RESERVE) + host->iso_channel_usage[channel] = HPSB_CHANNEL_RESERVED; + else if (flags & ISOCH_EXCL) + host->iso_channel_usage[channel] = HPSB_CHANNEL_EXCLUSIVE; + else /* shared channel */ + host->iso_channel_usage[channel] = HPSB_CHANNEL_SHARED; + } else if ((host->iso_channel_usage[channel] != HPSB_CHANNEL_SHARED) || + ((flags & (ISOCH_EXCL | ISOCH_RESERVE)) != 0)) { + spin_unlock_irqrestore(&host->channel_access_lock, slflags); + HPSB_WARN("iso channel %d not available for opening", channel); + return -EBUSY; + ... [truncated message content] |
From: SVN U. <ben...@li...> - 2002-08-09 05:09:19
|
Author: bencollins Date: 2002-08-09 09:56:54 -0400 (Fri, 09 Aug 2002) New Revision: 548 Added: branches/gasp/ Modified: branches/gasp/eth1394.c Log: Test branch for gasp patch Copied: gasp (from rev 547, trunk) Modified: branches/gasp/eth1394.c ============================================================================== --- trunk/eth1394.c (original) +++ branches/gasp/eth1394.c 2002-08-09 09:56:55.000000000 -0400 @@ -97,7 +97,7 @@ sizeof (struct eth1394_sf_hdr) }; -MODULE_AUTHOR("Ben Collins (bco...@de...)"); +MODULE_AUTHOR("Ben Collins <bco...@de...>"); MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)"); MODULE_LICENSE("GPL"); |
From: SVN U. <ben...@li...> - 2002-08-09 04:30:53
|
Author: bencollins Date: 2002-08-09 09:18:29 -0400 (Fri, 09 Aug 2002) New Revision: 547 Modified: trunk/nodemgr.c Log: Fix proc devices listing for some odd cases Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2002-08-09 09:18:29.000000000 -0400 @@ -133,16 +133,24 @@ /* Now the unit directories */ list_for_each (l, &ne->unit_directories) { struct unit_directory *ud = list_entry (l, struct unit_directory, node_list); + int printed = 0; // small hack + PUTF(" Unit Directory %d:\n", ud_count++); - if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) + if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) { PUTF(" Vendor/Model ID: %s [%06x]", ud->vendor_name ?: "Unknown", ud->vendor_id); - else if (ud->flags & UNIT_DIRECTORY_MODEL_ID) /* Have to put something */ - PUTF(" Vendor/Model ID: %s [%06x]", - ne->vendor_name ?: "Unknown", ne->vendor_id); - if (ud->flags & UNIT_DIRECTORY_MODEL_ID) + printed = 1; + } + if (ud->flags & UNIT_DIRECTORY_MODEL_ID) { + if (!printed) + PUTF(" Vendor/Model ID: %s [%06x]", + ne->vendor_name ?: "Unknown", ne->vendor_id); PUTF(" / %s [%06x]", ud->model_name ?: "Unknown", ud->model_id); - PUTF("\n"); + printed = 1; + } + if (printed) + PUTF("\n"); + if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) PUTF(" Software Specifier ID: %06x\n", ud->specifier_id); if (ud->flags & UNIT_DIRECTORY_VERSION) |
From: SVN U. <ben...@li...> - 2002-08-09 03:56:58
|
Author: bencollins Date: 2002-08-09 08:44:37 -0400 (Fri, 09 Aug 2002) New Revision: 546 Modified: trunk/eth1394.c Log: Add rev to init string Modified: trunk/eth1394.c ============================================================================== --- trunk/eth1394.c (original) +++ trunk/eth1394.c 2002-08-09 08:44:38.000000000 -0400 @@ -77,7 +77,7 @@ printk(KERN_ERR fmt, ## args) static char version[] __devinitdata = - "eth1394.c:v0.50 15/Jul/01 Ben Collins <bco...@de...>"; + "$Rev$ Ben Collins <bco...@de...>"; /* Our ieee1394 highlevel driver */ #define ETHER1394_DRIVER_NAME "ether1394" |
From: SVN U. <ben...@li...> - 2002-08-09 03:53:16
|
Author: bencollins Date: 2002-08-09 08:40:53 -0400 (Fri, 09 Aug 2002) New Revision: 545 Modified: trunk/Config.help trunk/Config.in trunk/Makefile trunk/Makefile.in trunk/amdtp.c trunk/amdtp.h trunk/cmp.c trunk/cmp.h trunk/csr.c trunk/csr.h trunk/dv1394-private.h trunk/dv1394.c trunk/dv1394.h trunk/eth1394.c trunk/eth1394.h trunk/highlevel.c trunk/highlevel.h trunk/hosts.c trunk/hosts.h trunk/ieee1394.h trunk/ieee1394_core.c trunk/ieee1394_core.h trunk/ieee1394_hotplug.h trunk/ieee1394_transactions.c trunk/ieee1394_transactions.h trunk/ieee1394_types.h trunk/nodemgr.c trunk/nodemgr.h trunk/ohci1394.c trunk/ohci1394.h trunk/pcilynx.c trunk/pcilynx.h trunk/raw1394.c trunk/raw1394.h trunk/sbp2.c trunk/sbp2.h trunk/video1394.c trunk/video1394.h Log: Enable Rev keyword for all files, just to make things easier |
From: SVN U. <ben...@li...> - 2002-08-09 03:40:01
|
Author: bencollins Date: 2002-08-09 08:27:40 -0400 (Fri, 09 Aug 2002) New Revision: 544 Modified: trunk/eth1394.c Log: Added GPL module license Modified: trunk/eth1394.c ============================================================================== --- trunk/eth1394.c (original) +++ trunk/eth1394.c 2002-08-09 08:27:40.000000000 -0400 @@ -99,6 +99,7 @@ MODULE_AUTHOR("Ben Collins (bco...@de...)"); MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)"); +MODULE_LICENSE("GPL"); /* Find our host_info struct for a given host pointer. Must be called * under spinlock. */ |