patch-2.4.19 linux-2.4.19/drivers/net/tokenring/lanstreamer.c

Next file: linux-2.4.19/drivers/net/tokenring/lanstreamer.h
Previous file: linux-2.4.19/drivers/net/tokenring/Makefile
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/drivers/net/tokenring/lanstreamer.c linux-2.4.19/drivers/net/tokenring/lanstreamer.c
@@ -60,6 +60,11 @@
  *		malloc free checks, reviewed code. <alan@redhat.com>
  *  03/13/00 - Added spinlocks for smp
  *  03/08/01 - Added support for module_init() and module_exit()
+ *  08/15/01 - Added ioctl() functionality for debugging, changed netif_*_queue
+ *             calls and other incorrectness - Kent Yoder <yoder1@us.ibm.com>
+ *  11/05/01 - Restructured the interrupt function, added delays, reduced the 
+ *             the number of TX descriptors to 1, which together can prevent 
+ *             the card from locking up the box - <yoder1@us.ibm.com>
  *  
  *  To Do:
  *
@@ -84,6 +89,14 @@
 
 #define STREAMER_NETWORK_MONITOR 0
 
+/* #define CONFIG_PROC_FS */
+
+/*
+ *  Allow or disallow ioctl's for debugging
+ */
+
+#define STREAMER_IOCTL 0
+
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -105,6 +118,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
+#include <linux/version.h>
 #include <net/checksum.h>
 
 #include <asm/io.h>
@@ -121,7 +135,8 @@
  * Official releases will only have an a.b.c version number format.
  */
 
-static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan";
+static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n"
+                        "              v0.5.1 03/04/02 - Kent Yoder";
 
 static struct pci_device_id streamer_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
@@ -175,6 +190,10 @@
 MODULE_PARM(message_level,
 	    "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i");
 
+#if STREAMER_IOCTL
+static int streamer_ioctl(struct net_device *, struct ifreq *, int);
+#endif
+
 static int streamer_reset(struct net_device *dev);
 static int streamer_open(struct net_device *dev);
 static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -206,6 +225,8 @@
   __u32 mmio_start, mmio_end, mmio_flags, mmio_len;
   int rc=0;
   static int card_no=-1;
+  u16 pcr;
+  u8 cls = 0;
 
 #if STREAMER_DEBUG
   printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev);
@@ -281,7 +302,11 @@
 			dev->hard_start_xmit = &streamer_xmit;
 			dev->change_mtu = &streamer_change_mtu;
 			dev->stop = &streamer_close;
+#if STREAMER_IOCTL
+			dev->do_ioctl = &streamer_ioctl;
+#else
 			dev->do_ioctl = NULL;
+#endif
 			dev->set_multicast_list = &streamer_set_rx_mode;
 			dev->get_stats = &streamer_get_stats;
 			dev->set_mac_address = &streamer_set_mac_address;
@@ -303,6 +328,27 @@
 
   spin_lock_init(&streamer_priv->streamer_lock);
   
+  pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
+  cls <<= 2;
+  if (cls != SMP_CACHE_BYTES) {
+         printk(KERN_INFO "  PCI cache line size set incorrectly "
+                "(%i bytes) by BIOS/FW, ", cls);
+         if (cls > SMP_CACHE_BYTES)
+                printk("expecting %i\n", SMP_CACHE_BYTES);
+         else {
+                printk("correcting to %i\n", SMP_CACHE_BYTES);
+                pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+                                      SMP_CACHE_BYTES >> 2);
+         }
+  }
+
+  pci_read_config_word (pdev, PCI_COMMAND, &pcr);
+
+  pcr |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_SERR);
+
+  pci_write_config_word (pdev, PCI_COMMAND, pcr);
+  pci_read_config_word (pdev, PCI_COMMAND, &pcr);
+
   printk("%s \n", version);
   printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name,
 	 streamer_priv->streamer_card_name,
@@ -403,6 +449,7 @@
 	printk("GPR: %x\n", readw(streamer_mmio + GPR));
 	printk("SISRMASK: %x\n", readw(streamer_mmio + SISR_MASK));
 #endif
+	writew(readw(streamer_mmio + BCTL) | (BCTL_RX_FIFO_8 | BCTL_TX_FIFO_8), streamer_mmio + BCTL );
 
 	if (streamer_priv->streamer_ring_speed == 0) {	/* Autosense */
 		writew(readw(streamer_mmio + GPR) | GPR_AUTOSENSE,
@@ -558,8 +605,6 @@
 	do {
 		int i;
 
-		save_flags(flags);
-		cli();
 		for (i = 0; i < SRB_COMMAND_SIZE; i += 2) {
 			writew(0, streamer_mmio + LAPDINC);
 		}
@@ -599,11 +644,12 @@
 		}
 		printk("\n");
 #endif
-
+		spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
 		streamer_priv->srb_queued = 1;
 
 		/* signal solo that SRB command has been issued */
 		writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
+		spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags);
 
 		while (streamer_priv->srb_queued) {
 			interruptible_sleep_on_timeout(&streamer_priv->srb_wait, 5 * HZ);
@@ -617,7 +663,6 @@
 				break;
 			}
 		}
-		restore_flags(flags);
 
 #if STREAMER_DEBUG
 		printk("SISR_MASK: %x\n", readw(streamer_mmio + SISR_MASK));
@@ -767,9 +812,12 @@
 		streamer_priv->streamer_tx_ring[i].bufcnt_framelen = 0;
 		streamer_priv->streamer_tx_ring[i].buffer = 0;
 		streamer_priv->streamer_tx_ring[i].buflen = 0;
+		streamer_priv->streamer_tx_ring[i].rsvd1 = 0;
+		streamer_priv->streamer_tx_ring[i].rsvd2 = 0;
+		streamer_priv->streamer_tx_ring[i].rsvd3 = 0;
 	}
 	streamer_priv->streamer_tx_ring[STREAMER_TX_RING_SIZE - 1].forward =
-					virt_to_bus(&streamer_priv->streamer_tx_ring[0]);;
+					virt_to_bus(&streamer_priv->streamer_tx_ring[0]);
 
 	streamer_priv->free_tx_ring_entries = STREAMER_TX_RING_SIZE;
 	streamer_priv->tx_ring_free = 0;	/* next entry in tx ring to use */
@@ -941,37 +989,30 @@
 	__u8 *streamer_mmio = streamer_priv->streamer_mmio;
 	__u16 sisr;
 	__u16 misr;
-	__u16 sisrmask;
+	u8 max_intr = MAX_INTR;
 
-	sisrmask = SISR_MI;
-	writew(~sisrmask, streamer_mmio + SISR_MASK_RUM);
+	spin_lock(&streamer_priv->streamer_lock);
 	sisr = readw(streamer_mmio + SISR);
-	writew(~sisr, streamer_mmio + SISR_RUM);
-	misr = readw(streamer_mmio + MISR_RUM);
-	writew(~misr, streamer_mmio + MISR_RUM);
 
-	if (!sisr) 
-	{		/* Interrupt isn't for us */
-  	        writew(~misr,streamer_mmio+MISR_RUM);
-		return;
-	}
+	while((sisr & (SISR_MI | SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | 
+		       SISR_ARB_CMD | SISR_TRB_REPLY | SISR_PAR_ERR | SISR_SERR_ERR))
+               && (max_intr > 0)) {
 
-	spin_lock(&streamer_priv->streamer_lock);
+		if(sisr & SISR_PAR_ERR) {
+			writew(~SISR_PAR_ERR, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
+		}
 
-	if ((sisr & (SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY))
-	    || (misr & (MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF))) {
-		if (sisr & SISR_SRB_REPLY) {
-			if (streamer_priv->srb_queued == 1) {
-				wake_up_interruptible(&streamer_priv->srb_wait);
-			} else if (streamer_priv->srb_queued == 2) {
-				streamer_srb_bh(dev);
-			}
-			streamer_priv->srb_queued = 0;
+		else if(sisr & SISR_SERR_ERR) {
+			writew(~SISR_SERR_ERR, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
-		/* SISR_SRB_REPLY */
+
+		else if(sisr & SISR_MI) {
+			misr = readw(streamer_mmio + MISR_RUM);
+
 		if (misr & MISR_TX2_EOF) {
-			while (streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) 
-			{
+				while(streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) {
 				streamer_priv->tx_ring_last_status = (streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1);
 				streamer_priv->free_tx_ring_entries++;
 				streamer_priv->streamer_stats.tx_bytes += streamer_priv->tx_ring_skb[streamer_priv->tx_ring_last_status]->len;
@@ -981,6 +1022,9 @@
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].status = 0;
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].bufcnt_framelen = 0;
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].buflen = 0;
+				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd1 = 0;
+				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd2 = 0;
+				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd3 = 0;
 			}
 			netif_wake_queue(dev);
 		}
@@ -989,7 +1033,30 @@
 			streamer_rx(dev);
 		}
 		/* MISR_RX_EOF */
-		if (sisr & SISR_ADAPTER_CHECK) {
+
+			if (misr & MISR_RX_NOBUF) {
+				/* According to the documentation, we don't have to do anything,  
+                                 * but trapping it keeps it out of /var/log/messages.  
+                                 */
+			}		/* SISR_RX_NOBUF */
+
+			writew(~misr, streamer_mmio + MISR_RUM);
+			(void)readw(streamer_mmio + MISR_RUM);
+		}
+
+		else if (sisr & SISR_SRB_REPLY) {
+			if (streamer_priv->srb_queued == 1) {
+				wake_up_interruptible(&streamer_priv->srb_wait);
+			} else if (streamer_priv->srb_queued == 2) {
+				streamer_srb_bh(dev);
+			}
+			streamer_priv->srb_queued = 0;
+
+			writew(~SISR_SRB_REPLY, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
+		}
+
+		else if (sisr & SISR_ADAPTER_CHECK) {
 			printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
 			writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA);
 			printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n",
@@ -1001,38 +1068,37 @@
 		}
 
 		/* SISR_ADAPTER_CHECK */
-		if (sisr & SISR_ASB_FREE) {
+		else if (sisr & SISR_ASB_FREE) {
 			/* Wake up anything that is waiting for the asb response */
 			if (streamer_priv->asb_queued) {
 				streamer_asb_bh(dev);
 			}
+			writew(~SISR_ASB_FREE, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
 		/* SISR_ASB_FREE */
-		if (sisr & SISR_ARB_CMD) {
+		else if (sisr & SISR_ARB_CMD) {
 			streamer_arb_cmd(dev);
+			writew(~SISR_ARB_CMD, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
 		/* SISR_ARB_CMD */
-		if (sisr & SISR_TRB_REPLY) {
+		else if (sisr & SISR_TRB_REPLY) {
 			/* Wake up anything that is waiting for the trb response */
 			if (streamer_priv->trb_queued) {
 				wake_up_interruptible(&streamer_priv->
 						      trb_wait);
 			}
 			streamer_priv->trb_queued = 0;
+			writew(~SISR_TRB_REPLY, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
 		/* SISR_TRB_REPLY */
-		if (misr & MISR_RX_NOBUF) {
-			/* According to the documentation, we don't have to do anything, but trapping it keeps it out of
-			   /var/log/messages.  */
-		}		/* SISR_RX_NOBUF */
-	} else {
-		printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",
-		       dev->name, sisr);
-		printk(KERN_WARNING "%s: SISR_MASK: %x\n", dev->name,
-		       readw(streamer_mmio + SISR_MASK));
-	}			/* One if the interrupts we want */
 
-	writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+		sisr = readw(streamer_mmio + SISR);
+		max_intr--;
+	} /* while() */		
+
 	spin_unlock(&streamer_priv->streamer_lock) ; 
 }
 
@@ -1044,13 +1110,16 @@
 	unsigned long flags ;
 
 	spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
-	netif_stop_queue(dev);
 
 	if (streamer_priv->free_tx_ring_entries) {
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0;
-		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len;
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00020000 | skb->len;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = virt_to_bus(skb->data);
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd1 = skb->len;
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd2 = 0;
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd3 = 0;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buflen = skb->len;
+
 		streamer_priv->tx_ring_skb[streamer_priv->tx_ring_free] = skb;
 		streamer_priv->free_tx_ring_entries--;
 #if STREAMER_DEBUG_PACKETS
@@ -1067,12 +1136,13 @@
 #endif
 
 		writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA);
+		(void)readl(streamer_mmio + TX2LFDA);
 
 		streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
-		netif_wake_queue(dev);
 		spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
 		return 0;
 	} else {
+	        netif_stop_queue(dev);
 	        spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
 		return 1;
 	}
@@ -1092,12 +1162,13 @@
 	writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC);
 	writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
 
 	streamer_priv->srb_queued = 1;
 	writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
 
+	spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags);
+
 	while (streamer_priv->srb_queued) 
 	{
 		interruptible_sleep_on_timeout(&streamer_priv->srb_wait,
@@ -1114,7 +1185,6 @@
 		}
 	}
 
-	restore_flags(flags);
 	streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1);
 
 	for (i = 0; i < STREAMER_RX_RING_SIZE; i++) {
@@ -1808,6 +1878,64 @@
 #endif
 #endif
 
+#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+        int i;
+	struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+	u8 *streamer_mmio = streamer_priv->streamer_mmio;
+
+	switch(cmd) {
+	case IOCTL_SISR_MASK:
+		writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+		break;
+	case IOCTL_SPIN_LOCK_TEST:
+	        printk(KERN_INFO "spin_lock() called.\n");
+		spin_lock(&streamer_priv->streamer_lock);
+		spin_unlock(&streamer_priv->streamer_lock);
+		printk(KERN_INFO "spin_unlock() finished.\n");
+		break;
+	case IOCTL_PRINT_BDAS:
+	        printk(KERN_INFO "bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n",
+		       readw(streamer_mmio + RXBDA),
+		       readw(streamer_mmio + RXLBDA),
+		       readw(streamer_mmio + TX2FDA),
+		       readw(streamer_mmio + TX2LFDA));
+		break;
+	case IOCTL_PRINT_REGISTERS:
+	        printk(KERN_INFO "registers:\n");
+		printk(KERN_INFO "SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask  %04x mask  %04x\n", 
+		       readw(streamer_mmio + SISR),
+		       readw(streamer_mmio + MISR_RUM),
+		       readw(streamer_mmio + LISR),
+		       readw(streamer_mmio + BCTL),
+		       readw(streamer_mmio + BMCTL_SUM),
+		       readw(streamer_mmio + SISR_MASK),
+		       readw(streamer_mmio + MISR_MASK));
+		break;
+	case IOCTL_PRINT_RX_BUFS:
+	        printk(KERN_INFO "Print rx bufs:\n");
+		for(i=0; i<STREAMER_RX_RING_SIZE; i++)
+		        printk(KERN_INFO "rx_ring %d status: 0x%x\n", i, 
+			       streamer_priv->streamer_rx_ring[i].status);
+		break;
+	case IOCTL_PRINT_TX_BUFS:
+	        printk(KERN_INFO "Print tx bufs:\n");
+		for(i=0; i<STREAMER_TX_RING_SIZE; i++)
+		        printk(KERN_INFO "tx_ring %d status: 0x%x\n", i, 
+			       streamer_priv->streamer_tx_ring[i].status);
+		break;
+	case IOCTL_RX_CMD:
+	        streamer_rx(dev);
+		printk(KERN_INFO "Sent rx command.\n");
+		break;
+	default:
+	        printk(KERN_INFO "Bad ioctl!\n");
+	}
+	return 0;
+}
+#endif
+
 static struct pci_driver streamer_pci_driver = {
   name:       "lanstreamer",
   id_table:   streamer_pci_tbl,

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