linux1394-cvslog Mailing List for IEEE 1394 for Linux (Page 12)
Brought to you by:
aeb,
bencollins
You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(10) |
Jul
(12) |
Aug
(8) |
Sep
(9) |
Oct
(4) |
Nov
(5) |
Dec
(5) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(7) |
Feb
(3) |
Mar
(15) |
Apr
(12) |
May
(5) |
Jun
(9) |
Jul
(32) |
Aug
(39) |
Sep
(42) |
Oct
(22) |
Nov
(28) |
Dec
(8) |
2002 |
Jan
(37) |
Feb
(47) |
Mar
(6) |
Apr
(29) |
May
(33) |
Jun
(9) |
Jul
(28) |
Aug
(30) |
Sep
(15) |
Oct
(75) |
Nov
(37) |
Dec
(31) |
2003 |
Jan
|
Feb
(89) |
Mar
(41) |
Apr
(13) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: SVN U. <ben...@li...> - 2002-10-06 13:45:23
|
Author: bencollins Date: 2002-10-06 09:45:19 -0400 (Sun, 06 Oct 2002) New Revision: 593 Added: tags/v2.5/2.5.41-r587/ Removed: tags/v2.5/2.5.40-r587/ Log: Tag point merged by Linus. Should be available in 2.5.41 Copied: 2.5.41-r587 (from rev 592, tags/v2.5/2.5.40-r587) |
From: SVN U. <ben...@li...> - 2002-10-04 21:07:30
|
Author: bencollins Date: 2002-10-05 02:02:56 -0400 (Sat, 05 Oct 2002) New Revision: 592 Removed: branches/config-rom-gen/ branches/mpeg1394/ branches/weihs/ Modified: trunk/cmp.c trunk/csr.c trunk/csr.h trunk/eth1394.c trunk/highlevel.c trunk/highlevel.h trunk/hosts.h trunk/ieee1394_core.c trunk/ieee1394_transactions.c trunk/ieee1394_transactions.h trunk/ieee1394_types.h trunk/ohci1394.c trunk/pcilynx.c trunk/raw1394.c trunk/raw1394.h trunk/sbp2.c trunk/sbp2.h Log: Merge Weihs branch to trunk. Delete the obsolete config-rom-gen, mpeg1394 and weihs branches now. Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2002-10-05 02:02:59.000000000 -0400 @@ -5,9 +5,19 @@ * highlevel or lowlevel code * * Copyright (C) 1999, 2000 Andreas E. Bombe + * 2002 Manfred Weihs <we...@ic...> * * This code is licensed under the GPL. See the file COPYING in the root * directory of the kernel sources for details. + * + * + * Contributions: + * + * Manfred Weihs <we...@ic...> + * loopback functionality in hpsb_send_packet + * allow highlevel drivers to disable automatic response generation + * and to generate responses themselves (deferred) + * */ #include <linux/config.h> @@ -372,12 +382,19 @@ build_speed_map(host, host->node_count); } +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_INFO("selfid_complete called with successful SelfID stage " + "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id); +#endif /* 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; + } else { + host->is_busmgr = 0; + host->is_irm = 0; } host->reset_retries = 0; @@ -448,6 +465,45 @@ packet->state = hpsb_queued; + if (packet->node_id == host->node_id) + { /* it is a local request, so handle it locally */ + quadlet_t *data; + size_t size=packet->data_size+packet->header_size; + + int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + data = kmalloc(packet->header_size + packet->data_size, kmflags); + if (!data) { + HPSB_ERR("unable to allocate memory for concatenating header and data"); + return 0; + } + + memcpy(data, packet->header, packet->header_size); + + if (packet->data_size) + { + if (packet->data_be) { + memcpy(((u8*)data)+packet->header_size, packet->data, packet->data_size); + } else { + int i; + quadlet_t *my_data=(quadlet_t*) ((u8*) data + packet->data_size); + for (i=0; i < packet->data_size/4; i++) { + my_data[i] = cpu_to_be32(packet->data[i]); + } + } + } + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + dump_packet("send packet local:", packet->header, + packet->header_size); +#endif + hpsb_packet_sent(host, packet, packet->expect_response?ACK_PENDING:ACK_COMPLETE); + hpsb_packet_received(host, data, size, 0); + + kfree(data); + + return 1; + } + if (packet->type == hpsb_async && packet->node_id != ALL_NODES) { packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64 @@ -600,8 +656,10 @@ { struct hpsb_packet *packet; int length, rcode, extcode; + quadlet_t buffer; nodeid_t source = data[1] >> 16; - nodeid_t dest = data[0] >> 16; + nodeid_t dest = data[0] >> 16; + u16 flags = (u16) data[0]; u64 addr; /* big FIXME - no error checking is done for an out of bounds length */ @@ -610,10 +668,11 @@ case TCODE_WRITEQ: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; rcode = highlevel_write(host, source, dest, data+3, - addr, 4); + addr, 4, flags); if (!write_acked - && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) { + && (((data[0] >> 16) & NODE_MASK) != NODE_MASK) + && (rcode >= 0)) { /* not a broadcast write, reply */ PREP_REPLY_PACKET(0); fill_async_write_resp(packet, rcode); @@ -624,10 +683,11 @@ case TCODE_WRITEB: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; rcode = highlevel_write(host, source, dest, data+4, - addr, data[3]>>16); + addr, data[3]>>16, flags); if (!write_acked - && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) { + && (((data[0] >> 16) & NODE_MASK) != NODE_MASK) + && (rcode >= 0)) { /* not a broadcast write, reply */ PREP_REPLY_PACKET(0); fill_async_write_resp(packet, rcode); @@ -636,12 +696,14 @@ break; case TCODE_READQ: - PREP_REPLY_PACKET(0); - addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_read(host, source, data, addr, 4); - fill_async_readquad_resp(packet, rcode, *data); - send_packet_nocare(packet); + rcode = highlevel_read(host, source, &buffer, addr, 4, flags); + + if (rcode >= 0) { + PREP_REPLY_PACKET(0); + fill_async_readquad_resp(packet, rcode, buffer); + send_packet_nocare(packet); + } break; case TCODE_READB: @@ -650,9 +712,12 @@ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; rcode = highlevel_read(host, source, packet->data, addr, - length); - fill_async_readblock_resp(packet, rcode, length); - send_packet_nocare(packet); + length, flags); + + if (rcode >= 0) { + fill_async_readblock_resp(packet, rcode, length); + send_packet_nocare(packet); + } break; case TCODE_LOCK_REQUEST: @@ -670,7 +735,7 @@ switch (length) { case 4: rcode = highlevel_lock(host, source, packet->data, addr, - data[4], 0, extcode); + data[4], 0, extcode,flags); fill_async_lock_resp(packet, rcode, extcode, 4); break; case 8: @@ -679,13 +744,13 @@ rcode = highlevel_lock(host, source, packet->data, addr, data[5], data[4], - extcode); + extcode, flags); fill_async_lock_resp(packet, rcode, extcode, 4); } else { rcode = highlevel_lock64(host, source, (octlet_t *)packet->data, addr, *(octlet_t *)(data + 4), 0ULL, - extcode); + extcode, flags); fill_async_lock_resp(packet, rcode, extcode, 8); } break; @@ -694,15 +759,20 @@ (octlet_t *)packet->data, addr, *(octlet_t *)(data + 6), *(octlet_t *)(data + 4), - extcode); + extcode, flags); fill_async_lock_resp(packet, rcode, extcode, 8); break; default: - fill_async_lock_resp(packet, RCODE_TYPE_ERROR, + rcode = RCODE_TYPE_ERROR; + fill_async_lock_resp(packet, rcode, extcode, 0); } - send_packet_nocare(packet); + if (rcode >= 0) { + send_packet_nocare(packet); + } else { + free_hpsb_packet(packet); + } break; } @@ -1109,6 +1179,7 @@ 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); @@ -1119,6 +1190,7 @@ EXPORT_SYMBOL(hpsb_register_highlevel); EXPORT_SYMBOL(hpsb_unregister_highlevel); EXPORT_SYMBOL(hpsb_register_addrspace); +EXPORT_SYMBOL(hpsb_unregister_addrspace); EXPORT_SYMBOL(hpsb_listen_channel); EXPORT_SYMBOL(hpsb_unlisten_channel); EXPORT_SYMBOL(highlevel_read); @@ -1135,6 +1207,8 @@ EXPORT_SYMBOL(hpsb_node_read); EXPORT_SYMBOL(hpsb_node_write); EXPORT_SYMBOL(hpsb_node_lock); +EXPORT_SYMBOL(hpsb_update_config_rom); +EXPORT_SYMBOL(hpsb_get_config_rom); EXPORT_SYMBOL(hpsb_register_protocol); EXPORT_SYMBOL(hpsb_unregister_protocol); EXPORT_SYMBOL(hpsb_release_unit_directory); Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-10-05 02:02:59.000000000 -0400 @@ -1905,7 +1905,7 @@ ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu; } -static size_t ohci_get_rom(struct hpsb_host *host, const quadlet_t **ptr) +static size_t ohci_get_rom(struct hpsb_host *host, quadlet_t **ptr) { struct ti_ohci *ohci=host->hostdata; Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2002-10-05 02:02:59.000000000 -0400 @@ -4,9 +4,27 @@ * Raw interface to the bus * * Copyright (C) 1999, 2000 Andreas E. Bombe + * 2001, 2002 Manfred Weihs <we...@ic...> + * 2002 Christian Toegel <chr...@gm...> * * This code is licensed under the GPL. See the file COPYING in the root * directory of the kernel sources for details. + * + * + * Contributions: + * + * Manfred Weihs <we...@ic...> + * configuration ROM manipulation + * address range mapping + * adaptation for new (transparent) loopback mechanism + * sending of arbitrary async packets + * Christian Toegel <chr...@gm...> + * address range mapping + * lock64 request + * transmit physical packet + * busreset notification control (switch on/off) + * busreset with selection of type (short/long) + * request_reply */ #include <linux/kernel.h> @@ -40,6 +58,16 @@ #define ptr2int(x) ((u64)(u32)x) #endif +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG +#define RAW1394_DEBUG +#endif + +#ifdef RAW1394_DEBUG +#define DBGMSG(fmt, args...) \ +printk(KERN_INFO "raw1394:" fmt "\n" , ## args) +#else +#define DBGMSG(fmt, args...) +#endif static devfs_handle_t devfs_handle; @@ -53,6 +81,21 @@ static atomic_t iso_buffer_size; static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */ +static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer, + u64 addr, unsigned int length, u16 flags); +static int arm_write (struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, unsigned int length, u16 flags); +static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags); +static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags); +static struct hpsb_address_ops arm_ops = { + read: arm_read, + write: arm_write, + lock: arm_lock, + lock64: arm_lock64, +}; + static void queue_complete_cb(struct pending_request *req); static struct pending_request *__alloc_pending_request(int flags) @@ -64,7 +107,7 @@ if (req != NULL) { memset(req, 0, sizeof(struct pending_request)); INIT_LIST_HEAD(&req->list); - INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL); + INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL); } return req; @@ -128,7 +171,8 @@ req->req.length = 0; } - free_tlabel(packet->host, packet->node_id, packet->tlabel); + if (req->req.type != RAW1394_REQ_PHYPACKET) + free_tlabel(packet->host, packet->node_id, packet->tlabel); queue_complete_req(req); } @@ -137,6 +181,7 @@ static void add_host(struct hpsb_host *host) { struct host_info *hi; + unsigned long flags; hi = (struct host_info *)kmalloc(sizeof(struct host_info), SLAB_KERNEL); if (hi != NULL) { @@ -144,10 +189,10 @@ hi->host = host; INIT_LIST_HEAD(&hi->file_info_list); - spin_lock_irq(&host_info_lock); + spin_lock_irqsave(&host_info_lock, flags); list_add_tail(&hi->list, &host_info_list); host_count++; - spin_unlock_irq(&host_info_lock); + spin_unlock_irqrestore(&host_info_lock, flags); } atomic_inc(&internal_generation); @@ -172,15 +217,22 @@ static void remove_host(struct hpsb_host *host) { struct host_info *hi; + unsigned long flags; - spin_lock_irq(&host_info_lock); + spin_lock_irqsave(&host_info_lock, flags); hi = find_host_info(host); if (hi != NULL) { list_del(&hi->list); host_count--; + /* + FIXME: adressranges should be removed + and fileinfo states should be initialized + (including setting generation to + internal-generation ...) + */ } - spin_unlock_irq(&host_info_lock); + spin_unlock_irqrestore(&host_info_lock, flags); if (hi == NULL) { printk(KERN_ERR "raw1394: attempt to remove unknown host " @@ -207,20 +259,22 @@ if (hi != NULL) { list_for_each(lh, &hi->file_info_list) { fi = list_entry(lh, struct file_info, list); - req = __alloc_pending_request(SLAB_ATOMIC); + if (fi->notification == RAW1394_NOTIFY_ON) { + req = __alloc_pending_request(SLAB_ATOMIC); - if (req != NULL) { - req->file_info = fi; - req->req.type = RAW1394_REQ_BUS_RESET; - req->req.generation = get_hpsb_generation(host); - req->req.misc = (host->node_id << 16) - | host->node_count; - if (fi->protocol_version > 3) { - req->req.misc |= ((host->irm_id - & NODE_MASK) << 8); - } + if (req != NULL) { + req->file_info = fi; + req->req.type = RAW1394_REQ_BUS_RESET; + req->req.generation = get_hpsb_generation(host); + req->req.misc = (host->node_id << 16) + | host->node_count; + if (fi->protocol_version > 3) { + req->req.misc |= ((host->irm_id + & NODE_MASK) << 8); + } - queue_complete_req(req); + queue_complete_req(req); + } } } } @@ -529,7 +583,7 @@ { int channel = req->req.misc; - spin_lock(&host_info_lock); + spin_lock_irq(&host_info_lock); if ((channel > 63) || (channel < -64)) { req->req.error = RAW1394_ERROR_INVALID_ARG; } else if (channel >= 0) { @@ -556,7 +610,7 @@ req->req.length = 0; queue_complete_req(req); - spin_unlock(&host_info_lock); + spin_unlock_irq(&host_info_lock); } static void handle_fcp_listen(struct file_info *fi, struct pending_request *req) @@ -579,84 +633,9 @@ queue_complete_req(req); } -static int handle_local_request(struct file_info *fi, - struct pending_request *req, int node) -{ - u64 addr = req->req.address & 0xffffffffffffULL; - - req->data = kmalloc(req->req.length, SLAB_KERNEL); - if (!req->data) return -ENOMEM; - req->free_data = 1; - - switch (req->req.type) { - case RAW1394_REQ_ASYNC_READ: - req->req.error = highlevel_read(fi->host, node, req->data, addr, - req->req.length); - break; - - case RAW1394_REQ_ASYNC_WRITE: - if (copy_from_user(req->data, int2ptr(req->req.sendb), - req->req.length)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - break; - } - - req->req.error = highlevel_write(fi->host, node, node, req->data, - addr, req->req.length); - req->req.length = 0; - break; - case RAW1394_REQ_LOCK: - if ((req->req.misc == EXTCODE_FETCH_ADD) - || (req->req.misc == EXTCODE_LITTLE_ADD)) { - if (req->req.length != 4) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - break; - } - } else { - if (req->req.length != 8) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - break; - } - } - - if (copy_from_user(req->data, int2ptr(req->req.sendb), - req->req.length)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - break; - } - - if (req->req.length == 8) { - req->req.error = highlevel_lock(fi->host, node, - req->data, addr, - req->data[1], - req->data[0], - req->req.misc); - req->req.length = 4; - } else { - req->req.error = highlevel_lock(fi->host, node, - req->data, addr, - req->data[0], 0, - req->req.misc); - } - break; - - case RAW1394_REQ_LOCK64: - default: - req->req.error = RAW1394_ERROR_STATE_ORDER; - } - - if (req->req.error) - req->req.length = 0; - if (req->req.error >= 0) - req->req.error |= ACK_PENDING << 16; - - queue_complete_req(req); - return sizeof(struct raw1394_request); -} - -static int handle_remote_request(struct file_info *fi, - struct pending_request *req, int node) +static int handle_async_request(struct file_info *fi, + struct pending_request *req, int node) { struct hpsb_packet *packet = NULL; u64 addr = req->req.address & 0xffffffffffffULL; @@ -664,11 +643,13 @@ switch (req->req.type) { case RAW1394_REQ_ASYNC_READ: if (req->req.length == 4) { + DBGMSG("quadlet_read_request called"); packet = hpsb_make_readqpacket(fi->host, node, addr); if (!packet) return -ENOMEM; req->data = &packet->header[3]; } else { + DBGMSG("block_read_request called"); packet = hpsb_make_readbpacket(fi->host, node, addr, req->req.length); if (!packet) return -ENOMEM; @@ -681,6 +662,7 @@ if (req->req.length == 4) { quadlet_t x; + DBGMSG("quadlet_write_request called"); if (copy_from_user(&x, int2ptr(req->req.sendb), 4)) { req->req.error = RAW1394_ERROR_MEMFAULT; } @@ -689,6 +671,7 @@ x); if (!packet) return -ENOMEM; } else { + DBGMSG("block_write_request called"); packet = hpsb_make_writebpacket(fi->host, node, addr, req->req.length); if (!packet) return -ENOMEM; @@ -702,6 +685,7 @@ break; case RAW1394_REQ_LOCK: + DBGMSG("lock_request called"); if ((req->req.misc == EXTCODE_FETCH_ADD) || (req->req.misc == EXTCODE_LITTLE_ADD)) { if (req->req.length != 4) { @@ -730,6 +714,33 @@ break; case RAW1394_REQ_LOCK64: + DBGMSG("lock64_request called"); + if ((req->req.misc == EXTCODE_FETCH_ADD) + || (req->req.misc == EXTCODE_LITTLE_ADD)) { + if (req->req.length != 8) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + break; + } + } else { + if (req->req.length != 16) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + break; + } + } + packet = hpsb_make_lock64packet(fi->host, node, addr, + req->req.misc); + if (!packet) return -ENOMEM; + + if (copy_from_user(packet->data, int2ptr(req->req.sendb), + req->req.length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + break; + } + + req->data = packet->data; + req->req.length = 8; + break; + default: req->req.error = RAW1394_ERROR_STATE_ORDER; } @@ -803,25 +814,1093 @@ return sizeof(struct raw1394_request); } -static int state_connected(struct file_info *fi, struct pending_request *req) +static int handle_async_send(struct file_info *fi, struct pending_request *req) { - int node = req->req.address >> 48; + struct hpsb_packet *packet; + int header_length = req->req.misc & 0xffff; + int expect_response = req->req.misc >> 16; - req->req.error = RAW1394_ERROR_NONE; + if ((header_length > req->req.length) || + (header_length < 12)) + { + req->req.error = RAW1394_ERROR_INVALID_ARG; + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } - if (req->req.type == RAW1394_REQ_ISO_SEND) { - return handle_iso_send(fi, req, node); + packet = alloc_hpsb_packet(req->req.length-header_length); + req->packet = packet; + if (!packet) return -ENOMEM; + + if (copy_from_user(packet->header, int2ptr(req->req.sendb), + header_length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); } - if (req->req.generation != get_hpsb_generation(fi->host)) { - req->req.error = RAW1394_ERROR_GENERATION; - req->req.generation = get_hpsb_generation(fi->host); + if (copy_from_user(packet->data, ((u8*) int2ptr(req->req.sendb)) + header_length, + packet->data_size)) { + req->req.error = RAW1394_ERROR_MEMFAULT; req->req.length = 0; queue_complete_req(req); return sizeof(struct raw1394_request); } + packet->type = hpsb_async; + packet->node_id = packet->header[0] >> 16; + packet->tcode = (packet->header[0] >> 4) & 0xf; + packet->tlabel = (packet->header[0] >> 10) &0x3f; + packet->host = fi->host; + packet->expect_response = expect_response; + packet->header_size=header_length; + packet->data_size=req->req.length-header_length; + + req->tq.data = req; + req->tq.routine = (void (*)(void*))queue_complete_req; + req->req.length = 0; + queue_task(&req->tq, &packet->complete_tq); + + spin_lock_irq(&fi->reqlists_lock); + list_add_tail(&req->list, &fi->req_pending); + spin_unlock_irq(&fi->reqlists_lock); + + /* Update the generation of the packet just before sending. */ + packet->generation = get_hpsb_generation(fi->host); + + if (!hpsb_send_packet(packet)) { + req->req.error = RAW1394_ERROR_SEND_ERROR; + queue_complete_req(req); + } + + return sizeof(struct raw1394_request); +} + +static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer, + u64 addr, unsigned int length, u16 flags) +{ + struct pending_request *req; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi = NULL; + struct list_head *entry; + struct arm_addr *arm_addr = NULL; + struct arm_request *arm_req = NULL; + struct arm_response *arm_resp = NULL; + int found=0, size=0, rcode=-1; + struct arm_request_response *arm_req_resp = NULL; + + DBGMSG("arm_read called by node: %X" + "addr: %4.4x %8.8x length: %u", nodeid, + (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), + length); + spin_lock(&host_info_lock); + hi = find_host_info(host); /* search address-entry */ + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + fi = list_entry(lh, struct file_info, list); + entry = fi->addr_list.next; + while (entry != &(fi->addr_list)) { + arm_addr = list_entry(entry, struct arm_addr, addr_list); + if (((arm_addr->start) <= (addr)) && + ((arm_addr->end) >= (addr+length))) { + found = 1; + break; + } + entry = entry->next; + } + if (found) { + break; + } + } + } + rcode = -1; + if (!found) { + printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock(&host_info_lock); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_read addr_entry FOUND"); + } + if (arm_addr->rec_length < length) { + DBGMSG("arm_read blocklength too big -> rcode_data_error"); + rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */ + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_READ) { + if (!(arm_addr->client_transactions & ARM_READ)) { + memcpy(buffer,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), + length); + DBGMSG("arm_read -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_read -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_READ) { + DBGMSG("arm_read -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + DBGMSG("arm_read -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + if (rcode == RCODE_COMPLETE) { + size = sizeof(struct arm_request)+sizeof(struct arm_response) + + length * sizeof(byte_t) + + sizeof (struct arm_request_response); + } else { + size = sizeof(struct arm_request)+sizeof(struct arm_response) + + sizeof (struct arm_request_response); + } + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + DBGMSG("arm_read -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data=1; + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req_resp = (struct arm_request_response *) (req->data); + arm_req = (struct arm_request *) ((byte_t *)(req->data) + + (sizeof (struct arm_request_response))); + arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + + (sizeof(struct arm_request))); + arm_req->buffer = NULL; + arm_resp->buffer = NULL; + if (rcode == RCODE_COMPLETE) { + arm_resp->buffer = ((byte_t *)(arm_resp) + + (sizeof(struct arm_response))); + memcpy (arm_resp->buffer, + (arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), + length); + arm_resp->buffer = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request) + + sizeof (struct arm_response)); + } + arm_resp->buffer_length = (rcode == RCODE_COMPLETE) ? length : 0; + arm_resp->response_code = rcode; + arm_req->buffer_length = 0; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = 0; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = host->node_id; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response)); + arm_req_resp->response = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request)); + queue_complete_req(req); + } + spin_unlock(&host_info_lock); + return(rcode); +} + +static int arm_write (struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, unsigned int length, u16 flags) +{ + struct pending_request *req; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi = NULL; + struct list_head *entry; + struct arm_addr *arm_addr = NULL; + struct arm_request *arm_req = NULL; + struct arm_response *arm_resp = NULL; + int found=0, size=0, rcode=-1, length_conflict=0; + struct arm_request_response *arm_req_resp = NULL; + + DBGMSG("arm_write called by node: %X" + "addr: %4.4x %8.8x length: %u", nodeid, + (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), + length); + spin_lock(&host_info_lock); + hi = find_host_info(host); /* search address-entry */ + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + fi = list_entry(lh, struct file_info, list); + entry = fi->addr_list.next; + while (entry != &(fi->addr_list)) { + arm_addr = list_entry(entry, struct arm_addr, addr_list); + if (((arm_addr->start) <= (addr)) && + ((arm_addr->end) >= (addr+length))) { + found = 1; + break; + } + entry = entry->next; + } + if (found) { + break; + } + } + } + rcode = -1; + if (!found) { + printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock(&host_info_lock); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_write addr_entry FOUND"); + } + if (arm_addr->rec_length < length) { + DBGMSG("arm_write blocklength too big -> rcode_data_error"); + length_conflict = 1; + rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */ + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_WRITE) { + if (!(arm_addr->client_transactions & ARM_WRITE)) { + memcpy((arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), + data, length); + DBGMSG("arm_write -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_write -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_WRITE) { + DBGMSG("arm_write -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + DBGMSG("arm_write -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request my be retried */ + } + size = sizeof(struct arm_request)+sizeof(struct arm_response) + + (length) * sizeof(byte_t) + + sizeof (struct arm_request_response); + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + DBGMSG("arm_write -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data=1; + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req_resp = (struct arm_request_response *) (req->data); + arm_req = (struct arm_request *) ((byte_t *)(req->data) + + (sizeof (struct arm_request_response))); + arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + + (sizeof(struct arm_request))); + arm_req->buffer = ((byte_t *)(arm_resp) + + (sizeof(struct arm_response))); + arm_resp->buffer = NULL; + memcpy (arm_req->buffer, data, length); + arm_req->buffer = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request) + + sizeof (struct arm_response)); + arm_req->buffer_length = length; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = 0; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = destid; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_resp->buffer_length = 0; + arm_resp->response_code = rcode; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response)); + arm_req_resp->response = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request)); + queue_complete_req(req); + } + spin_unlock(&host_info_lock); + return(rcode); +} + +static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags) +{ + struct pending_request *req; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi = NULL; + struct list_head *entry; + struct arm_addr *arm_addr = NULL; + struct arm_request *arm_req = NULL; + struct arm_response *arm_resp = NULL; + int found=0, size=0, rcode=-1; + quadlet_t old, new; + struct arm_request_response *arm_req_resp = NULL; + + if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || + ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { + DBGMSG("arm_lock called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X", + nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), + ext_tcode & 0xFF , be32_to_cpu(data)); + } else { + DBGMSG("arm_lock called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X", + nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), + ext_tcode & 0xFF , be32_to_cpu(data), be32_to_cpu(arg)); + } + spin_lock(&host_info_lock); + hi = find_host_info(host); /* search address-entry */ + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + fi = list_entry(lh, struct file_info, list); + entry = fi->addr_list.next; + while (entry != &(fi->addr_list)) { + arm_addr = list_entry(entry, struct arm_addr, addr_list); + if (((arm_addr->start) <= (addr)) && + ((arm_addr->end) >= (addr+sizeof(*store)))) { + found = 1; + break; + } + entry = entry->next; + } + if (found) { + break; + } + } + } + rcode = -1; + if (!found) { + printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock(&host_info_lock); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_lock addr_entry FOUND"); + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_LOCK) { + if (!(arm_addr->client_transactions & ARM_LOCK)) { + memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), + sizeof(old)); + switch (ext_tcode) { + case (EXTCODE_MASK_SWAP): + new = data | (old & ~arg); + break; + case (EXTCODE_COMPARE_SWAP): + if (old == arg) { + new = data; + } else { + new = old; + } + break; + case (EXTCODE_FETCH_ADD): + new = cpu_to_be32(be32_to_cpu(data) + be32_to_cpu(old)); + break; + case (EXTCODE_LITTLE_ADD): + new = cpu_to_le32(le32_to_cpu(data) + le32_to_cpu(old)); + break; + case (EXTCODE_BOUNDED_ADD): + if (old != arg) { + new = cpu_to_be32(be32_to_cpu(data) + + be32_to_cpu(old)); + } else { + new = old; + } + break; + case (EXTCODE_WRAP_ADD): + if (old != arg) { + new = cpu_to_be32(be32_to_cpu(data) + + be32_to_cpu(old)); + } else { + new = data; + } + break; + default: + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + printk(KERN_ERR "raw1394: arm_lock FAILED " + "ext_tcode not allowed -> rcode_type_error\n"); + break; + } /*switch*/ + if (rcode == -1) { + DBGMSG("arm_lock -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + memcpy (store, &old, sizeof(*store)); + memcpy ((arm_addr->addr_space_buffer)+ + (addr-(arm_addr->start)), + &new, sizeof(*store)); + } + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_lock -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_LOCK) { + DBGMSG("arm_lock -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + DBGMSG("arm_lock -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + size = sizeof(struct arm_request)+sizeof(struct arm_response) + + 3 * sizeof(*store) + + sizeof (struct arm_request_response); /* maximum */ + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + DBGMSG("arm_lock -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data=1; + arm_req_resp = (struct arm_request_response *) (req->data); + arm_req = (struct arm_request *) ((byte_t *)(req->data) + + (sizeof (struct arm_request_response))); + arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + + (sizeof(struct arm_request))); + arm_req->buffer = ((byte_t *)(arm_resp) + + (sizeof(struct arm_response))); + arm_resp->buffer = ((byte_t *)(arm_req->buffer) + + (2* sizeof(*store))); + if ((ext_tcode == EXTCODE_FETCH_ADD) || + (ext_tcode == EXTCODE_LITTLE_ADD)) { + arm_req->buffer_length = sizeof(*store); + memcpy (arm_req->buffer, &data, sizeof(*store)); + + } else { + arm_req->buffer_length = 2 * sizeof(*store); + memcpy (arm_req->buffer, &arg, sizeof(*store)); + memcpy (((arm_req->buffer) + sizeof(*store)), + &data, sizeof(*store)); + } + if (rcode == RCODE_COMPLETE) { + arm_resp->buffer_length = sizeof(*store); + memcpy (arm_resp->buffer, &old, sizeof(*store)); + } else { + arm_resp->buffer = NULL; + arm_resp->buffer_length = 0; + } + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | + (ARM_LOCK & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = ext_tcode; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = host->node_id; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_resp->response_code = rcode; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response)); + arm_req_resp->response = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request)); + arm_req->buffer = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request) + + sizeof (struct arm_response)); + arm_resp->buffer = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request) + + sizeof (struct arm_response) + + 2* sizeof (*store)); + queue_complete_req(req); + } + spin_unlock(&host_info_lock); + return(rcode); +} + +static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags) +{ + struct pending_request *req; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi = NULL; + struct list_head *entry; + struct arm_addr *arm_addr = NULL; + struct arm_request *arm_req = NULL; + struct arm_response *arm_resp = NULL; + int found=0, size=0, rcode=-1; + octlet_t old, new; + struct arm_request_response *arm_req_resp = NULL; + + if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || + ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { + DBGMSG("arm_lock64 called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ", + nodeid, (u16) ((addr >>32) & 0xFFFF), + (u32) (addr & 0xFFFFFFFF), + ext_tcode & 0xFF , + (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), + (u32) (be64_to_cpu(data) & 0xFFFFFFFF)); + } else { + DBGMSG("arm_lock64 called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: " + "%8.8X %8.8X ", + nodeid, (u16) ((addr >>32) & 0xFFFF), + (u32) (addr & 0xFFFFFFFF), + ext_tcode & 0xFF , + (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), + (u32) (be64_to_cpu(data) & 0xFFFFFFFF), + (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF), + (u32) (be64_to_cpu(arg) & 0xFFFFFFFF)); + } + spin_lock(&host_info_lock); + hi = find_host_info(host); /* search addressentry in file_info's for host */ + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + fi = list_entry(lh, struct file_info, list); + entry = fi->addr_list.next; + while (entry != &(fi->addr_list)) { + arm_addr = list_entry(entry, struct arm_addr, addr_list); + if (((arm_addr->start) <= (addr)) && + ((arm_addr->end) >= (addr+sizeof(*store)))) { + found = 1; + break; + } + entry = entry->next; + } + if (found) { + break; + } + } + } + rcode = -1; + if (!found) { + printk(KERN_ERR "raw1394: arm_lock64 FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock(&host_info_lock); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_lock64 addr_entry FOUND"); + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_LOCK) { + if (!(arm_addr->client_transactions & ARM_LOCK)) { + memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), + sizeof(old)); + switch (ext_tcode) { + case (EXTCODE_MASK_SWAP): + new = data | (old & ~arg); + break; + case (EXTCODE_COMPARE_SWAP): + if (old == arg) { + new = data; + } else { + new = old; + } + break; + case (EXTCODE_FETCH_ADD): + new = cpu_to_be64(be64_to_cpu(data) + be64_to_cpu(old)); + break; + case (EXTCODE_LITTLE_ADD): + new = cpu_to_le64(le64_to_cpu(data) + le64_to_cpu(old)); + break; + case (EXTCODE_BOUNDED_ADD): + if (old != arg) { + new = cpu_to_be64(be64_to_cpu(data) + + be64_to_cpu(old)); + } else { + new = old; + } + break; + case (EXTCODE_WRAP_ADD): + if (old != arg) { + new = cpu_to_be64(be64_to_cpu(data) + + be64_to_cpu(old)); + } else { + new = data; + } + break; + default: + printk(KERN_ERR "raw1394: arm_lock64 FAILED " + "ext_tcode not allowed -> rcode_type_error\n"); + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + break; + } /*switch*/ + if (rcode == -1) { + DBGMSG("arm_lock64 -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + memcpy (store, &old, sizeof(*store)); + memcpy ((arm_addr->addr_space_buffer)+ + (addr-(arm_addr->start)), + &new, sizeof(*store)); + } + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_lock64 -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_LOCK) { + DBGMSG("arm_lock64 -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + spin_unlock(&host_info_lock); + DBGMSG("arm_lock64 -> rcode_conflict_error"); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + size = sizeof(struct arm_request)+sizeof(struct arm_response) + + 3 * sizeof(*store) + + sizeof (struct arm_request_response); /* maximum */ + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + spin_unlock(&host_info_lock); + DBGMSG("arm_lock64 -> rcode_conflict_error"); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data=1; + arm_req_resp = (struct arm_request_response *) (req->data); + arm_req = (struct arm_request *) ((byte_t *)(req->data) + + (sizeof (struct arm_request_response))); + arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + + (sizeof(struct arm_request))); + ar... [truncated message content] |
From: SVN U. <ben...@li...> - 2002-10-04 18:06:23
|
Author: bencollins Date: 2002-10-04 23:01:55 -0400 (Fri, 04 Oct 2002) New Revision: 591 Modified: branches/mpeg1394/ branches/mpeg1394/amdtp.c branches/mpeg1394/dv1394-private.h branches/mpeg1394/dv1394.c branches/mpeg1394/eth1394.h branches/mpeg1394/ieee1394_core.c branches/mpeg1394/ieee1394_core.h branches/mpeg1394/nodemgr.c branches/mpeg1394/ohci1394.c branches/mpeg1394/pcilynx.c branches/mpeg1394/raw1394.c branches/mpeg1394/sbp2.c Log: Merge changes from trunk Modified: branches/mpeg1394/ieee1394_core.c ============================================================================== --- branches/mpeg1394/ieee1394_core.c (original) +++ branches/mpeg1394/ieee1394_core.c 2002-10-04 23:01:58.000000000 -0400 @@ -19,6 +19,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/proc_fs.h> +#include <linux/tqueue.h> #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/semaphore.h> @@ -66,6 +67,29 @@ printk("\n"); } +static void process_complete_tasks(struct hpsb_packet *packet) +{ + struct list_head *lh, *next; + + list_for_each_safe(lh, next, &packet->complete_tq) { + struct tq_struct *tq = list_entry(lh, struct tq_struct, list); + list_del(&tq->list); + schedule_task(tq); + } + + return; +} + +/** + * hpsb_add_packet_complete_task - add a new task for when a packet completes + * @packet: the packet whose completion we want the task added to + * @tq: the tq_struct describing the task to add + */ +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq) +{ + list_add_tail(&tq->list, &packet->complete_tq); + return; +} /** * alloc_hpsb_packet - allocate new packet structure @@ -384,7 +408,7 @@ packet->state = hpsb_complete; up(&packet->state_change); up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); return; } @@ -396,7 +420,7 @@ spin_unlock_irqrestore(&host->pending_pkt_lock, flags); up(&packet->state_change); - queue_task(&host->timeout_tq, &tq_timer); + schedule_task(&host->timeout_tq); } /** @@ -534,7 +558,7 @@ packet->state = hpsb_complete; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } @@ -754,7 +778,7 @@ packet->state = hpsb_complete; packet->ack_code = ACKX_ABORTED; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } } @@ -786,9 +810,9 @@ } } - if (!list_empty(&host->pending_packets)) { - queue_task(&host->timeout_tq, &tq_timer); - } + if (!list_empty(&host->pending_packets)) + schedule_task(&host->timeout_tq); + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); list_for_each(lh, &expiredlist) { @@ -796,7 +820,7 @@ packet->state = hpsb_complete; packet->ack_code = ACKX_TIMEOUT; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } } @@ -1055,6 +1079,7 @@ EXPORT_SYMBOL(hpsb_ref_host); EXPORT_SYMBOL(hpsb_unref_host); EXPORT_SYMBOL(hpsb_speedto_str); +EXPORT_SYMBOL(hpsb_add_packet_complete_task); EXPORT_SYMBOL(alloc_hpsb_packet); EXPORT_SYMBOL(free_hpsb_packet); Modified: branches/mpeg1394/ohci1394.c ============================================================================== --- branches/mpeg1394/ohci1394.c (original) +++ branches/mpeg1394/ohci1394.c 2002-10-04 23:01:58.000000000 -0400 @@ -810,7 +810,6 @@ { struct ti_ohci *ohci = host->hostdata; struct dma_trm_ctx *d; - unsigned char tcode; unsigned long flags; if (packet->data_size > ohci->max_packet_size) { @@ -821,10 +820,14 @@ } /* 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 (packet->type == hpsb_raw) + d = &ohci->at_req_context; + else if (packet->tcode == TCODE_ISO_DATA) + d = &ohci->it_context; + else if (packet->tcode & 0x02) + d = &ohci->at_resp_context; + else + d = &ohci->at_req_context; spin_lock_irqsave(&d->lock,flags); Modified: branches/mpeg1394/ieee1394_core.h ============================================================================== --- branches/mpeg1394/ieee1394_core.h (original) +++ branches/mpeg1394/ieee1394_core.h 2002-10-04 23:01:58.000000000 -0400 @@ -69,7 +69,7 @@ /* Very core internal, don't care. */ struct semaphore state_change; - task_queue complete_tq; + struct list_head complete_tq; /* Store jiffies for implementing bus timeouts. */ unsigned long sendtime; @@ -77,6 +77,9 @@ quadlet_t embedded_header[5]; }; +/* add a new task for when a packet completes */ +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq); + static inline struct hpsb_packet *driver_packet(struct list_head *l) { return list_entry(l, struct hpsb_packet, driver_list); Modified: branches/mpeg1394/amdtp.c ============================================================================== --- branches/mpeg1394/amdtp.c (original) +++ branches/mpeg1394/amdtp.c 2002-10-04 23:01:58.000000000 -0400 @@ -196,7 +196,7 @@ /* This implements a circular buffer for incoming samples. */ struct buffer { - int head, tail, length, size; + size_t head, tail, length, size; unsigned char data[0]; }; @@ -623,9 +623,9 @@ } static unsigned char *buffer_put_bytes(struct buffer *buffer, - int max, int *actual) + size_t max, size_t *actual) { - int length; + size_t length; unsigned char *p; p = &buffer->data[buffer->tail]; @@ -1089,7 +1089,8 @@ { struct stream *s = file->private_data; unsigned char *p; - int i, length; + int i; + size_t length; if (s->packet_pool == NULL) return -EBADFD; Modified: branches/mpeg1394/dv1394-private.h ============================================================================== --- branches/mpeg1394/dv1394-private.h (original) +++ branches/mpeg1394/dv1394-private.h 2002-10-04 23:01:58.000000000 -0400 @@ -301,7 +301,8 @@ unsigned long data; /* Max # of packets per frame */ - #define MAX_PACKETS 320 + /* 320 is enough for NTSC, need to check what PAL is */ + #define MAX_PACKETS 500 /* a PAGE_SIZE memory pool for allocating CIP headers Modified: branches/mpeg1394/raw1394.c ============================================================================== --- branches/mpeg1394/raw1394.c (original) +++ branches/mpeg1394/raw1394.c 2002-10-04 23:01:58.000000000 -0400 @@ -743,7 +743,7 @@ } req->tq.data = req; - queue_task(&req->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &req->tq); spin_lock_irq(&fi->reqlists_lock); list_add_tail(&req->list, &fi->req_pending); @@ -786,7 +786,7 @@ req->tq.data = req; req->tq.routine = (void (*)(void*))queue_complete_req; req->req.length = 0; - queue_task(&req->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &req->tq); spin_lock_irq(&fi->reqlists_lock); list_add_tail(&req->list, &fi->req_pending); Modified: branches/mpeg1394/nodemgr.c ============================================================================== --- branches/mpeg1394/nodemgr.c (original) +++ branches/mpeg1394/nodemgr.c 2002-10-04 23:01:58.000000000 -0400 @@ -195,6 +195,10 @@ ret = hpsb_read(host, nodeid, generation, address, quad, 4); if (!ret) break; + + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout (HZ/3)) + return -1; } *quad = be32_to_cpu(*quad); @@ -207,8 +211,10 @@ { quadlet_t quad; int size = 0; + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) return -1; + if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) { /* This is the offset. */ address += 4 * CONFIG_ROM_VALUE(quad); @@ -217,6 +223,7 @@ /* Now we got the size of the text descriptor leaf. */ size = CONFIG_ROM_LEAF_LENGTH(quad); } + return size; } @@ -228,7 +235,7 @@ int i, size, ret; if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad) - && CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF) + || CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF) return -1; /* This is the offset. */ Modified: branches/mpeg1394/sbp2.c ============================================================================== --- branches/mpeg1394/sbp2.c (original) +++ branches/mpeg1394/sbp2.c 2002-10-04 23:01:58.000000000 -0400 @@ -358,8 +358,8 @@ */ /* - * Change sbp2_max_speed on module load if you have a bad IEEE-1394 controller - * that has trouble running 2KB packets at 400mb. + * Change sbp2_max_speed on module load if you have a bad IEEE-1394 + * controller that has trouble running 2KB packets at 400mb. * * NOTE: On certain OHCI parts I have seen short packets on async transmit * (probably due to PCI latency/throughput issues with the part). You can @@ -375,48 +375,54 @@ static int sbp2_max_speed = SPEED_400; /* - * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent down to - * us at a time (debugging). This might be necessary for very badly behaved sbp2 devices. + * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent + * down to us at a time (debugging). This might be necessary for very + * badly behaved sbp2 devices. */ MODULE_PARM(sbp2_serialize_io,"i"); MODULE_PARM_DESC(sbp2_serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)"); static int sbp2_serialize_io = 0; /* serialize I/O - available for debugging purposes */ /* - * Bump up sbp2_max_sectors if you'd like to support very large sized transfers. Please note - * that some older sbp2 bridge chips are broken for transfers greater or equal to 128KB. - * Default is a value of 255 sectors, or just under 128KB (at 512 byte sector size). I can note - * that the Oxsemi sbp2 chipsets have no problems supporting very large transfer sizes. + * Bump up sbp2_max_sectors if you'd like to support very large sized + * transfers. Please note that some older sbp2 bridge chips are broken for + * transfers greater or equal to 128KB. Default is a value of 255 + * sectors, or just under 128KB (at 512 byte sector size). I can note that + * the Oxsemi sbp2 chipsets have no problems supporting very large + * transfer sizes. */ MODULE_PARM(sbp2_max_sectors,"i"); MODULE_PARM_DESC(sbp2_max_sectors, "Change max sectors per I/O supported (default = 255)"); static int sbp2_max_sectors = SBP2_MAX_SECTORS; /* - * Adjust sbp2_max_outstanding_cmds to tune performance if you have many sbp2 devices attached - * (or if you need to do some debugging). + * Adjust sbp2_max_outstanding_cmds to tune performance if you have many + * sbp2 devices attached (or if you need to do some debugging). */ MODULE_PARM(sbp2_max_outstanding_cmds,"i"); MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)"); static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS; /* - * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than one concurrent/linked - * command per sbp2 device may allow some performance gains, but some older sbp2 devices have - * firmware bugs resulting in problems when linking commands... so, enable this with care. - * I can note that the Oxsemi OXFW911 sbp2 chipset works very well with large numbers of - * concurrent/linked commands. =) + * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than + * one concurrent/linked command per sbp2 device may allow some + * performance gains, but some older sbp2 devices have firmware bugs + * resulting in problems when linking commands... so, enable this with + * care. I can note that the Oxsemi OXFW911 sbp2 chipset works very well + * with large numbers of concurrent/linked commands. =) */ MODULE_PARM(sbp2_max_cmds_per_lun,"i"); MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)"); static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN; /* - * Exclusive login to sbp2 device? In most cases, the sbp2 driver should do an exclusive login, as it's - * generally unsafe to have two hosts talking to a single sbp2 device at the same time (filesystem - * coherency, etc.). If you're running an sbp2 device that supports multiple logins, and you're either - * running read-only filesystems or some sort of special filesystem supporting multiple hosts, then - * set sbp2_exclusive_login to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four + * Exclusive login to sbp2 device? In most cases, the sbp2 driver should + * do an exclusive login, as it's generally unsafe to have two hosts + * talking to a single sbp2 device at the same time (filesystem coherency, + * etc.). If you're running an sbp2 device that supports multiple logins, + * and you're either running read-only filesystems or some sort of special + * filesystem supporting multiple hosts, then set sbp2_exclusive_login to + * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four * concurrent logins. */ MODULE_PARM(sbp2_exclusive_login,"i"); @@ -424,9 +430,14 @@ static int sbp2_exclusive_login = 1; /* - * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on if your sbp2 device - * is not properly handling the SCSI inquiry command. This hack makes the inquiry look more - * like a typical MS Windows inquiry. + * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on + * if your sbp2 device is not properly handling the SCSI inquiry command. + * This hack makes the inquiry look more like a typical MS Windows + * inquiry. + * + * If sbp2_force_inquiry_hack=1 is required for your device to work, + * please submit the logged sbp2_firmware_revision value of this device to + * the linux1394-devel mailing list. */ MODULE_PARM(sbp2_force_inquiry_hack,"i"); MODULE_PARM_DESC(sbp2_force_inquiry_hack, "Force SCSI inquiry hack (default = 0)"); @@ -551,13 +562,17 @@ .update = sbp2_update }; -/* List of device firmware's that require a forced 36 byte inquiry. Note - * the final 0x0 needs to be there for denoting end of list. */ +/* List of device firmware's that require a forced 36 byte inquiry. */ static u32 sbp2_broken_inquiry_list[] = { 0x00002800, /* Stefan Richter <ric...@ba...> */ - 0x0 + /* DViCO Momobay CX-1 */ + 0x00000200 /* Andreas Plesch <pl...@fa...> */ + /* QPS Fire DVDBurner */ }; +#define NUM_BROKEN_INQUIRY_DEVS \ + (sizeof(sbp2_broken_inquiry_list)/sizeof(*sbp2_broken_inquiry_list)) + /************************************** * General utility functions **************************************/ @@ -788,7 +803,7 @@ request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet; request_packet->tq.data = request_packet; request_packet->hi_context = hi; - queue_task(&request_packet->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &request_packet->tq); /* * Now, put the packet on the in-use list. @@ -1915,7 +1930,10 @@ /* Firmware revision */ scsi_id->sbp2_firmware_revision = CONFIG_ROM_VALUE(ud->quadlets[i]); - SBP2_DEBUG("sbp2_firmware_revision = %x", + if (sbp2_force_inquiry_hack) + SBP2_INFO("sbp2_firmware_revision = %x", + (unsigned int) scsi_id->sbp2_firmware_revision); + else SBP2_DEBUG("sbp2_firmware_revision = %x", (unsigned int) scsi_id->sbp2_firmware_revision); break; @@ -1949,19 +1967,14 @@ /* Check for a blacklisted set of devices that require us to force * a 36 byte host inquiry. This can be overriden as a module param - * (to force all hosts). - * - * XXX If this does not detect your firmware as being defective, - * but using the sbp2_force_inquiry_hack allows your device to - * work, please submit the value of your firmware revision to the - * linux1394-devel mailing list. */ - for (i = 0; sbp2_broken_inquiry_list[i]; i++) { + * (to force all hosts). */ + for (i = 0; i < NUM_BROKEN_INQUIRY_DEVS; i++) { if ((scsi_id->sbp2_firmware_revision & 0xffff00) == sbp2_broken_inquiry_list[i]) { SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround", NODE_BUS_ARGS(scsi_id->ne->nodeid)); scsi_id->workarounds |= SBP2_BREAKAGE_INQUIRY_HACK; - break; // No need to continue. + break; /* No need to continue. */ } } } Modified: branches/mpeg1394/eth1394.h ============================================================================== --- branches/mpeg1394/eth1394.h (original) +++ branches/mpeg1394/eth1394.h 2002-10-04 23:01:58.000000000 -0400 @@ -51,7 +51,7 @@ struct net_device *dev; }; -/* This is our task struct. It's used for the complete_tq callback. */ +/* This is our task struct. It's used for the packet complete callback. */ struct packet_task { struct sk_buff *skb; /* Socket buffer we are sending */ nodeid_t dest_node; /* Destination of the packet */ Modified: branches/mpeg1394/pcilynx.c ============================================================================== --- branches/mpeg1394/pcilynx.c (original) +++ branches/mpeg1394/pcilynx.c 2002-10-04 23:01:58.000000000 -0400 @@ -887,13 +887,14 @@ struct memdata *md = (struct memdata *)file->private_data; ssize_t bcount; size_t alignfix; - int off = (int)*offset; /* avoid useless 64bit-arithmetic */ + loff_t off = *offset; /* avoid useless 64bit-arithmetic */ ssize_t retval; void *membase; if (*offset != off) /* Check for EOF before we trust wrap */ return 0; + /* FIXME: Signed wrap is undefined in C - wants fixing up */ if (off + count > off) return 0; Modified: branches/mpeg1394/dv1394.c ============================================================================== --- branches/mpeg1394/dv1394.c (original) +++ branches/mpeg1394/dv1394.c 2002-10-04 23:01:59.000000000 -0400 @@ -2139,7 +2139,7 @@ const char *buffer, unsigned long count, void *data) { int len = 0; - char new_value[64]; + char new_value[65]; char *pos; struct video_card *video = (struct video_card*) data; @@ -2151,11 +2151,12 @@ if (copy_from_user( new_value, buffer, len)) return -EFAULT; + new_value[len] = 0; pos = strchr(new_value, '='); if (pos != NULL) { int val_len = len - (pos-new_value) - 1; - char buf[64]; - memset(buf, 0, 64); + char buf[65]; + memset(buf, 0, 65); strncpy(buf, pos+1, val_len); if (buf[val_len-1] == '\n') buf[val_len-1] = 0; |
From: SVN U. <ben...@li...> - 2002-10-04 18:05:19
|
Author: bencollins Date: 2002-10-04 23:00:51 -0400 (Fri, 04 Oct 2002) New Revision: 590 Modified: branches/rawiso/ branches/rawiso/amdtp.c branches/rawiso/dv1394-private.h branches/rawiso/dv1394.c branches/rawiso/eth1394.h branches/rawiso/ieee1394_core.c branches/rawiso/ieee1394_core.h branches/rawiso/nodemgr.c branches/rawiso/ohci1394.c branches/rawiso/pcilynx.c branches/rawiso/raw1394.c branches/rawiso/sbp2.c branches/rawiso/video1394.c Log: Merge changes from trunk Modified: branches/rawiso/ieee1394_core.c ============================================================================== --- branches/rawiso/ieee1394_core.c (original) +++ branches/rawiso/ieee1394_core.c 2002-10-04 23:00:54.000000000 -0400 @@ -19,6 +19,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/proc_fs.h> +#include <linux/tqueue.h> #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/semaphore.h> @@ -67,6 +68,29 @@ printk("\n"); } +static void process_complete_tasks(struct hpsb_packet *packet) +{ + struct list_head *lh, *next; + + list_for_each_safe(lh, next, &packet->complete_tq) { + struct tq_struct *tq = list_entry(lh, struct tq_struct, list); + list_del(&tq->list); + schedule_task(tq); + } + + return; +} + +/** + * hpsb_add_packet_complete_task - add a new task for when a packet completes + * @packet: the packet whose completion we want the task added to + * @tq: the tq_struct describing the task to add + */ +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq) +{ + list_add_tail(&tq->list, &packet->complete_tq); + return; +} /** * alloc_hpsb_packet - allocate new packet structure @@ -161,7 +185,10 @@ abort_requests(host); host->in_bus_reset = 1; host->irm_id = -1; + host->is_irm = 0; host->busmgr_id = -1; + host->is_busmgr = 0; + host->is_cycmst = 0; host->node_count = 0; host->selfid_count = 0; @@ -355,7 +382,10 @@ } host->reset_retries = 0; - if (isroot) host->driver->devctl(host, ACT_CYCLE_MASTER, 1); + if (isroot) { + host->driver->devctl(host, ACT_CYCLE_MASTER, 1); + host->is_cycmst = 1; + } atomic_inc(&host->generation); host->in_bus_reset = 0; highlevel_host_reset(host); @@ -379,7 +409,7 @@ packet->state = hpsb_complete; up(&packet->state_change); up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); return; } @@ -391,7 +421,7 @@ spin_unlock_irqrestore(&host->pending_pkt_lock, flags); up(&packet->state_change); - queue_task(&host->timeout_tq, &tq_timer); + schedule_task(&host->timeout_tq); } /** @@ -529,7 +559,7 @@ packet->state = hpsb_complete; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } @@ -749,7 +779,7 @@ packet->state = hpsb_complete; packet->ack_code = ACKX_ABORTED; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } } @@ -781,9 +811,9 @@ } } - if (!list_empty(&host->pending_packets)) { - queue_task(&host->timeout_tq, &tq_timer); - } + if (!list_empty(&host->pending_packets)) + schedule_task(&host->timeout_tq); + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); list_for_each(lh, &expiredlist) { @@ -791,7 +821,7 @@ packet->state = hpsb_complete; packet->ack_code = ACKX_TIMEOUT; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } } @@ -1050,6 +1080,7 @@ EXPORT_SYMBOL(hpsb_ref_host); EXPORT_SYMBOL(hpsb_unref_host); EXPORT_SYMBOL(hpsb_speedto_str); +EXPORT_SYMBOL(hpsb_add_packet_complete_task); EXPORT_SYMBOL(alloc_hpsb_packet); EXPORT_SYMBOL(free_hpsb_packet); Modified: branches/rawiso/ohci1394.c ============================================================================== --- branches/rawiso/ohci1394.c (original) +++ branches/rawiso/ohci1394.c 2002-10-04 23:00:54.000000000 -0400 @@ -597,7 +597,7 @@ ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, pci_resource_start(ohci->dev, 0), - pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE, + pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1, ohci->max_packet_size); } @@ -812,7 +812,6 @@ { struct ti_ohci *ohci = host->hostdata; struct dma_trm_ctx *d; - unsigned char tcode; unsigned long flags; if (packet->data_size > ohci->max_packet_size) { @@ -823,10 +822,14 @@ } /* 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 (packet->type == hpsb_raw) + d = &ohci->at_req_context; + else if (packet->tcode == TCODE_ISO_DATA) + d = &ohci->it_context; + else if (packet->tcode & 0x02) + d = &ohci->at_resp_context; + else + d = &ohci->at_req_context; spin_lock_irqsave(&d->lock,flags); Modified: branches/rawiso/amdtp.c ============================================================================== --- branches/rawiso/amdtp.c (original) +++ branches/rawiso/amdtp.c 2002-10-04 23:00:54.000000000 -0400 @@ -196,7 +196,7 @@ /* This implements a circular buffer for incoming samples. */ struct buffer { - int head, tail, length, size; + size_t head, tail, length, size; unsigned char data[0]; }; @@ -623,9 +623,9 @@ } static unsigned char *buffer_put_bytes(struct buffer *buffer, - int max, int *actual) + size_t max, size_t *actual) { - int length; + size_t length; unsigned char *p; p = &buffer->data[buffer->tail]; @@ -1089,7 +1089,8 @@ { struct stream *s = file->private_data; unsigned char *p; - int i, length; + int i; + size_t length; if (s->packet_pool == NULL) return -EBADFD; Modified: branches/rawiso/ieee1394_core.h ============================================================================== --- branches/rawiso/ieee1394_core.h (original) +++ branches/rawiso/ieee1394_core.h 2002-10-04 23:00:54.000000000 -0400 @@ -69,7 +69,7 @@ /* Very core internal, don't care. */ struct semaphore state_change; - task_queue complete_tq; + struct list_head complete_tq; /* Store jiffies for implementing bus timeouts. */ unsigned long sendtime; @@ -77,6 +77,9 @@ quadlet_t embedded_header[5]; }; +/* add a new task for when a packet completes */ +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq); + static inline struct hpsb_packet *driver_packet(struct list_head *l) { return list_entry(l, struct hpsb_packet, driver_list); Modified: branches/rawiso/dv1394-private.h ============================================================================== --- branches/rawiso/dv1394-private.h (original) +++ branches/rawiso/dv1394-private.h 2002-10-04 23:00:54.000000000 -0400 @@ -301,7 +301,8 @@ unsigned long data; /* Max # of packets per frame */ - #define MAX_PACKETS 320 + /* 320 is enough for NTSC, need to check what PAL is */ + #define MAX_PACKETS 500 /* a PAGE_SIZE memory pool for allocating CIP headers Modified: branches/rawiso/raw1394.c ============================================================================== --- branches/rawiso/raw1394.c (original) +++ branches/rawiso/raw1394.c 2002-10-04 23:00:54.000000000 -0400 @@ -744,7 +744,7 @@ } req->tq.data = req; - queue_task(&req->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &req->tq); spin_lock_irq(&fi->reqlists_lock); list_add_tail(&req->list, &fi->req_pending); @@ -787,7 +787,7 @@ req->tq.data = req; req->tq.routine = (void (*)(void*))queue_complete_req; req->req.length = 0; - queue_task(&req->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &req->tq); spin_lock_irq(&fi->reqlists_lock); list_add_tail(&req->list, &fi->req_pending); Modified: branches/rawiso/nodemgr.c ============================================================================== --- branches/rawiso/nodemgr.c (original) +++ branches/rawiso/nodemgr.c 2002-10-04 23:00:54.000000000 -0400 @@ -195,6 +195,10 @@ ret = hpsb_read(host, nodeid, generation, address, quad, 4); if (!ret) break; + + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout (HZ/3)) + return -1; } *quad = be32_to_cpu(*quad); @@ -207,8 +211,10 @@ { quadlet_t quad; int size = 0; + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) return -1; + if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) { /* This is the offset. */ address += 4 * CONFIG_ROM_VALUE(quad); @@ -217,6 +223,7 @@ /* Now we got the size of the text descriptor leaf. */ size = CONFIG_ROM_LEAF_LENGTH(quad); } + return size; } @@ -228,7 +235,7 @@ int i, size, ret; if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad) - && CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF) + || CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF) return -1; /* This is the offset. */ Modified: branches/rawiso/sbp2.c ============================================================================== --- branches/rawiso/sbp2.c (original) +++ branches/rawiso/sbp2.c 2002-10-04 23:00:54.000000000 -0400 @@ -358,8 +358,8 @@ */ /* - * Change sbp2_max_speed on module load if you have a bad IEEE-1394 controller - * that has trouble running 2KB packets at 400mb. + * Change sbp2_max_speed on module load if you have a bad IEEE-1394 + * controller that has trouble running 2KB packets at 400mb. * * NOTE: On certain OHCI parts I have seen short packets on async transmit * (probably due to PCI latency/throughput issues with the part). You can @@ -375,48 +375,54 @@ static int sbp2_max_speed = SPEED_400; /* - * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent down to - * us at a time (debugging). This might be necessary for very badly behaved sbp2 devices. + * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent + * down to us at a time (debugging). This might be necessary for very + * badly behaved sbp2 devices. */ MODULE_PARM(sbp2_serialize_io,"i"); MODULE_PARM_DESC(sbp2_serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)"); static int sbp2_serialize_io = 0; /* serialize I/O - available for debugging purposes */ /* - * Bump up sbp2_max_sectors if you'd like to support very large sized transfers. Please note - * that some older sbp2 bridge chips are broken for transfers greater or equal to 128KB. - * Default is a value of 255 sectors, or just under 128KB (at 512 byte sector size). I can note - * that the Oxsemi sbp2 chipsets have no problems supporting very large transfer sizes. + * Bump up sbp2_max_sectors if you'd like to support very large sized + * transfers. Please note that some older sbp2 bridge chips are broken for + * transfers greater or equal to 128KB. Default is a value of 255 + * sectors, or just under 128KB (at 512 byte sector size). I can note that + * the Oxsemi sbp2 chipsets have no problems supporting very large + * transfer sizes. */ MODULE_PARM(sbp2_max_sectors,"i"); MODULE_PARM_DESC(sbp2_max_sectors, "Change max sectors per I/O supported (default = 255)"); static int sbp2_max_sectors = SBP2_MAX_SECTORS; /* - * Adjust sbp2_max_outstanding_cmds to tune performance if you have many sbp2 devices attached - * (or if you need to do some debugging). + * Adjust sbp2_max_outstanding_cmds to tune performance if you have many + * sbp2 devices attached (or if you need to do some debugging). */ MODULE_PARM(sbp2_max_outstanding_cmds,"i"); MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)"); static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS; /* - * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than one concurrent/linked - * command per sbp2 device may allow some performance gains, but some older sbp2 devices have - * firmware bugs resulting in problems when linking commands... so, enable this with care. - * I can note that the Oxsemi OXFW911 sbp2 chipset works very well with large numbers of - * concurrent/linked commands. =) + * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than + * one concurrent/linked command per sbp2 device may allow some + * performance gains, but some older sbp2 devices have firmware bugs + * resulting in problems when linking commands... so, enable this with + * care. I can note that the Oxsemi OXFW911 sbp2 chipset works very well + * with large numbers of concurrent/linked commands. =) */ MODULE_PARM(sbp2_max_cmds_per_lun,"i"); MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)"); static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN; /* - * Exclusive login to sbp2 device? In most cases, the sbp2 driver should do an exclusive login, as it's - * generally unsafe to have two hosts talking to a single sbp2 device at the same time (filesystem - * coherency, etc.). If you're running an sbp2 device that supports multiple logins, and you're either - * running read-only filesystems or some sort of special filesystem supporting multiple hosts, then - * set sbp2_exclusive_login to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four + * Exclusive login to sbp2 device? In most cases, the sbp2 driver should + * do an exclusive login, as it's generally unsafe to have two hosts + * talking to a single sbp2 device at the same time (filesystem coherency, + * etc.). If you're running an sbp2 device that supports multiple logins, + * and you're either running read-only filesystems or some sort of special + * filesystem supporting multiple hosts, then set sbp2_exclusive_login to + * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four * concurrent logins. */ MODULE_PARM(sbp2_exclusive_login,"i"); @@ -424,9 +430,14 @@ static int sbp2_exclusive_login = 1; /* - * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on if your sbp2 device - * is not properly handling the SCSI inquiry command. This hack makes the inquiry look more - * like a typical MS Windows inquiry. + * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on + * if your sbp2 device is not properly handling the SCSI inquiry command. + * This hack makes the inquiry look more like a typical MS Windows + * inquiry. + * + * If sbp2_force_inquiry_hack=1 is required for your device to work, + * please submit the logged sbp2_firmware_revision value of this device to + * the linux1394-devel mailing list. */ MODULE_PARM(sbp2_force_inquiry_hack,"i"); MODULE_PARM_DESC(sbp2_force_inquiry_hack, "Force SCSI inquiry hack (default = 0)"); @@ -551,13 +562,17 @@ .update = sbp2_update }; -/* List of device firmware's that require a forced 36 byte inquiry. Note - * the final 0x0 needs to be there for denoting end of list. */ +/* List of device firmware's that require a forced 36 byte inquiry. */ static u32 sbp2_broken_inquiry_list[] = { 0x00002800, /* Stefan Richter <ric...@ba...> */ - 0x0 + /* DViCO Momobay CX-1 */ + 0x00000200 /* Andreas Plesch <pl...@fa...> */ + /* QPS Fire DVDBurner */ }; +#define NUM_BROKEN_INQUIRY_DEVS \ + (sizeof(sbp2_broken_inquiry_list)/sizeof(*sbp2_broken_inquiry_list)) + /************************************** * General utility functions **************************************/ @@ -788,7 +803,7 @@ request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet; request_packet->tq.data = request_packet; request_packet->hi_context = hi; - queue_task(&request_packet->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &request_packet->tq); /* * Now, put the packet on the in-use list. @@ -1915,7 +1930,10 @@ /* Firmware revision */ scsi_id->sbp2_firmware_revision = CONFIG_ROM_VALUE(ud->quadlets[i]); - SBP2_DEBUG("sbp2_firmware_revision = %x", + if (sbp2_force_inquiry_hack) + SBP2_INFO("sbp2_firmware_revision = %x", + (unsigned int) scsi_id->sbp2_firmware_revision); + else SBP2_DEBUG("sbp2_firmware_revision = %x", (unsigned int) scsi_id->sbp2_firmware_revision); break; @@ -1949,19 +1967,14 @@ /* Check for a blacklisted set of devices that require us to force * a 36 byte host inquiry. This can be overriden as a module param - * (to force all hosts). - * - * XXX If this does not detect your firmware as being defective, - * but using the sbp2_force_inquiry_hack allows your device to - * work, please submit the value of your firmware revision to the - * linux1394-devel mailing list. */ - for (i = 0; sbp2_broken_inquiry_list[i]; i++) { + * (to force all hosts). */ + for (i = 0; i < NUM_BROKEN_INQUIRY_DEVS; i++) { if ((scsi_id->sbp2_firmware_revision & 0xffff00) == sbp2_broken_inquiry_list[i]) { SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround", NODE_BUS_ARGS(scsi_id->ne->nodeid)); scsi_id->workarounds |= SBP2_BREAKAGE_INQUIRY_HACK; - break; // No need to continue. + break; /* No need to continue. */ } } } Modified: branches/rawiso/eth1394.h ============================================================================== --- branches/rawiso/eth1394.h (original) +++ branches/rawiso/eth1394.h 2002-10-04 23:00:54.000000000 -0400 @@ -51,7 +51,7 @@ struct net_device *dev; }; -/* This is our task struct. It's used for the complete_tq callback. */ +/* This is our task struct. It's used for the packet complete callback. */ struct packet_task { struct sk_buff *skb; /* Socket buffer we are sending */ nodeid_t dest_node; /* Destination of the packet */ Modified: branches/rawiso/pcilynx.c ============================================================================== --- branches/rawiso/pcilynx.c (original) +++ branches/rawiso/pcilynx.c 2002-10-04 23:00:54.000000000 -0400 @@ -887,10 +887,17 @@ struct memdata *md = (struct memdata *)file->private_data; ssize_t bcount; size_t alignfix; - int off = (int)*offset; /* avoid useless 64bit-arithmetic */ + loff_t off = *offset; /* avoid useless 64bit-arithmetic */ ssize_t retval; void *membase; + if (*offset != off) /* Check for EOF before we trust wrap */ + return 0; + + /* FIXME: Signed wrap is undefined in C - wants fixing up */ + if (off + count > off) + return 0; + if ((off + count) > PCILYNX_MAX_MEMORY + 1) { count = PCILYNX_MAX_MEMORY + 1 - off; } Modified: branches/rawiso/video1394.c ============================================================================== --- branches/rawiso/video1394.c (original) +++ branches/rawiso/video1394.c 2002-10-04 23:00:55.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; @@ -853,13 +853,13 @@ } ohci->ISO_channel_usage |= mask; - if (v.buf_size<=0) { + if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) { PRINT(KERN_ERR, ohci->id, "Invalid %d length buffer requested",v.buf_size); return -EFAULT; } - if (v.nb_buffers<=0) { + if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) { PRINT(KERN_ERR, ohci->id, "Invalid %d buffers requested",v.nb_buffers); return -EFAULT; Modified: branches/rawiso/dv1394.c ============================================================================== --- branches/rawiso/dv1394.c (original) +++ branches/rawiso/dv1394.c 2002-10-04 23:00:55.000000000 -0400 @@ -2139,7 +2139,7 @@ const char *buffer, unsigned long count, void *data) { int len = 0; - char new_value[64]; + char new_value[65]; char *pos; struct video_card *video = (struct video_card*) data; @@ -2151,11 +2151,12 @@ if (copy_from_user( new_value, buffer, len)) return -EFAULT; + new_value[len] = 0; pos = strchr(new_value, '='); if (pos != NULL) { int val_len = len - (pos-new_value) - 1; - char buf[64]; - memset(buf, 0, 64); + char buf[65]; + memset(buf, 0, 65); strncpy(buf, pos+1, val_len); if (buf[val_len-1] == '\n') buf[val_len-1] = 0; |
From: SVN U. <ben...@li...> - 2002-10-04 17:15:46
|
Author: bencollins Date: 2002-10-04 22:11:14 -0400 (Fri, 04 Oct 2002) New Revision: 589 Modified: branches/weihs/ branches/weihs/amdtp.c branches/weihs/dv1394-private.h branches/weihs/dv1394.c branches/weihs/eth1394.h branches/weihs/ieee1394_core.c branches/weihs/ieee1394_core.h branches/weihs/nodemgr.c branches/weihs/ohci1394.c branches/weihs/pcilynx.c branches/weihs/raw1394.c branches/weihs/sbp2.c Log: Merge to trunk Modified: branches/weihs/ieee1394_core.c ============================================================================== --- branches/weihs/ieee1394_core.c (original) +++ branches/weihs/ieee1394_core.c 2002-10-04 22:11:17.000000000 -0400 @@ -29,6 +29,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/proc_fs.h> +#include <linux/tqueue.h> #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/semaphore.h> @@ -76,6 +77,29 @@ printk("\n"); } +static void process_complete_tasks(struct hpsb_packet *packet) +{ + struct list_head *lh, *next; + + list_for_each_safe(lh, next, &packet->complete_tq) { + struct tq_struct *tq = list_entry(lh, struct tq_struct, list); + list_del(&tq->list); + schedule_task(tq); + } + + return; +} + +/** + * hpsb_add_packet_complete_task - add a new task for when a packet completes + * @packet: the packet whose completion we want the task added to + * @tq: the tq_struct describing the task to add + */ +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq) +{ + list_add_tail(&tq->list, &packet->complete_tq); + return; +} /** * alloc_hpsb_packet - allocate new packet structure @@ -401,7 +425,7 @@ packet->state = hpsb_complete; up(&packet->state_change); up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); return; } @@ -413,7 +437,7 @@ spin_unlock_irqrestore(&host->pending_pkt_lock, flags); up(&packet->state_change); - queue_task(&host->timeout_tq, &tq_timer); + schedule_task(&host->timeout_tq); } /** @@ -590,7 +614,7 @@ packet->state = hpsb_complete; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } @@ -824,7 +848,7 @@ packet->state = hpsb_complete; packet->ack_code = ACKX_ABORTED; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } } @@ -856,9 +880,9 @@ } } - if (!list_empty(&host->pending_packets)) { - queue_task(&host->timeout_tq, &tq_timer); - } + if (!list_empty(&host->pending_packets)) + schedule_task(&host->timeout_tq); + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); list_for_each(lh, &expiredlist) { @@ -866,7 +890,7 @@ packet->state = hpsb_complete; packet->ack_code = ACKX_TIMEOUT; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } } @@ -1125,6 +1149,7 @@ EXPORT_SYMBOL(hpsb_ref_host); EXPORT_SYMBOL(hpsb_unref_host); EXPORT_SYMBOL(hpsb_speedto_str); +EXPORT_SYMBOL(hpsb_add_packet_complete_task); EXPORT_SYMBOL(alloc_hpsb_packet); EXPORT_SYMBOL(free_hpsb_packet); Modified: branches/weihs/ohci1394.c ============================================================================== --- branches/weihs/ohci1394.c (original) +++ branches/weihs/ohci1394.c 2002-10-04 22:11:17.000000000 -0400 @@ -810,7 +810,6 @@ { struct ti_ohci *ohci = host->hostdata; struct dma_trm_ctx *d; - unsigned char tcode; unsigned long flags; if (packet->data_size > ohci->max_packet_size) { @@ -821,10 +820,14 @@ } /* 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 (packet->type == hpsb_raw) + d = &ohci->at_req_context; + else if (packet->tcode == TCODE_ISO_DATA) + d = &ohci->it_context; + else if (packet->tcode & 0x02) + d = &ohci->at_resp_context; + else + d = &ohci->at_req_context; spin_lock_irqsave(&d->lock,flags); Modified: branches/weihs/ieee1394_core.h ============================================================================== --- branches/weihs/ieee1394_core.h (original) +++ branches/weihs/ieee1394_core.h 2002-10-04 22:11:17.000000000 -0400 @@ -69,7 +69,7 @@ /* Very core internal, don't care. */ struct semaphore state_change; - task_queue complete_tq; + struct list_head complete_tq; /* Store jiffies for implementing bus timeouts. */ unsigned long sendtime; @@ -77,6 +77,9 @@ quadlet_t embedded_header[5]; }; +/* add a new task for when a packet completes */ +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq); + static inline struct hpsb_packet *driver_packet(struct list_head *l) { return list_entry(l, struct hpsb_packet, driver_list); Modified: branches/weihs/amdtp.c ============================================================================== --- branches/weihs/amdtp.c (original) +++ branches/weihs/amdtp.c 2002-10-04 22:11:17.000000000 -0400 @@ -196,7 +196,7 @@ /* This implements a circular buffer for incoming samples. */ struct buffer { - int head, tail, length, size; + size_t head, tail, length, size; unsigned char data[0]; }; @@ -623,9 +623,9 @@ } static unsigned char *buffer_put_bytes(struct buffer *buffer, - int max, int *actual) + size_t max, size_t *actual) { - int length; + size_t length; unsigned char *p; p = &buffer->data[buffer->tail]; @@ -1089,7 +1089,8 @@ { struct stream *s = file->private_data; unsigned char *p; - int i, length; + int i; + size_t length; if (s->packet_pool == NULL) return -EBADFD; Modified: branches/weihs/dv1394-private.h ============================================================================== --- branches/weihs/dv1394-private.h (original) +++ branches/weihs/dv1394-private.h 2002-10-04 22:11:17.000000000 -0400 @@ -301,7 +301,8 @@ unsigned long data; /* Max # of packets per frame */ - #define MAX_PACKETS 320 + /* 320 is enough for NTSC, need to check what PAL is */ + #define MAX_PACKETS 500 /* a PAGE_SIZE memory pool for allocating CIP headers Modified: branches/weihs/raw1394.c ============================================================================== --- branches/weihs/raw1394.c (original) +++ branches/weihs/raw1394.c 2002-10-04 22:11:17.000000000 -0400 @@ -754,7 +754,7 @@ } req->tq.data = req; - queue_task(&req->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &req->tq); spin_lock_irq(&fi->reqlists_lock); list_add_tail(&req->list, &fi->req_pending); @@ -797,7 +797,7 @@ req->tq.data = req; req->tq.routine = (void (*)(void*))queue_complete_req; req->req.length = 0; - queue_task(&req->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &req->tq); spin_lock_irq(&fi->reqlists_lock); list_add_tail(&req->list, &fi->req_pending); Modified: branches/weihs/nodemgr.c ============================================================================== --- branches/weihs/nodemgr.c (original) +++ branches/weihs/nodemgr.c 2002-10-04 22:11:17.000000000 -0400 @@ -195,6 +195,10 @@ ret = hpsb_read(host, nodeid, generation, address, quad, 4); if (!ret) break; + + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout (HZ/3)) + return -1; } *quad = be32_to_cpu(*quad); @@ -207,8 +211,10 @@ { quadlet_t quad; int size = 0; + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) return -1; + if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) { /* This is the offset. */ address += 4 * CONFIG_ROM_VALUE(quad); @@ -217,6 +223,7 @@ /* Now we got the size of the text descriptor leaf. */ size = CONFIG_ROM_LEAF_LENGTH(quad); } + return size; } @@ -228,7 +235,7 @@ int i, size, ret; if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad) - && CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF) + || CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF) return -1; /* This is the offset. */ Modified: branches/weihs/sbp2.c ============================================================================== --- branches/weihs/sbp2.c (original) +++ branches/weihs/sbp2.c 2002-10-04 22:11:18.000000000 -0400 @@ -358,8 +358,8 @@ */ /* - * Change sbp2_max_speed on module load if you have a bad IEEE-1394 controller - * that has trouble running 2KB packets at 400mb. + * Change sbp2_max_speed on module load if you have a bad IEEE-1394 + * controller that has trouble running 2KB packets at 400mb. * * NOTE: On certain OHCI parts I have seen short packets on async transmit * (probably due to PCI latency/throughput issues with the part). You can @@ -375,48 +375,54 @@ static int sbp2_max_speed = SPEED_400; /* - * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent down to - * us at a time (debugging). This might be necessary for very badly behaved sbp2 devices. + * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent + * down to us at a time (debugging). This might be necessary for very + * badly behaved sbp2 devices. */ MODULE_PARM(sbp2_serialize_io,"i"); MODULE_PARM_DESC(sbp2_serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)"); static int sbp2_serialize_io = 0; /* serialize I/O - available for debugging purposes */ /* - * Bump up sbp2_max_sectors if you'd like to support very large sized transfers. Please note - * that some older sbp2 bridge chips are broken for transfers greater or equal to 128KB. - * Default is a value of 255 sectors, or just under 128KB (at 512 byte sector size). I can note - * that the Oxsemi sbp2 chipsets have no problems supporting very large transfer sizes. + * Bump up sbp2_max_sectors if you'd like to support very large sized + * transfers. Please note that some older sbp2 bridge chips are broken for + * transfers greater or equal to 128KB. Default is a value of 255 + * sectors, or just under 128KB (at 512 byte sector size). I can note that + * the Oxsemi sbp2 chipsets have no problems supporting very large + * transfer sizes. */ MODULE_PARM(sbp2_max_sectors,"i"); MODULE_PARM_DESC(sbp2_max_sectors, "Change max sectors per I/O supported (default = 255)"); static int sbp2_max_sectors = SBP2_MAX_SECTORS; /* - * Adjust sbp2_max_outstanding_cmds to tune performance if you have many sbp2 devices attached - * (or if you need to do some debugging). + * Adjust sbp2_max_outstanding_cmds to tune performance if you have many + * sbp2 devices attached (or if you need to do some debugging). */ MODULE_PARM(sbp2_max_outstanding_cmds,"i"); MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)"); static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS; /* - * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than one concurrent/linked - * command per sbp2 device may allow some performance gains, but some older sbp2 devices have - * firmware bugs resulting in problems when linking commands... so, enable this with care. - * I can note that the Oxsemi OXFW911 sbp2 chipset works very well with large numbers of - * concurrent/linked commands. =) + * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than + * one concurrent/linked command per sbp2 device may allow some + * performance gains, but some older sbp2 devices have firmware bugs + * resulting in problems when linking commands... so, enable this with + * care. I can note that the Oxsemi OXFW911 sbp2 chipset works very well + * with large numbers of concurrent/linked commands. =) */ MODULE_PARM(sbp2_max_cmds_per_lun,"i"); MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)"); static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN; /* - * Exclusive login to sbp2 device? In most cases, the sbp2 driver should do an exclusive login, as it's - * generally unsafe to have two hosts talking to a single sbp2 device at the same time (filesystem - * coherency, etc.). If you're running an sbp2 device that supports multiple logins, and you're either - * running read-only filesystems or some sort of special filesystem supporting multiple hosts, then - * set sbp2_exclusive_login to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four + * Exclusive login to sbp2 device? In most cases, the sbp2 driver should + * do an exclusive login, as it's generally unsafe to have two hosts + * talking to a single sbp2 device at the same time (filesystem coherency, + * etc.). If you're running an sbp2 device that supports multiple logins, + * and you're either running read-only filesystems or some sort of special + * filesystem supporting multiple hosts, then set sbp2_exclusive_login to + * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four * concurrent logins. */ MODULE_PARM(sbp2_exclusive_login,"i"); @@ -424,9 +430,14 @@ static int sbp2_exclusive_login = 1; /* - * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on if your sbp2 device - * is not properly handling the SCSI inquiry command. This hack makes the inquiry look more - * like a typical MS Windows inquiry. + * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on + * if your sbp2 device is not properly handling the SCSI inquiry command. + * This hack makes the inquiry look more like a typical MS Windows + * inquiry. + * + * If sbp2_force_inquiry_hack=1 is required for your device to work, + * please submit the logged sbp2_firmware_revision value of this device to + * the linux1394-devel mailing list. */ MODULE_PARM(sbp2_force_inquiry_hack,"i"); MODULE_PARM_DESC(sbp2_force_inquiry_hack, "Force SCSI inquiry hack (default = 0)"); @@ -551,13 +562,17 @@ .update = sbp2_update }; -/* List of device firmware's that require a forced 36 byte inquiry. Note - * the final 0x0 needs to be there for denoting end of list. */ +/* List of device firmware's that require a forced 36 byte inquiry. */ static u32 sbp2_broken_inquiry_list[] = { 0x00002800, /* Stefan Richter <ric...@ba...> */ - 0x0 + /* DViCO Momobay CX-1 */ + 0x00000200 /* Andreas Plesch <pl...@fa...> */ + /* QPS Fire DVDBurner */ }; +#define NUM_BROKEN_INQUIRY_DEVS \ + (sizeof(sbp2_broken_inquiry_list)/sizeof(*sbp2_broken_inquiry_list)) + /************************************** * General utility functions **************************************/ @@ -788,7 +803,7 @@ request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet; request_packet->tq.data = request_packet; request_packet->hi_context = hi; - queue_task(&request_packet->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &request_packet->tq); /* * Now, put the packet on the in-use list. @@ -1915,7 +1930,10 @@ /* Firmware revision */ scsi_id->sbp2_firmware_revision = CONFIG_ROM_VALUE(ud->quadlets[i]); - SBP2_DEBUG("sbp2_firmware_revision = %x", + if (sbp2_force_inquiry_hack) + SBP2_INFO("sbp2_firmware_revision = %x", + (unsigned int) scsi_id->sbp2_firmware_revision); + else SBP2_DEBUG("sbp2_firmware_revision = %x", (unsigned int) scsi_id->sbp2_firmware_revision); break; @@ -1949,19 +1967,14 @@ /* Check for a blacklisted set of devices that require us to force * a 36 byte host inquiry. This can be overriden as a module param - * (to force all hosts). - * - * XXX If this does not detect your firmware as being defective, - * but using the sbp2_force_inquiry_hack allows your device to - * work, please submit the value of your firmware revision to the - * linux1394-devel mailing list. */ - for (i = 0; sbp2_broken_inquiry_list[i]; i++) { + * (to force all hosts). */ + for (i = 0; i < NUM_BROKEN_INQUIRY_DEVS; i++) { if ((scsi_id->sbp2_firmware_revision & 0xffff00) == sbp2_broken_inquiry_list[i]) { SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround", NODE_BUS_ARGS(scsi_id->ne->nodeid)); scsi_id->workarounds |= SBP2_BREAKAGE_INQUIRY_HACK; - break; // No need to continue. + break; /* No need to continue. */ } } } Modified: branches/weihs/eth1394.h ============================================================================== --- branches/weihs/eth1394.h (original) +++ branches/weihs/eth1394.h 2002-10-04 22:11:18.000000000 -0400 @@ -51,7 +51,7 @@ struct net_device *dev; }; -/* This is our task struct. It's used for the complete_tq callback. */ +/* This is our task struct. It's used for the packet complete callback. */ struct packet_task { struct sk_buff *skb; /* Socket buffer we are sending */ nodeid_t dest_node; /* Destination of the packet */ Modified: branches/weihs/pcilynx.c ============================================================================== --- branches/weihs/pcilynx.c (original) +++ branches/weihs/pcilynx.c 2002-10-04 22:11:18.000000000 -0400 @@ -887,13 +887,14 @@ struct memdata *md = (struct memdata *)file->private_data; ssize_t bcount; size_t alignfix; - int off = (int)*offset; /* avoid useless 64bit-arithmetic */ + loff_t off = *offset; /* avoid useless 64bit-arithmetic */ ssize_t retval; void *membase; if (*offset != off) /* Check for EOF before we trust wrap */ return 0; + /* FIXME: Signed wrap is undefined in C - wants fixing up */ if (off + count > off) return 0; Modified: branches/weihs/dv1394.c ============================================================================== --- branches/weihs/dv1394.c (original) +++ branches/weihs/dv1394.c 2002-10-04 22:11:18.000000000 -0400 @@ -2139,7 +2139,7 @@ const char *buffer, unsigned long count, void *data) { int len = 0; - char new_value[64]; + char new_value[65]; char *pos; struct video_card *video = (struct video_card*) data; @@ -2151,11 +2151,12 @@ if (copy_from_user( new_value, buffer, len)) return -EFAULT; + new_value[len] = 0; pos = strchr(new_value, '='); if (pos != NULL) { int val_len = len - (pos-new_value) - 1; - char buf[64]; - memset(buf, 0, 64); + char buf[65]; + memset(buf, 0, 65); strncpy(buf, pos+1, val_len); if (buf[val_len-1] == '\n') buf[val_len-1] = 0; |
From: SVN U. <ben...@li...> - 2002-10-04 17:10:02
|
Author: bencollins Date: 2002-10-04 22:05:37 -0400 (Fri, 04 Oct 2002) New Revision: 588 Added: tags/v2.4/2.4.20-pre9-r587/ tags/v2.5/2.5.40-r587/ Log: New sync points for Linus and Marcelo Copied: 2.4.20-pre9-r587 (from rev 587, trunk) Copied: 2.5.40-r587 (from rev 587, trunk) |
From: SVN U. <ben...@li...> - 2002-10-04 17:01:05
|
Author: bencollins Date: 2002-10-04 21:56:40 -0400 (Fri, 04 Oct 2002) New Revision: 587 Modified: trunk/amdtp.c Log: One more size_t change Modified: trunk/amdtp.c ============================================================================== --- trunk/amdtp.c (original) +++ trunk/amdtp.c 2002-10-04 21:56:40.000000000 -0400 @@ -1089,7 +1089,8 @@ { struct stream *s = file->private_data; unsigned char *p; - int i, length; + int i; + size_t length; if (s->packet_pool == NULL) return -EBADFD; |
From: SVN U. <ben...@li...> - 2002-10-04 16:57:11
|
Author: bencollins Date: 2002-10-04 21:52:33 -0400 (Fri, 04 Oct 2002) New Revision: 586 Modified: trunk/amdtp.c trunk/dv1394.c trunk/pcilynx.c Log: Various security related fixes from Alan Cox (via 2.4.20-pre9 patch) Modified: trunk/amdtp.c ============================================================================== --- trunk/amdtp.c (original) +++ trunk/amdtp.c 2002-10-04 21:52:34.000000000 -0400 @@ -196,7 +196,7 @@ /* This implements a circular buffer for incoming samples. */ struct buffer { - int head, tail, length, size; + size_t head, tail, length, size; unsigned char data[0]; }; @@ -623,9 +623,9 @@ } static unsigned char *buffer_put_bytes(struct buffer *buffer, - int max, int *actual) + size_t max, size_t *actual) { - int length; + size_t length; unsigned char *p; p = &buffer->data[buffer->tail]; Modified: trunk/pcilynx.c ============================================================================== --- trunk/pcilynx.c (original) +++ trunk/pcilynx.c 2002-10-04 21:52:34.000000000 -0400 @@ -887,13 +887,14 @@ struct memdata *md = (struct memdata *)file->private_data; ssize_t bcount; size_t alignfix; - int off = (int)*offset; /* avoid useless 64bit-arithmetic */ + loff_t off = *offset; /* avoid useless 64bit-arithmetic */ ssize_t retval; void *membase; if (*offset != off) /* Check for EOF before we trust wrap */ return 0; + /* FIXME: Signed wrap is undefined in C - wants fixing up */ if (off + count > off) return 0; Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2002-10-04 21:52:34.000000000 -0400 @@ -2139,7 +2139,7 @@ const char *buffer, unsigned long count, void *data) { int len = 0; - char new_value[64]; + char new_value[65]; char *pos; struct video_card *video = (struct video_card*) data; @@ -2151,11 +2151,12 @@ if (copy_from_user( new_value, buffer, len)) return -EFAULT; + new_value[len] = 0; pos = strchr(new_value, '='); if (pos != NULL) { int val_len = len - (pos-new_value) - 1; - char buf[64]; - memset(buf, 0, 64); + char buf[65]; + memset(buf, 0, 65); strncpy(buf, pos+1, val_len); if (buf[val_len-1] == '\n') buf[val_len-1] = 0; |
From: SVN U. <ben...@li...> - 2002-10-03 20:23:33
|
Author: bencollins Date: 2002-10-04 01:18:54 -0400 (Fri, 04 Oct 2002) New Revision: 585 Modified: branches/weihs/csr.c branches/weihs/hosts.h branches/weihs/raw1394.c Log: Applied to from Manfred Weihs adding two new functions and fixing compile problem Modified: branches/weihs/raw1394.c ============================================================================== --- branches/weihs/raw1394.c (original) +++ branches/weihs/raw1394.c 2002-10-04 01:18:55.000000000 -0400 @@ -1157,7 +1157,7 @@ struct arm_request_response *arm_req_resp = NULL; if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || - ((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD)) { + ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { DBGMSG("arm_lock called by node: %X " "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X", nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), @@ -1355,7 +1355,7 @@ struct arm_request_response *arm_req_resp = NULL; if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || - ((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD)) { + ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { DBGMSG("arm_lock64 called by node: %X " "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ", nodeid, (u16) ((addr >>32) & 0xFFFF), Modified: branches/weihs/hosts.h ============================================================================== --- branches/weihs/hosts.h (original) +++ branches/weihs/hosts.h 2002-10-04 01:18:55.000000000 -0400 @@ -180,4 +180,24 @@ void hpsb_add_host(struct hpsb_host *host); void hpsb_remove_host(struct hpsb_host *h); +/* updates the configuration rom of a host. + * rom_version must be the current version, + * otherwise it will fail with return value -1. + * Return value -2 indicates that the new + * rom version is too big. + * Return value 0 indicates success + */ +int hpsb_update_config_rom(struct hpsb_host *host, + const quadlet_t *new_rom, size_t size, unsigned char rom_version); + +/* reads the current version of the configuration rom of a host. + * buffersize is the size of the buffer, rom_size + * returns the size of the current rom image. + * rom_version is the version number of the fetched rom. + * return value -1 indicates, that the buffer was + * too small, 0 indicates success. + */ +int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer, + size_t buffersize, size_t *rom_size, unsigned char *rom_version); + #endif /* _IEEE1394_HOSTS_H */ Modified: branches/weihs/csr.c ============================================================================== --- branches/weihs/csr.c (original) +++ branches/weihs/csr.c 2002-10-04 01:18:55.000000000 -0400 @@ -85,7 +85,7 @@ { host->csr.lock = SPIN_LOCK_UNLOCKED; - host->csr.rom_size = host->ops->get_rom(host, &host->csr.rom); + host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom); host->csr.rom_version = 0; host->csr.state = 0; host->csr.node_ids = 0; |
From: SVN U. <ben...@li...> - 2002-10-02 22:30:31
|
Author: bencollins Date: 2002-10-03 03:26:01 -0400 (Thu, 03 Oct 2002) New Revision: 584 Modified: trunk/eth1394.h trunk/ieee1394_core.c trunk/ieee1394_core.h trunk/raw1394.c trunk/sbp2.c Log: Remove use of obsoleted tqueue.h interfaces. Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2002-10-03 03:26:03.000000000 -0400 @@ -19,6 +19,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/proc_fs.h> +#include <linux/tqueue.h> #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/semaphore.h> @@ -66,6 +67,29 @@ printk("\n"); } +static void process_complete_tasks(struct hpsb_packet *packet) +{ + struct list_head *lh, *next; + + list_for_each_safe(lh, next, &packet->complete_tq) { + struct tq_struct *tq = list_entry(lh, struct tq_struct, list); + list_del(&tq->list); + schedule_task(tq); + } + + return; +} + +/** + * hpsb_add_packet_complete_task - add a new task for when a packet completes + * @packet: the packet whose completion we want the task added to + * @tq: the tq_struct describing the task to add + */ +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq) +{ + list_add_tail(&tq->list, &packet->complete_tq); + return; +} /** * alloc_hpsb_packet - allocate new packet structure @@ -384,7 +408,7 @@ packet->state = hpsb_complete; up(&packet->state_change); up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); return; } @@ -396,7 +420,7 @@ spin_unlock_irqrestore(&host->pending_pkt_lock, flags); up(&packet->state_change); - queue_task(&host->timeout_tq, &tq_timer); + schedule_task(&host->timeout_tq); } /** @@ -534,7 +558,7 @@ packet->state = hpsb_complete; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } @@ -754,7 +778,7 @@ packet->state = hpsb_complete; packet->ack_code = ACKX_ABORTED; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } } @@ -786,9 +810,9 @@ } } - if (!list_empty(&host->pending_packets)) { - queue_task(&host->timeout_tq, &tq_timer); - } + if (!list_empty(&host->pending_packets)) + schedule_task(&host->timeout_tq); + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); list_for_each(lh, &expiredlist) { @@ -796,7 +820,7 @@ packet->state = hpsb_complete; packet->ack_code = ACKX_TIMEOUT; up(&packet->state_change); - run_task_queue(&packet->complete_tq); + process_complete_tasks(packet); } } @@ -1055,6 +1079,7 @@ EXPORT_SYMBOL(hpsb_ref_host); EXPORT_SYMBOL(hpsb_unref_host); EXPORT_SYMBOL(hpsb_speedto_str); +EXPORT_SYMBOL(hpsb_add_packet_complete_task); EXPORT_SYMBOL(alloc_hpsb_packet); EXPORT_SYMBOL(free_hpsb_packet); Modified: trunk/ieee1394_core.h ============================================================================== --- trunk/ieee1394_core.h (original) +++ trunk/ieee1394_core.h 2002-10-03 03:26:03.000000000 -0400 @@ -69,7 +69,7 @@ /* Very core internal, don't care. */ struct semaphore state_change; - task_queue complete_tq; + struct list_head complete_tq; /* Store jiffies for implementing bus timeouts. */ unsigned long sendtime; @@ -77,6 +77,9 @@ quadlet_t embedded_header[5]; }; +/* add a new task for when a packet completes */ +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq); + static inline struct hpsb_packet *driver_packet(struct list_head *l) { return list_entry(l, struct hpsb_packet, driver_list); Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2002-10-03 03:26:04.000000000 -0400 @@ -743,7 +743,7 @@ } req->tq.data = req; - queue_task(&req->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &req->tq); spin_lock_irq(&fi->reqlists_lock); list_add_tail(&req->list, &fi->req_pending); @@ -786,7 +786,7 @@ req->tq.data = req; req->tq.routine = (void (*)(void*))queue_complete_req; req->req.length = 0; - queue_task(&req->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &req->tq); spin_lock_irq(&fi->reqlists_lock); list_add_tail(&req->list, &fi->req_pending); Modified: trunk/sbp2.c ============================================================================== --- trunk/sbp2.c (original) +++ trunk/sbp2.c 2002-10-03 03:26:04.000000000 -0400 @@ -803,7 +803,7 @@ request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet; request_packet->tq.data = request_packet; request_packet->hi_context = hi; - queue_task(&request_packet->tq, &packet->complete_tq); + hpsb_add_packet_complete_task(packet, &request_packet->tq); /* * Now, put the packet on the in-use list. Modified: trunk/eth1394.h ============================================================================== --- trunk/eth1394.h (original) +++ trunk/eth1394.h 2002-10-03 03:26:04.000000000 -0400 @@ -51,7 +51,7 @@ struct net_device *dev; }; -/* This is our task struct. It's used for the complete_tq callback. */ +/* This is our task struct. It's used for the packet complete callback. */ struct packet_task { struct sk_buff *skb; /* Socket buffer we are sending */ nodeid_t dest_node; /* Destination of the packet */ |
From: SVN U. <dm...@li...> - 2002-10-02 18:12:54
|
Author: dmaas Date: 2002-10-02 23:08:22 -0400 (Wed, 02 Oct 2002) New Revision: 583 Modified: trunk/dv1394-private.h Log: dv1394 - increase MAX_PACKETS to solve problem reported by Christian Zoffoli Modified: trunk/dv1394-private.h ============================================================================== --- trunk/dv1394-private.h (original) +++ trunk/dv1394-private.h 2002-10-02 23:08:23.000000000 -0400 @@ -301,7 +301,8 @@ unsigned long data; /* Max # of packets per frame */ - #define MAX_PACKETS 320 + /* 320 is enough for NTSC, need to check what PAL is */ + #define MAX_PACKETS 500 /* a PAGE_SIZE memory pool for allocating CIP headers |
From: SVN U. <ben...@li...> - 2002-09-26 20:50:35
|
Author: bencollins Date: 2002-09-26 16:50:19 -0400 (Thu, 26 Sep 2002) New Revision: 582 Added: tags/v2.4/2.4.20-pre8/ Removed: tags/v2.4/2.4.20-pre6/ Log: Reflect exact merge point Copied: 2.4.20-pre8 (from rev 579, tags/v2.4/2.4.20-pre6) |
From: SVN U. <ben...@li...> - 2002-09-25 02:46:37
|
Author: bencollins Date: 2002-09-25 07:38:53 -0400 (Wed, 25 Sep 2002) New Revision: 581 Modified: trunk/nodemgr.c Log: Reimplement nodemgr_read_quadlet() to use a short scheduled timeout. Should decrease a reported problem with devices on high usage buses. Based on a report by Wim Coekaerts. Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2002-09-25 07:38:54.000000000 -0400 @@ -195,6 +195,10 @@ ret = hpsb_read(host, nodeid, generation, address, quad, 4); if (!ret) break; + + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout (HZ/3)) + return -1; } *quad = be32_to_cpu(*quad); @@ -207,8 +211,10 @@ { quadlet_t quad; int size = 0; + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) return -1; + if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) { /* This is the offset. */ address += 4 * CONFIG_ROM_VALUE(quad); @@ -217,6 +223,7 @@ /* Now we got the size of the text descriptor leaf. */ size = CONFIG_ROM_LEAF_LENGTH(quad); } + return size; } |
From: SVN U. <ben...@li...> - 2002-09-25 01:29:25
|
Author: bencollins Date: 2002-09-25 06:21:48 -0400 (Wed, 25 Sep 2002) New Revision: 580 Modified: trunk/nodemgr.c Log: Fix logic in nodemgr_read_text_leaf for checking return of quadlet read and the value returned. Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2002-09-25 06:21:49.000000000 -0400 @@ -228,7 +228,7 @@ int i, size, ret; if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad) - && CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF) + || CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF) return -1; /* This is the offset. */ |
From: SVN U. <ben...@li...> - 2002-09-23 12:51:22
|
Author: bencollins Date: 2002-09-23 17:44:07 -0400 (Mon, 23 Sep 2002) New Revision: 579 Modified: trunk/sbp2.c Log: Apply patch from Stefan Richter to add QPS Fire DVDBurner to broken inquiry list, with a little bit of cleanup. Also, re-indented some of the comments to 76char widths. Modified: trunk/sbp2.c ============================================================================== --- trunk/sbp2.c (original) +++ trunk/sbp2.c 2002-09-23 17:44:08.000000000 -0400 @@ -358,8 +358,8 @@ */ /* - * Change sbp2_max_speed on module load if you have a bad IEEE-1394 controller - * that has trouble running 2KB packets at 400mb. + * Change sbp2_max_speed on module load if you have a bad IEEE-1394 + * controller that has trouble running 2KB packets at 400mb. * * NOTE: On certain OHCI parts I have seen short packets on async transmit * (probably due to PCI latency/throughput issues with the part). You can @@ -375,48 +375,54 @@ static int sbp2_max_speed = SPEED_400; /* - * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent down to - * us at a time (debugging). This might be necessary for very badly behaved sbp2 devices. + * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent + * down to us at a time (debugging). This might be necessary for very + * badly behaved sbp2 devices. */ MODULE_PARM(sbp2_serialize_io,"i"); MODULE_PARM_DESC(sbp2_serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)"); static int sbp2_serialize_io = 0; /* serialize I/O - available for debugging purposes */ /* - * Bump up sbp2_max_sectors if you'd like to support very large sized transfers. Please note - * that some older sbp2 bridge chips are broken for transfers greater or equal to 128KB. - * Default is a value of 255 sectors, or just under 128KB (at 512 byte sector size). I can note - * that the Oxsemi sbp2 chipsets have no problems supporting very large transfer sizes. + * Bump up sbp2_max_sectors if you'd like to support very large sized + * transfers. Please note that some older sbp2 bridge chips are broken for + * transfers greater or equal to 128KB. Default is a value of 255 + * sectors, or just under 128KB (at 512 byte sector size). I can note that + * the Oxsemi sbp2 chipsets have no problems supporting very large + * transfer sizes. */ MODULE_PARM(sbp2_max_sectors,"i"); MODULE_PARM_DESC(sbp2_max_sectors, "Change max sectors per I/O supported (default = 255)"); static int sbp2_max_sectors = SBP2_MAX_SECTORS; /* - * Adjust sbp2_max_outstanding_cmds to tune performance if you have many sbp2 devices attached - * (or if you need to do some debugging). + * Adjust sbp2_max_outstanding_cmds to tune performance if you have many + * sbp2 devices attached (or if you need to do some debugging). */ MODULE_PARM(sbp2_max_outstanding_cmds,"i"); MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)"); static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS; /* - * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than one concurrent/linked - * command per sbp2 device may allow some performance gains, but some older sbp2 devices have - * firmware bugs resulting in problems when linking commands... so, enable this with care. - * I can note that the Oxsemi OXFW911 sbp2 chipset works very well with large numbers of - * concurrent/linked commands. =) + * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than + * one concurrent/linked command per sbp2 device may allow some + * performance gains, but some older sbp2 devices have firmware bugs + * resulting in problems when linking commands... so, enable this with + * care. I can note that the Oxsemi OXFW911 sbp2 chipset works very well + * with large numbers of concurrent/linked commands. =) */ MODULE_PARM(sbp2_max_cmds_per_lun,"i"); MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)"); static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN; /* - * Exclusive login to sbp2 device? In most cases, the sbp2 driver should do an exclusive login, as it's - * generally unsafe to have two hosts talking to a single sbp2 device at the same time (filesystem - * coherency, etc.). If you're running an sbp2 device that supports multiple logins, and you're either - * running read-only filesystems or some sort of special filesystem supporting multiple hosts, then - * set sbp2_exclusive_login to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four + * Exclusive login to sbp2 device? In most cases, the sbp2 driver should + * do an exclusive login, as it's generally unsafe to have two hosts + * talking to a single sbp2 device at the same time (filesystem coherency, + * etc.). If you're running an sbp2 device that supports multiple logins, + * and you're either running read-only filesystems or some sort of special + * filesystem supporting multiple hosts, then set sbp2_exclusive_login to + * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four * concurrent logins. */ MODULE_PARM(sbp2_exclusive_login,"i"); @@ -424,9 +430,14 @@ static int sbp2_exclusive_login = 1; /* - * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on if your sbp2 device - * is not properly handling the SCSI inquiry command. This hack makes the inquiry look more - * like a typical MS Windows inquiry. + * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on + * if your sbp2 device is not properly handling the SCSI inquiry command. + * This hack makes the inquiry look more like a typical MS Windows + * inquiry. + * + * If sbp2_force_inquiry_hack=1 is required for your device to work, + * please submit the logged sbp2_firmware_revision value of this device to + * the linux1394-devel mailing list. */ MODULE_PARM(sbp2_force_inquiry_hack,"i"); MODULE_PARM_DESC(sbp2_force_inquiry_hack, "Force SCSI inquiry hack (default = 0)"); @@ -551,13 +562,17 @@ .update = sbp2_update }; -/* List of device firmware's that require a forced 36 byte inquiry. Note - * the final 0x0 needs to be there for denoting end of list. */ +/* List of device firmware's that require a forced 36 byte inquiry. */ static u32 sbp2_broken_inquiry_list[] = { 0x00002800, /* Stefan Richter <ric...@ba...> */ - 0x0 + /* DViCO Momobay CX-1 */ + 0x00000200 /* Andreas Plesch <pl...@fa...> */ + /* QPS Fire DVDBurner */ }; +#define NUM_BROKEN_INQUIRY_DEVS \ + (sizeof(sbp2_broken_inquiry_list)/sizeof(*sbp2_broken_inquiry_list)) + /************************************** * General utility functions **************************************/ @@ -1915,7 +1930,10 @@ /* Firmware revision */ scsi_id->sbp2_firmware_revision = CONFIG_ROM_VALUE(ud->quadlets[i]); - SBP2_DEBUG("sbp2_firmware_revision = %x", + if (sbp2_force_inquiry_hack) + SBP2_INFO("sbp2_firmware_revision = %x", + (unsigned int) scsi_id->sbp2_firmware_revision); + else SBP2_DEBUG("sbp2_firmware_revision = %x", (unsigned int) scsi_id->sbp2_firmware_revision); break; @@ -1949,19 +1967,14 @@ /* Check for a blacklisted set of devices that require us to force * a 36 byte host inquiry. This can be overriden as a module param - * (to force all hosts). - * - * XXX If this does not detect your firmware as being defective, - * but using the sbp2_force_inquiry_hack allows your device to - * work, please submit the value of your firmware revision to the - * linux1394-devel mailing list. */ - for (i = 0; sbp2_broken_inquiry_list[i]; i++) { + * (to force all hosts). */ + for (i = 0; i < NUM_BROKEN_INQUIRY_DEVS; i++) { if ((scsi_id->sbp2_firmware_revision & 0xffff00) == sbp2_broken_inquiry_list[i]) { SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround", NODE_BUS_ARGS(scsi_id->ne->nodeid)); scsi_id->workarounds |= SBP2_BREAKAGE_INQUIRY_HACK; - break; // No need to continue. + break; /* No need to continue. */ } } } |
From: SVN U. <hog...@li...> - 2002-09-23 07:58:37
|
Author: hogsberg Date: 2002-09-23 12:51:24 -0400 (Mon, 23 Sep 2002) New Revision: 578 Modified: trunk/ohci1394.c Log: Detect raw packets correctly. Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-09-23 12:51:25.000000000 -0400 @@ -810,7 +810,6 @@ { struct ti_ohci *ohci = host->hostdata; struct dma_trm_ctx *d; - unsigned char tcode; unsigned long flags; if (packet->data_size > ohci->max_packet_size) { @@ -821,10 +820,14 @@ } /* 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 (packet->type == hpsb_raw) + d = &ohci->at_req_context; + else if (packet->tcode == TCODE_ISO_DATA) + d = &ohci->it_context; + else if (packet->tcode & 0x02) + d = &ohci->at_resp_context; + else + d = &ohci->at_req_context; spin_lock_irqsave(&d->lock,flags); |
From: SVN U. <ben...@li...> - 2002-09-19 13:06:53
|
Author: bencollins Date: 2002-09-19 18:00:29 -0400 (Thu, 19 Sep 2002) New Revision: 577 Modified: branches/weihs/ branches/weihs/Makefile branches/weihs/amdtp.c branches/weihs/amdtp.h branches/weihs/cmp.c branches/weihs/csr.c branches/weihs/dv1394-private.h branches/weihs/dv1394.c branches/weihs/eth1394.c branches/weihs/highlevel.c branches/weihs/hosts.c branches/weihs/hosts.h branches/weihs/ieee1394_core.c branches/weihs/ieee1394_core.h branches/weihs/ieee1394_transactions.c branches/weihs/nodemgr.c branches/weihs/ohci1394.c branches/weihs/ohci1394.h branches/weihs/pcilynx.c branches/weihs/pcilynx.h branches/weihs/raw1394.c branches/weihs/sbp2.c branches/weihs/sbp2.h branches/weihs/video1394.c Log: Merge with trunk Modified: branches/weihs/ieee1394_core.c ============================================================================== --- branches/weihs/ieee1394_core.c (original) +++ branches/weihs/ieee1394_core.c 2002-09-19 18:00:33.000000000 -0400 @@ -32,7 +32,6 @@ #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/semaphore.h> -#include <asm/smplock.h> #include "ieee1394_types.h" #include "ieee1394.h" @@ -152,7 +151,7 @@ int hpsb_reset_bus(struct hpsb_host *host, int type) { if (!host->in_bus_reset) { - host->ops->devctl(host, RESET_BUS, type); + host->driver->devctl(host, RESET_BUS, type); return 0; } else { return 1; @@ -171,7 +170,10 @@ abort_requests(host); host->in_bus_reset = 1; host->irm_id = -1; + host->is_irm = 0; host->busmgr_id = -1; + host->is_busmgr = 0; + host->is_cycmst = 0; host->node_count = 0; host->selfid_count = 0; @@ -372,7 +374,10 @@ } host->reset_retries = 0; - if (isroot) host->ops->devctl(host, ACT_CYCLE_MASTER, 1); + if (isroot) { + host->driver->devctl(host, ACT_CYCLE_MASTER, 1); + host->is_cycmst = 1; + } atomic_inc(&host->generation); host->in_bus_reset = 0; highlevel_host_reset(host); @@ -497,7 +502,7 @@ } #endif - return host->ops->transmit_packet(host, packet); + return host->driver->transmit_packet(host, packet); } static void send_packet_nocare(struct hpsb_packet *packet) @@ -807,7 +812,7 @@ struct list_head *lh; LIST_HEAD(llist); - host->ops->devctl(host, CANCEL_REQUESTS, 0); + host->driver->devctl(host, CANCEL_REQUESTS, 0); spin_lock_irqsave(&host->pending_pkt_lock, flags); list_splice(&host->pending_packets, &llist); @@ -881,8 +886,8 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file); static struct file_operations ieee1394_chardev_ops = { - owner: THIS_MODULE, - open: ieee1394_dispatch_open, + .owner =THIS_MODULE, + .open = ieee1394_dispatch_open, }; devfs_handle_t ieee1394_devfs_handle; @@ -932,19 +937,57 @@ write_unlock(&ieee1394_chardevs_lock); } +/* + ieee1394_get_chardev() - look up and acquire a character device + driver that has previously registered using ieee1394_register_chardev() + + On success, returns 1 and sets module and file_ops to the driver. + The module will have an incremented reference count. + + On failure, returns 0. + The module will NOT have an incremented reference count. +*/ + +static int ieee1394_get_chardev(int blocknum, + struct module **module, + struct file_operations **file_ops) +{ + int ret = 0; + + if( (blocknum < 0) || (blocknum > 15) ) + return ret; + + read_lock(&ieee1394_chardevs_lock); + + *module = ieee1394_chardevs[blocknum].module; + *file_ops = ieee1394_chardevs[blocknum].file_ops; + + if(*file_ops == NULL) + goto out; + + /* don't need try_inc_mod_count if the driver is non-modular */ + if(*module && (try_inc_mod_count(*module) == 0)) + goto out; + + /* success! */ + ret = 1; + +out: + read_unlock(&ieee1394_chardevs_lock); + return ret; +} + /* the point of entry for open() on any ieee1394 character device */ static int ieee1394_dispatch_open(struct inode *inode, struct file *file) { struct file_operations *file_ops; struct module *module; int blocknum; - int retval = -ENODEV; + int retval; /* Maintaining correct module reference counts is tricky here! - For Linux v2.4 and later: - The key thing to remember is that the VFS increments the reference count of ieee1394 before it calls ieee1394_dispatch_open(). @@ -957,16 +1000,7 @@ If the open() fails, then the VFS will drop the reference count of whatever module file->f_op->owner points to, immediately after this function returns. - - The comments below refer to the 2.4 case, since the 2.2 - case is trivial. - */ - -#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \ - if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0) -#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \ - if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0) /* shift away lower four bits of the minor to get the index of the ieee1394_driver @@ -974,20 +1008,10 @@ blocknum = (minor(inode->i_rdev) >> 4) & 0xF; - /* printk("ieee1394_dispatch_open(%d)", blocknum); */ + /* look up the driver */ - read_lock(&ieee1394_chardevs_lock); - module = ieee1394_chardevs[blocknum].module; - /* bump the reference count of the driver that - will receive the open() */ - INCREF(module); - file_ops = ieee1394_chardevs[blocknum].file_ops; - read_unlock(&ieee1394_chardevs_lock); - - if(file_ops == NULL) { - DECREF(module); - goto out_fail; - } + if(ieee1394_get_chardev(blocknum, &module, &file_ops) == 0) + return -ENODEV; /* redirect all subsequent requests to the driver's own file_operations */ @@ -999,42 +1023,42 @@ /* follow through with the open() */ retval = file_ops->open(inode, file); - if(retval) { + if(retval == 0) { - /* if the open() failed, then we need to drop the - extra reference we gave to the task-specific - driver */ + /* If the open() succeeded, then ieee1394 will be left + with an extra module reference, so we discard it here. - DECREF(module); - goto out_fail; + The task-specific driver still has the extra + reference given to it by ieee1394_get_chardev(). + This extra reference prevents the module from + unloading while the file is open, and will be + dropped by the VFS when the file is released. + */ - } else { - - /* if the open() succeeded, then ieee1394 will be left - with an extra module reference, so we discard it here.*/ + if(THIS_MODULE) + __MOD_DEC_USE_COUNT((struct module*) THIS_MODULE); + + /* note that if ieee1394 is compiled into the kernel, + THIS_MODULE will be (void*) NULL, hence the if and + the cast are necessary */ - DECREF(THIS_MODULE); + } else { - /* the task-specific driver still has the extra - reference we gave it. This extra reference prevents - the module from unloading while the file is open, - and will be dropped by the VFS when the file is - released. */ + /* if the open() failed, then we need to drop the + extra reference we gave to the task-specific + driver */ - return 0; - } - -out_fail: - /* point the file's f_ops back to ieee1394. The VFS will then - decrement ieee1394's reference count immediately after this - function returns. */ + if(module) + __MOD_DEC_USE_COUNT(module); - file->f_op = &ieee1394_chardev_ops; - return retval; + /* point the file's f_ops back to ieee1394. The VFS will then + decrement ieee1394's reference count immediately after this + function returns. */ + + file->f_op = &ieee1394_chardev_ops; + } -#undef INCREF -#undef DECREF - + return retval; } struct proc_dir_entry *ieee1394_procfs_entry; @@ -1095,8 +1119,6 @@ module_exit(ieee1394_cleanup); /* Exported symbols */ -EXPORT_SYMBOL(hpsb_register_lowlevel); -EXPORT_SYMBOL(hpsb_unregister_lowlevel); EXPORT_SYMBOL(hpsb_alloc_host); EXPORT_SYMBOL(hpsb_add_host); EXPORT_SYMBOL(hpsb_remove_host); Modified: branches/weihs/ohci1394.c ============================================================================== --- branches/weihs/ohci1394.c (original) +++ branches/weihs/ohci1394.c 2002-09-19 18:00:33.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) { @@ -443,10 +439,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); } @@ -477,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); @@ -571,18 +537,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) */ @@ -629,7 +595,7 @@ ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, pci_resource_start(ohci->dev, 0), - pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE, + pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1, ohci->max_packet_size); } @@ -789,13 +755,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 +767,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; + 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->pending_first == NULL) - d->pending_last = NULL; - else + + if (d->free_prgs == 0) PRINT(KERN_INFO, ohci->id, "Transmit DMA FIFO ctx=%d is full... waiting",d->ctx); @@ -857,25 +819,16 @@ 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; - 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); - /* 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); @@ -929,8 +882,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: @@ -1033,46 +986,62 @@ 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_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, @@ -1143,7 +1112,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) @@ -1154,7 +1123,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) @@ -1165,7 +1134,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) @@ -1175,7 +1144,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) @@ -1185,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) { @@ -1507,25 +1449,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 +1509,7 @@ d->ctx); #endif - nextpacket = packet->xnext; + list_del(&packet->driver_list); hpsb_packet_sent(ohci->host, packet, ack & 0xf); if (datasize) { @@ -1588,90 +1521,64 @@ 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); 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 = (struct ti_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]) { + 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]); + d->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->ohci->dev, sizeof(struct dma_cmd), + 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; + /* Mark this context as freed. */ + d->ohci = NULL; } -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; - } - } - - 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; @@ -1689,8 +1596,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)); @@ -1701,8 +1608,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)); @@ -1711,8 +1618,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++) { @@ -1726,8 +1633,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; } @@ -1741,80 +1648,68 @@ } 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; } } 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 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; + 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]) { + 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->ohci->dev, sizeof(struct at_dma_prg), + 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; + /* Mark this context as freed. */ + d->ohci = NULL; } -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; - } - } - - 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; @@ -1829,8 +1724,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)); @@ -1846,17 +1741,28 @@ } 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; } } 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 d; + return 0; } static u16 ohci_crc16 (u32 *ptr, int length) @@ -2028,15 +1934,14 @@ return reg_read(ohci, OHCI1394_CSRData); } -static struct hpsb_host_operations ohci1394_ops = { - get_rom: ohci_get_rom, - transmit_packet: ohci_transmit, - devctl: ohci_devctl, - hw_csr_reg: ohci_hw_csr_reg, +static struct hpsb_host_driver ohci1394_driver = { + .name = OHCI1394_DRIVER_NAME, + .get_rom = ohci_get_rom, + .transmit_packet = ohci_transmit, + .devctl = ohci_devctl, + .hw_csr_reg = ohci_hw_csr_reg, }; -static struct hpsb_host_driver *ohci1394_driver; - /*********************************** @@ -2059,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); @@ -2069,7 +1973,7 @@ card_id_counter++); pci_set_master(dev); - host = hpsb_alloc_host(ohci1394_driver, sizeof(struct ti_ohci)); + host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci)); if (!host) FAIL(-ENOMEM, "Failed to allocate host structure"); ohci = host->hostdata; @@ -2151,68 +2055,78 @@ 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); + /* Start off with a soft reset, to clear everything to a sane + * state. */ + ohci_soft_reset(ohci); - if (ohci->ir_context == NULL) - FAIL(-ENOMEM, "Failed to allocate IR context"); + /* 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); - - /* IT DMA context allocation */ - ohci->it_context = - alloc_dma_trm_ctx(ohci, DMA_CTX_ISO, 0, IT_NUM_DESC, - OHCI1394_IsoXmitContextBase); + /* 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); - if (ohci->it_context == NULL) - FAIL(-ENOMEM, "Failed to allocate IT context"); + 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); - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - ohci->irq_hooks[i].irq_handler = NULL; - ohci->irq_hooks[i].data = NULL; - } + /* IR DMA context */ + 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 */ + 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"); + if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); @@ -2308,12 +2222,12 @@ static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = { { - class: PCI_CLASS_FIREWIRE_OHCI, - class_mask: 0x00ffffff, - vendor: PCI_ANY_ID, - device: PCI_ANY_ID, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, + .class = PCI_CLASS_FIREWIRE_OHCI, + .class_mask = 0x00ffffff, + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { 0, }, }; @@ -2321,10 +2235,10 @@ MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); static struct pci_driver ohci1394_pci_driver = { - name: OHCI1394_DRIVER_NAME, - id_table: ohci1394_pci_tbl, - probe: ohci1394_pci_probe, - remove: ohci1394_pci_remove, + .name = OHCI1394_DRIVER_NAME, + .id_table = ohci1394_pci_tbl, + .probe = ohci1394_pci_probe, + .remove = ohci1394_pci_remove, }; @@ -2355,65 +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; - 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); - } - } + 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; - - /* 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 (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; } - if(i >= OHCI1394_MAX_IRQ_HOOKS) - return -EBUSY; + spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); - ohci->irq_hooks[i].irq_handler = irq_handler; - ohci->irq_hooks[i].data = data; + 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; + } - /* ohci1394 will never be unloaded while an IRQ hook is - in use, because the user must reference this symbol */ + spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); - return 0; + 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; - - 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; - } + unsigned long 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); /*********************************** @@ -2427,27 +2345,11 @@ static void __exit ohci1394_cleanup (void) { pci_unregister_driver(&ohci1394_pci_driver); - hpsb_unregister_lowlevel(ohci1394_driver); } static int __init ohci1394_init(void) { - int ret; - - ohci1394_driver = hpsb_register_lowlevel(&ohci1394_ops, - OHCI1394_DRIVER_NAME); - if (!ohci1394_driver) { - PRINT_G(KERN_ERR, "hpsb_register_lowlevel failed"); - return -ENOMEM; - } - - ret = pci_module_init(&ohci1394_pci_driver); - if (ret < 0) { - PRINT_G(KERN_ERR, "pci_module_init failed"); - hpsb_unregister_lowlevel(ohci1394_driver); - return ret; - } - return ret; + return pci_module_init(&ohci1394_pci_driver); } module_init(ohci1394_init); Modified: branches/weihs/ieee1394_core.h ============================================================================== --- branches/weihs/ieee1394_core.h (original) +++ branches/weihs/ieee1394_core.h 2002-09-19 18:00: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: branches/weihs/amdtp.c ============================================================================== --- branches/weihs/amdtp.c (original) +++ branches/weihs/amdtp.c 2002-09-19 18:00:34.000000000 -0400 @@ -32,7 +32,7 @@ * That is outside the scope of this driver, and furthermore it is not * really standardized yet. * - * The Audio and Music Data Tranmission Protocol is avaiable at + * The Audio and Music Data Tranmission Protocol is available at * * http://www.1394ta.org/Download/Technology/Specifications/2001/AM20Final-jf2.pdf * @@ -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> @@ -89,9 +88,13 @@ #define FMT_AMDTP 0x10 #define FDF_AM824 0x00 -#define FDF_SFC_32KHZ 0x00 /* 32kHz */ -#define FDF_SFC_44K1HZ 0x01 /* 44.1kHz */ -#define FDF_SFC_48KHZ 0x02 /* 44.1kHz */ +#define FDF_SFC_32KHZ 0x00 +#define FDF_SFC_44K1HZ 0x01 +#define FDF_SFC_48KHZ 0x02 +#define FDF_SFC_88K2HZ 0x03 +#define FDF_SFC_96KHZ 0x04 +#define FDF_SFC_176K4HZ 0x05 +#define FDF_SFC_192KHZ 0x06 struct descriptor_block { struct output_more_immediate { @@ -113,15 +116,70 @@ struct packet { struct descriptor_block *db; dma_addr_t db_bus; - quadlet_t *payload; + struct iso_packet *payload; dma_addr_t payload_bus; }; +#include <asm/byteorder.h> + +#if defined __BIG_ENDIAN_BITFIELD + +struct iso_packet { + /* First quadlet */ + unsigned int dbs : 8; + unsigned int eoh0 : 2; + unsigned int sid : 6; + + unsigned int dbc : 8; + unsigned int fn : 2; + unsigned int qpc : 3; + unsigned int sph : 1; + unsigned int reserved : 2; + + /* Second quadlet */ + unsigned int fdf : 8; + unsigned int eoh1 : 2; + unsigned int fmt : 6; + + unsigned int syt : 16; + + quadlet_t data[0]; +}; + +#elif defined __LITTLE_ENDIAN_BITFIELD + +struct iso_packet { + /* First quadlet */ + unsigned int sid : 6; + unsigned int eoh0 : 2; + unsigned int dbs : 8; + + unsigned int reserved : 2; + unsigned int sph : 1; + unsigned int qpc : 3; + unsigned int fn : 2; + unsigned int dbc : 8; + + /* Second quadlet */ + unsigned int fmt : 6; + unsigned int eoh1 : 2; + unsigned int fdf : 8; + + unsigned int syt : 16; + + quadlet_t data[0]; +}; + +#else + +#error Unknown bitfield type + +#endif + struct fraction { int integer; int numerator; int denominator; - int counter; }; #define PACKET_LIST_SIZE 256 @@ -148,6 +206,8 @@ int rate; int dimension; int fdf; + int mode; + int sample_format; struct cmp_pcr *opcr; /* Input samples are copied here. */ @@ -157,7 +217,7 @@ unsigned char dbc; struct packet_list *current_packet_list; int current_packet; - struct fraction packet_size_fraction; + struct fraction ready_samples, samples_per_cycle; /* We use these to generate control bits when we are packing * iec958 data. @@ -176,8 +236,7 @@ * written back in the dma programs. */ atomic_t cycle_count, cycle_count2; - int cycle_offset; - struct fraction syt_fraction; + struct fraction cycle_offset, ticks_per_syt_offset; int syt_interval; int stale_count; @@ -192,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. */ @@ -220,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) { @@ -255,7 +297,7 @@ OHCI1394_CONTEXT_WAKE); } -void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx) +void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx, int synchronous) { u32 control; int wait; @@ -265,13 +307,15 @@ OHCI1394_CONTEXT_RUN); wmb(); - for (wait = 0; wait < 5; wait++) { - control = reg_read(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16); - if ((control & OHCI1394_CONTEXT_ACTIVE) == 0) - break; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + if (synchronous) { + for (wait = 0; wait < 5; wait++) { + control = reg_read(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16); + if ((control & OHCI1394_CONTEXT_ACTIVE) == 0) + break; + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } } } @@ -297,6 +341,27 @@ return pl; } +static void stream_start_dma(struct stream *s, struct packet_list *pl) +{ + u32 syt_cycle, cycle_count, start_cycle; + + cycle_count = reg_read(s->host->host->hostdata, + OHCI1394_IsochronousCycleTimer) >> 12; + syt_cycle = (pl->last_cycle_count - PACKET_LIST_SIZE + 1) & 0x0f; + + /* We program the DMA controller to start transmission at + * least 17 cycles from now - this happens when the lower four + * bits of cycle_count is 0x0f and syt_cycle is 0, in this + * case the start cycle is cycle_count - 15 + 32. */ + start_cycle = (cycle_count & ~0x0f) + 32 + syt_cycle; + if ((start_cycle & 0x1fff) >= 8000) + start_cycle = start_cycle - 8000 + 0x2000; + + ohci1394_start_it_ctx(s->host->ohci, s->iso_tasklet.context, + pl->packets[0].db_bus, 3, + start_cycle & 0x7fff); +} + static void stream_put_dma_packet_list(struct stream *s, struct packet_list *pl) { @@ -315,26 +380,16 @@ 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; - ohci1394_wake_it_ctx(s->host->ohci, s->iso_context); - } - else { - u32 syt, cycle_count; - - cycle_count = reg_read(s->host->host->hostdata, - OHCI1394_IsochronousCycleTimer) >> 12; - syt = (pl->packets[0].payload[1] >> 12) & 0x0f; - cycle_count = (cycle_count & ~0x0f) + 32 + syt; - if ((cycle_count & 0x1fff) >= 8000) - cycle_count = cycle_count - 8000 + 0x2000; - - ohci1394_start_it_ctx(s->host->ohci, s->iso_context, - pl->packets[0].db_bus, 3, - cycle_count & 0x7fff); + last->db->header_desc.skip = pl->packets[0].db_bus | 3; + 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; @@ -430,36 +485,42 @@ f->integer = numerator / denominator; f->numerator = numerator % denominator; f->denominator = denominator; - f->counter = 0; } -static int fraction_next_size(struct fraction *f) +static __inline__ void fraction_add(struct fraction *dst, + struct fraction *src1, + struct fraction *src2) { - return f->integer + ((f->counter + f->numerator) / f->denominator); + /* assert: src1->denominator == src2->denominator */ + + int sum, denom; + + /* We use these two local variables to allow gcc to optimize + * the division and the modulo into only one division. */ + + sum = src1->numerator + src2->numerator; + denom = src1->denominator; + dst->integer = src1->integer + src2->integer + sum / denom; + dst->numerator = sum % denom; + dst->denominator = denom; } -static void fraction_inc(struct fraction *f) +static __inline__ void fraction_sub_int(struct fraction *dst, + struct fraction *src, int integer) { - f->counter = (f->counter + f->numerator) % f->denominator; + dst->integer = src->integer - integer; + dst->numerator = src->numerator; + dst->denominator = src->denominator; } -static void amdtp_irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data) +static __inline__ int fraction_floor(struct fraction *frac) { - 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); + return frac->integer; +} - if (s != NULL) - stream_shift_packet_lists(s); +static __inline__ int fraction_ceil(struct fraction *frac) +{ + return frac->integer + (frac->numerator > 0 ? 1 : 0); } void packet_initialize(struct packet *p, struct packet *next) @@ -473,18 +534,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; @@ -633,17 +695,33 @@ } } +static void fill_payload_le16(struct stream *s, quadlet_t *data, int nevents) +{ + quadlet_t *event, sample, bits; + unsigned char *p; + int i, j; + + for (i = 0, event = data; i < nevents; i++) { + + for (j = 0; j < s->dimension; j++) { + p = buffer_get_bytes(s->input, 2); + sample = (p[1] << 16) | (p[0] << 8); + bits = get_header_bits(s, j, sample); + event[j] = cpu_to_be32((bits << 24) | sample); + } + + event += s->dimension; + if (++s->iec958_frame_count == 192) + s->iec958_frame_count = 0; + } +} static void fill_packet(struct stream *s, struct packet *packet, int nevents) { - int size, node_id, i, j; - quadlet_t *event; - unsigned char *p; - u32 control, sample, bits; - int syt_index, syt, next; + int syt_index, syt, size; + u32 control; size = (nevents * s->dimension + 2) * sizeof(quadlet_t); - node_id = s->host->host->node_id & 0x3f; /* Update DMA descriptors */ packet->db->payload_desc.status = 0; @@ -656,41 +734,45 @@ (s->iso_channel << 8) | (TCODE_ISO_DATA << 4); packet->db->header_desc.header[1] = size << 16; - /* Fill cip header */ - syt_index = s->dbc & (s->syt_interval - 1); - if (syt_index == 0 || syt_index + nevents > s->syt_interval) { + /* Calculate synchronization timestamp (syt). First we + * determine syt_index, that is, the index in the packet of + * the sample for which the timestamp is valid. */ + syt_index = (s->syt_interval - s->dbc) & (s->syt_interval - 1); + if (syt_index < nevents) { syt = ((atomic_read(&s->cycle_count) << 12) | - s->cycle_offset) & 0xffff; - next = fraction_next_size(&s->syt_fraction) + s->cycle_offset; + s->cycle_offset.integer) & 0xffff; + fraction_add(&s->cycle_offset, + &s->cycle_offset, &s->ticks_per_syt_offset); + /* This next addition should be modulo 8000 (0x1f40), * but we only use the lower 4 bits of cycle_count, so * we dont need the modulo. */ - atomic_add(next / 3072, &s->cycle_count); - s->cycle_offset = next % 3072; - fraction_inc(&s->syt_fraction); + atomic_add(s->cycle_offset.integer / 3072, &s->cycle_count); + s->cycle_offset.integer %= 3072; } - else { + else syt = 0xffff; - next = 0; - } - atomic_inc(&s->cycle_count2); - packet->payload[0] = cpu_to_be32((node_id << 24) | (s->dimension << 16) | s->dbc); - packet->payload[1] = cpu_to_be32((1 << 31) | (FMT_AMDTP << 24) | (s->fdf << 16) | syt); - - /* Fill payload */ - for (i = 0, event = &packet->payload[2]; i < nevents; i++) { - - for (j = 0; j < s->dimension; j++) { - p = buffer_get_bytes(s->input, 2); - sample = (p[1] << 16) | (p[0] << 8); - bits = get_header_bits(s, j, sample); - event[j] = cpu_to_be32((bits << 24) | sample); - } - - event += s->dimension; - if (++s->iec958_frame_count == 192) - s->iec958_frame_count = 0; + atomic_inc(&s->cycle_count2); + + /* Fill cip header */ + packet->payload->eoh0 = 0; + packet->payload->sid = s->host->host->node_id & 0x3f; + packet->payload->dbs = s->dimension; + packet->payload->fn = 0; + packet->payload->qpc = 0; + packet->payload->sph = 0; + packet->payload->reserved = 0; + packet->payload->dbc = s->dbc; + packet->payload->eoh1 = 2; + packet->payload->fmt = FMT_AMDTP; + packet->payload->fdf = s->fdf; + packet->payload->syt = cpu_to_be16(syt); + + switch (s->sample_format) { + case AMDTP_INPUT_LE16: + fill_payload_le16(s, packet->payload->data, nevents); + break; } s->dbc += nevents; @@ -700,13 +782,44 @@ { struct packet *p; int nevents; + struct fraction next; + + /* The AMDTP specifies two transmission modes: blocking and + * non-blocking. In blocking mode you always transfer + * syt_interval or zero samples, whereas in non-blocking mode + * you send as many samples as you have available at transfer + * time. + * + * The fraction samples_per_cycle specifies the number of + * samples that become available per cycle. We add this to + * the fraction ready_samples, which specifies the number of + * leftover samples from the previous transmission. The sum, + * stored in the fraction next, specifies the number of + * samples available for transmission, and from this we + * determine the number of samples to actually transmit. + */ + + while (1) { + fraction_add(&next, &s->ready_samples, &s->samples_per_cycle); + if (s->mode == AMDTP_MODE_BLOCKING) { + if (fraction_floor(&next) >= s->syt_interval) + nevents = s->syt_interval; + else + nevents = 0; + } + else + nevents = fraction_floor(&next); + + p = stream_current_packet(s); + if (s->input->length < nevents * s->dimension * 2 || p == NULL) + break; - while (nevents = fraction_next_size(&s->packet_size_fraction), - p = stream_current_packet(s), - nevents * s->dimension * 2 <= s->input->length && p != NULL) { fill_packet(s, p, nevents); - fraction_inc(&s->packet_size_fraction); stream_queue_packet(s); + + /* Now that we have successfully queued the packet for + * transmission, we update the fraction ready_samples. */ + fraction_sub_int(&s->ready_samples, &next, nevents); } } @@ -714,9 +827,10 @@ { int max_nevents, max_packet_size, i; - max_nevents = s->packet_size_fraction.integer; - if (s->packet_size_fraction.numerator > 0) - max_nevents++; + if (s->mode == AMDTP_MODE_BLOCKING) + max_nevents = s->syt_interval; + else + max_nevents = fraction_ceil(&s->samples_per_cycle); max_packet_size = max_nevents * s->dimension * 4 + 8; s->packet_pool = pci_pool_create("packet pool", s->host->ohci->dev, @@ -763,15 +877,20 @@ plug->p2p_count, plug->channel); s->iso_channel = plug->channel; if (plug->p2p_count > 0) { - /* start streaming */ + struct packet_list *pl; + + pl = list_entry(s->dma_packet_lists.next, struct packet_list, link); + stream_start_dma(s, pl); } else { - /* stop streaming */ + ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 0); } } static int stream_configure(struct stream *s, int cmd, struct amdtp_ioctl *cfg) { + const int transfer_delay = 9000; + if (cfg->format <= AMDTP_FORMAT_IEC958_AC3) s->format = cfg->format; else @@ -782,32 +901,59 @@ s->syt_interval = 8; s->fdf = FDF_SFC_32KHZ; s->iec958_rate_code = 0x0c; - s->rate = cfg->rate; break; case 44100: s->syt_interval = 8; s->fdf = FDF_SFC_44K1HZ; s->iec958_rate_code = 0x00; - s->rate = cfg->rate; break; case 48000: s->syt_interval = 8; s->fdf = FDF_SFC_48KHZ; s->iec958_rate_code = 0x04; - s->rate = cfg->rate; break; + case 88200: + s->syt_interval = 16; + s->fdf = FDF_SFC_88K2HZ; + s->iec958_rate_code = 0x00; + break; + case 96000: + s->syt_interval = 16; + s->fdf = FDF_SFC_96KHZ; + s->iec958_rate_code = 0x00; + break; + case 176400: + s->syt_interval = 32; + s->fdf = FDF_SFC_176K4HZ; + s->iec958_rate_code = 0x00; + break; + case 192000: + s->syt_interval = 32; + s->fdf = FDF_SFC_192KHZ; + s->iec958_rate_code = 0x00; + break; + default: return -EINVAL; } - fraction_init(&s->packet_size_fraction, s->rate, 8000); + s->rate = cfg->rate; + fraction_init(&s->samples_per_cycle, s->rate, 8000); + fraction_init(&s->ready_samples, 0, 8000); - /* The syt_fraction is initialized to the number of ticks - * between syt_interval events. The number of ticks per + /* The ticks_per_syt_offset is initialized to the number of + * ticks between syt_interval events. The number of ticks per * second is 24.576e6, so the number of ticks between * syt_interval events is 24.576e6 * syt_interval / rate. */ - fraction_init(&s->syt_fraction, 24576000 * s->syt_interval, s->rate); + fraction_init(&s->ticks_per_syt_offset, + 24576000 * s->syt_interval, s->rate); + fraction_init(&s->cycle_offset, (transfer_delay % 3072) * s->rate, s->rate); + atomic_set(&s->cycle_count, transfer_delay / 3072); + atomic_set(&s->cycle_count2, 0); + + s->mode = cfg->mode; + s->sample_format = AMDTP_INPUT_LE16; /* When using the AM824 raw subformat we can stream signals of * any dimension. The IEC958 subformat, however, only @@ -858,7 +1004,6 @@ { struct stream *s; unsigned long flags; - const int transfer_delay = 8651; /* approx 352 us */ s = kmalloc(sizeof(struct stream), SLAB_KERNEL); if (s == NULL) @@ -873,10 +1018,6 @@ return NULL; } - s->cycle_offset = transfer_delay % 3072; - atomic_set(&s->cycle_count, transfer_delay / 3072); - atomic_set(&s->cycle_count2, 0); - s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev, sizeof(struct descriptor_block), 16, 0, SLAB_KERNEL); @@ -892,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); @@ -920,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); - 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); @@ -969,8 +1113,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; } @@ -983,7 +1132,6 @@ { struct stream *s = file->private_data; struct amdtp_ioctl cfg; - int new; switch(cmd) { @@ -994,23 +1142,23 @@ else return stream_configure(s, cmd, &cfg); - case AMDTP_IOC_PING: ... [truncated message content] |
From: SVN U. <ben...@li...> - 2002-09-19 12:18:04
|
Author: bencollins Date: 2002-09-19 17:11:47 -0400 (Thu, 19 Sep 2002) New Revision: 576 Modified: branches/mpeg1394/ branches/mpeg1394/Config.in branches/mpeg1394/Makefile branches/mpeg1394/amdtp.c branches/mpeg1394/amdtp.h branches/mpeg1394/cmp.c branches/mpeg1394/csr.c branches/mpeg1394/dv1394-private.h branches/mpeg1394/dv1394.c branches/mpeg1394/eth1394.c branches/mpeg1394/highlevel.c branches/mpeg1394/hosts.c branches/mpeg1394/hosts.h branches/mpeg1394/ieee1394_core.c branches/mpeg1394/ieee1394_core.h branches/mpeg1394/ieee1394_transactions.c branches/mpeg1394/nodemgr.c branches/mpeg1394/ohci1394.c branches/mpeg1394/ohci1394.h branches/mpeg1394/pcilynx.c branches/mpeg1394/pcilynx.h branches/mpeg1394/raw1394.c branches/mpeg1394/sbp2.c branches/mpeg1394/sbp2.h branches/mpeg1394/video1394.c Log: Merge with trunk Modified: branches/mpeg1394/ieee1394_core.c ============================================================================== --- branches/mpeg1394/ieee1394_core.c (original) +++ branches/mpeg1394/ieee1394_core.c 2002-09-19 17:11:52.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" @@ -142,7 +141,7 @@ int hpsb_reset_bus(struct hpsb_host *host, int type) { if (!host->in_bus_reset) { - host->ops->devctl(host, RESET_BUS, type); + host->driver->devctl(host, RESET_BUS, type); return 0; } else { return 1; @@ -161,7 +160,10 @@ abort_requests(host); host->in_bus_reset = 1; host->irm_id = -1; + host->is_irm = 0; host->busmgr_id = -1; + host->is_busmgr = 0; + host->is_cycmst = 0; host->node_count = 0; host->selfid_count = 0; @@ -355,7 +357,10 @@ } host->reset_retries = 0; - if (isroot) host->ops->devctl(host, ACT_CYCLE_MASTER, 1); + if (isroot) { + host->driver->devctl(host, ACT_CYCLE_MASTER, 1); + host->is_cycmst = 1; + } atomic_inc(&host->generation); host->in_bus_reset = 0; highlevel_host_reset(host); @@ -441,7 +446,7 @@ } #endif - return host->ops->transmit_packet(host, packet); + return host->driver->transmit_packet(host, packet); } static void send_packet_nocare(struct hpsb_packet *packet) @@ -737,7 +742,7 @@ struct list_head *lh; LIST_HEAD(llist); - host->ops->devctl(host, CANCEL_REQUESTS, 0); + host->driver->devctl(host, CANCEL_REQUESTS, 0); spin_lock_irqsave(&host->pending_pkt_lock, flags); list_splice(&host->pending_packets, &llist); @@ -811,8 +816,8 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file); static struct file_operations ieee1394_chardev_ops = { - owner: THIS_MODULE, - open: ieee1394_dispatch_open, + .owner =THIS_MODULE, + .open = ieee1394_dispatch_open, }; devfs_handle_t ieee1394_devfs_handle; @@ -862,19 +867,57 @@ write_unlock(&ieee1394_chardevs_lock); } +/* + ieee1394_get_chardev() - look up and acquire a character device + driver that has previously registered using ieee1394_register_chardev() + + On success, returns 1 and sets module and file_ops to the driver. + The module will have an incremented reference count. + + On failure, returns 0. + The module will NOT have an incremented reference count. +*/ + +static int ieee1394_get_chardev(int blocknum, + struct module **module, + struct file_operations **file_ops) +{ + int ret = 0; + + if( (blocknum < 0) || (blocknum > 15) ) + return ret; + + read_lock(&ieee1394_chardevs_lock); + + *module = ieee1394_chardevs[blocknum].module; + *file_ops = ieee1394_chardevs[blocknum].file_ops; + + if(*file_ops == NULL) + goto out; + + /* don't need try_inc_mod_count if the driver is non-modular */ + if(*module && (try_inc_mod_count(*module) == 0)) + goto out; + + /* success! */ + ret = 1; + +out: + read_unlock(&ieee1394_chardevs_lock); + return ret; +} + /* the point of entry for open() on any ieee1394 character device */ static int ieee1394_dispatch_open(struct inode *inode, struct file *file) { struct file_operations *file_ops; struct module *module; int blocknum; - int retval = -ENODEV; + int retval; /* Maintaining correct module reference counts is tricky here! - For Linux v2.4 and later: - The key thing to remember is that the VFS increments the reference count of ieee1394 before it calls ieee1394_dispatch_open(). @@ -887,16 +930,7 @@ If the open() fails, then the VFS will drop the reference count of whatever module file->f_op->owner points to, immediately after this function returns. - - The comments below refer to the 2.4 case, since the 2.2 - case is trivial. - */ - -#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \ - if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0) -#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \ - if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0) /* shift away lower four bits of the minor to get the index of the ieee1394_driver @@ -904,20 +938,10 @@ blocknum = (minor(inode->i_rdev) >> 4) & 0xF; - /* printk("ieee1394_dispatch_open(%d)", blocknum); */ + /* look up the driver */ - read_lock(&ieee1394_chardevs_lock); - module = ieee1394_chardevs[blocknum].module; - /* bump the reference count of the driver that - will receive the open() */ - INCREF(module); - file_ops = ieee1394_chardevs[blocknum].file_ops; - read_unlock(&ieee1394_chardevs_lock); - - if(file_ops == NULL) { - DECREF(module); - goto out_fail; - } + if(ieee1394_get_chardev(blocknum, &module, &file_ops) == 0) + return -ENODEV; /* redirect all subsequent requests to the driver's own file_operations */ @@ -929,42 +953,42 @@ /* follow through with the open() */ retval = file_ops->open(inode, file); - if(retval) { + if(retval == 0) { - /* if the open() failed, then we need to drop the - extra reference we gave to the task-specific - driver */ + /* If the open() succeeded, then ieee1394 will be left + with an extra module reference, so we discard it here. - DECREF(module); - goto out_fail; + The task-specific driver still has the extra + reference given to it by ieee1394_get_chardev(). + This extra reference prevents the module from + unloading while the file is open, and will be + dropped by the VFS when the file is released. + */ - } else { - - /* if the open() succeeded, then ieee1394 will be left - with an extra module reference, so we discard it here.*/ + if(THIS_MODULE) + __MOD_DEC_USE_COUNT((struct module*) THIS_MODULE); + + /* note that if ieee1394 is compiled into the kernel, + THIS_MODULE will be (void*) NULL, hence the if and + the cast are necessary */ - DECREF(THIS_MODULE); + } else { - /* the task-specific driver still has the extra - reference we gave it. This extra reference prevents - the module from unloading while the file is open, - and will be dropped by the VFS when the file is - released. */ + /* if the open() failed, then we need to drop the + extra reference we gave to the task-specific + driver */ - return 0; - } - -out_fail: - /* point the file's f_ops back to ieee1394. The VFS will then - decrement ieee1394's reference count immediately after this - function returns. */ + if(module) + __MOD_DEC_USE_COUNT(module); - file->f_op = &ieee1394_chardev_ops; - return retval; + /* point the file's f_ops back to ieee1394. The VFS will then + decrement ieee1394's reference count immediately after this + function returns. */ + + file->f_op = &ieee1394_chardev_ops; + } -#undef INCREF -#undef DECREF - + return retval; } struct proc_dir_entry *ieee1394_procfs_entry; @@ -1025,8 +1049,6 @@ module_exit(ieee1394_cleanup); /* Exported symbols */ -EXPORT_SYMBOL(hpsb_register_lowlevel); -EXPORT_SYMBOL(hpsb_unregister_lowlevel); EXPORT_SYMBOL(hpsb_alloc_host); EXPORT_SYMBOL(hpsb_add_host); EXPORT_SYMBOL(hpsb_remove_host); Modified: branches/mpeg1394/ohci1394.c ============================================================================== --- branches/mpeg1394/ohci1394.c (original) +++ branches/mpeg1394/ohci1394.c 2002-09-19 17:11:52.000000000 -0400 @@ -37,7 +37,7 @@ * . DMA error recovery * * Known bugs: - * . Apple PowerBook detected but not working yet (still true?) + * . devctl BUS_RESET arg confusion (reset type or root holdoff?) */ /* @@ -77,12 +77,6 @@ * . Config ROM generation */ -/* Issues: - * - * - devctl BUS_RESET should treat arg as reset type - * - */ - #include <linux/config.h> #include <linux/kernel.h> #include <linux/list.h> @@ -176,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) { @@ -228,7 +218,7 @@ spin_lock_irqsave (&ohci->phy_reg_lock, flags); - reg_write(ohci, OHCI1394_PhyControl, (((u16)addr << 8) & 0x00000f00) | 0x00008000); + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000); for (i = 0; i < OHCI_LOOP_COUNT; i++) { if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000) @@ -256,7 +246,7 @@ spin_lock_irqsave (&ohci->phy_reg_lock, flags); - reg_write(ohci, OHCI1394_PhyControl, 0x00004000 | (((u16)addr << 8) & 0x00000f00) | data); + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000); for (i = 0; i < OHCI_LOOP_COUNT; i++) { r = reg_read(ohci, OHCI1394_PhyControl); @@ -295,8 +285,6 @@ size_t size; quadlet_t q0, q1; - mdelay(10); - /* Check status of self-id reception */ if (ohci->selfid_swap) @@ -367,13 +355,6 @@ break; mdelay(1); } - - /* Now reenable LPS, since that's usually what we want after a - * softreset anyway. Wait 50msec to make sure we have full link - * enabled. */ - reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); - mdelay(50); - DBGMSG (ohci->id, "Soft reset finished"); } @@ -458,10 +439,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); } @@ -497,9 +476,9 @@ /* Put some defaults to these undefined bus options */ buf = reg_read(ohci, OHCI1394_BusOptions); - buf |= 0x60000000; /* Enable CMC and ISC */ + buf |= 0xE0000000; /* Enable IRMC, CMC and ISC */ buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */ - buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */ + buf &= ~0x18000000; /* Disable PMC and BMC */ reg_write(ohci, OHCI1394_BusOptions, buf); /* Set the bus number */ @@ -511,8 +490,10 @@ /* Clear link control register */ reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); - /* Enable cycle timer and cycle master */ + /* Enable cycle timer and cycle master and set the IRM + * contender bit in our self ID packets. */ reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000); + set_phy_reg_mask(ohci, 4, 0xc0); /* Clear interrupt registers */ reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); @@ -556,18 +537,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) */ @@ -614,7 +595,7 @@ ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, pci_resource_start(ohci->dev, 0), - pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0), + pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1, ohci->max_packet_size); } @@ -774,13 +755,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; } @@ -792,22 +767,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; + 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->pending_first == NULL) - d->pending_last = NULL; - else + + if (d->free_prgs == 0) PRINT(KERN_INFO, ohci->id, "Transmit DMA FIFO ctx=%d is full... waiting",d->ctx); @@ -842,25 +819,16 @@ 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; - 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); - /* 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); @@ -914,8 +882,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: @@ -1018,46 +986,62 @@ 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_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, @@ -1128,7 +1112,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) @@ -1139,7 +1123,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) @@ -1150,7 +1134,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) @@ -1160,7 +1144,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) @@ -1170,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) { @@ -1492,25 +1449,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; @@ -1561,7 +1509,7 @@ d->ctx); #endif - nextpacket = packet->xnext; + list_del(&packet->driver_list); hpsb_packet_sent(ohci->host, packet, ack & 0xf); if (datasize) { @@ -1573,90 +1521,64 @@ 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); 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 = (struct ti_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]) { + 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]); + d->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->ohci->dev, sizeof(struct dma_cmd), + 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; + /* Mark this context as freed. */ + d->ohci = NULL; } -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; - } - } - - 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; @@ -1674,8 +1596,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)); @@ -1686,8 +1608,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)); @@ -1696,8 +1618,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++) { @@ -1711,8 +1633,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; } @@ -1726,80 +1648,68 @@ } 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; } } 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 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; + 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]) { + 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->ohci->dev, sizeof(struct at_dma_prg), + 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); - } - - /* clear the ISO context usage bit */ - if ((*d)->type == DMA_CTX_ISO) { - clear_bit((*d)->ctx, &ohci->it_ctx_usage); + kfree(d->prg_cpu); + kfree(d->prg_bus); } - kfree(*d); - *d = NULL; - return 0; + /* Mark this context as freed. */ + d->ohci = NULL; } -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; - } - } - - 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; @@ -1814,8 +1724,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)); @@ -1831,17 +1741,28 @@ } 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; } } 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 d; + return 0; } static u16 ohci_crc16 (u32 *ptr, int length) @@ -2013,15 +1934,14 @@ return reg_read(ohci, OHCI1394_CSRData); } -static struct hpsb_host_operations ohci1394_ops = { - get_rom: ohci_get_rom, - transmit_packet: ohci_transmit, - devctl: ohci_devctl, - hw_csr_reg: ohci_hw_csr_reg, +static struct hpsb_host_driver ohci1394_driver = { + .name = OHCI1394_DRIVER_NAME, + .get_rom = ohci_get_rom, + .transmit_packet = ohci_transmit, + .devctl = ohci_devctl, + .hw_csr_reg = ohci_hw_csr_reg, }; -static struct hpsb_host_driver *ohci1394_driver; - /*********************************** @@ -2043,8 +1963,7 @@ struct hpsb_host *host; struct ti_ohci *ohci; /* shortcut to currently handled device */ - unsigned long ohci_base, ohci_len; - int i; + unsigned long ohci_base; if (version_printed++ == 0) PRINT_G(KERN_INFO, "%s", version); @@ -2054,13 +1973,14 @@ card_id_counter++); pci_set_master(dev); - host = hpsb_alloc_host(ohci1394_driver, sizeof(struct ti_ohci)); + host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci)); if (!host) FAIL(-ENOMEM, "Failed to allocate host structure"); ohci = host->hostdata; ohci->id = card_id_counter++; ohci->dev = dev; ohci->host = host; + ohci->init_state = OHCI_INIT_ALLOC_HOST; host->pdev = dev; pci_set_drvdata(dev, ohci); @@ -2076,76 +1996,54 @@ * zero. Should this work? Obviously it's not defined what these * registers will read when they aren't supported. Bleh! */ if (dev->vendor == PCI_VENDOR_ID_APPLE && - dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { - ohci->no_swap_incoming = 1; - ohci->selfid_swap = 0; + dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { + ohci->no_swap_incoming = 1; + ohci->selfid_swap = 0; } else ohci->selfid_swap = 1; #endif - /* csr_config rom allocation */ - ohci->csr_config_rom_cpu = - pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, - &ohci->csr_config_rom_bus); - OHCI_DMA_ALLOC("consistent csr_config_rom"); - if (ohci->csr_config_rom_cpu == NULL) - FAIL(-ENOMEM, "Failed to allocate buffer config rom"); - - + /* We hardwire the MMIO length, since some CardBus adaptors + * fail to report the right length. Anyway, the ohci spec + * clearly says it's 2kb, so this shouldn't be a problem. */ ohci_base = pci_resource_start(dev, 0); - ohci_len = pci_resource_len(dev, 0); - - if (!request_mem_region (ohci_base, ohci_len, OHCI1394_DRIVER_NAME)) - FAIL(-ENOMEM, "MMIO resource (0x%lx@0x%lx) unavailable, aborting.", - ohci_base, ohci_len); - - ohci->registers = ioremap(ohci_base, ohci_len); + if (pci_resource_len(dev, 0) != OHCI1394_REGISTER_SIZE) + PRINT(KERN_WARNING, ohci->id, "Unexpected PCI resource length of %lx!", + pci_resource_len(dev, 0)); + + /* Seems PCMCIA handles this internally. Not sure why. Seems + * pretty bogus to force a driver to special case this. */ +#ifndef PCMCIA + if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME)) + FAIL(-ENOMEM, "MMIO resource (0x%lx - 0x%lx) unavailable", + ohci_base, ohci_base + OHCI1394_REGISTER_SIZE); +#endif + ohci->init_state = OHCI_INIT_HAVE_MEM_REGION; + ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE); if (ohci->registers == NULL) FAIL(-ENXIO, "Failed to remap registers - card not accessible"); - + ohci->init_state = OHCI_INIT_HAVE_IOMAPPING; DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers); + /* csr_config rom allocation */ + ohci->csr_config_rom_cpu = + pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, + &ohci->csr_config_rom_bus); + OHCI_DMA_ALLOC("consistent csr_config_rom"); + if (ohci->csr_config_rom_cpu == NULL) + FAIL(-ENOMEM, "Failed to allocate buffer config rom"); + ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER; - /* Start off with a softreset, to clear everything to a sane - * state. This will also set Link Power State (LPS), which we - * need in order to start accessing most of the registers. */ - ohci_soft_reset(ohci); - - /* determinte the number of available IR and IT contexts right away, - because they need to be known for alloc_dma_*_ctx() */ - 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->ir_ctx_usage = 0; - - /* set the usage bits for non-existent contexts so they can't be allocated */ - for(i = ohci->nb_iso_rcv_ctx; i < sizeof(ohci->ir_ctx_usage)*8; i++) - __set_bit(i, &ohci->ir_ctx_usage); - - 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); - - ohci->it_ctx_usage = 0; - - /* set the usage bits for non-existent contexts so they can't be allocated */ - for(i = ohci->nb_iso_xmit_ctx; i < sizeof(ohci->it_ctx_usage)*8; i++) - __set_bit(i, &ohci->it_ctx_usage); - - - /* - * self-id dma buffer allocation - */ + /* self-id dma buffer allocation */ ohci->selfid_buf_cpu = pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, &ohci->selfid_buf_bus); OHCI_DMA_ALLOC("consistent selfid_buf"); + if (ohci->selfid_buf_cpu == NULL) FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets"); + ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER; if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on " @@ -2155,74 +2053,90 @@ /* No self-id errors at startup */ ohci->self_id_errors = 0; + 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"); - /* 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); + /* Start off with a soft reset, to clear everything to a sane + * state. */ + ohci_soft_reset(ohci); - if (ohci->ir_context == NULL) - FAIL(-ENOMEM, "Failed to allocate IR context"); + /* 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); - - /* IT DMA context allocation */ - ohci->it_context = - alloc_dma_trm_ctx(ohci, DMA_CTX_ISO, 0, IT_NUM_DESC, - OHCI1394_IsoXmitContextBase); + /* 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); - if (ohci->it_context == NULL) - FAIL(-ENOMEM, "Failed to allocate IT context"); + 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); - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - ohci->irq_hooks[i].irq_handler = NULL; - ohci->irq_hooks[i].data = NULL; - } + /* IR DMA context */ + 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 */ + 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"); + if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); + ohci->init_state = OHCI_INIT_HAVE_IRQ; ohci_initialize(ohci); /* Tell the highlevel this host is ready */ hpsb_add_host(host); + ohci->init_state = OHCI_INIT_DONE; return 0; #undef FAIL @@ -2231,73 +2145,62 @@ static void ohci1394_pci_remove(struct pci_dev *pdev) { struct ti_ohci *ohci; - quadlet_t buf; ohci = pci_get_drvdata(pdev); if (!ohci) return; - if (ohci->host) + switch (ohci->init_state) { + case OHCI_INIT_DONE: hpsb_remove_host(ohci->host); - /* Soft reset before we start */ - ohci_soft_reset(ohci); + case OHCI_INIT_HAVE_IRQ: + /* Soft reset before we start - this disables + * interrupts and clears linkEnable and LPS. */ + ohci_soft_reset(ohci); + free_irq(ohci->dev->irq, ohci); + + case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE: + /* Free AR dma */ + free_dma_rcv_ctx(&ohci->ar_req_context); + free_dma_rcv_ctx(&ohci->ar_resp_context); + + /* Free AT dma */ + free_dma_trm_ctx(&ohci->at_req_context); + free_dma_trm_ctx(&ohci->at_resp_context); - /* Free AR dma */ - free_dma_rcv_ctx(&ohci->ar_req_context); - free_dma_rcv_ctx(&ohci->ar_resp_context); - - /* Free AT dma */ - free_dma_trm_ctx(&ohci->at_req_context); - free_dma_trm_ctx(&ohci->at_resp_context); - - /* Free IR dma */ - free_dma_rcv_ctx(&ohci->ir_context); - - /* Free IT dma */ - free_dma_trm_ctx(&ohci->it_context); - - /* Disable all interrupts */ - reg_write(ohci, OHCI1394_IntMaskClear, 0x80000000); - free_irq(ohci->dev->irq, ohci); - - /* Free self-id buffer */ - if (ohci->selfid_buf_cpu) { + /* Free IR dma */ + free_dma_rcv_ctx(&ohci->ir_context); + + /* Free IT dma */ + free_dma_trm_ctx(&ohci->it_context); + + case OHCI_INIT_HAVE_SELFID_BUFFER: pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, ohci->selfid_buf_cpu, ohci->selfid_buf_bus); OHCI_DMA_FREE("consistent selfid_buf"); - } - - /* Free config rom */ - if (ohci->csr_config_rom_cpu) { + + case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER: pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, - ohci->csr_config_rom_cpu, + ohci->csr_config_rom_cpu, ohci->csr_config_rom_bus); OHCI_DMA_FREE("consistent csr_config_rom"); - } - - /* Disable our bus options */ - buf = reg_read(ohci, OHCI1394_BusOptions); - buf &= ~0xf8000000; - buf |= 0x00ff0000; - reg_write(ohci, OHCI1394_BusOptions, buf); - /* Clear LinkEnable and LPS */ - reg_write(ohci, OHCI1394_HCControlClear, 0x000a0000); - - if (ohci->registers) + case OHCI_INIT_HAVE_IOMAPPING: iounmap(ohci->registers); - release_mem_region (pci_resource_start(ohci->dev, 0), - pci_resource_len(ohci->dev, 0)); + case OHCI_INIT_HAVE_MEM_REGION: +#ifndef PCMCIA + release_mem_region(pci_resource_start(ohci->dev, 0), + OHCI1394_REGISTER_SIZE); +#endif #ifdef CONFIG_ALL_PPC - /* On UniNorth, power down the cable and turn off the - * chip clock when the module is removed to save power - * on laptops. Turning it back ON is done by the arch - * code when pci_enable_device() is called - */ + /* On UniNorth, power down the cable and turn off the chip + * clock when the module is removed to save power on + * laptops. Turning it back ON is done by the arch code when + * pci_enable_device() is called */ { struct device_node* of_node; @@ -2309,20 +2212,22 @@ } #endif /* CONFIG_ALL_PPC */ - pci_set_drvdata(ohci->dev, NULL); - hpsb_unref_host(ohci->host); + case OHCI_INIT_ALLOC_HOST: + pci_set_drvdata(ohci->dev, NULL); + hpsb_unref_host(ohci->host); + } } #define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = { { - class: PCI_CLASS_FIREWIRE_OHCI, - class_mask: 0x00ffffff, - vendor: PCI_ANY_ID, - device: PCI_ANY_ID, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, + .class = PCI_CLASS_FIREWIRE_OHCI, + .class_mask = 0x00ffffff, + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { 0, }, }; @@ -2330,10 +2235,10 @@ MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); static struct pci_driver ohci1394_pci_driver = { - name: OHCI1394_DRIVER_NAME, - id_table: ohci1394_pci_tbl, - probe: ohci1394_pci_probe, - remove: ohci1394_pci_remove, + .name = OHCI1394_DRIVER_NAME, + .id_table = ohci1394_pci_tbl, + .probe = ohci1394_pci_probe, + .remove = ohci1394_pci_remove, }; @@ -2364,65 +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; - 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); - } - } + 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; - - /* 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 (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; } - if(i >= OHCI1394_MAX_IRQ_HOOKS) - return -EBUSY; + spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); - ohci->irq_hooks[i].irq_handler = irq_handler; - ohci->irq_hooks[i].data = data; + 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; + } - /* ohci1394 will never be unloaded while an IRQ hook is - in use, because the user must reference this symbol */ + spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); - return 0; + 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; - - 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; - } + unsigned long 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); /*********************************** @@ -2436,27 +2345,11 @@ static void __exit ohci1394_cleanup (void) { pci_unregister_driver(&ohci1394_pci_driver); - hpsb_unregister_lowlevel(ohci1394_driver); } static int __init ohci1394_init(void) { - int ret; - - ohci1394_driver = hpsb_register_lowlevel(&ohci1394_ops, - OHCI1394_DRIVER_NAME); - if (!ohci1394_driver) { - PRINT_G(KERN_ERR, "hpsb_register_lowlevel failed"); - return -ENOMEM; - } - - ret = pci_module_init(&ohci1394_pci_driver); - if (ret < 0) { - PRINT_G(KERN_ERR, "pci_module_init failed"); - hpsb_unregister_lowlevel(ohci1394_driver); - return ret; - } - return ret; + return pci_module_init(&ohci1394_pci_driver); } module_init(ohci1394_init); Modified: branches/mpeg1394/amdtp.c ============================================================================== --- branches/mpeg1394/amdtp.c (original) +++ branches/mpeg1394/amdtp.c 2002-09-19 17:11:52.000000000 -0400 @@ -32,7 +32,7 @@ * That is outside the scope of this driver, and furthermore it is not * really standardized yet. * - * The Audio and Music Data Tranmission Protocol is avaiable at + * The Audio and Music Data Tranmission Protocol is available at * * http://www.1394ta.org/Download/Technology/Specifications/2001/AM20Final-jf2.pdf * @@ -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> @@ -89,9 +88,13 @@ #define FMT_AMDTP 0x10 #define FDF_AM824 0x00 -#define FDF_SFC_32KHZ 0x00 /* 32kHz */ -#define FDF_SFC_44K1HZ 0x01 /* 44.1kHz */ -#define FDF_SFC_48KHZ 0x02 /* 44.1kHz */ +#define FDF_SFC_32KHZ 0x00 +#define FDF_SFC_44K1HZ 0x01 +#define FDF_SFC_48KHZ 0x02 +#define FDF_SFC_88K2HZ 0x03 +#define FDF_SFC_96KHZ 0x04 +#define FDF_SFC_176K4HZ 0x05 +#define FDF_SFC_192KHZ 0x06 struct descriptor_block { struct output_more_immediate { @@ -113,15 +116,70 @@ struct packet { struct descriptor_block *db; dma_addr_t db_bus; - quadlet_t *payload; + struct iso_packet *payload; dma_addr_t payload_bus; }; +#include <asm/byteorder.h> + +#if defined __BIG_ENDIAN_BITFIELD + +struct iso_packet { + /* First quadlet */ + unsigned int dbs : 8; + unsigned int eoh0 : 2; + unsigned int sid : 6; + + unsigned int dbc : 8; + unsigned int fn : 2; + unsigned int qpc : 3; + unsigned int sph : 1; + unsigned int reserved : 2; + + /* Second quadlet */ + unsigned int fdf : 8; + unsigned int eoh1 : 2; + unsigned int fmt : 6; + + unsigned int syt : 16; + + quadlet_t data[0]; +}; + +#elif defined __LITTLE_ENDIAN_BITFIELD + +struct iso_packet { + /* First quadlet */ + unsigned int sid : 6; + unsigned int eoh0 : 2; + unsigned int dbs : 8; + + unsigned int reserved : 2; + unsigned int sph : 1; + unsigned int qpc : 3; + unsigned int fn : 2; + unsigned int dbc : 8; + + /* Second quadlet */ + unsigned int fmt : 6; + unsigned int eoh1 : 2; + unsigned int fdf : 8; + + unsigned int syt : 16; + + quadlet_t data[0]; +}; + +#else + +#error Unknown bitfield type + +#endif + struct fraction { int integer; int numerator; int denominator; - int counter; }; #define PACKET_LIST_SIZE 256 @@ -148,6 +206,8 @@ int rate; int dimension; int fdf; + int mode; + int sample_format; struct cmp_pcr *opcr; /* Input samples are copied here. */ @@ -157,7 +217,7 @@ unsigned char dbc; struct packet_list *current_packet_list; int current_packet; - struct fraction packet_size_fraction; + struct fraction ready_samples, samples_per_cycle; /* We use these to generate control bits when we are packing * iec958 data. @@ -176,8 +236,7 @@ * written back in the dma programs. */ atomic_t cycle_count, cycle_count2; - int cycle_offset; - struct fraction syt_fraction; + struct fraction cycle_offset, ticks_per_syt_offset; int syt_interval; int stale_count; @@ -192,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. */ @@ -220,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) { @@ -255,7 +297,7 @@ OHCI1394_CONTEXT_WAKE); } -void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx) +void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx, int synchronous) { u32 control; int wait; @@ -265,13 +307,15 @@ OHCI1394_CONTEXT_RUN); wmb(); - for (wait = 0; wait < 5; wait++) { - control = reg_read(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16); - if ((control & OHCI1394_CONTEXT_ACTIVE) == 0) - break; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + if (synchronous) { + for (wait = 0; wait < 5; wait++) { + control = reg_read(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16); + if ((control & OHCI1394_CONTEXT_ACTIVE) == 0) + break; + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } } } @@ -297,6 +341,27 @@ return pl; } +static void stream_start_dma(struct stream *s, struct packet_list *pl) +{ + u32 syt_cycle, cycle_count, start_cycle; + + cycle_count = reg_read(s->host->host->hostdata, + OHCI1394_IsochronousCycleTimer) >> 12; + syt_cycle = (pl->last_cycle_count - PACKET_LIST_SIZE + 1) & 0x0f; + + /* We program the DMA controller to start transmission at + * least 17 cycles from now - this happens when the lower four + * bits of cycle_count is 0x0f and syt_cycle is 0, in this + * case the start cycle is cycle_count - 15 + 32. */ + start_cycle = (cycle_count & ~0x0f) + 32 + syt_cycle; + if ((start_cycle & 0x1fff) >= 8000) + start_cycle = start_cycle - 8000 + 0x2000; + + ohci1394_start_it_ctx(s->host->ohci, s->iso_tasklet.context, + pl->packets[0].db_bus, 3, + start_cycle & 0x7fff); +} + static void stream_put_dma_packet_list(struct stream *s, struct packet_list *pl) { @@ -315,26 +380,16 @@ 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; - ohci1394_wake_it_ctx(s->host->ohci, s->iso_context); - } - else { - u32 syt, cycle_count; - - cycle_count = reg_read(s->host->host->hostdata, - OHCI1394_IsochronousCycleTimer) >> 12; - syt = (pl->packets[0].payload[1] >> 12) & 0x0f; - cycle_count = (cycle_count & ~0x0f) + 32 + syt; - if ((cycle_count & 0x1fff) >= 8000) - cycle_count = cycle_count - 8000 + 0x2000; - - ohci1394_start_it_ctx(s->host->ohci, s->iso_context, - pl->packets[0].db_bus, 3, - cycle_count & 0x7fff); + last->db->header_desc.skip = pl->packets[0].db_bus | 3; + 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; @@ -430,36 +485,42 @@ f->integer = numerator / denominator; f->numerator = numerator % denominator; f->denominator = denominator; - f->counter = 0; } -static int fraction_next_size(struct fraction *f) +static __inline__ void fraction_add(struct fraction *dst, + struct fraction *src1, + struct fraction *src2) { - return f->integer + ((f->counter + f->numerator) / f->denominator); + /* assert: src1->denominator == src2->denominator */ + + int sum, denom; + + /* We use these two local variables to allow gcc to optimize + * the division and the modulo into only one division. */ + + sum = src1->numerator + src2->numerator; + denom = src1->denominator; + dst->integer = src1->integer + src2->integer + sum / denom; + dst->numerator = sum % denom; + dst->denominator = denom; } -static void fraction_inc(struct fraction *f) +static __inline__ void fraction_sub_int(struct fraction *dst, + struct fraction *src, int integer) { - f->counter = (f->counter + f->numerator) % f->denominator; + dst->integer = src->integer - integer; + dst->numerator = src->numerator; + dst->denominator = src->denominator; } -static void amdtp_irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data) +static __inline__ int fraction_floor(struct fraction *frac) { - 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); + return frac->integer; +} - if (s != NULL) - stream_shift_packet_lists(s); +static __inline__ int fraction_ceil(struct fraction *frac) +{ + return frac->integer + (frac->numerator > 0 ? 1 : 0); } void packet_initialize(struct packet *p, struct packet *next) @@ -473,18 +534,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; @@ -633,17 +695,33 @@ } } +static void fill_payload_le16(struct stream *s, quadlet_t *data, int nevents) +{ + quadlet_t *event, sample, bits; + unsigned char *p; + int i, j; + + for (i = 0, event = data; i < nevents; i++) { + + for (j = 0; j < s->dimension; j++) { + p = buffer_get_bytes(s->input, 2); + sample = (p[1] << 16) | (p[0] << 8); + bits = get_header_bits(s, j, sample); + event[j] = cpu_to_be32((bits << 24) | sample); + } + + event += s->dimension; + if (++s->iec958_frame_count == 192) + s->iec958_frame_count = 0; + } +} static void fill_packet(struct stream *s, struct packet *packet, int nevents) { - int size, node_id, i, j; - quadlet_t *event; - unsigned char *p; - u32 control, sample, bits; - int syt_index, syt, next; + int syt_index, syt, size; + u32 control; size = (nevents * s->dimension + 2) * sizeof(quadlet_t); - node_id = s->host->host->node_id & 0x3f; /* Update DMA descriptors */ packet->db->payload_desc.status = 0; @@ -656,41 +734,45 @@ (s->iso_channel << 8) | (TCODE_ISO_DATA << 4); packet->db->header_desc.header[1] = size << 16; - /* Fill cip header */ - syt_index = s->dbc & (s->syt_interval - 1); - if (syt_index == 0 || syt_index + nevents > s->syt_interval) { + /* Calculate synchronization timestamp (syt). First we + * determine syt_index, that is, the index in the packet of + * the sample for which the timestamp is valid. */ + syt_index = (s->syt_interval - s->dbc) & (s->syt_interval - 1); + if (syt_index < nevents) { syt ... [truncated message content] |
From: SVN U. <ben...@li...> - 2002-09-19 12:08:39
|
Author: bencollins Date: 2002-09-19 17:02:22 -0400 (Thu, 19 Sep 2002) New Revision: 575 Modified: branches/config-rom-gen/ branches/config-rom-gen/Makefile branches/config-rom-gen/amdtp.c branches/config-rom-gen/amdtp.h branches/config-rom-gen/cmp.c branches/config-rom-gen/csr.c branches/config-rom-gen/dv1394-private.h branches/config-rom-gen/dv1394.c branches/config-rom-gen/eth1394.c branches/config-rom-gen/highlevel.c branches/config-rom-gen/hosts.c branches/config-rom-gen/hosts.h branches/config-rom-gen/ieee1394_core.c branches/config-rom-gen/ieee1394_core.h branches/config-rom-gen/nodemgr.c branches/config-rom-gen/ohci1394.c branches/config-rom-gen/ohci1394.h branches/config-rom-gen/pcilynx.c branches/config-rom-gen/pcilynx.h branches/config-rom-gen/raw1394.c branches/config-rom-gen/sbp2.c branches/config-rom-gen/sbp2.h branches/config-rom-gen/video1394.c Log: Merge to current rev Modified: branches/config-rom-gen/ieee1394_core.c ============================================================================== --- branches/config-rom-gen/ieee1394_core.c (original) +++ branches/config-rom-gen/ieee1394_core.c 2002-09-19 17:02:26.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" @@ -142,7 +141,7 @@ int hpsb_reset_bus(struct hpsb_host *host, int type) { if (!host->in_bus_reset) { - host->ops->devctl(host, RESET_BUS, type); + host->driver->devctl(host, RESET_BUS, type); return 0; } else { return 1; @@ -161,7 +160,10 @@ abort_requests(host); host->in_bus_reset = 1; host->irm_id = -1; + host->is_irm = 0; host->busmgr_id = -1; + host->is_busmgr = 0; + host->is_cycmst = 0; host->node_count = 0; host->selfid_count = 0; @@ -355,7 +357,10 @@ } host->reset_retries = 0; - if (isroot) host->ops->devctl(host, ACT_CYCLE_MASTER, 1); + if (isroot) { + host->driver->devctl(host, ACT_CYCLE_MASTER, 1); + host->is_cycmst = 1; + } atomic_inc(&host->generation); host->in_bus_reset = 0; highlevel_host_reset(host); @@ -441,7 +446,7 @@ } #endif - return host->ops->transmit_packet(host, packet); + return host->driver->transmit_packet(host, packet); } static void send_packet_nocare(struct hpsb_packet *packet) @@ -737,7 +742,7 @@ struct list_head *lh; LIST_HEAD(llist); - host->ops->devctl(host, CANCEL_REQUESTS, 0); + host->driver->devctl(host, CANCEL_REQUESTS, 0); spin_lock_irqsave(&host->pending_pkt_lock, flags); list_splice(&host->pending_packets, &llist); @@ -811,8 +816,8 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file); static struct file_operations ieee1394_chardev_ops = { - owner: THIS_MODULE, - open: ieee1394_dispatch_open, + .owner =THIS_MODULE, + .open = ieee1394_dispatch_open, }; devfs_handle_t ieee1394_devfs_handle; @@ -862,19 +867,57 @@ write_unlock(&ieee1394_chardevs_lock); } +/* + ieee1394_get_chardev() - look up and acquire a character device + driver that has previously registered using ieee1394_register_chardev() + + On success, returns 1 and sets module and file_ops to the driver. + The module will have an incremented reference count. + + On failure, returns 0. + The module will NOT have an incremented reference count. +*/ + +static int ieee1394_get_chardev(int blocknum, + struct module **module, + struct file_operations **file_ops) +{ + int ret = 0; + + if( (blocknum < 0) || (blocknum > 15) ) + return ret; + + read_lock(&ieee1394_chardevs_lock); + + *module = ieee1394_chardevs[blocknum].module; + *file_ops = ieee1394_chardevs[blocknum].file_ops; + + if(*file_ops == NULL) + goto out; + + /* don't need try_inc_mod_count if the driver is non-modular */ + if(*module && (try_inc_mod_count(*module) == 0)) + goto out; + + /* success! */ + ret = 1; + +out: + read_unlock(&ieee1394_chardevs_lock); + return ret; +} + /* the point of entry for open() on any ieee1394 character device */ static int ieee1394_dispatch_open(struct inode *inode, struct file *file) { struct file_operations *file_ops; struct module *module; int blocknum; - int retval = -ENODEV; + int retval; /* Maintaining correct module reference counts is tricky here! - For Linux v2.4 and later: - The key thing to remember is that the VFS increments the reference count of ieee1394 before it calls ieee1394_dispatch_open(). @@ -887,16 +930,7 @@ If the open() fails, then the VFS will drop the reference count of whatever module file->f_op->owner points to, immediately after this function returns. - - The comments below refer to the 2.4 case, since the 2.2 - case is trivial. - */ - -#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \ - if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0) -#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \ - if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0) /* shift away lower four bits of the minor to get the index of the ieee1394_driver @@ -904,20 +938,10 @@ blocknum = (minor(inode->i_rdev) >> 4) & 0xF; - /* printk("ieee1394_dispatch_open(%d)", blocknum); */ + /* look up the driver */ - read_lock(&ieee1394_chardevs_lock); - module = ieee1394_chardevs[blocknum].module; - /* bump the reference count of the driver that - will receive the open() */ - INCREF(module); - file_ops = ieee1394_chardevs[blocknum].file_ops; - read_unlock(&ieee1394_chardevs_lock); - - if(file_ops == NULL) { - DECREF(module); - goto out_fail; - } + if(ieee1394_get_chardev(blocknum, &module, &file_ops) == 0) + return -ENODEV; /* redirect all subsequent requests to the driver's own file_operations */ @@ -929,42 +953,42 @@ /* follow through with the open() */ retval = file_ops->open(inode, file); - if(retval) { + if(retval == 0) { - /* if the open() failed, then we need to drop the - extra reference we gave to the task-specific - driver */ + /* If the open() succeeded, then ieee1394 will be left + with an extra module reference, so we discard it here. - DECREF(module); - goto out_fail; + The task-specific driver still has the extra + reference given to it by ieee1394_get_chardev(). + This extra reference prevents the module from + unloading while the file is open, and will be + dropped by the VFS when the file is released. + */ - } else { - - /* if the open() succeeded, then ieee1394 will be left - with an extra module reference, so we discard it here.*/ + if(THIS_MODULE) + __MOD_DEC_USE_COUNT((struct module*) THIS_MODULE); + + /* note that if ieee1394 is compiled into the kernel, + THIS_MODULE will be (void*) NULL, hence the if and + the cast are necessary */ - DECREF(THIS_MODULE); + } else { - /* the task-specific driver still has the extra - reference we gave it. This extra reference prevents - the module from unloading while the file is open, - and will be dropped by the VFS when the file is - released. */ + /* if the open() failed, then we need to drop the + extra reference we gave to the task-specific + driver */ - return 0; - } - -out_fail: - /* point the file's f_ops back to ieee1394. The VFS will then - decrement ieee1394's reference count immediately after this - function returns. */ + if(module) + __MOD_DEC_USE_COUNT(module); - file->f_op = &ieee1394_chardev_ops; - return retval; + /* point the file's f_ops back to ieee1394. The VFS will then + decrement ieee1394's reference count immediately after this + function returns. */ + + file->f_op = &ieee1394_chardev_ops; + } -#undef INCREF -#undef DECREF - + return retval; } struct proc_dir_entry *ieee1394_procfs_entry; @@ -1025,8 +1049,6 @@ module_exit(ieee1394_cleanup); /* Exported symbols */ -EXPORT_SYMBOL(hpsb_register_lowlevel); -EXPORT_SYMBOL(hpsb_unregister_lowlevel); EXPORT_SYMBOL(hpsb_alloc_host); EXPORT_SYMBOL(hpsb_add_host); EXPORT_SYMBOL(hpsb_remove_host); Modified: branches/config-rom-gen/ohci1394.c ============================================================================== --- branches/config-rom-gen/ohci1394.c (original) +++ branches/config-rom-gen/ohci1394.c 2002-09-19 17:02:27.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) { @@ -443,10 +439,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); } @@ -477,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); @@ -571,18 +537,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) */ @@ -629,7 +595,7 @@ ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, pci_resource_start(ohci->dev, 0), - pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE, + pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1, ohci->max_packet_size); } @@ -789,13 +755,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 +767,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; + 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->pending_first == NULL) - d->pending_last = NULL; - else + + if (d->free_prgs == 0) PRINT(KERN_INFO, ohci->id, "Transmit DMA FIFO ctx=%d is full... waiting",d->ctx); @@ -857,25 +819,16 @@ 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; - 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); - /* 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); @@ -929,8 +882,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: @@ -1033,46 +986,62 @@ 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_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, @@ -1143,7 +1112,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) @@ -1154,7 +1123,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) @@ -1165,7 +1134,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) @@ -1175,7 +1144,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) @@ -1185,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) { @@ -1507,25 +1449,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 +1509,7 @@ d->ctx); #endif - nextpacket = packet->xnext; + list_del(&packet->driver_list); hpsb_packet_sent(ohci->host, packet, ack & 0xf); if (datasize) { @@ -1588,90 +1521,64 @@ 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); 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 = (struct ti_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]) { + 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]); + d->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->ohci->dev, sizeof(struct dma_cmd), + 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; + /* Mark this context as freed. */ + d->ohci = NULL; } -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; - } - } - - 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; @@ -1689,8 +1596,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)); @@ -1701,8 +1608,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)); @@ -1711,8 +1618,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++) { @@ -1726,8 +1633,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; } @@ -1741,80 +1648,68 @@ } 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; } } 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 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; + 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]) { + 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->ohci->dev, sizeof(struct at_dma_prg), + 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; + /* Mark this context as freed. */ + d->ohci = NULL; } -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; - } - } - - 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; @@ -1829,8 +1724,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)); @@ -1846,17 +1741,28 @@ } 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; } } 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 d; + return 0; } static u16 ohci_crc16 (u32 *ptr, int length) @@ -2028,15 +1934,14 @@ return reg_read(ohci, OHCI1394_CSRData); } -static struct hpsb_host_operations ohci1394_ops = { - get_rom: ohci_get_rom, - transmit_packet: ohci_transmit, - devctl: ohci_devctl, - hw_csr_reg: ohci_hw_csr_reg, +static struct hpsb_host_driver ohci1394_driver = { + .name = OHCI1394_DRIVER_NAME, + .get_rom = ohci_get_rom, + .transmit_packet = ohci_transmit, + .devctl = ohci_devctl, + .hw_csr_reg = ohci_hw_csr_reg, }; -static struct hpsb_host_driver *ohci1394_driver; - /*********************************** @@ -2059,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); @@ -2069,7 +1973,7 @@ card_id_counter++); pci_set_master(dev); - host = hpsb_alloc_host(ohci1394_driver, sizeof(struct ti_ohci)); + host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci)); if (!host) FAIL(-ENOMEM, "Failed to allocate host structure"); ohci = host->hostdata; @@ -2151,68 +2055,78 @@ 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); + /* Start off with a soft reset, to clear everything to a sane + * state. */ + ohci_soft_reset(ohci); - if (ohci->ir_context == NULL) - FAIL(-ENOMEM, "Failed to allocate IR context"); + /* 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); - - /* IT DMA context allocation */ - ohci->it_context = - alloc_dma_trm_ctx(ohci, DMA_CTX_ISO, 0, IT_NUM_DESC, - OHCI1394_IsoXmitContextBase); + /* 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); - if (ohci->it_context == NULL) - FAIL(-ENOMEM, "Failed to allocate IT context"); + 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); - for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { - ohci->irq_hooks[i].irq_handler = NULL; - ohci->irq_hooks[i].data = NULL; - } + /* IR DMA context */ + 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 */ + 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"); + if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); @@ -2308,12 +2222,12 @@ static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = { { - class: PCI_CLASS_FIREWIRE_OHCI, - class_mask: 0x00ffffff, - vendor: PCI_ANY_ID, - device: PCI_ANY_ID, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, + .class = PCI_CLASS_FIREWIRE_OHCI, + .class_mask = 0x00ffffff, + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { 0, }, }; @@ -2321,10 +2235,10 @@ MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); static struct pci_driver ohci1394_pci_driver = { - name: OHCI1394_DRIVER_NAME, - id_table: ohci1394_pci_tbl, - probe: ohci1394_pci_probe, - remove: ohci1394_pci_remove, + .name = OHCI1394_DRIVER_NAME, + .id_table = ohci1394_pci_tbl, + .probe = ohci1394_pci_probe, + .remove = ohci1394_pci_remove, }; @@ -2355,65 +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; - 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); - } - } + 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; - - /* 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 (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; } - if(i >= OHCI1394_MAX_IRQ_HOOKS) - return -EBUSY; + spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); - ohci->irq_hooks[i].irq_handler = irq_handler; - ohci->irq_hooks[i].data = data; + 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; + } - /* ohci1394 will never be unloaded while an IRQ hook is - in use, because the user must reference this symbol */ + spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); - return 0; + 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; - - 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; - } + unsigned long 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); /*********************************** @@ -2427,27 +2345,11 @@ static void __exit ohci1394_cleanup (void) { pci_unregister_driver(&ohci1394_pci_driver); - hpsb_unregister_lowlevel(ohci1394_driver); } static int __init ohci1394_init(void) { - int ret; - - ohci1394_driver = hpsb_register_lowlevel(&ohci1394_ops, - OHCI1394_DRIVER_NAME); - if (!ohci1394_driver) { - PRINT_G(KERN_ERR, "hpsb_register_lowlevel failed"); - return -ENOMEM; - } - - ret = pci_module_init(&ohci1394_pci_driver); - if (ret < 0) { - PRINT_G(KERN_ERR, "pci_module_init failed"); - hpsb_unregister_lowlevel(ohci1394_driver); - return ret; - } - return ret; + return pci_module_init(&ohci1394_pci_driver); } module_init(ohci1394_init); Modified: branches/config-rom-gen/amdtp.c ============================================================================== --- branches/config-rom-gen/amdtp.c (original) +++ branches/config-rom-gen/amdtp.c 2002-09-19 17:02:27.000000000 -0400 @@ -32,7 +32,7 @@ * That is outside the scope of this driver, and furthermore it is not * really standardized yet. * - * The Audio and Music Data Tranmission Protocol is avaiable at + * The Audio and Music Data Tranmission Protocol is available at * * http://www.1394ta.org/Download/Technology/Specifications/2001/AM20Final-jf2.pdf * @@ -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> @@ -89,9 +88,13 @@ #define FMT_AMDTP 0x10 #define FDF_AM824 0x00 -#define FDF_SFC_32KHZ 0x00 /* 32kHz */ -#define FDF_SFC_44K1HZ 0x01 /* 44.1kHz */ -#define FDF_SFC_48KHZ 0x02 /* 44.1kHz */ +#define FDF_SFC_32KHZ 0x00 +#define FDF_SFC_44K1HZ 0x01 +#define FDF_SFC_48KHZ 0x02 +#define FDF_SFC_88K2HZ 0x03 +#define FDF_SFC_96KHZ 0x04 +#define FDF_SFC_176K4HZ 0x05 +#define FDF_SFC_192KHZ 0x06 struct descriptor_block { struct output_more_immediate { @@ -113,15 +116,70 @@ struct packet { struct descriptor_block *db; dma_addr_t db_bus; - quadlet_t *payload; + struct iso_packet *payload; dma_addr_t payload_bus; }; +#include <asm/byteorder.h> + +#if defined __BIG_ENDIAN_BITFIELD + +struct iso_packet { + /* First quadlet */ + unsigned int dbs : 8; + unsigned int eoh0 : 2; + unsigned int sid : 6; + + unsigned int dbc : 8; + unsigned int fn : 2; + unsigned int qpc : 3; + unsigned int sph : 1; + unsigned int reserved : 2; + + /* Second quadlet */ + unsigned int fdf : 8; + unsigned int eoh1 : 2; + unsigned int fmt : 6; + + unsigned int syt : 16; + + quadlet_t data[0]; +}; + +#elif defined __LITTLE_ENDIAN_BITFIELD + +struct iso_packet { + /* First quadlet */ + unsigned int sid : 6; + unsigned int eoh0 : 2; + unsigned int dbs : 8; + + unsigned int reserved : 2; + unsigned int sph : 1; + unsigned int qpc : 3; + unsigned int fn : 2; + unsigned int dbc : 8; + + /* Second quadlet */ + unsigned int fmt : 6; + unsigned int eoh1 : 2; + unsigned int fdf : 8; + + unsigned int syt : 16; + + quadlet_t data[0]; +}; + +#else + +#error Unknown bitfield type + +#endif + struct fraction { int integer; int numerator; int denominator; - int counter; }; #define PACKET_LIST_SIZE 256 @@ -148,6 +206,8 @@ int rate; int dimension; int fdf; + int mode; + int sample_format; struct cmp_pcr *opcr; /* Input samples are copied here. */ @@ -157,7 +217,7 @@ unsigned char dbc; struct packet_list *current_packet_list; int current_packet; - struct fraction packet_size_fraction; + struct fraction ready_samples, samples_per_cycle; /* We use these to generate control bits when we are packing * iec958 data. @@ -176,8 +236,7 @@ * written back in the dma programs. */ atomic_t cycle_count, cycle_count2; - int cycle_offset; - struct fraction syt_fraction; + struct fraction cycle_offset, ticks_per_syt_offset; int syt_interval; int stale_count; @@ -192,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. */ @@ -220,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) { @@ -255,7 +297,7 @@ OHCI1394_CONTEXT_WAKE); } -void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx) +void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx, int synchronous) { u32 control; int wait; @@ -265,13 +307,15 @@ OHCI1394_CONTEXT_RUN); wmb(); - for (wait = 0; wait < 5; wait++) { - control = reg_read(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16); - if ((control & OHCI1394_CONTEXT_ACTIVE) == 0) - break; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + if (synchronous) { + for (wait = 0; wait < 5; wait++) { + control = reg_read(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16); + if ((control & OHCI1394_CONTEXT_ACTIVE) == 0) + break; + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } } } @@ -297,6 +341,27 @@ return pl; } +static void stream_start_dma(struct stream *s, struct packet_list *pl) +{ + u32 syt_cycle, cycle_count, start_cycle; + + cycle_count = reg_read(s->host->host->hostdata, + OHCI1394_IsochronousCycleTimer) >> 12; + syt_cycle = (pl->last_cycle_count - PACKET_LIST_SIZE + 1) & 0x0f; + + /* We program the DMA controller to start transmission at + * least 17 cycles from now - this happens when the lower four + * bits of cycle_count is 0x0f and syt_cycle is 0, in this + * case the start cycle is cycle_count - 15 + 32. */ + start_cycle = (cycle_count & ~0x0f) + 32 + syt_cycle; + if ((start_cycle & 0x1fff) >= 8000) + start_cycle = start_cycle - 8000 + 0x2000; + + ohci1394_start_it_ctx(s->host->ohci, s->iso_tasklet.context, + pl->packets[0].db_bus, 3, + start_cycle & 0x7fff); +} + static void stream_put_dma_packet_list(struct stream *s, struct packet_list *pl) { @@ -315,26 +380,16 @@ 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; - ohci1394_wake_it_ctx(s->host->ohci, s->iso_context); - } - else { - u32 syt, cycle_count; - - cycle_count = reg_read(s->host->host->hostdata, - OHCI1394_IsochronousCycleTimer) >> 12; - syt = (pl->packets[0].payload[1] >> 12) & 0x0f; - cycle_count = (cycle_count & ~0x0f) + 32 + syt; - if ((cycle_count & 0x1fff) >= 8000) - cycle_count = cycle_count - 8000 + 0x2000; - - ohci1394_start_it_ctx(s->host->ohci, s->iso_context, - pl->packets[0].db_bus, 3, - cycle_count & 0x7fff); + last->db->header_desc.skip = pl->packets[0].db_bus | 3; + 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; @@ -430,36 +485,42 @@ f->integer = numerator / denominator; f->numerator = numerator % denominator; f->denominator = denominator; - f->counter = 0; } -static int fraction_next_size(struct fraction *f) +static __inline__ void fraction_add(struct fraction *dst, + struct fraction *src1, + struct fraction *src2) { - return f->integer + ((f->counter + f->numerator) / f->denominator); + /* assert: src1->denominator == src2->denominator */ + + int sum, denom; + + /* We use these two local variables to allow gcc to optimize + * the division and the modulo into only one division. */ + + sum = src1->numerator + src2->numerator; + denom = src1->denominator; + dst->integer = src1->integer + src2->integer + sum / denom; + dst->numerator = sum % denom; + dst->denominator = denom; } -static void fraction_inc(struct fraction *f) +static __inline__ void fraction_sub_int(struct fraction *dst, + struct fraction *src, int integer) { - f->counter = (f->counter + f->numerator) % f->denominator; + dst->integer = src->integer - integer; + dst->numerator = src->numerator; + dst->denominator = src->denominator; } -static void amdtp_irq_handler(int card, quadlet_t isoRecvIntEvent, - quadlet_t isoXmitIntEvent, void *data) +static __inline__ int fraction_floor(struct fraction *frac) { - 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); + return frac->integer; +} - if (s != NULL) - stream_shift_packet_lists(s); +static __inline__ int fraction_ceil(struct fraction *frac) +{ + return frac->integer + (frac->numerator > 0 ? 1 : 0); } void packet_initialize(struct packet *p, struct packet *next) @@ -473,18 +534,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; @@ -633,17 +695,33 @@ } } +static void fill_payload_le16(struct stream *s, quadlet_t *data, int nevents) +{ + quadlet_t *event, sample, bits; + unsigned char *p; + int i, j; + + for (i = 0, event = data; i < nevents; i++) { + + for (j = 0; j < s->dimension; j++) { + p = buffer_get_bytes(s->input, 2); + sample = (p[1] << 16) | (p[0] << 8); + bits = get_header_bits(s, j, sample); + event[j] = cpu_to_be32((bits << 24) | sample); + } + + event += s->dimension; + if (++s->iec958_frame_count == 192) + s->iec958_frame_count = 0; + } +} static void fill_packet(struct stream *s, struct packet *packet, int nevents) { - int size, node_id, i, j; - quadlet_t *event; - unsigned char *p; - u32 control, sample, bits; - int syt_index, syt, next; + int syt_index, syt, size; + u32 control; size = (nevents * s->dimension + 2) * sizeof(quadlet_t); - node_id = s->host->host->node_id & 0x3f; /* Update DMA descriptors */ packet->db->payload_desc.status = 0; @@ -656,41 +734,45 @@ (s->iso_channel << 8) | (TCODE_ISO_DATA << 4); packet->db->header_desc.header[1] = size << 16; - /* Fill cip header */ - syt_index = s->dbc & (s->syt_interval - 1); - if (syt_index == 0 || syt_index + nevents > s->syt_interval) { + /* Calculate synchronization timestamp (syt). First we + * determine syt_index, that is, the index in the packet of + * the sample for which the timestamp is valid. */ + syt_index = (s->syt_interval - s->dbc) & (s->syt_interval - 1); + if (syt_index < nevents) { syt = ((atomic_read(&s->cycle_count) << 12) | - s->cycle_offset) & 0xffff; - next = fraction_next_size(&s->syt_fraction) + s->cycle_offset; + s->cycle_offset.integer) & 0xffff; + fraction_add(&s->cycle_offset, + &s->cycle_offset, &s->ticks_per_syt_offset); + /* This next addition should be modulo 8000 (0x1f40), * but we only use the lower 4 bits of cycle_count, so * we dont need the modulo. */ - atomic_add(next / 3072, &s->cycle_count); - s->cycle_offset = next % 3072; - fraction_inc(&s->syt_fraction); + atomic_add(s->cycle_offset.integer / 3072, &s->cycle_count); + s->cycle_offset.integer %= 3072; } - else { + else syt = 0xffff; - next = 0; - } - atomic_inc(&s->cycle_count2); - packet->payload[0] = cpu_to_be32((node_id << 24) | (s->dimension << 16) | s->dbc); - packet->payload[1] = cpu_to_be32((1 << 31) | (FMT_AMDTP << 24) | (s->fdf << 16) | syt); - - /* Fill payload */ - for (i = 0, event = &packet->payload[2]; i < nevents; i++) { - - for (j = 0; j < s->dimension; j++) { - p = buffer_get_bytes(s->input, 2); - sample = (p[1] << 16) | (p[0] << 8); - bits = get_header_bits(s, j, sample); - event[j] = cpu_to_be32((bits << 24) | sample); - } - - event += s->dimension; - if (++s->iec958_frame_count == 192) - s->iec958_frame_count = 0; + atomic_inc(&s->cycle_count2); + + /* Fill cip header */ + packet->payload->eoh0 = 0; + packet->payload->sid = s->host->host->node_id & 0x3f; + packet->payload->dbs = s->dimension; + packet->payload->fn = 0; + packet->payload->qpc = 0; + packet->payload->sph = 0; + packet->payload->reserved = 0; + packet->payload->dbc = s->dbc; + packet->payload->eoh1 = 2; + packet->payload->fmt = FMT_AMDTP; + packet->payload->fdf = s->fdf; + packet->payload->syt = cpu_to_be16(syt); + + switch (s->sample_format) { + case AMDTP_INPUT_LE16: + fill_payload_le16(s, packet->payload->data, nevents); + break; } s->dbc += nevents; @@ -700,13 +782,44 @@ { struct packet *p; int nevents; + struct fraction next; + + /* The AMDTP specifies two transmission modes: blocking and + * non-blocking. In blocking mode you always transfer + * syt_interval or zero samples, whereas in non-blocking mode + * you send as many samples as you have available at transfer + * time. + * + * The fraction samples_per_cycle specifies the number of + * samples that become available per cycle. We add this to + * the fraction ready_samples, which specifies the number of + * leftover samples from the previous transmission. The sum, + * stored in the fraction next, specifies the number of + * samples available for transmission, and from this we + * determine the number of samples to actually transmit. + */ + + while (1) { + fraction_add(&next, &s->ready_samples, &s->samples_per_cycle); + if (s->mode == AMDTP_MODE_BLOCKING) { + if (fraction_floor(&next) >= s->syt_interval) + nevents = s->syt_interval; + else + nevents = 0; + } + else + nevents = fraction_floor(&next); + + p = stream_current_packet(s); + if (s->input->length < nevents * s->dimension * 2 || p == NULL) + break; - while (nevents = fraction_next_size(&s->packet_size_fraction), - p = stream_current_packet(s), - nevents * s->dimension * 2 <= s->input->length && p != NULL) { fill_packet(s, p, nevents); - fraction_inc(&s->packet_size_fraction); stream_queue_packet(s); + + /* Now that we have successfully queued the packet for + * transmission, we update the fraction ready_samples. */ + fraction_sub_int(&s->ready_samples, &next, nevents); } } @@ -714,9 +827,10 @@ { int max_nevents, max_packet_size, i; - max_nevents = s->packet_size_fraction.integer; - if (s->packet_size_fraction.numerator > 0) - max_nevents++; + if (s->mode == AMDTP_MODE_BLOCKING) + max_nevents = s->syt_interval; + else + max_nevents = fraction_ceil(&s->samples_per_cycle); max_packet_size = max_nevents * s->dimension * 4 + 8; s->packet_pool = pci_pool_create("packet pool", s->host->ohci->dev, @@ -763,15 +877,20 @@ plug->p2p_count, plug->channel); s->iso_channel = plug->channel; if (plug->p2p_count > 0) { - /* start streaming */ + struct packet_list *pl; + + pl = list_entry(s->dma_packet_lists.next, struct packet_list, link); + stream_start_dma(s, pl); } else { - /* stop streaming */ + ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 0); } } static int stream_configure(struct stream *s, int cmd, struct amdtp_ioctl *cfg) { + const int transfer_delay = 9000; + if (cfg->format <= AMDTP_FORMAT_IEC958_AC3) s->format = cfg->format; else @@ -782,32 +901,59 @@ s->syt_interval = 8; s->fdf = FDF_SFC_32KHZ; s->iec958_rate_code = 0x0c; - s->rate = cfg->rate; break; case 44100: s->syt_interval = 8; s->fdf = FDF_SFC_44K1HZ; s->iec958_rate_code = 0x00; - s->rate = cfg->rate; break; case 48000: s->syt_interval = 8; s->fdf = FDF_SFC_48KHZ; s->iec958_rate_code = 0x04; - s->rate = cfg->rate; break; + case 88200: + s->syt_interval = 16; + s->fdf = FDF_SFC_88K2HZ; + s->iec958_rate_code = 0x00; + break; + case 96000: + s->syt_interval = 16; + s->fdf = FDF_SFC_96KHZ; + s->iec958_rate_code = 0x00; + break; + case 176400: + s->syt_interval = 32; + s->fdf = FDF_SFC_176K4HZ; + s->iec958_rate_code = 0x00; + break; + case 192000: + s->syt_interval = 32; + s->fdf = FDF_SFC_192KHZ; + s->iec958_rate_code = 0x00; + break; + default: return -EINVAL; } - fraction_init(&s->packet_size_fraction, s->rate, 8000); + s->rate = cfg->rate; + fraction_init(&s->samples_per_cycle, s->rate, 8000); + fraction_init(&s->ready_samples, 0, 8000); - /* The syt_fraction is initialized to the number of ticks - * between syt_interval events. The number of ticks per + /* The ticks_per_syt_offset is initialized to the number of + * ticks between syt_interval events. The number of ticks per * second is 24.576e6, so the number of ticks between * syt_interval events is 24.576e6 * syt_interval / rate. */ - fraction_init(&s->syt_fraction, 24576000 * s->syt_interval, s->rate); + fraction_init(&s->ticks_per_syt_offset, + 24576000 * s->syt_interval, s->rate); + fraction_init(&s->cycle_offset, (transfer_delay % 3072) * s->rate, s->rate); + atomic_set(&s->cycle_count, transfer_delay / 3072); + atomic_set(&s->cycle_count2, 0); + + s->mode = cfg->mode; + s->sample_format = AMDTP_INPUT_LE16; /* When using the AM824 raw subformat we can stream signals of * any dimension. The IEC958 subformat, however, only @@ -858,7 +1004,6 @@ { struct stream *s; unsigned long flags; - const int transfer_delay = 8651; /* approx 352 us */ s = kmalloc(sizeof(struct stream), SLAB_KERNEL); if (s == NULL) @@ -873,10 +1018,6 @@ return NULL; } - s->cycle_offset = transfer_delay % 3072; - atomic_set(&s->cycle_count, transfer_delay / 3072); - atomic_set(&s->cycle_count2, 0); - s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev, sizeof(struct descriptor_block), 16, 0, SLAB_KERNEL); @@ -892,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); @@ -920,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); - 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); @@ -969,8 +1113,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; } @@ -983,7 +1132,6 @@ { struct stream *s = file->private_data; struct amdtp_ioctl cfg; - int new; switch(cmd) { @@ -994,23 +1142,23 @@ else return stream_configure(s, cmd, &cfg); - case AMDTP_IOC_PING: - HPSB_INFO("ping: offsetting timpestamps %ld ticks", arg); - new = s->cycle_offset + arg; - s->cycle_offset = 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_... [truncated message content] |
From: SVN U. <ben...@li...> - 2002-09-19 12:02:45
|
Author: bencollins Date: 2002-09-19 16:56:25 -0400 (Thu, 19 Sep 2002) New Revision: 574 Added: tags/v2.5/2.5.36/ Removed: tags/v2.5/2.5.34/ Log: Record actual merge point Copied: 2.5.36 (from rev 572, tags/v2.5/2.5.34) |
From: SVN U. <ben...@li...> - 2002-09-18 14:08:48
|
Author: bencollins Date: 2002-09-18 19:02:50 -0400 (Wed, 18 Sep 2002) New Revision: 573 Modified: trunk/ohci1394.c Log: Trivial fix for math to show the MMIO range being used Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2002-09-18 19:02:50.000000000 -0400 @@ -595,7 +595,7 @@ ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, pci_resource_start(ohci->dev, 0), - pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE, + pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1, ohci->max_packet_size); } |
From: SVN U. <hog...@li...> - 2002-09-17 09:14:00
|
Author: hogsberg Date: 2002-09-17 14:08:09 -0400 (Tue, 17 Sep 2002) New Revision: 572 Modified: trunk/ieee1394_core.c Log: Update is_cycmst, is_irm and is_busmgr flags correctly. Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2002-09-17 14:08:09.000000000 -0400 @@ -160,7 +160,10 @@ abort_requests(host); host->in_bus_reset = 1; host->irm_id = -1; + host->is_irm = 0; host->busmgr_id = -1; + host->is_busmgr = 0; + host->is_cycmst = 0; host->node_count = 0; host->selfid_count = 0; @@ -354,7 +357,10 @@ } host->reset_retries = 0; - if (isroot) host->driver->devctl(host, ACT_CYCLE_MASTER, 1); + if (isroot) { + host->driver->devctl(host, ACT_CYCLE_MASTER, 1); + host->is_cycmst = 1; + } atomic_inc(&host->generation); host->in_bus_reset = 0; highlevel_host_reset(host); |
From: SVN U. <ben...@li...> - 2002-09-13 04:23:31
|
Author: bencollins Date: 2002-09-13 07:11:58 -0400 (Fri, 13 Sep 2002) New Revision: 570 Modified: trunk/pcilynx.c Log: Merge in change to check for wrap Modified: trunk/pcilynx.c ============================================================================== --- trunk/pcilynx.c (original) +++ trunk/pcilynx.c 2002-09-13 07:11:59.000000000 -0400 @@ -891,6 +891,12 @@ ssize_t retval; void *membase; + if (*offset != off) /* Check for EOF before we trust wrap */ + return 0; + + if (off + count > off) + return 0; + if ((off + count) > PCILYNX_MAX_MEMORY + 1) { count = PCILYNX_MAX_MEMORY + 1 - off; } |
From: SVN U. <ben...@li...> - 2002-09-13 04:11:19
|
Author: bencollins Date: 2002-09-13 08:28:24 -0400 (Fri, 13 Sep 2002) New Revision: 571 Added: tags/v2.4/2.4.20-pre6/ tags/v2.5/2.5.34/ Log: Update tags for new sync to Marcelo and Linus Copied: 2.4.20-pre6 (from rev 570, trunk) Copied: 2.5.34 (from rev 570, trunk) |
From: SVN U. <hog...@li...> - 2002-09-12 19:38:58
|
Author: hogsberg Date: 2002-09-13 00:27:13 -0400 (Fri, 13 Sep 2002) New Revision: 569 Modified: trunk/video1394.c Log: Add overflow checks from Alan Cox Modified: trunk/video1394.c ============================================================================== --- trunk/video1394.c (original) +++ trunk/video1394.c 2002-09-13 00:27:13.000000000 -0400 @@ -853,13 +853,13 @@ } ohci->ISO_channel_usage |= mask; - if (v.buf_size<=0) { + if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) { PRINT(KERN_ERR, ohci->id, "Invalid %d length buffer requested",v.buf_size); return -EFAULT; } - if (v.nb_buffers<=0) { + if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) { PRINT(KERN_ERR, ohci->id, "Invalid %d buffers requested",v.nb_buffers); return -EFAULT; |