patch-2.1.126 linux/drivers/net/z85230.c
Next file: linux/drivers/net/z85230.h
Previous file: linux/drivers/net/via-rhine.c
Back to the patch index
Back to the overall index
- Lines: 434
- Date:
Sat Oct 17 15:33:45 1998
- Orig file:
v2.1.125/linux/drivers/net/z85230.c
- Orig date:
Wed Sep 9 14:51:08 1998
diff -u --recursive --new-file v2.1.125/linux/drivers/net/z85230.c linux/drivers/net/z85230.c
@@ -152,8 +152,9 @@
3, ENT_HM|RxCRC_ENAB|Rx8,
5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
9, 0, /* Disable interrupts */
+ 6, 0xFF,
7, FLAG,
- 10, ABUNDER|MARKIDLE|NRZ|CRCPS,
+ 10, ABUNDER|NRZ|CRCPS,/*MARKIDLE ??*/
11, TCTRxCP,
14, DISDPLL,
15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
@@ -176,8 +177,9 @@
3, ENT_HM|RxCRC_ENAB|Rx8,
5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
9, 0, /* Disable interrupts */
+ 6, 0xFF,
7, FLAG,
- 10, ABUNDER|MARKIDLE|NRZ|CRCPS,
+ 10, ABUNDER|NRZ|CRCPS, /* MARKIDLE?? */
11, TCTRxCP,
14, DISDPLL,
15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
@@ -389,6 +391,8 @@
if(chan->rxdma_on)
{
/* Special condition check only */
+ u8 r7=read_zsreg(chan, R7);
+ u8 r6=read_zsreg(chan, R6);
u8 status=read_zsreg(chan, R1);
if(status&END_FR)
{
@@ -418,6 +422,7 @@
static void z8530_dma_status(struct z8530_channel *chan)
{
+ unsigned long flags;
u8 status=read_zsreg(chan, R0);
u8 altered=chan->status^status;
@@ -427,10 +432,12 @@
{
if(status&TxEOM)
{
+ flags=claim_dma_lock();
/* Transmit underrun */
disable_dma(chan->txdma);
clear_dma_ff(chan->txdma);
chan->txdma_on=0;
+ release_dma_lock(flags);
z8530_tx_done(chan);
}
}
@@ -461,6 +468,15 @@
EXPORT_SYMBOL(z8530_dma_sync);
+struct z8530_irqhandler z8530_txdma_sync=
+{
+ z8530_rx,
+ z8530_dma_tx,
+ z8530_dma_status
+};
+
+EXPORT_SYMBOL(z8530_txdma_sync);
+
/*
* Interrupt vectors for a Z8530 that is in 'parked' mode.
* For machines with PCI Z85x30 cards, or level triggered interrupts
@@ -566,7 +582,7 @@
irqs->status(&dev->chanB);
}
}
- if(work==200)
+ if(work==5000)
printk(KERN_ERR "%s: interrupt jammed - abort(0x%X)!\n", dev->name, intr);
/* Ok all done */
locker=0;
@@ -619,6 +635,8 @@
int z8530_sync_dma_open(struct device *dev, struct z8530_channel *c)
{
+ unsigned long flags;
+
c->sync = 1;
c->mtu = dev->mtu;
c->count = 0;
@@ -665,6 +683,7 @@
return -ENOBUFS;
}
c->tx_dma_used=0;
+ c->dma_tx = 1;
c->dma_num=0;
c->dma_ready=1;
@@ -672,13 +691,23 @@
* Enable DMA control mode
*/
- c->regs[R1]|= WT_RDY_RT|WT_FN_RDYFN;
+ /*
+ * TX DMA via DIR/REQ
+ */
+
+ c->regs[R14]|= DTRREQ;
+ write_zsreg(c, R14, c->regs[R14]);
+
+ /*
+ * RX DMA via W/Req
+ */
+
+ c->regs[R1]|= WT_FN_RDYFN;
+ c->regs[R1]|= WT_RDY_RT;
c->regs[R1]|= INT_ERR_Rx;
write_zsreg(c, R1, c->regs[R1]);
c->regs[R1]|= WT_RDY_ENAB;
write_zsreg(c, R1, c->regs[R1]);
- c->regs[R14]|= DTRREQ;
- write_zsreg(c, R14, c->regs[R14]);
/*
* DMA interrupts
@@ -688,9 +717,11 @@
* Set up the DMA configuration
*/
+ flags=claim_dma_lock();
+
disable_dma(c->rxdma);
clear_dma_ff(c->rxdma);
- set_dma_mode(c->rxdma, DMA_MODE_READ);
+ set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);
set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0]));
set_dma_count(c->rxdma, c->mtu);
enable_dma(c->rxdma);
@@ -700,6 +731,8 @@
set_dma_mode(c->txdma, DMA_MODE_WRITE);
disable_dma(c->txdma);
+ release_dma_lock(flags);
+
/*
* Select the DMA interrupt handlers
*/
@@ -719,6 +752,8 @@
int z8530_sync_dma_close(struct device *dev, struct z8530_channel *c)
{
u8 chk;
+ unsigned long flags;
+
c->irqs = &z8530_nop;
c->max = 0;
c->sync = 0;
@@ -726,12 +761,17 @@
/*
* Disable the PC DMA channels
*/
-
+
+ flags=claim_dma_lock();
disable_dma(c->rxdma);
clear_dma_ff(c->rxdma);
+
c->rxdma_on = 0;
+
disable_dma(c->txdma);
clear_dma_ff(c->txdma);
+ release_dma_lock(flags);
+
c->txdma_on = 0;
c->tx_dma_used = 0;
@@ -775,6 +815,137 @@
EXPORT_SYMBOL(z8530_sync_dma_close);
+int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c)
+{
+ printk("Opening sync interface for TX-DMA\n");
+ c->sync = 1;
+ c->mtu = dev->mtu;
+ c->count = 0;
+ c->skb = NULL;
+ c->skb2 = NULL;
+
+ /*
+ * Load the PIO receive ring
+ */
+
+ z8530_rx_done(c);
+ z8530_rx_done(c);
+
+ /*
+ * Load the DMA interfaces up
+ */
+
+ c->rxdma_on = 0;
+ c->txdma_on = 0;
+
+ c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+ if(c->tx_dma_buf[0]==NULL)
+ {
+ kfree(c->rx_buf[0]);
+ kfree(c->rx_buf[1]);
+ c->rx_buf[0]=NULL;
+ return -ENOBUFS;
+ }
+ c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+ if(c->tx_dma_buf[1]==NULL)
+ {
+ kfree(c->tx_dma_buf[0]);
+ kfree(c->rx_buf[0]);
+ kfree(c->rx_buf[1]);
+ c->rx_buf[0]=NULL;
+ c->rx_buf[1]=NULL;
+ c->tx_dma_buf[0]=NULL;
+ return -ENOBUFS;
+ }
+ c->tx_dma_used=0;
+ c->dma_num=0;
+ c->dma_ready=1;
+ c->dma_tx = 1;
+
+ /*
+ * Enable DMA control mode
+ */
+
+ /*
+ * TX DMA via DIR/REQ
+ */
+ c->regs[R14]|= DTRREQ;
+ write_zsreg(c, R14, c->regs[R14]);
+
+ /*
+ * Set up the DMA configuration
+ */
+
+ disable_dma(c->txdma);
+ clear_dma_ff(c->txdma);
+ set_dma_mode(c->txdma, DMA_MODE_WRITE);
+ disable_dma(c->txdma);
+
+ /*
+ * Select the DMA interrupt handlers
+ */
+
+ c->rxdma_on = 0;
+ c->txdma_on = 1;
+ c->tx_dma_used = 1;
+
+ c->irqs = &z8530_txdma_sync;
+ printk("Loading RX\n");
+ z8530_rtsdtr(c,1);
+ printk("Rx interrupts ON\n");
+ write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+ return 0;
+}
+
+EXPORT_SYMBOL(z8530_sync_txdma_open);
+
+int z8530_sync_txdma_close(struct device *dev, struct z8530_channel *c)
+{
+ u8 chk;
+ c->irqs = &z8530_nop;
+ c->max = 0;
+ c->sync = 0;
+
+ /*
+ * Disable the PC DMA channels
+ */
+
+ disable_dma(c->txdma);
+ clear_dma_ff(c->txdma);
+ c->txdma_on = 0;
+ c->tx_dma_used = 0;
+
+ /*
+ * Disable DMA control mode
+ */
+
+ c->regs[R1]&= ~WT_RDY_ENAB;
+ write_zsreg(c, R1, c->regs[R1]);
+ c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);
+ c->regs[R1]|= INT_ALL_Rx;
+ write_zsreg(c, R1, c->regs[R1]);
+ c->regs[R14]&= ~DTRREQ;
+ write_zsreg(c, R14, c->regs[R14]);
+
+ if(c->tx_dma_buf[0])
+ {
+ kfree(c->tx_dma_buf[0]);
+ c->tx_dma_buf[0]=NULL;
+ }
+ if(c->tx_dma_buf[1])
+ {
+ kfree(c->tx_dma_buf[1]);
+ c->tx_dma_buf[1]=NULL;
+ }
+ chk=read_zsreg(c,R0);
+ write_zsreg(c, R3, c->regs[R3]);
+ z8530_rtsdtr(c,0);
+ return 0;
+}
+
+
+EXPORT_SYMBOL(z8530_sync_txdma_close);
+
/*
* Describe a Z8530 in a standard format. We must pass the I/O as
* the port offset isnt predictable. The main reason for this function
@@ -929,7 +1100,12 @@
if(c->tx_skb==NULL)
{
/* Idle on */
- disable_dma(c->txdma);
+ if(c->txdma)
+ {
+ flags=claim_dma_lock();
+ disable_dma(c->txdma);
+ release_dma_lock(flags);
+ }
c->txcount=0;
}
else
@@ -938,19 +1114,22 @@
c->txcount=c->tx_skb->len;
- if(c->tx_dma_used)
+ if(c->dma_tx)
{
/*
- * FIXME. DMA is broken for the non 85230,
+ * FIXME. DMA is broken for the original 8530,
* on the older parts we need to set a flag and
* wait for a further TX interrupt to fire this
* stage off
*/
+
+ flags=claim_dma_lock();
disable_dma(c->txdma);
clear_dma_ff(c->txdma);
set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr));
set_dma_count(c->txdma, c->txcount);
enable_dma(c->txdma);
+ release_dma_lock(flags);
write_zsreg(c, R5, c->regs[R5]|TxENAB);
}
else
@@ -1020,16 +1199,21 @@
* Save the ready state and the buffer currently
* being used as the DMA target
*/
+
int ready=c->dma_ready;
- char *rxb=c->rx_buf[c->dma_num];
+ unsigned char *rxb=c->rx_buf[c->dma_num];
+ unsigned long flags;
/*
* Complete this DMA. Neccessary to find the length
*/
+
+ flags=claim_dma_lock();
+
disable_dma(c->rxdma);
clear_dma_ff(c->rxdma);
c->rxdma_on=0;
- ct=c->mtu-get_dma_residue(c->rxdma)-4;
+ ct=c->mtu-get_dma_residue(c->rxdma);
if(ct<0)
ct=2; /* Shit happens.. */
c->dma_ready=0;
@@ -1042,16 +1226,21 @@
if(ready)
{
c->dma_num^=1;
- set_dma_mode(c->rxdma, DMA_MODE_READ);
+ set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);
set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num]));
set_dma_count(c->rxdma, c->mtu);
c->rxdma_on = 1;
enable_dma(c->rxdma);
+ /* Stop any frames that we missed the head of
+ from passing */
+ write_zsreg(c, R0, RES_Rx_CRC);
}
else
/* Can't occur as we dont reenable the DMA irq until
after the flip is done */
printk("DMA flip overrun!\n");
+
+ release_dma_lock(flags);
/*
* Shove the old buffer into an sk_buff. We can't DMA
@@ -1068,7 +1257,6 @@
{
skb_put(skb, ct);
memcpy(skb->data, rxb, ct);
- skb_pull(skb,2);
}
c->dma_ready=1;
}
@@ -1127,6 +1315,21 @@
printk("Lost a frame\n");
}
+/*
+ * Cannot DMA over a 64K boundary on a PC
+ */
+
+extern inline int spans_boundary(struct sk_buff *skb)
+{
+ unsigned long a=(unsigned long)skb->data;
+ a^=(a+skb->len);
+ if(a&0x00010000) /* If the 64K bit is different.. */
+ {
+ printk("spanner\n");
+ return 1;
+ }
+ return 0;
+}
/*
* Queue a packet for transmission. Because we have rather
@@ -1151,7 +1354,7 @@
* limit, then copy to the flip buffer
*/
- if(c->dma_tx && (unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024)
+ if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb)))
{
/*
* Send the flip buffer, and flip the flippy bit.
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov