patch-2.4.2 linux/drivers/net/tokenring/tms380tr.c

Next file: linux/drivers/net/tokenring/tms380tr.h
Previous file: linux/drivers/net/tokenring/smctr.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.1/linux/drivers/net/tokenring/tms380tr.c linux/drivers/net/tokenring/tms380tr.c
@@ -8,18 +8,12 @@
  *  http://www.linux-sna.org
  *
  *  This software may be used and distributed according to the terms
- *  of the GNU Public License, incorporated herein by reference.
+ *  of the GNU General Public License, incorporated herein by reference.
  *
  *  The following modules are currently available for card support:
  *	- tmspci (Generic PCI card support)
  *	- abyss (Madge PCI support)
- *  
- *  The following cards are currently lacking support, even
- *  though they were supported in previous versions, because
- *  their code did not get migrated into a seperate module:
- *	- SysKonnect TR4/16(+) ISA	(SK-4190)
- *  They are no longer supported by this driver, at least until
- *  a module gets written for them.
+ *      - tmsisa (SysKonnect TR4/16 ISA)
  *
  *  Sources:
  *  	- The hardware related parts of this driver are take from
@@ -38,6 +32,7 @@
  *    CG	Christoph Goos		cgoos@syskonnect.de
  *    AF	Adam Fritzler		mid@auk.cx
  *    MLP       Mike Phillips           phillim@amtrak.com
+ *    JF	Jochen Friedrich	jochen@scram.de
  *     
  *  Modification History:
  *	29-Aug-97	CG	Created
@@ -57,10 +52,15 @@
  *	30-Dec-99	AF	Turned tms380tr into a library ala 8390.
  *				Madge support is provided in the abyss module
  *				Generic PCI support is in the tmspci module.
- *
+ *	30-Nov-00	JF	Updated PCI code to support IO MMU via
+ *				pci_map_static(). Alpha uses this MMU for ISA
+ *				as well.
+ *      14-Jan-01	JF	Fix DMA on ifdown/ifup sequences. Some 
+ *      			cleanup.
+ *      			
  *  To do:
  *    1. Multi/Broadcast packet handling (this may have fixed itself)
- *    2. Write a sktrisa module that includes the old ISA support
+ *    2. Write a sktrisa module that includes the old ISA support (done)
  *    3. Allow modules to load their own microcode
  *    4. Speed up the BUD process -- freezing the kernel for 3+sec is
  *         quite unacceptable.
@@ -68,7 +68,7 @@
  */
 
 #ifdef MODULE
-static const char *version = "tms380tr.c: v1.07 21/01/2000 by Christoph Goos, Adam Fritzler\n";
+static const char *version = "tms380tr.c: v1.08 14/01/2001 by Christoph Goos, Adam Fritzler\n";
 #endif
 
 #ifdef MODULE
@@ -84,7 +84,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/time.h>
 #include <asm/system.h>
@@ -125,9 +125,6 @@
 static void	tms380tr_cancel_tx_queue(struct net_local* tp);
 static int 	tms380tr_chipset_init(struct net_device *dev);
 static void 	tms380tr_chk_irq(struct net_device *dev);
-#if 0
-static unsigned char tms380tr_chk_frame(struct net_device *dev, unsigned char *Addr);
-#endif
 static void 	tms380tr_chk_outstanding_cmds(struct net_device *dev);
 static void 	tms380tr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr);
 static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqType);
@@ -191,7 +188,7 @@
 
 
 
-#if TMS380TR_DEBUG > 0
+#if 0 /* TMS380TR_DEBUG > 0 */
 static int madgemc_sifprobe(struct net_device *dev)
 {
         unsigned char old, chk1, chk2;
@@ -259,6 +256,16 @@
 	int err;
 	
 	/* Reset the hardware here. Don't forget to set the station address. */
+
+	if(dev->dma > 0) 
+	{
+		unsigned long flags=claim_dma_lock();
+		disable_dma(dev->dma);
+		set_dma_mode(dev->dma, DMA_MODE_CASCADE);
+		enable_dma(dev->dma);
+		release_dma_lock(flags);
+	}
+	
 	err = tms380tr_chipset_init(dev);
   	if(err)
 	{
@@ -275,6 +282,7 @@
 
 	printk(KERN_INFO "%s: Adapter RAM size: %dK\n", 
 	       dev->name, tms380tr_read_ptr(dev));
+
 	tms380tr_enable_interrupts(dev);
 	tms380tr_open_adapter(dev);
 
@@ -334,18 +342,26 @@
 	tms380tr_init_opb(dev);
 	tms380tr_init_net_local(dev);
 
+	if(tms380tr_debug > 3)
+		printk(KERN_INFO "%s: Resetting adapter...\n", dev->name);
 	err = tms380tr_reset_adapter(dev);
 	if(err < 0)
 		return (-1);
 
+	if(tms380tr_debug > 3)
+		printk(KERN_INFO "%s: Bringup diags...\n", dev->name);
 	err = tms380tr_bringup_diags(dev);
 	if(err < 0)
 		return (-1);
 
+	if(tms380tr_debug > 3)
+		printk(KERN_INFO "%s: Init adapter...\n", dev->name);
 	err = tms380tr_init_adapter(dev);
 	if(err < 0)
 		return (-1);
 
+	if(tms380tr_debug > 3)
+		printk(KERN_INFO "%s: Done!\n", dev->name);
 	return (0);
 }
 
@@ -356,6 +372,7 @@
 {
 	struct net_local *tp = (struct net_local *)dev->priv;
 	int i;
+	dma_addr_t dmabuf;
 
 	tp->scb.CMD	= 0;
 	tp->scb.Parm[0] = 0;
@@ -381,11 +398,11 @@
 
 	skb_queue_head_init(&tp->SendSkbQueue);
 	tp->QueueSkb = MAX_TX_QUEUE;
-	
+
 	/* Create circular chain of transmit lists */
 	for (i = 0; i < TPL_NUM; i++)
 	{
-		tp->Tpl[i].NextTPLAddr = htonl((unsigned long) virt_to_bus(&tp->Tpl[(i+1) % TPL_NUM]));
+		tp->Tpl[i].NextTPLAddr = htonl(((char *)(&tp->Tpl[(i+1) % TPL_NUM]) - (char *)tp) + tp->dmabuffer); /* DMA buffer may be MMU driven */
 		tp->Tpl[i].Status	= 0;
 		tp->Tpl[i].FrameSize	= 0;
 		tp->Tpl[i].FragList[0].DataCount	= 0;
@@ -393,6 +410,7 @@
 		tp->Tpl[i].NextTPLPtr	= &tp->Tpl[(i+1) % TPL_NUM];
 		tp->Tpl[i].MData	= NULL;
 		tp->Tpl[i].TPLIndex	= i;
+		tp->Tpl[i].DMABuff	= 0;
 		tp->Tpl[i].BusyFlag	= 0;
 	}
 
@@ -401,19 +419,20 @@
 	/* Create circular chain of receive lists */
 	for (i = 0; i < RPL_NUM; i++)
 	{
-		tp->Rpl[i].NextRPLAddr = htonl((unsigned long) virt_to_bus(&tp->Rpl[(i+1) % RPL_NUM]));
+		tp->Rpl[i].NextRPLAddr = htonl(((char *)(&tp->Rpl[(i+1) % RPL_NUM]) - (char *)tp) + tp->dmabuffer); /* DMA buffer may be MMU driven */
 		tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);
 		tp->Rpl[i].FrameSize = 0;
 		tp->Rpl[i].FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize);
 
 		/* Alloc skb and point adapter to data area */
 		tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize);
+			tp->Rpl[i].DMABuff = 0;
 
 		/* skb == NULL ? then use local buffer */
 		if(tp->Rpl[i].Skb == NULL)
 		{
 			tp->Rpl[i].SkbStat = SKB_UNAVAILABLE;
-			tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
+			tp->Rpl[i].FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[i] - (char *)tp) + tp->dmabuffer);
 			tp->Rpl[i].MData = tp->LocalRxBuffers[i];
 		}
 		else	/* SKB != NULL */
@@ -422,17 +441,19 @@
 			skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize);
 
 			/* data unreachable for DMA ? then use local buffer */
-			if(tp->dmalimit && virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > tp->dmalimit)
+			dmabuf = pci_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE);
+			if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit))
 			{
 				tp->Rpl[i].SkbStat = SKB_DATA_COPY;
-				tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
+				tp->Rpl[i].FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[i] - (char *)tp) + tp->dmabuffer);
 				tp->Rpl[i].MData = tp->LocalRxBuffers[i];
 			}
 			else	/* DMA directly in skb->data */
 			{
 				tp->Rpl[i].SkbStat = SKB_DMA_DIRECT;
-				tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->Rpl[i].Skb->data));
+				tp->Rpl[i].FragList[0].DataAddr = htonl(dmabuf);
 				tp->Rpl[i].MData = tp->Rpl[i].Skb->data;
+				tp->Rpl[i].DMABuff = dmabuf;
 			}
 		}
 
@@ -506,7 +527,7 @@
 	tp->ocpl.TXBufMin	 = TX_BUF_MIN;
 	tp->ocpl.TXBufMax	 = TX_BUF_MAX;
 
-	Addr = htonl(virt_to_bus(tp->ProductID));
+	Addr = htonl(((char *)tp->ProductID - (char *)tp) + tp->dmabuffer);
 
 	tp->ocpl.ProdIDAddr[0]	 = LOWORD(Addr);
 	tp->ocpl.ProdIDAddr[1]	 = HIWORD(Addr);
@@ -610,10 +631,11 @@
 {
 	TPL *tpl;
 	short length;
-	unsigned char *buf, *newbuf;
+	unsigned char *buf;
 	struct sk_buff *skb;
 	int i;
-    
+	dma_addr_t dmabuf, newbuf;
+   
 	for(;;)
 	{
 		/* Try to get a free TPL from the chain.
@@ -634,26 +656,30 @@
 			return;
 
 		tp->QueueSkb++;
+		dmabuf = 0;
+
 		/* Is buffer reachable for Busmaster-DMA? */
-		if(tp->dmalimit && virt_to_bus((void*)(((long) skb->data) + skb->len)) > tp->dmalimit)
+
+		length	= skb->len;
+		dmabuf = pci_map_single(tp->pdev, skb->data, length, PCI_DMA_TODEVICE);
+		if(tp->dmalimit && (dmabuf + length > tp->dmalimit))
 		{
 			/* Copy frame to local buffer */
+			pci_unmap_single(tp->pdev, dmabuf, length, PCI_DMA_TODEVICE);
+			dmabuf  = 0;
 			i 	= tp->TplFree->TPLIndex;
-			length 	= skb->len;
 			buf 	= tp->LocalTxBuffers[i];
 			memcpy(buf, skb->data, length);
-			newbuf 	= buf;
+			newbuf 	= ((char *)buf - (char *)tp) + tp->dmabuffer;
 		}
 		else
 		{
 			/* Send direct from skb->data */
-			length = skb->len;
-			newbuf = skb->data;
+			newbuf	= dmabuf;
+			buf	= skb->data;
 		}
-
 		/* Source address in packet? */
-		tms380tr_chk_src_addr(newbuf, dev->dev_addr);
-
+		tms380tr_chk_src_addr(buf, dev->dev_addr);
 		tp->LastSendTime	= jiffies;
 		tpl 			= tp->TplFree;	/* Get the "free" TPL */
 		tpl->BusyFlag 		= 1;		/* Mark TPL as busy */
@@ -661,12 +687,13 @@
     
 		/* Save the skb for delayed return of skb to system */
 		tpl->Skb = skb;
+		tpl->DMABuff = dmabuf;
 		tpl->FragList[0].DataCount = cpu_to_be16((unsigned short)length);
-		tpl->FragList[0].DataAddr  = htonl(virt_to_bus(newbuf));
+		tpl->FragList[0].DataAddr  = htonl(newbuf);
 
 		/* Write the data length in the transmit list. */
 		tpl->FrameSize 	= cpu_to_be16((unsigned short)length);
-		tpl->MData 	= newbuf;
+		tpl->MData 	= buf;
 
 		/* Transmit the frame and set the status values. */
 		tms380tr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME
@@ -1155,9 +1182,10 @@
 	}
 	
 	SIFWRITEW(0xFF00, SIFCMD);
+#if 0
 	if(dev->dma > 0) /* what the? */
 		SIFWRITEB(0xff, POSREG);
-
+#endif
 	tms380tr_cancel_tx_queue(tp);
 
 	return (0);
@@ -1331,6 +1359,7 @@
 		}
 	} while(count == 0);
 
+	printk(KERN_INFO "%s: Adapter Download Failed\n", dev->name);
 	return (-1);
 }
 
@@ -1381,6 +1410,7 @@
 
 	Status = SIFREADW(SIFSTS);
 	
+	printk(KERN_INFO "%s: Hardware error\n", dev->name);
 	/* Hardware error occurred! */
 	Status &= 0x001f;
 	if (Status & 0x0010)
@@ -1412,9 +1442,16 @@
 	int i, loop_cnt, retry_cnt;
 
 	/* Normalize: byte order low/high, word order high/low! (only IPB!) */
-	tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb));
-	tp->ipb.SSB_Addr = SWAPW(virt_to_bus(&tp->ssb));
+	tp->ipb.SCB_Addr = SWAPW(((char *)&tp->scb - (char *)tp) + tp->dmabuffer);
+	tp->ipb.SSB_Addr = SWAPW(((char *)&tp->ssb - (char *)tp) + tp->dmabuffer);
 
+	if(tms380tr_debug > 3)
+	{
+		printk(KERN_INFO "%s: buffer (real): %lx\n", dev->name, (long) &tp->scb);
+		printk(KERN_INFO "%s: buffer (virt): %lx\n", dev->name, (long) ((char *)&tp->scb - (char *)tp) + tp->dmabuffer);
+		printk(KERN_INFO "%s: buffer (DMA) : %lx\n", dev->name, (long) tp->dmabuffer);
+		printk(KERN_INFO "%s: buffer (tp)  : %lx\n", dev->name, (long) tp);
+	}
 	/* Maximum: three initialization retries */
 	retry_cnt = INIT_MAX_RETRIES;
 
@@ -1454,8 +1491,11 @@
 			i = 0;
 			do {	/* Test if contents of SCB is valid */
 				if(SCB_Test[i] != *(cb_ptr + i))
+				{
+					printk(KERN_INFO "%s: DMA failed\n", dev->name);
 					/* DMA data error: wrong data in SCB */
 					return (-1);
+				}
 				i++;
 			} while(i < 6);
 
@@ -1477,6 +1517,7 @@
 				Status = SIFREADW(SIFSTS);
 				Status &= STS_ERROR_MASK;
 				/* ShowInitialisationErrorCode(Status); */
+				printk(KERN_INFO "%s: Status error: %d\n", dev->name, Status);
 				return (-1); /* Unrecoverable error */
 			}
 			else
@@ -1491,6 +1532,7 @@
 		}
 	} while(retry_cnt > 0);
 
+	printk(KERN_INFO "%s: Retry exceeded\n", dev->name);
 	return (-1);
 }
 
@@ -1520,7 +1562,7 @@
 			/* Execute OPEN command	*/
 			tp->CMDqueue ^= OC_OPEN;
 
-			Addr = htonl(virt_to_bus(&tp->ocpl));
+			Addr = htonl(((char *)&tp->ocpl - (char *)tp) + tp->dmabuffer);
 			tp->scb.Parm[0] = LOWORD(Addr);
 			tp->scb.Parm[1] = HIWORD(Addr);
 			tp->scb.CMD = OPEN;
@@ -1554,7 +1596,7 @@
 			if(tp->CMDqueue & OC_RECEIVE)
 			{
 				tp->CMDqueue ^= OC_RECEIVE;
-				Addr = htonl(virt_to_bus(tp->RplHead));
+				Addr = htonl(((char *)tp->RplHead - (char *)tp) + tp->dmabuffer);
 				tp->scb.Parm[0] = LOWORD(Addr);
 				tp->scb.Parm[1] = HIWORD(Addr);
 				tp->scb.CMD = RECEIVE;
@@ -1595,7 +1637,7 @@
 
 						tp->CMDqueue ^= OC_TRANSMIT;
 						tms380tr_cancel_tx_queue(tp);
-						Addr = htonl(virt_to_bus(tp->TplBusy));
+						Addr = htonl(((char *)tp->TplBusy - (char *)tp) + tp->dmabuffer);
 						tp->scb.Parm[0] = LOWORD(Addr);
 						tp->scb.Parm[1] = HIWORD(Addr);
 						tp->scb.CMD = TRANSMIT;
@@ -1634,7 +1676,7 @@
 									if(tp->CMDqueue & OC_READ_ERROR_LOG)
 									{
 										tp->CMDqueue ^= OC_READ_ERROR_LOG;
-										Addr = htonl(virt_to_bus(&tp->errorlogtable));
+										Addr = htonl(((char *)&tp->errorlogtable - (char *)tp) + tp->dmabuffer);
 										tp->scb.Parm[0] = LOWORD(Addr);
 										tp->scb.Parm[1] = HIWORD(Addr);
 										tp->scb.CMD = READ_ERROR_LOG;
@@ -1976,8 +2018,9 @@
 		tpl->BusyFlag = 0;		/* "free" TPL */
 
 		printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl);
-
-		dev_kfree_skb(tpl->Skb);
+		if (tpl->DMABuff)
+			pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_any(tpl->Skb);
 	}
 
 	for(;;)
@@ -1986,7 +2029,7 @@
 		if(skb == NULL)
 			break;
 		tp->QueueSkb++;
-		dev_kfree_skb(skb);
+		dev_kfree_skb_any(skb);
 	}
 
 	return;
@@ -2053,7 +2096,9 @@
 		}
 
 		tp->MacStat.tx_packets++;
-		dev_kfree_skb(tpl->Skb);
+		if (tpl->DMABuff)
+			pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_irq(tpl->Skb);
 		tpl->BusyFlag = 0;	/* "free" TPL */
 	}
 
@@ -2075,6 +2120,7 @@
 	unsigned int Length, Length2;
 	RPL *rpl;
 	RPL *SaveHead;
+	dma_addr_t dmabuf;
 
 	/* NOTE: At this point the SSB from RECEIVE STATUS is no longer
 	 * available, because the CLEAR SSB command has already been issued.
@@ -2118,81 +2164,68 @@
 				tp->RplHead = SaveHead;
 				break;	/* Return to tms380tr_interrupt */
 			}
-#if 0  		/* This might happen for multicast or broadcast packets.
-		   The upper layers are expected to handle this, not here */
-
-			/* Drop frames sent by myself */
-			if(tms380tr_chk_frame(dev, rpl->MData))
-			{
-				printk(KERN_INFO "%s: Received my own frame\n",
-					dev->name);
-				if(rpl->Skb != NULL)
-					dev_kfree_skb(rpl->Skb);
-			}
-			else
-#endif
-			{
-			  tms380tr_update_rcv_stats(tp,ReceiveDataPtr,Length);
+			tms380tr_update_rcv_stats(tp,ReceiveDataPtr,Length);
 			  
-			  if(tms380tr_debug > 3)
-			    printk("%s: Packet Length %04X (%d)\n",
-				   dev->name, Length, Length);
+			if(tms380tr_debug > 3)
+				printk("%s: Packet Length %04X (%d)\n",
+					dev->name, Length, Length);
 			  
-				/* Indicate the received frame to system the
-				 * adapter does the Source-Routing padding for 
-				 * us. See: OpenOptions in tms380tr_init_opb()
-				 */
-				skb = rpl->Skb;
-				if(rpl->SkbStat == SKB_UNAVAILABLE)
+			/* Indicate the received frame to system the
+			 * adapter does the Source-Routing padding for 
+			 * us. See: OpenOptions in tms380tr_init_opb()
+			 */
+			skb = rpl->Skb;
+			if(rpl->SkbStat == SKB_UNAVAILABLE)
+			{
+				/* Try again to allocate skb */
+				skb = dev_alloc_skb(tp->MaxPacketSize);
+				if(skb == NULL)
 				{
-					/* Try again to allocate skb */
-					skb = dev_alloc_skb(tp->MaxPacketSize);
-					if(skb == NULL)
-					{
-						/* Update Stats ?? */
-					}
-					else
-					{
-						skb->dev	= dev;
-						skb_put(skb, tp->MaxPacketSize);
-						rpl->SkbStat 	= SKB_DATA_COPY;
-						ReceiveDataPtr 	= rpl->MData;
-					}
+					/* Update Stats ?? */
 				}
-
-				if(rpl->SkbStat == SKB_DATA_COPY
-					|| rpl->SkbStat == SKB_DMA_DIRECT)
+				else
 				{
-					if(rpl->SkbStat == SKB_DATA_COPY)
-						memmove(skb->data, ReceiveDataPtr, Length);
-
-					/* Deliver frame to system */
-					rpl->Skb = NULL;
-					skb_trim(skb,Length);
-					skb->protocol = tr_type_trans(skb,dev);
-					netif_rx(skb);
+					skb->dev	= dev;
+					skb_put(skb, tp->MaxPacketSize);
+					rpl->SkbStat 	= SKB_DATA_COPY;
+					ReceiveDataPtr 	= rpl->MData;
 				}
 			}
+
+			if(rpl->SkbStat == SKB_DATA_COPY
+				|| rpl->SkbStat == SKB_DMA_DIRECT)
+			{
+				if(rpl->SkbStat == SKB_DATA_COPY)
+					memmove(skb->data, ReceiveDataPtr, Length);
+
+				/* Deliver frame to system */
+				rpl->Skb = NULL;
+				skb_trim(skb,Length);
+				skb->protocol = tr_type_trans(skb,dev);
+				netif_rx(skb);
+			}
 		}
 		else	/* Invalid frame */
 		{
 			if(rpl->Skb != NULL)
-				dev_kfree_skb(rpl->Skb);
+				dev_kfree_skb_irq(rpl->Skb);
 
 			/* Skip list. */
 			if(rpl->Status & RX_START_FRAME)
 				/* Frame start bit is set -> overflow. */
 				tp->MacStat.rx_errors++;
 		}
+		if (rpl->DMABuff)
+			pci_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, PCI_DMA_TODEVICE);
+		rpl->DMABuff = 0;
 
 		/* Allocate new skb for rpl */
 		rpl->Skb = dev_alloc_skb(tp->MaxPacketSize);
-
 		/* skb == NULL ? then use local buffer */
 		if(rpl->Skb == NULL)
 		{
 			rpl->SkbStat = SKB_UNAVAILABLE;
-			rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));
+			rpl->FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[rpl->RPLIndex] - (char *)tp) + tp->dmabuffer);
 			rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];
 		}
 		else	/* skb != NULL */
@@ -2201,18 +2234,20 @@
 			skb_put(rpl->Skb, tp->MaxPacketSize);
 
 			/* Data unreachable for DMA ? then use local buffer */
-			if(tp->dmalimit && virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize > tp->dmalimit)
+			dmabuf = pci_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE);
+			if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit))
 			{
 				rpl->SkbStat = SKB_DATA_COPY;
-				rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));
+				rpl->FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[rpl->RPLIndex] - (char *)tp) + tp->dmabuffer);
 				rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];
 			}
 			else
 			{
 				/* DMA directly in skb->data */
 				rpl->SkbStat = SKB_DMA_DIRECT;
-				rpl->FragList[0].DataAddr = htonl(virt_to_bus(rpl->Skb->data));
+				rpl->FragList[0].DataAddr = htonl(dmabuf);
 				rpl->MData = rpl->Skb->data;
+				rpl->DMABuff = dmabuf;
 			}
 		}
 
@@ -2267,29 +2302,6 @@
 	return;
 }
 
-#if 0
-/*
- * Check if it is a frame of myself. Compare source address with my current
- * address in reverse direction, and mask out the TR_RII.
- */
-static unsigned char tms380tr_chk_frame(struct net_device *dev, unsigned char *Addr)
-{
-	int i;
-
-	for(i = 5; i > 0; i--)
-	{
-		if(Addr[8 + i] != dev->dev_addr[i])
-			return (0);
-	}
-
-	/* Mask out RIF bit. */
-	if((Addr[8] & ~TR_RII) != (unsigned char)(dev->dev_addr[0]))
-		return (0);
-
-	return (1);  /* It is my frame. */
-}
-#endif
-
 static int tms380tr_set_mac_address(struct net_device *dev, void *addr)
 {
 	struct net_local *tp = (struct net_local *)dev->priv;
@@ -2322,18 +2334,46 @@
 }
 #endif
 
-int tmsdev_init(struct net_device *dev)
+void tmsdev_term(struct net_device *dev)
+{
+	struct net_local *tp;
+
+	tp = (struct net_local *) dev->priv;
+	pci_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local),
+		PCI_DMA_BIDIRECTIONAL);
+	kfree(dev->priv);
+}
+
+int tmsdev_init(struct net_device *dev, unsigned long dmalimit, 
+		struct pci_dev *pdev)
 {
 	if (dev->priv == NULL)
 	{
 		struct net_local *tms_local;
+		dma_addr_t buffer;
 		
 		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA);
 		if (dev->priv == NULL)
+		{
+                        printk("%s: Out of memory for DMA\n",
+                                dev->name);
 			return -ENOMEM;
+		}
 		memset(dev->priv, 0, sizeof(struct net_local));
 		tms_local = (struct net_local *)dev->priv;
 		init_waitqueue_head(&tms_local->wait_for_tok_int);
+		tms_local->dmalimit = dmalimit;
+		tms_local->pdev = pdev;
+                buffer = pci_map_single(pdev, (void *)tms_local,
+                        sizeof(struct net_local), PCI_DMA_BIDIRECTIONAL);
+                if (buffer + sizeof(struct net_local) > dmalimit)
+                {
+			printk("%s: Memory not accessible for DMA\n",
+				dev->name);
+			tmsdev_term(dev);
+			return -ENOMEM;
+		}
+		tms_local->dmabuffer = buffer;
 	}
 	
 	/* These can be overridden by the card driver if needed */
@@ -2357,6 +2397,7 @@
 EXPORT_SYMBOL(tms380tr_close);
 EXPORT_SYMBOL(tms380tr_interrupt);
 EXPORT_SYMBOL(tmsdev_init);
+EXPORT_SYMBOL(tmsdev_term);
 EXPORT_SYMBOL(tms380tr_wait);
 
 struct module *TMS380_module = NULL;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)