summaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-10-05 01:18:40 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-10-05 01:18:40 +0000
commit012bb3e61e5eced6c610f9e036372bf0c8def2d1 (patch)
tree87efc733f9b164e8c85c0336f92c8fb7eff6d183 /drivers/ieee1394
parent625a1589d3d6464b5d90b8a0918789e3afffd220 (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.c14
-rw-r--r--drivers/ieee1394/hosts.h4
-rw-r--r--drivers/ieee1394/ieee1394_core.c46
-rw-r--r--drivers/ieee1394/ieee1394_core.h9
-rw-r--r--drivers/ieee1394/ieee1394_syms.c12
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c57
-rw-r--r--drivers/ieee1394/ieee1394_types.h4
-rw-r--r--drivers/ieee1394/ohci1394.c222
-rw-r--r--drivers/ieee1394/ohci1394.h19
-rw-r--r--drivers/ieee1394/pcilynx.c304
-rw-r--r--drivers/ieee1394/pcilynx.h15
-rw-r--r--drivers/ieee1394/raw1394.c103
-rw-r--r--drivers/ieee1394/raw1394.h5
-rw-r--r--drivers/ieee1394/video1394.c66
-rw-r--r--drivers/ieee1394/video1394.h2
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,