diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
commit | 012bb3e61e5eced6c610f9e036372bf0c8def2d1 (patch) | |
tree | 87efc733f9b164e8c85c0336f92c8fb7eff6d183 /drivers/ieee1394 | |
parent | 625a1589d3d6464b5d90b8a0918789e3afffd220 (diff) |
Merge with Linux 2.4.0-test9. Please check DECstation, I had a number
of rejects to fixup while integrating Linus patches. I also found
that this kernel will only boot SMP on Origin; the UP kernel freeze
soon after bootup with SCSI timeout messages. I commit this anyway
since I found that the last CVS versions had the same problem.
Diffstat (limited to 'drivers/ieee1394')
-rw-r--r-- | drivers/ieee1394/hosts.c | 14 | ||||
-rw-r--r-- | drivers/ieee1394/hosts.h | 4 | ||||
-rw-r--r-- | drivers/ieee1394/ieee1394_core.c | 46 | ||||
-rw-r--r-- | drivers/ieee1394/ieee1394_core.h | 9 | ||||
-rw-r--r-- | drivers/ieee1394/ieee1394_syms.c | 12 | ||||
-rw-r--r-- | drivers/ieee1394/ieee1394_transactions.c | 57 | ||||
-rw-r--r-- | drivers/ieee1394/ieee1394_types.h | 4 | ||||
-rw-r--r-- | drivers/ieee1394/ohci1394.c | 222 | ||||
-rw-r--r-- | drivers/ieee1394/ohci1394.h | 19 | ||||
-rw-r--r-- | drivers/ieee1394/pcilynx.c | 304 | ||||
-rw-r--r-- | drivers/ieee1394/pcilynx.h | 15 | ||||
-rw-r--r-- | drivers/ieee1394/raw1394.c | 103 | ||||
-rw-r--r-- | drivers/ieee1394/raw1394.h | 5 | ||||
-rw-r--r-- | drivers/ieee1394/video1394.c | 66 | ||||
-rw-r--r-- | drivers/ieee1394/video1394.h | 2 |
15 files changed, 568 insertions, 314 deletions
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c index 8e0e80da1..a7b4e0360 100644 --- a/drivers/ieee1394/hosts.c +++ b/drivers/ieee1394/hosts.c @@ -61,8 +61,9 @@ int hpsb_inc_host_usage(struct hpsb_host *host) struct hpsb_host_template *tmpl; struct hpsb_host *h; int retval = 0; + unsigned long flags; - spin_lock(&templates_lock); + spin_lock_irqsave(&templates_lock, flags); for (tmpl = templates; (tmpl != NULL) && !retval; tmpl = tmpl->next) { for (h = tmpl->hosts; h != NULL; h = h->next) { @@ -74,7 +75,7 @@ int hpsb_inc_host_usage(struct hpsb_host *host) } } - spin_unlock(&templates_lock); + spin_unlock_irqrestore(&templates_lock, flags); return retval; } @@ -99,11 +100,11 @@ struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, } memset(h, 0, sizeof(struct hpsb_host) + hd_size); - h->tlabel_count = 64; INIT_LIST_HEAD(&h->pending_packets); spin_lock_init(&h->pending_pkt_lock); + + sema_init(&h->tlabel_count, 64); spin_lock_init(&h->tlabel_lock); - init_waitqueue_head(&h->tlabel_wait); h->timeout_tq.routine = (void (*)(void*))abort_timedouts; h->timeout_tq.data = h; @@ -154,10 +155,7 @@ static void init_hosts(struct hpsb_host_template *tmpl) host->initialized = 1; highlevel_add_host(host); - reset_host_bus(host); - - //kernel_thread(hpsb_host_thread, host, - // CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + hpsb_reset_bus(host); } } diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h index 3465f27d7..827a47416 100644 --- a/drivers/ieee1394/hosts.h +++ b/drivers/ieee1394/hosts.h @@ -4,6 +4,7 @@ #include <linux/wait.h> #include <linux/tqueue.h> +#include <asm/semaphore.h> #include "ieee1394_types.h" #include "csr.h" @@ -22,9 +23,8 @@ struct hpsb_host { /* A bitmask where a set bit means that this tlabel is in use. * FIXME - should be handled per node instead of per bus. */ u32 tlabel_pool[2]; - int tlabel_count; + struct semaphore tlabel_count; spinlock_t tlabel_lock; - wait_queue_head_t tlabel_wait; int reset_retries; quadlet_t *topology_map; diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index e0641271b..d186fc755 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -127,30 +127,37 @@ void free_hpsb_packet(struct hpsb_packet *packet) } -void reset_host_bus(struct hpsb_host *host) +int hpsb_reset_bus(struct hpsb_host *host) { if (!host->initialized) { - return; + return 1; } - hpsb_bus_reset(host); - host->template->devctl(host, RESET_BUS, 0); + if (!hpsb_bus_reset(host)) { + host->template->devctl(host, RESET_BUS, 0); + return 0; + } else { + return 1; + } } -void hpsb_bus_reset(struct hpsb_host *host) +int hpsb_bus_reset(struct hpsb_host *host) { - if (!host->in_bus_reset) { - abort_requests(host); - host->in_bus_reset = 1; - host->irm_id = -1; - host->busmgr_id = -1; - host->node_count = 0; - host->selfid_count = 0; - } else { + if (host->in_bus_reset) { HPSB_NOTICE(__FUNCTION__ " called while bus reset already in progress"); + return 1; } + + abort_requests(host); + host->in_bus_reset = 1; + host->irm_id = -1; + host->busmgr_id = -1; + host->node_count = 0; + host->selfid_count = 0; + + return 0; } @@ -311,7 +318,7 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) if (host->reset_retries++ < 20) { /* selfid stage did not complete without error */ HPSB_NOTICE("error in SelfID stage - resetting"); - reset_host_bus(host); + hpsb_reset_bus(host); return; } else { HPSB_NOTICE("stopping out-of-control reset loop"); @@ -332,6 +339,7 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) host->reset_retries = 0; inc_hpsb_generation(); + if (isroot) host->template->devctl(host, ACT_CYCLE_MASTER, 1); highlevel_host_reset(host); } @@ -374,7 +382,7 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, * * The packet is sent through the host specified in the packet->host field. * Before sending, the packet's transmit speed is automatically determined using - * the local speed map. + * the local speed map when it is an async, non-broadcast packet. * * Possibilities for failure are that host is either not initialized, in bus * reset, the packet's generation number doesn't match the current generation @@ -392,8 +400,12 @@ int hpsb_send_packet(struct hpsb_packet *packet) } packet->state = queued; - packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64 - + (packet->node_id & NODE_MASK)]; + + if (packet->type == async && packet->node_id != ALL_NODES) { + packet->speed_code = + host->speed_map[(host->node_id & NODE_MASK) * 64 + + (packet->node_id & NODE_MASK)]; + } #ifdef CONFIG_IEEE1394_VERBOSEDEBUG switch (packet->speed_code) { diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index faeeca45d..d2505b9cb 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -73,7 +73,6 @@ struct hpsb_packet { }; -void reset_host_bus(struct hpsb_host *host); void abort_timedouts(struct hpsb_host *host); void abort_requests(struct hpsb_host *host); @@ -106,6 +105,9 @@ inline static void inc_hpsb_generation(void) */ int hpsb_send_packet(struct hpsb_packet *packet); +/* Initiate bus reset on the given host. Returns 1 if bus reset already in + * progress, 0 otherwise. */ +int hpsb_reset_bus(struct hpsb_host *host); /* * The following functions are exported for host driver module usage. All of @@ -114,8 +116,9 @@ int hpsb_send_packet(struct hpsb_packet *packet); * them directly. */ -/* Notify a bus reset to the core. */ -void hpsb_bus_reset(struct hpsb_host *host); +/* Notify a bus reset to the core. Returns 1 if bus reset already in progress, + * 0 otherwise. */ +int hpsb_bus_reset(struct hpsb_host *host); /* * Hand over received selfid packet to the core. Complement check (second diff --git a/drivers/ieee1394/ieee1394_syms.c b/drivers/ieee1394/ieee1394_syms.c index 39a61a01b..1b4721444 100644 --- a/drivers/ieee1394/ieee1394_syms.c +++ b/drivers/ieee1394/ieee1394_syms.c @@ -17,7 +17,6 @@ #include "hosts.h" #include "ieee1394_core.h" #include "ieee1394_transactions.h" -/* #include "events.h" */ #include "highlevel.h" #include "guid.h" @@ -30,6 +29,7 @@ EXPORT_SYMBOL(hpsb_dec_host_usage); EXPORT_SYMBOL(alloc_hpsb_packet); EXPORT_SYMBOL(free_hpsb_packet); EXPORT_SYMBOL(hpsb_send_packet); +EXPORT_SYMBOL(hpsb_reset_bus); EXPORT_SYMBOL(hpsb_bus_reset); EXPORT_SYMBOL(hpsb_selfid_received); EXPORT_SYMBOL(hpsb_selfid_complete); @@ -39,6 +39,16 @@ EXPORT_SYMBOL(hpsb_generation); EXPORT_SYMBOL(get_tlabel); EXPORT_SYMBOL(free_tlabel); +EXPORT_SYMBOL(fill_async_readquad); +EXPORT_SYMBOL(fill_async_readquad_resp); +EXPORT_SYMBOL(fill_async_readblock); +EXPORT_SYMBOL(fill_async_readblock_resp); +EXPORT_SYMBOL(fill_async_writequad); +EXPORT_SYMBOL(fill_async_writeblock); +EXPORT_SYMBOL(fill_async_write_resp); +EXPORT_SYMBOL(fill_async_lock); +EXPORT_SYMBOL(fill_async_lock_resp); +EXPORT_SYMBOL(fill_iso_packet); EXPORT_SYMBOL(hpsb_make_readqpacket); EXPORT_SYMBOL(hpsb_make_readbpacket); EXPORT_SYMBOL(hpsb_make_writeqpacket); diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c index 179834ac7..a87058b61 100644 --- a/drivers/ieee1394/ieee1394_transactions.c +++ b/drivers/ieee1394/ieee1394_transactions.c @@ -155,56 +155,29 @@ void fill_iso_packet(struct hpsb_packet *packet, int length, int channel, * Return value: The allocated transaction label or -1 if there was no free * tlabel and @wait is false. */ -static int __get_tlabel(struct hpsb_host *host, nodeid_t nodeid) +int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait) { int tlabel; + unsigned long flags; - if (host->tlabel_count) { - host->tlabel_count--; - - if (host->tlabel_pool[0] != ~0) { - tlabel = ffz(host->tlabel_pool[0]); - host->tlabel_pool[0] |= 1 << tlabel; - } else { - tlabel = ffz(host->tlabel_pool[1]); - host->tlabel_pool[1] |= 1 << tlabel; - tlabel += 32; - } - return tlabel; + if (wait) { + down(&host->tlabel_count); + } else { + if (down_trylock(&host->tlabel_count)) return -1; } - return -1; -} - -int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait) -{ - unsigned long flags; - int tlabel; - wait_queue_t wq; spin_lock_irqsave(&host->tlabel_lock, flags); - tlabel = __get_tlabel(host, nodeid); - if (tlabel != -1 || !wait) { - spin_unlock_irqrestore(&host->tlabel_lock, flags); - return tlabel; - } - - init_waitqueue_entry(&wq, current); - add_wait_queue(&host->tlabel_wait, &wq); - - for (;;) { - set_current_state(TASK_UNINTERRUPTIBLE); - tlabel = __get_tlabel(host, nodeid); - if (tlabel != -1) break; - - spin_unlock_irqrestore(&host->tlabel_lock, flags); - schedule(); - spin_lock_irqsave(&host->tlabel_lock, flags); + if (host->tlabel_pool[0] != ~0) { + tlabel = ffz(host->tlabel_pool[0]); + host->tlabel_pool[0] |= 1 << tlabel; + } else { + tlabel = ffz(host->tlabel_pool[1]); + host->tlabel_pool[1] |= 1 << tlabel; + tlabel += 32; } spin_unlock_irqrestore(&host->tlabel_lock, flags); - set_current_state(TASK_RUNNING); - remove_wait_queue(&host->tlabel_wait, &wq); return tlabel; } @@ -233,11 +206,9 @@ void free_tlabel(struct hpsb_host *host, nodeid_t nodeid, int tlabel) host->tlabel_pool[1] &= ~(1 << (tlabel-32)); } - host->tlabel_count++; - spin_unlock_irqrestore(&host->tlabel_lock, flags); - wake_up(&host->tlabel_wait); + up(&host->tlabel_count); } diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h index 84be6aa05..8175fa8f9 100644 --- a/drivers/ieee1394/ieee1394_types.h +++ b/drivers/ieee1394/ieee1394_types.h @@ -53,7 +53,7 @@ extern __inline__ int get_order(unsigned long size) return order; } - +#include <linux/mm.h> #include <linux/pci.h> inline static int pci_enable_device(struct pci_dev *dev) { @@ -114,7 +114,7 @@ extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, BUG(); } -struct scatterlist {}; +#include <asm/scatterlist.h> extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 05e1063d7..6dc42555d 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -56,6 +56,8 @@ * . Apple PowerBook detection * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de> * . Reset the board properly before leaving + misc cleanups + * Leon van Stuivenberg <leonvs@iae.nl> + * . Bug fixes */ #include <linux/config.h> @@ -253,7 +255,7 @@ inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host, return -1; } - size = ((self_id_count&0x0000EFFC)>>2) - 1; + size = ((self_id_count&0x00001FFC)>>2) - 1; q++; while (size > 0) { @@ -652,6 +654,15 @@ static void insert_packet(struct ti_ohci *ohci, * FIXME: check that the packet data buffer * do not cross a page boundary */ + if (cross_bound((unsigned long)packet->data, + packet->data_size)>0) { + /* FIXME: do something about it */ + PRINT(KERN_ERR, ohci->id, __FUNCTION__ + ": packet data addr: %p size %d bytes " + "cross page boundary", + packet->data, packet->data_size); + } + d->prg_cpu[idx]->end.address = pci_map_single(ohci->dev, packet->data, packet->data_size, PCI_DMA_TODEVICE); @@ -734,7 +745,7 @@ static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet) unsigned char tcode; unsigned long flags; - if (packet->data_size >= ohci->max_packet_size) { + if (packet->data_size > ohci->max_packet_size) { PRINT(KERN_ERR, ohci->id, "transmit packet size = %d too big", packet->data_size); @@ -803,11 +814,11 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) u32 nodeId = reg_read(ohci, OHCI1394_NodeID); if ((nodeId & (1<<30)) && (nodeId & 0x3f)) { /* - * enable cycleTimer cycleMaster cycleSource + * enable cycleTimer, cycleMaster */ DBGMSG(ohci->id, "Cycle master enabled"); reg_write(ohci, OHCI1394_LinkControlSet, - 0x00700000); + 0x00300000); } } else { /* disable cycleTimer, cycleMaster, cycleSource */ @@ -830,61 +841,67 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) break; case ISO_LISTEN_CHANNEL: + { + int *isochannels, offset= OHCI1394_IRMultiChanMaskLoSet; + unsigned int channel= (unsigned int)arg; + unsigned int channelbit= channel; + u32 setMask= 0x00000001; + + /* save people from themselves */ + if (channel > 63) + break; + + if (channel > 31) { + isochannels= &(((int*)&ohci->IR_channel_usage)[0]); + channelbit-= 32; + offset= OHCI1394_IRMultiChanMaskHiSet; + } + else + isochannels= &(((int*)&ohci->IR_channel_usage)[1]); - spin_lock_irqsave(&ohci->IR_channel_lock, flags); + while(channelbit--) setMask= setMask << 1; - if (!test_and_set_bit(arg, &ohci->IR_channel_usage)) { - DBGMSG(ohci->id, - "listening enabled on channel %d", arg); - - if (arg > 31) { - u32 setMask= 0x00000001; - arg-= 32; - while(arg--) setMask= setMask << 1; - reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, - setMask); - } else { - u32 setMask= 0x00000001; - while(arg--) setMask= setMask << 1; - reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, - setMask); - } + spin_lock_irqsave(&ohci->IR_channel_lock, flags); - } + if (!test_and_set_bit(channelbit, isochannels)) + reg_write(ohci, offset, setMask); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + DBGMSG(ohci->id, "listening enabled on channel %u", channel); break; - + } case ISO_UNLISTEN_CHANNEL: + { + int *isochannels, offset= OHCI1394_IRMultiChanMaskLoClear; + unsigned int channel= (unsigned int)arg; + unsigned int channelbit= channel; + u32 clearMask= 0x00000001; + + /* save people from themselves */ + if (channel > 63) + break; + + if (channel > 31) { + isochannels= &(((int*)&ohci->IR_channel_usage)[0]); + channelbit-= 32; + offset= OHCI1394_IRMultiChanMaskHiClear; + } + else + isochannels= &(((int*)&ohci->IR_channel_usage)[1]); - spin_lock_irqsave(&ohci->IR_channel_lock, flags); + while(channelbit--) clearMask= clearMask << 1; - if (test_and_clear_bit(arg, &ohci->IR_channel_usage)) { - DBGMSG(ohci->id, - "listening disabled on iso channel %d", arg); - - if (arg > 31) { - u32 clearMask= 0x00000001; - arg-= 32; - while(arg--) clearMask= clearMask << 1; - reg_write(ohci, - OHCI1394_IRMultiChanMaskHiClear, - clearMask); - } else { - u32 clearMask= 0x00000001; - while(arg--) clearMask= clearMask << 1; - reg_write(ohci, - OHCI1394_IRMultiChanMaskLoClear, - clearMask); - } + spin_lock_irqsave(&ohci->IR_channel_lock, flags); - } + if (!test_and_clear_bit(channelbit, isochannels)) + reg_write(ohci, offset, clearMask); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + DBGMSG(ohci->id, "listening disabled on channel %u", channel); break; - + } default: - PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet\n", + PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet", cmd); break; } @@ -904,6 +921,7 @@ static void dma_trm_reset(struct dma_trm_ctx *d) { struct ti_ohci *ohci; unsigned long flags; + struct hpsb_packet *nextpacket; if (d==NULL) { PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg"); @@ -919,8 +937,9 @@ static void dma_trm_reset(struct dma_trm_ctx *d) 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 = d->fifo_first->xnext; + d->fifo_first = nextpacket; } d->fifo_first = d->fifo_last = NULL; @@ -929,9 +948,10 @@ static void dma_trm_reset(struct dma_trm_ctx *d) 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 = d->pending_first->xnext; + d->pending_first = nextpacket; } d->pending_first = d->pending_last = NULL; @@ -1072,6 +1092,20 @@ static void ohci_irq_handler(int irq, void *dev_id, } if (event & OHCI1394_selfIDComplete) { if (host->in_bus_reset) { + /* + * Begin Fix (JSG): Check to make sure our + * node id is valid + */ + node_id = reg_read(ohci, OHCI1394_NodeID); + if (!(node_id & 0x80000000)) { + mdelay(1); /* phy is upset - + * this happens once in + * a while on hot-plugs... + * give it a ms to recover + */ + } + /* End Fix (JSG) */ + node_id = reg_read(ohci, OHCI1394_NodeID); if (node_id & 0x80000000) { /* NodeID valid */ phyid = node_id & 0x0000003f; @@ -1346,9 +1380,10 @@ static void dma_trm_bh(void *data) { struct dma_trm_ctx *d = (struct dma_trm_ctx*)data; struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); - struct hpsb_packet *packet; + struct hpsb_packet *packet, *nextpacket; unsigned long flags; u32 ack; + size_t datasize; spin_lock_irqsave(&d->lock, flags); @@ -1363,7 +1398,8 @@ static void dma_trm_bh(void *data) while (d->fifo_first) { packet = d->fifo_first; - if (packet->data_size) + datasize = d->fifo_first->data_size; + if (datasize) ack = d->prg_cpu[d->sent_ind]->end.status>>16; else ack = d->prg_cpu[d->sent_ind]->begin.status>>16; @@ -1372,20 +1408,40 @@ static void dma_trm_bh(void *data) /* this packet hasn't been sent yet*/ break; - DBGMSG(ohci->id, - "Packet sent to node %d ack=0x%X spd=%d ctx=%d", - (packet->header[0]>>16)&0x3f, ack&0x1f, (ack>>5)&0x3, - d->ctx); +#ifdef OHCI1394_DEBUG + if (datasize) + DBGMSG(ohci->id, + "Packet sent to node %d tcode=0x%X tLabel=" + "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d", + (d->prg_cpu[d->sent_ind]->data[1]>>16)&0x3f, + (d->prg_cpu[d->sent_ind]->data[0]>>4)&0xf, + (d->prg_cpu[d->sent_ind]->data[0]>>10)&0x3f, + ack&0x1f, (ack>>5)&0x3, + d->prg_cpu[d->sent_ind]->data[3]>>16, + d->ctx); + else + DBGMSG(ohci->id, + "Packet sent to node %d tcode=0x%X tLabel=" + "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d", + (d->prg_cpu[d->sent_ind]->data[1]>>16)&0x3f, + (d->prg_cpu[d->sent_ind]->data[0]>>4)&0xf, + (d->prg_cpu[d->sent_ind]->data[0]>>10)&0x3f, + ack&0x1f, (ack>>5)&0x3, + d->prg_cpu[d->sent_ind]->data[3], + d->ctx); +#endif + + nextpacket = packet->xnext; hpsb_packet_sent(ohci->host, packet, ack&0xf); - if (packet->data_size) + if (datasize) pci_unmap_single(ohci->dev, d->prg_cpu[d->sent_ind]->end.address, - packet->data_size, PCI_DMA_TODEVICE); + datasize, PCI_DMA_TODEVICE); d->sent_ind = (d->sent_ind+1)%d->num_desc; d->free_prgs++; - d->fifo_first = d->fifo_first->xnext; + d->fifo_first = nextpacket; } if (d->fifo_first==NULL) d->fifo_last=NULL; @@ -1687,22 +1743,36 @@ static int add_card(struct pci_dev *dev) FAIL("failed to allocate buffer config rom"); } - DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x", - *((char *)ohci->csr_config_rom_cpu+4)); - /* * self-id dma buffer allocation * FIXME: some early chips may need 8KB alignment for the - * selfid buffer + * selfid buffer... if you have problems a temporary fic + * is to allocate 8192 bytes instead of 2048 */ ohci->selfid_buf_cpu = pci_alloc_consistent(ohci->dev, 2048, &ohci->selfid_buf_bus); if (ohci->selfid_buf_cpu == NULL) { FAIL("failed to allocate DMA buffer for self-id packets"); } - if ((unsigned long)ohci->selfid_buf_cpu & 0xfff) + if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) PRINT(KERN_INFO, ohci->id, "Selfid buffer %p not aligned on " - "8Kb boundary", ohci->selfid_buf_cpu); + "8Kb boundary... may cause pb on some CXD3222 chip", + ohci->selfid_buf_cpu); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) + ohci->registers = ioremap_nocache(dev->base_address[0], + OHCI1394_REGISTER_SIZE); +#else + ohci->registers = ioremap_nocache(dev->resource[0].start, + OHCI1394_REGISTER_SIZE); +#endif + + if (ohci->registers == NULL) { + FAIL("failed to remap registers - card not accessible"); + } + + PRINT(KERN_INFO, ohci->id, "remapped memory spaces reg 0x%p", + ohci->registers); ohci->ar_req_context = alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC, @@ -1711,7 +1781,9 @@ static int add_card(struct pci_dev *dev) OHCI1394_AsReqRcvContextControlClear, OHCI1394_AsReqRcvCommandPtr); - if (ohci->ar_req_context == NULL) return 1; + if (ohci->ar_req_context == NULL) { + FAIL("failed to allocate AR Req context"); + } ohci->ar_resp_context = alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC, @@ -1758,21 +1830,6 @@ static int add_card(struct pci_dev *dev) ohci->IR_channel_usage= 0x0000000000000000; spin_lock_init(&ohci->IR_channel_lock); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) - ohci->registers = ioremap_nocache(dev->base_address[0], - OHCI1394_REGISTER_SIZE); -#else - ohci->registers = ioremap_nocache(dev->resource[0].start, - OHCI1394_REGISTER_SIZE); -#endif - - if (ohci->registers == NULL) { - FAIL("failed to remap registers - card not accessible"); - } - - PRINT(KERN_INFO, ohci->id, "remapped memory spaces reg 0x%p", - ohci->registers); - if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) { PRINT(KERN_INFO, ohci->id, "allocated interrupt %d", dev->irq); @@ -1782,6 +1839,9 @@ static int add_card(struct pci_dev *dev) ohci_init_config_rom(ohci); + DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x", + *((char *)ohci->csr_config_rom_cpu+4)); + return 0; #undef FAIL } @@ -2116,7 +2176,7 @@ static int init_driver() create_proc_read_entry ("ohci1394", 0, NULL, ohci1394_read_proc, NULL); #else if (proc_register(&proc_root, &ohci_proc_entry)) { - PRINT_G(KERN_ERR, "unable to register proc file\n"); + PRINT_G(KERN_ERR, "unable to register proc file"); return -EIO; } #endif @@ -2290,7 +2350,7 @@ void cleanup_module(void) #endif #endif - PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n"); + PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module"); } int init_module(void) @@ -2298,7 +2358,7 @@ int init_module(void) memset(cards, 0, MAX_OHCI1394_CARDS * sizeof (struct ti_ohci)); if (hpsb_register_lowlevel(get_ohci_template())) { - PRINT_G(KERN_ERR, "registering failed\n"); + PRINT_G(KERN_ERR, "registering failed"); return -ENXIO; } return 0; diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h index af1aeb2a6..7c362d8d6 100644 --- a/drivers/ieee1394/ohci1394.h +++ b/drivers/ieee1394/ohci1394.h @@ -91,16 +91,16 @@ #define OHCI1394_MAX_SELF_ID_ERRORS 16 #define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */ -#define AR_REQ_BUF_SIZE 4096 /* size of AR req buffers */ -#define AR_REQ_SPLIT_BUF_SIZE 4096 /* split packet buffer */ +#define AR_REQ_BUF_SIZE PAGE_SIZE /* size of AR req buffers */ +#define AR_REQ_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ #define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */ -#define AR_RESP_BUF_SIZE 4096 /* size of AR resp buffers */ -#define AR_RESP_SPLIT_BUF_SIZE 4096 /* split packet buffer */ +#define AR_RESP_BUF_SIZE PAGE_SIZE /* size of AR resp buffers */ +#define AR_RESP_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ #define IR_NUM_DESC 16 /* number of IR descriptors */ -#define IR_BUF_SIZE 4096 /* 6480 bytes/buffer */ -#define IR_SPLIT_BUF_SIZE 4096 /* split packet buffer */ +#define IR_BUF_SIZE PAGE_SIZE /* 4096 bytes/buffer */ +#define IR_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ #define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */ #define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */ @@ -112,10 +112,17 @@ struct dma_cmd { u32 status; }; +/* + * FIXME: + * It is important that a single at_dma_prg does not cross a page boundary + * The proper way to do it would be to do the check dynamically as the + * programs are inserted into the AT fifo. + */ struct at_dma_prg { struct dma_cmd begin; quadlet_t data[4]; struct dma_cmd end; + quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */ }; /* DMA receive context */ diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index 16aeaa92d..352f85408 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -18,16 +18,6 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* - * Lynx DMA usage: - * - * 0 is used for Lynx local bus transfers - * 1 is async/selfid receive - * 2 is iso receive - * 3 is async transmit - */ - - #include <linux/config.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -63,8 +53,8 @@ #define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args) #define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args) #else -#define PRINT_GD(level, fmt, args...) -#define PRINTD(level, card, fmt, args...) +#define PRINT_GD(level, fmt, args...) do {} while (0) +#define PRINTD(level, card, fmt, args...) do {} while (0) #endif static struct ti_lynx cards[MAX_PCILYNX_CARDS]; @@ -177,8 +167,8 @@ static int get_phy_reg(struct ti_lynx *lynx, int addr) spin_lock_irqsave(&lynx->phy_reg_lock, flags); + reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr)); do { - reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr)); retval = reg_read(lynx, LINK_PHY); if (i > 10000) { @@ -309,12 +299,11 @@ static quadlet_t generate_own_selfid(struct ti_lynx *lynx, lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22); lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */ lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */ - /* lsid |= (phyreg[6] & 0x01) << 11; *//* contender (phy dependent) */ - lsid |= 1 << 11; /* set contender (hack) */ + lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */ + /* lsid |= 1 << 11; *//* set contender (hack) */ lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */ - //for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */ - for (i = 0; i < (phyreg[2] & 0x1f); i++) { /* ports */ + for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */ if (phyreg[3 + i] & 0x4) { lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3) << (6 - i*2); @@ -380,47 +369,63 @@ static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host, size_t s hpsb_selfid_received(host, lsid); } + if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); + hpsb_selfid_complete(host, phyid, isroot); } -/* This must be called with the async.queue_lock held. */ -static void send_next_async(struct ti_lynx *lynx) +/* This must be called with the respective queue_lock held. */ +static void send_next(struct ti_lynx *lynx, int what) { struct ti_pcl pcl; - struct hpsb_packet *packet = lynx->async.queue; + struct lynx_send_data *d; + struct hpsb_packet *packet; - lynx->async.header_dma = pci_map_single(lynx->dev, packet->header, - packet->header_size, - PCI_DMA_TODEVICE); + d = (what == iso ? &lynx->iso_send : &lynx->async); + packet = d->queue; + + d->header_dma = pci_map_single(lynx->dev, packet->header, + packet->header_size, PCI_DMA_TODEVICE); if (packet->data_size) { - lynx->async.data_dma = pci_map_single(lynx->dev, packet->data, - packet->data_size, - PCI_DMA_TODEVICE); + d->data_dma = pci_map_single(lynx->dev, packet->data, + packet->data_size, + PCI_DMA_TODEVICE); } else { - lynx->async.data_dma = 0; + d->data_dma = 0; } pcl.next = PCL_NEXT_INVALID; pcl.async_error_next = PCL_NEXT_INVALID; #ifdef __BIG_ENDIAN - pcl.buffer[0].control = PCL_CMD_XMT | packet->speed_code << 14 - | packet->header_size; + pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size; #else - pcl.buffer[0].control = PCL_CMD_XMT | packet->speed_code << 14 - | packet->header_size | PCL_BIGENDIAN; + pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size + | PCL_BIGENDIAN; #endif - pcl.buffer[0].pointer = lynx->async.header_dma; + pcl.buffer[0].pointer = d->header_dma; pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size; - pcl.buffer[1].pointer = lynx->async.data_dma; + pcl.buffer[1].pointer = d->data_dma; + + switch (packet->type) { + case async: + pcl.buffer[0].control |= PCL_CMD_XMT; + break; + case iso: + pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE; + break; + case raw: + pcl.buffer[0].control |= PCL_CMD_UNFXMT; + break; + } if (!packet->data_be) { pcl.buffer[1].control |= PCL_BIGENDIAN; } - put_pcl(lynx, lynx->async.pcl, &pcl); - run_pcl(lynx, lynx->async.pcl_start, 3); + put_pcl(lynx, d->pcl, &pcl); + run_pcl(lynx, d->pcl_start, d->channel); } @@ -475,6 +480,10 @@ static int lynx_initialize(struct hpsb_host *host) pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl); put_pcl(lynx, lynx->async.pcl_start, &pcl); + pcl.next = pcl_bus(lynx, lynx->iso_send.pcl); + pcl.async_error_next = PCL_NEXT_INVALID; + put_pcl(lynx, lynx->iso_send.pcl_start, &pcl); + pcl.next = PCL_NEXT_INVALID; pcl.async_error_next = PCL_NEXT_INVALID; pcl.buffer[0].control = PCL_CMD_RCV | 4; @@ -499,15 +508,18 @@ static int lynx_initialize(struct hpsb_host *host) } put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl); - /* 85 bytes for each FIFO - FIXME - optimize or make configurable */ - /* reg_write(lynx, FIFO_SIZES, 0x00555555); */ - reg_write(lynx, FIFO_SIZES, 0x002020c0); + /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */ + reg_write(lynx, FIFO_SIZES, 0x003030a0); /* 20 byte threshold before triggering PCI transfer */ reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24); - /* 69 byte threshold on both send FIFOs before transmitting */ - reg_write(lynx, FIFO_XMIT_THRESHOLD, 0x4545); + /* threshold on both send FIFOs before transmitting: + FIFO size - cache line size - 1 */ + i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff; + i = 0x30 - i - 1; + reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i); reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394); + reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK @@ -515,15 +527,15 @@ static int lynx_initialize(struct hpsb_host *host) | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW | LINK_INT_ATF_UNDERFLOW); - reg_write(lynx, DMA1_WORD0_CMP_VALUE, 0); - reg_write(lynx, DMA1_WORD0_CMP_ENABLE, 0xa<<4); - reg_write(lynx, DMA1_WORD1_CMP_VALUE, 0); - reg_write(lynx, DMA1_WORD1_CMP_ENABLE, DMA_WORD1_CMP_MATCH_NODE_BCAST - | DMA_WORD1_CMP_MATCH_BROADCAST | DMA_WORD1_CMP_MATCH_LOCAL - | DMA_WORD1_CMP_MATCH_BUS_BCAST | DMA_WORD1_CMP_ENABLE_SELF_ID - | DMA_WORD1_CMP_ENABLE_MASTER); + reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); + reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4); + reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); + reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV), + DMA_WORD1_CMP_MATCH_NODE_BCAST | DMA_WORD1_CMP_MATCH_BROADCAST + | DMA_WORD1_CMP_MATCH_LOCAL | DMA_WORD1_CMP_MATCH_BUS_BCAST + | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER); - run_pcl(lynx, lynx->rcv_pcl_start, 1); + run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV); reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0); reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4); @@ -536,7 +548,7 @@ static int lynx_initialize(struct hpsb_host *host) | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX - | LINK_CONTROL_CYCSOURCE | LINK_CONTROL_CYCTIMEREN); + | LINK_CONTROL_CYCTIMEREN); /* attempt to enable contender bit -FIXME- would this work elsewhere? */ reg_set_bits(lynx, GPIO_CTRL_A, 0x1); @@ -559,14 +571,10 @@ static void lynx_release(struct hpsb_host *host) } } - -/* - * FIXME - does not support iso/raw transmits yet and will choke on them. - */ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet) { struct ti_lynx *lynx = host->hostdata; - struct hpsb_packet *p; + struct lynx_send_data *d; unsigned long flags; if (packet->data_size >= 4096) { @@ -575,27 +583,38 @@ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet) return 0; } + switch (packet->type) { + case async: + case raw: + d = &lynx->async; + break; + case iso: + d = &lynx->iso_send; + break; + default: + PRINT(KERN_ERR, lynx->id, "invalid packet type %d", + packet->type); + return 0; + } + packet->xnext = NULL; if (packet->tcode == TCODE_WRITEQ || packet->tcode == TCODE_READQ_RESPONSE) { cpu_to_be32s(&packet->header[3]); } - spin_lock_irqsave(&lynx->async.queue_lock, flags); + spin_lock_irqsave(&d->queue_lock, flags); - if (lynx->async.queue == NULL) { - lynx->async.queue = packet; - send_next_async(lynx); + if (d->queue == NULL) { + d->queue = packet; + d->queue_last = packet; + send_next(lynx, packet->type); } else { - p = lynx->async.queue; - while (p->xnext != NULL) { - p = p->xnext; - } - - p->xnext = packet; + d->queue_last->xnext = packet; + d->queue_last = packet; } - spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + spin_unlock_irqrestore(&d->queue_lock, flags); return 1; } @@ -652,7 +671,7 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) case CANCEL_REQUESTS: spin_lock_irqsave(&lynx->async.queue_lock, flags); - reg_write(lynx, DMA3_CHAN_CTRL, 0); + reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0); packet = lynx->async.queue; lynx->async.queue = NULL; @@ -718,18 +737,19 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) static int mem_open(struct inode*, struct file*); static int mem_release(struct inode*, struct file*); static unsigned int aux_poll(struct file*, struct poll_table_struct*); +static loff_t mem_llseek(struct file*, loff_t, int); static ssize_t mem_read (struct file*, char*, size_t, loff_t*); static ssize_t mem_write(struct file*, const char*, size_t, loff_t*); static struct file_operations aux_ops = { OWNER_THIS_MODULE - /* FIXME: should have custom llseek with bounds checking */ - read: mem_read, - write: mem_write, - poll: aux_poll, - open: mem_open, - release: mem_release, + read: mem_read, + write: mem_write, + poll: aux_poll, + llseek: mem_llseek, + open: mem_open, + release: mem_release, }; @@ -745,7 +765,7 @@ static void aux_setup_pcls(struct ti_lynx *lynx) static int mem_open(struct inode *inode, struct file *file) { int cid = MINOR(inode->i_rdev); - enum { rom, aux, ram } type; + enum { t_rom, t_aux, t_ram } type; struct memdata *md; V22_COMPAT_MOD_INC_USE_COUNT; @@ -760,14 +780,14 @@ static int mem_open(struct inode *inode, struct file *file) V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } - type = aux; + type = t_aux; } else if (cid < PCILYNX_MINOR_RAM_START) { cid -= PCILYNX_MINOR_ROM_START; if (cid >= num_of_cards || !cards[cid].local_rom) { V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } - type = rom; + type = t_rom; } else { /* WARNING: Know what you are doing when opening RAM. * It is currently used inside the driver! */ @@ -776,10 +796,10 @@ static int mem_open(struct inode *inode, struct file *file) V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } - type = ram; + type = t_ram; } - md = (struct memdata *)vmalloc(sizeof(struct memdata)); + md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL); if (md == NULL) { V22_COMPAT_MOD_DEC_USE_COUNT; return -ENOMEM; @@ -789,13 +809,13 @@ static int mem_open(struct inode *inode, struct file *file) md->cid = cid; switch (type) { - case rom: + case t_rom: md->type = rom; break; - case ram: + case t_ram: md->type = ram; break; - case aux: + case t_aux: atomic_set(&md->aux_intr_last_seen, atomic_read(&cards[cid].aux_intr_seen)); md->type = aux; @@ -811,7 +831,7 @@ static int mem_release(struct inode *inode, struct file *file) { struct memdata *md = (struct memdata *)file->private_data; - vfree(md); + kfree(md); V22_COMPAT_MOD_DEC_USE_COUNT; return 0; @@ -839,6 +859,29 @@ static unsigned int aux_poll(struct file *file, poll_table *pt) return mask; } +loff_t mem_llseek(struct file *file, loff_t offs, int orig) +{ + loff_t newoffs; + + switch (orig) { + case 0: + newoffs = offs; + break; + case 1: + newoffs = offs + file->f_pos; + break; + case 2: + newoffs = PCILYNX_MAX_MEMORY + 1 + offs; + break; + default: + return -EINVAL; + } + + if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL; + + file->f_pos = newoffs; + return newoffs; +} /* * do not DMA if count is too small because this will have a serious impact @@ -857,8 +900,6 @@ static ssize_t mem_dmaread(struct memdata *md, u32 physbuf, ssize_t count, int i; DECLARE_WAITQUEUE(wait, current); - //printk("buf 0x%08x %x count %d offset %d\n", physbuf, physbuf % 3, count, offset); - count &= ~3; count = MIN(count, 53196); retval = count; @@ -868,17 +909,7 @@ static ssize_t mem_dmaread(struct memdata *md, u32 physbuf, ssize_t count, PRINT(KERN_WARNING, md->lynx->id, "DMA ALREADY ACTIVE!"); } - switch (md->type) { - case rom: - reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_ROM | offset); - break; - case ram: - reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_RAM | offset); - break; - case aux: - reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_AUX | offset); - break; - } + reg_write(md->lynx, LBUS_ADDR, md->type | offset); pcl = edit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp); pcl->buffer[0].control = PCL_CMD_LBUS_TO_PCI | MIN(count, 4092); @@ -933,7 +964,7 @@ static ssize_t mem_read(struct file *file, char *buffer, size_t count, if ((off + count) > PCILYNX_MAX_MEMORY + 1) { count = PCILYNX_MAX_MEMORY + 1 - off; } - if (count <= 0) { + if (count == 0) { return 0; } @@ -1041,12 +1072,17 @@ static void lynx_irq_handler(int irq, void *dev_id, { struct ti_lynx *lynx = (struct ti_lynx *)dev_id; struct hpsb_host *host = lynx->host; - u32 intmask = reg_read(lynx, PCI_INT_STATUS); - u32 linkint = reg_read(lynx, LINK_INT_STATUS); + u32 intmask; + u32 linkint; + + linkint = reg_read(lynx, LINK_INT_STATUS); + intmask = reg_read(lynx, PCI_INT_STATUS); + + PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask, + linkint); - reg_write(lynx, PCI_INT_STATUS, intmask); reg_write(lynx, LINK_INT_STATUS, linkint); - //printk("-%d- one interrupt: 0x%08x / 0x%08x\n", lynx->id, intmask, linkint); + reg_write(lynx, PCI_INT_STATUS, intmask); #ifdef CONFIG_IEEE1394_PCILYNX_PORTS if (intmask & PCI_INT_AUX_INT) { @@ -1054,7 +1090,7 @@ static void lynx_irq_handler(int irq, void *dev_id, wake_up_interruptible(&lynx->aux_intr_wait); } - if (intmask & PCI_INT_DMA0_HLT) { + if (intmask & PCI_INT_DMA_HLT(CHANNEL_LOCALBUS)) { wake_up_interruptible(&lynx->mem_dma_intr_wait); } #endif @@ -1125,14 +1161,13 @@ static void lynx_irq_handler(int irq, void *dev_id, mark_bh(IMMEDIATE_BH); } - if (intmask & PCI_INT_DMA3_HLT) { - /* async send DMA completed */ + if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) { u32 ack; struct hpsb_packet *packet; spin_lock(&lynx->async.queue_lock); - ack = reg_read(lynx, DMA3_CHAN_STAT); + ack = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_SEND)); packet = lynx->async.queue; lynx->async.queue = packet->xnext; @@ -1144,7 +1179,7 @@ static void lynx_irq_handler(int irq, void *dev_id, } if (lynx->async.queue != NULL) { - send_next_async(lynx); + send_next(lynx, async); } spin_unlock(&lynx->async.queue_lock); @@ -1160,9 +1195,33 @@ static void lynx_irq_handler(int irq, void *dev_id, hpsb_packet_sent(host, packet, ack); } - if (intmask & (PCI_INT_DMA1_HLT | PCI_INT_DMA1_PCL)) { + if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) { + struct hpsb_packet *packet; + + spin_lock(&lynx->iso_send.queue_lock); + + packet = lynx->iso_send.queue; + lynx->iso_send.queue = packet->xnext; + + pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->iso_send.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } + + if (lynx->iso_send.queue != NULL) { + send_next(lynx, iso); + } + + spin_unlock(&lynx->iso_send.queue_lock); + + hpsb_packet_sent(host, packet, ACK_COMPLETE); + } + + if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) { /* general receive DMA completed */ - int stat = reg_read(lynx, DMA1_CHAN_STAT); + int stat = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_RCV)); PRINTD(KERN_DEBUG, lynx->id, "received packet size %d", stat & 0x1fff); @@ -1182,7 +1241,7 @@ static void lynx_irq_handler(int irq, void *dev_id, hpsb_packet_received(host, q_data, stat & 0x1fff, 0); } - run_pcl(lynx, lynx->rcv_pcl_start, 1); + run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV); } } @@ -1263,14 +1322,6 @@ static int add_card(struct pci_dev *dev) } pci_set_master(dev); - if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, - PCILYNX_DRIVER_NAME, lynx)) { - PRINT(KERN_INFO, lynx->id, "allocated interrupt %d", dev->irq); - lynx->state = have_intr; - } else { - FAIL("failed to allocate shared interrupt %d", dev->irq); - } - #ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE, &lynx->pcl_mem_dma); @@ -1329,6 +1380,16 @@ static int add_card(struct pci_dev *dev) } #endif + reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); + + if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, + PCILYNX_DRIVER_NAME, lynx)) { + PRINT(KERN_INFO, lynx->id, "allocated interrupt %d", dev->irq); + lynx->state = have_intr; + } else { + FAIL("failed to allocate shared interrupt %d", dev->irq); + } + /* alloc_pcl return values are not checked, it is expected that the * provided PCL space is sufficient for the initial allocations */ #ifdef CONFIG_IEEE1394_PCILYNX_PORTS @@ -1342,6 +1403,8 @@ static int add_card(struct pci_dev *dev) lynx->rcv_pcl_start = alloc_pcl(lynx); lynx->async.pcl = alloc_pcl(lynx); lynx->async.pcl_start = alloc_pcl(lynx); + lynx->iso_send.pcl = alloc_pcl(lynx); + lynx->iso_send.pcl_start = alloc_pcl(lynx); for (i = 0; i < NUM_ISORCV_PCL; i++) { lynx->iso_rcv.pcl[i] = alloc_pcl(lynx); @@ -1362,6 +1425,11 @@ static int add_card(struct pci_dev *dev) lynx->iso_rcv.tq.routine = (void (*)(void*))iso_rcv_bh; lynx->iso_rcv.tq.data = lynx; lynx->iso_rcv.lock = SPIN_LOCK_UNLOCKED; + + lynx->async.queue_lock = SPIN_LOCK_UNLOCKED; + lynx->async.channel = CHANNEL_ASYNC_SEND; + lynx->iso_send.queue_lock = SPIN_LOCK_UNLOCKED; + lynx->iso_send.channel = CHANNEL_ISO_SEND; PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, " "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom, @@ -1388,6 +1456,8 @@ static void remove_card(struct ti_lynx *lynx) int i; switch (lynx->state) { + case have_intr: + free_irq(lynx->dev->irq, lynx); case have_iomappings: reg_write(lynx, PCI_INT_ENABLE, 0); reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); @@ -1410,13 +1480,11 @@ static void remove_card(struct ti_lynx *lynx) pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer, lynx->mem_dma_buffer_dma); #endif - case have_pcl_mem: + case have_pcl_mem: #ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem, lynx->pcl_mem_dma); #endif - case have_intr: - free_irq(lynx->dev->irq, lynx); case clear: /* do nothing - already freed */ } diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h index ccb5a9f0b..6993b9519 100644 --- a/drivers/ieee1394/pcilynx.h +++ b/drivers/ieee1394/pcilynx.h @@ -19,11 +19,11 @@ #define ISORCV_PER_PAGE (PAGE_SIZE / MAX_ISORCV_SIZE) #define ISORCV_PAGES (NUM_ISORCV_PCL / ISORCV_PER_PAGE) -/* only iso rcv and localbus use these definitions so far */ #define CHANNEL_LOCALBUS 0 #define CHANNEL_ASYNC_RCV 1 #define CHANNEL_ISO_RCV 2 #define CHANNEL_ASYNC_SEND 3 +#define CHANNEL_ISO_SEND 4 typedef int pcl_t; @@ -88,12 +88,13 @@ struct ti_lynx { dma_addr_t rcv_page_dma; int rcv_active; - struct { + struct lynx_send_data { pcl_t pcl_start, pcl; - struct hpsb_packet *queue; + struct hpsb_packet *queue, *queue_last; spinlock_t queue_lock; dma_addr_t header_dma, data_dma; - } async; + int channel; + } async, iso_send; struct { pcl_t pcl[NUM_ISORCV_PCL]; @@ -113,7 +114,8 @@ struct memdata { struct ti_lynx *lynx; int cid; atomic_t aux_intr_last_seen; - enum { rom, aux, ram } type; + /* enum values are the same as LBUS_ADDR_SEL_* values below */ + enum { rom = 0x10000, aux = 0x20000, ram = 0 } type; }; @@ -147,6 +149,8 @@ inline static void reg_clear_bits(const struct ti_lynx *lynx, int offset, /* chip register definitions follow */ +#define PCI_LATENCY_CACHELINE 0x0c + #define MISC_CONTROL 0x40 #define MISC_CONTROL_SWRESET (1<<0) @@ -495,6 +499,7 @@ inline static void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan) #define PCL_LAST_CMD (PCL_LAST_BUFF) #define PCL_WAITSTAT (1<<17) #define PCL_BIGENDIAN (1<<16) +#define PCL_ISOMODE (1<<12) #define _(x) (__constant_cpu_to_be32(x)) diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 3c23c45a5..d10353855 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -33,6 +33,15 @@ #include "raw1394.h" +#if BITS_PER_LONG == 64 +#define int2ptr(x) ((void *)x) +#define ptr2int(x) ((u64)x) +#else +#define int2ptr(x) ((void *)(u32)x) +#define ptr2int(x) ((u64)(u32)x) +#endif + + static devfs_handle_t devfs_handle = NULL; LIST_HEAD(host_info_list); @@ -204,8 +213,13 @@ static void host_reset(struct hpsb_host *host) req->file_info = fi; req->req.type = RAW1394_REQ_BUS_RESET; req->req.generation = get_hpsb_generation(); - req->req.misc = (host->node_id << 16) + 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); } @@ -268,7 +282,7 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data, req->req.type = RAW1394_REQ_ISO_RECEIVE; req->req.generation = get_hpsb_generation(); req->req.misc = 0; - req->req.recvb = (u64)fi->iso_buffer; + req->req.recvb = ptr2int(fi->iso_buffer); req->req.length = MIN(length, fi->iso_buffer_length); list_add_tail(&req->list, &reqs); @@ -337,7 +351,7 @@ static void fcp_request(struct hpsb_host *host, int nodeid, int direction, req->req.type = RAW1394_REQ_FCP_REQUEST; req->req.generation = get_hpsb_generation(); req->req.misc = nodeid | (direction << 16); - req->req.recvb = (u64)fi->fcp_buffer; + req->req.recvb = ptr2int(fi->fcp_buffer); req->req.length = length; list_add_tail(&req->list, &reqs); @@ -387,7 +401,7 @@ static ssize_t dev_read(struct file *file, char *buffer, size_t count, req = list_entry(lh, struct pending_request, list); if (req->req.length) { - if (copy_to_user((void *)req->req.recvb, req->data, + if (copy_to_user(int2ptr(req->req.recvb), req->data, req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; } @@ -402,11 +416,16 @@ static ssize_t dev_read(struct file *file, char *buffer, size_t count, static int state_opened(struct file_info *fi, struct pending_request *req) { if (req->req.type == RAW1394_REQ_INITIALIZE) { - if (req->req.misc == RAW1394_KERNELAPI_VERSION) { + switch (req->req.misc) { + case RAW1394_KERNELAPI_VERSION: + case 3: fi->state = initialized; + fi->protocol_version = req->req.misc; req->req.error = RAW1394_ERROR_NONE; req->req.generation = get_hpsb_generation(); - } else { + break; + + default: req->req.error = RAW1394_ERROR_COMPAT; req->req.misc = RAW1394_KERNELAPI_VERSION; } @@ -488,6 +507,10 @@ static int state_initialized(struct file_info *fi, struct pending_request *req) req->req.error = RAW1394_ERROR_NONE; req->req.misc = (fi->host->node_id << 16) | fi->host->node_count; + if (fi->protocol_version > 3) { + req->req.misc |= + (fi->host->irm_id & NODE_MASK) << 8; + } } else { req->req.error = RAW1394_ERROR_INVALID_ARG; } @@ -519,7 +542,7 @@ static void handle_iso_listen(struct file_info *fi, struct pending_request *req) } else { fi->listen_channels |= 1ULL << channel; hpsb_listen_channel(hl_handle, fi->host, channel); - fi->iso_buffer = (void *)req->req.recvb; + fi->iso_buffer = int2ptr(req->req.recvb); fi->iso_buffer_length = req->req.length; } } else { @@ -545,7 +568,7 @@ static void handle_fcp_listen(struct file_info *fi, struct pending_request *req) if (fi->fcp_buffer) { req->req.error = RAW1394_ERROR_ALREADY; } else { - fi->fcp_buffer = (u8 *)req->req.recvb; + fi->fcp_buffer = (u8 *)int2ptr(req->req.recvb); } } else { if (!fi->fcp_buffer) { @@ -575,7 +598,7 @@ static int handle_local_request(struct file_info *fi, break; case RAW1394_REQ_ASYNC_WRITE: - if (copy_from_user(req->data, (void *)req->req.sendb, + if (copy_from_user(req->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; break; @@ -600,7 +623,7 @@ static int handle_local_request(struct file_info *fi, } } - if (copy_from_user(req->data, (void *)req->req.sendb, + if (copy_from_user(req->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; break; @@ -658,7 +681,7 @@ static int handle_remote_request(struct file_info *fi, if (req->req.length == 4) { quadlet_t x; - if (copy_from_user(&x, (void *)req->req.sendb, 4)) { + if (copy_from_user(&x, int2ptr(req->req.sendb), 4)) { req->req.error = RAW1394_ERROR_MEMFAULT; } @@ -670,7 +693,7 @@ static int handle_remote_request(struct file_info *fi, req->req.length); if (!packet) return -ENOMEM; - if (copy_from_user(packet->data, (void *)req->req.sendb, + if (copy_from_user(packet->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; } @@ -696,7 +719,7 @@ static int handle_remote_request(struct file_info *fi, req->req.misc); if (!packet) return -ENOMEM; - if (copy_from_user(packet->data, (void *)req->req.sendb, + if (copy_from_user(packet->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; break; @@ -735,12 +758,52 @@ static int handle_remote_request(struct file_info *fi, return sizeof(struct raw1394_request); } +static int handle_iso_send(struct file_info *fi, struct pending_request *req, + int channel) +{ + struct hpsb_packet *packet; + + packet = alloc_hpsb_packet(req->req.length); + if (!packet) return -ENOMEM; + req->packet = packet; + + fill_iso_packet(packet, req->req.length, channel & 0x3f, + (req->req.misc >> 16) & 0x3, req->req.misc & 0xf); + packet->type = iso; + packet->speed_code = req->req.address & 0x3; + packet->host = fi->host; + + if (copy_from_user(packet->data, int2ptr(req->req.sendb), + req->req.length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } + + req->tq.data = req; + req->tq.routine = (void (*)(void*))queue_complete_req; + req->req.length = 0; + queue_task(&req->tq, &packet->complete_tq); + + if (!hpsb_send_packet(packet)) { + req->req.error = RAW1394_ERROR_SEND_ERROR; + queue_complete_req(req); + } + + return sizeof(struct raw1394_request); +} + static int state_connected(struct file_info *fi, struct pending_request *req) { int node = req->req.address >> 48; req->req.error = RAW1394_ERROR_NONE; + if (req->req.type == RAW1394_REQ_ISO_SEND) { + return handle_iso_send(fi, req, node); + } + if (req->req.generation != get_hpsb_generation()) { req->req.error = RAW1394_ERROR_GENERATION; req->req.generation = get_hpsb_generation(); @@ -749,14 +812,18 @@ static int state_connected(struct file_info *fi, struct pending_request *req) return sizeof(struct raw1394_request); } - if (req->req.type == RAW1394_REQ_ISO_LISTEN) { + switch (req->req.type) { + case RAW1394_REQ_ISO_LISTEN: handle_iso_listen(fi, req); return sizeof(struct raw1394_request); - } - if (req->req.type == RAW1394_REQ_FCP_LISTEN) { + case RAW1394_REQ_FCP_LISTEN: handle_fcp_listen(fi, req); return sizeof(struct raw1394_request); + + case RAW1394_REQ_RESET_BUS: + hpsb_reset_bus(fi->host); + return sizeof(struct raw1394_request); } if (req->req.length == 0) { @@ -870,7 +937,7 @@ static int dev_release(struct inode *inode, struct file *file) struct pending_request *req; int done = 0, i; - lock_kernel(); + lock_kernel(); for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { hpsb_unlisten_channel(hl_handle, fi->host, i); @@ -915,7 +982,7 @@ static int dev_release(struct inode *inode, struct file *file) kfree(fi); V22_COMPAT_MOD_DEC_USE_COUNT; - unlock_kernel(); + unlock_kernel(); return 0; } diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h index b0d819429..98c629823 100644 --- a/drivers/ieee1394/raw1394.h +++ b/drivers/ieee1394/raw1394.h @@ -4,7 +4,7 @@ #define RAW1394_DEVICE_MAJOR 171 #define RAW1394_DEVICE_NAME "raw1394" -#define RAW1394_KERNELAPI_VERSION 3 +#define RAW1394_KERNELAPI_VERSION 4 /* state: opened */ #define RAW1394_REQ_INITIALIZE 1 @@ -18,9 +18,11 @@ #define RAW1394_REQ_ASYNC_WRITE 101 #define RAW1394_REQ_LOCK 102 #define RAW1394_REQ_LOCK64 103 +#define RAW1394_REQ_ISO_SEND 104 #define RAW1394_REQ_ISO_LISTEN 200 #define RAW1394_REQ_FCP_LISTEN 201 +#define RAW1394_REQ_RESET_BUS 202 /* kernel to user */ #define RAW1394_REQ_BUS_RESET 10000 @@ -79,6 +81,7 @@ struct file_info { struct list_head list; enum { opened, initialized, connected } state; + unsigned int protocol_version; struct hpsb_host *host; diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index f43d82803..d8d82a2a6 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -57,6 +57,10 @@ #define ISO_RECEIVE 0 #define ISO_TRANSMIT 1 +#ifndef virt_to_page +#define virt_to_page(x) MAP_NR(x) +#endif + struct it_dma_prg { struct dma_cmd begin; quadlet_t data[4]; @@ -84,6 +88,7 @@ struct dma_iso_ctx { int cmdPtr; int ctxMatch; wait_queue_head_t waitq; + spinlock_t lock; }; struct video_card { @@ -144,7 +149,7 @@ static struct video_template video_tmpl = { irq_handler }; */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#define page_address(x) ((void *) (x)) +#define page_address(x) (x) #endif /* Given PGD from the address space's page table, return the kernel @@ -163,7 +168,7 @@ static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) pte = *ptep; if(pte_present(pte)) { ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); + ret |= (adr & (PAGE_SIZE - 1)); } } } @@ -212,7 +217,7 @@ static void * rvmalloc(unsigned long size) void * mem; unsigned long adr, page; - mem=vmalloc(size); + mem=vmalloc_32(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, @@ -374,7 +379,7 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int ctx, int num_desc, d->packet_size = packet_size; - if (PAGE_SIZE % packet_size || packet_size>2048) { + if (PAGE_SIZE % packet_size || packet_size>4096) { PRINT(KERN_ERR, ohci->id, "Packet size %d not yet supported\n", packet_size); @@ -413,6 +418,8 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int ctx, int num_desc, } memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int)); + spin_lock_init(&d->lock); + PRINT(KERN_INFO, ohci->id, "Iso %s DMA: %d buffers " "of size %d allocated for a frame size %d, each with %d prgs", (type==ISO_RECEIVE) ? "receive" : "transmit", @@ -531,12 +538,14 @@ int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) return -EFAULT; } + spin_lock(&d->lock); for (i=0;i<d->num_desc;i++) { if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) { reset_ir_status(d, i); d->buffer_status[i] = VIDEO1394_BUFFER_READY; } } + spin_unlock(&d->lock); if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq); return 0; } @@ -551,12 +560,14 @@ int wakeup_dma_it_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) return -EFAULT; } + spin_lock(&d->lock); for (i=0;i<d->num_desc;i++) { if (d->it_prg[i][d->nb_cmd-1].end.status & 0xFFFF0000) { d->it_prg[i][d->nb_cmd-1].end.status = 0; d->buffer_status[i] = VIDEO1394_BUFFER_READY; } } + spin_unlock(&d->lock); if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq); return 0; } @@ -664,6 +675,7 @@ static int video1394_ioctl(struct inode *inode, struct file *file, { struct video_card *video = &video_cards[MINOR(inode->i_rdev)]; struct ti_ohci *ohci= video->ohci; + unsigned long flags; switch(cmd) { @@ -832,9 +844,12 @@ static int video1394_ioctl(struct inode *inode, struct file *file, return -EFAULT; } - if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { + spin_lock_irqsave(&d->lock,flags); + + if (d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED) { PRINT(KERN_ERR, ohci->id, "buffer %d is already used",v.buffer); + spin_unlock_irqrestore(&d->lock,flags); return -EFAULT; } @@ -849,6 +864,8 @@ static int video1394_ioctl(struct inode *inode, struct file *file, d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0; + spin_unlock_irqrestore(&d->lock,flags); + if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { DBGMSG(ohci->id, "Starting iso DMA ctx=%d",d->ctx); @@ -890,16 +907,26 @@ static int video1394_ioctl(struct inode *inode, struct file *file, return -EFAULT; } + /* + * I change the way it works so that it returns + * the last received frame. + */ + spin_lock_irqsave(&d->lock, flags); switch(d->buffer_status[v.buffer]) { case VIDEO1394_BUFFER_READY: d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; - return 0; + break; case VIDEO1394_BUFFER_QUEUED: #if 1 while(d->buffer_status[v.buffer]!= VIDEO1394_BUFFER_READY) { + spin_unlock_irqrestore(&d->lock, flags); interruptible_sleep_on(&d->waitq); - if(signal_pending(current)) return -EINTR; + spin_lock_irqsave(&d->lock, flags); + if(signal_pending(current)) { + spin_unlock_irqrestore(&d->lock,flags); + return -EINTR; + } } #else if (wait_event_interruptible(d->waitq, @@ -909,12 +936,30 @@ static int video1394_ioctl(struct inode *inode, struct file *file, return -EINTR; #endif d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; - return 0; + break; default: PRINT(KERN_ERR, ohci->id, "buffer %d is not queued",v.buffer); + spin_unlock_irqrestore(&d->lock, flags); return -EFAULT; } + + /* + * Look ahead to see how many more buffers have been received + */ + i=0; + while (d->buffer_status[(v.buffer+1)%d->num_desc]== + VIDEO1394_BUFFER_READY) { + v.buffer=(v.buffer+1)%d->num_desc; + i++; + } + spin_unlock_irqrestore(&d->lock, flags); + + v.buffer=i; + if(copy_to_user((void *)arg, &v, sizeof(v))) + return -EFAULT; + + return 0; } case VIDEO1394_TALK_QUEUE_BUFFER: { @@ -935,9 +980,12 @@ static int video1394_ioctl(struct inode *inode, struct file *file, return -EFAULT; } + spin_lock_irqsave(&d->lock,flags); + if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { PRINT(KERN_ERR, ohci->id, "buffer %d is already used",v.buffer); + spin_unlock_irqrestore(&d->lock,flags); return -EFAULT; } @@ -958,6 +1006,8 @@ static int video1394_ioctl(struct inode *inode, struct file *file, d->it_prg[d->last_buffer][d->nb_cmd-1].end.branchAddress = 0; + spin_unlock_irqrestore(&d->lock,flags); + if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { DBGMSG(ohci->id, "Starting iso transmit DMA ctx=%d", diff --git a/drivers/ieee1394/video1394.h b/drivers/ieee1394/video1394.h index dc6e5c981..00b578e51 100644 --- a/drivers/ieee1394/video1394.h +++ b/drivers/ieee1394/video1394.h @@ -22,7 +22,7 @@ #define VIDEO1394_DRIVER_NAME "video1394" -#define VIDEO1394_MAX_SIZE 0x400000 +#define VIDEO1394_MAX_SIZE 0x4000000 enum { VIDEO1394_BUFFER_FREE = 0, |