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

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

diff -urN linux-2.4.18/drivers/net/tokenring/olympic.c linux-2.4.19/drivers/net/tokenring/olympic.c
@@ -50,10 +50,16 @@
  *	      adapter when live does not take the system down with it.
  * 
  * 06/02/01 - Clean up, copy skb for small packets
+ * 
+ * 06/22/01 - Add EISR error handling routines 
+ *
+ * 07/19/01 - Improve bad LAA reporting, strip out freemem
+ *	      into a separate function, its called from 3 
+ *	      different places now. 
+ * 02/09/01 - Replaced sleep_on. 
  *
  *  To Do:
  *
- *	     Complete full Cardbus / hot-swap support.
  *	     Wake on lan	
  * 
  *  If Problems do Occur
@@ -105,7 +111,7 @@
  */
 
 static char version[] __devinitdata = 
-"Olympic.c v0.9.7 6/02/01 - Peter De Schrijver & Mike Phillips" ; 
+"Olympic.c v1.0.0 2/9/02  - Peter De Schrijver & Mike Phillips" ; 
 
 static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
 				   "Address Verification", "Neighbor Notification (Ring Poll)",
@@ -172,6 +178,7 @@
 static int olympic_xmit(struct sk_buff *skb, struct net_device *dev);
 static int olympic_close(struct net_device *dev);
 static void olympic_set_rx_mode(struct net_device *dev);
+static void olympic_freemem(struct net_device *dev) ;  
 static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static struct net_device_stats * olympic_get_stats(struct net_device *dev);
 static int olympic_set_mac_address(struct net_device *dev, void *addr) ; 
@@ -396,6 +403,8 @@
 	char open_error[255] ; 
 	int i, open_finished = 1 ;
 
+	DECLARE_WAITQUEUE(wait,current) ; 
+
 	if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) {
 		return -EAGAIN;
 	}
@@ -424,8 +433,6 @@
 	do {
 		int i;
 
-		save_flags(flags);
-		cli();
 		for(i=0;i<SRB_COMMAND_SIZE;i+=4)
 			writel(0,init_srb+i);
 		if(SRB_COMMAND_SIZE & 2)
@@ -441,8 +448,12 @@
 			writew(swab16(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), init_srb+8);
 		else
 			writew(swab16(OPEN_ADAPTER_ENABLE_FDX), init_srb+8);
+	
+		/* Test OR of first 3 bytes as its totally possible for 
+		 * someone to set the first 2 bytes to be zero, although this 
+		 * is an error, the first byte must have bit 6 set to 1  */
 
-		if (olympic_priv->olympic_laa[0]) {
+		if (olympic_priv->olympic_laa[0] | olympic_priv->olympic_laa[1] | olympic_priv->olympic_laa[2]) {
 			writeb(olympic_priv->olympic_laa[0],init_srb+12);
 			writeb(olympic_priv->olympic_laa[1],init_srb+13);
 			writeb(olympic_priv->olympic_laa[2],init_srb+14);
@@ -452,14 +463,20 @@
 			memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ;  
 		} 	
 		writeb(1,init_srb+30);
-	
+
+		spin_lock_irqsave(&olympic_priv->olympic_lock,flags);	
 		olympic_priv->srb_queued=1;
 
 		writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+		spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
 
 		t = jiffies ; 
+	
+		add_wait_queue(&olympic_priv->srb_wait,&wait) ;
+		set_current_state(TASK_INTERRUPTIBLE) ; 
+ 
  		while(olympic_priv->srb_queued) {        
-        		interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ);
+			schedule() ; 
         		if(signal_pending(current))	{            
 				printk(KERN_WARNING "%s: Signal received in open.\n",
                 			dev->name);
@@ -474,8 +491,11 @@
 				olympic_priv->srb_queued=0;
 				break ; 
 			} 
+			set_current_state(TASK_INTERRUPTIBLE) ; 
     		}
-		restore_flags(flags);
+		remove_wait_queue(&olympic_priv->srb_wait,&wait) ; 
+		set_current_state(TASK_RUNNING) ; 
+
 #if OLYMPIC_DEBUG
 		printk("init_srb(%p): ",init_srb);
 		for(i=0;i<20;i++)
@@ -515,6 +535,17 @@
 					return -EIO ; 
  
 				}	/* if autosense && open_finished */
+			} else if (init_srb[2] == 0x32) {
+				printk(KERN_WARNING "%s: Invalid LAA: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					dev->name, 
+					olympic_priv->olympic_laa[0],
+					olympic_priv->olympic_laa[1],
+					olympic_priv->olympic_laa[2],
+					olympic_priv->olympic_laa[3],
+					olympic_priv->olympic_laa[4],
+					olympic_priv->olympic_laa[5]) ; 
+				free_irq(dev->irq,dev) ; 
+				return -EIO ; 
 			} else {  
 				printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]);
 				free_irq(dev->irq, dev);
@@ -598,8 +629,7 @@
 	printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7])  );
 
 	printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]);
-	printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr =
-%08x\n",olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; 
+	printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr = %08x\n",olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; 
 #endif
 
 	writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);
@@ -634,7 +664,10 @@
 	olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */
 	olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */
 
-	writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE,olympic_mmio+SISR_MASK_SUM);
+	writel(0xffffffff, olympic_mmio+EISR_RWM) ; /* clean the eisr */
+	writel(0,olympic_mmio+EISR) ; 
+	writel(EISR_MASK_OPTIONS,olympic_mmio+EISR_MASK) ; /* enables most of the TX error interrupts */
+	writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE | SISR_ERR,olympic_mmio+SISR_MASK_SUM);
 
 #if OLYMPIC_DEBUG 
 	printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM));
@@ -822,6 +855,35 @@
 
 }
 
+static void olympic_freemem(struct net_device *dev) 
+{ 
+	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	int i;
+			
+	for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
+		dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
+		if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) {
+			pci_unmap_single(olympic_priv->pdev, 
+			le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer),
+			olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE);
+		}
+		olympic_priv->rx_status_last_received++;
+		olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
+	}
+	/* unmap rings */
+	pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, 
+		sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE);
+	pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr,
+		sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE);
+
+	pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, 
+		sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE);
+	pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, 
+		sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE);
+
+	return ; 
+}
+ 
 static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
 {
 	struct net_device *dev= (struct net_device *)dev_id;
@@ -842,9 +904,33 @@
 
 	spin_lock(&olympic_priv->olympic_lock);
 
+	/* Hotswap gives us this on removal */
+	if (sisr == 0xffffffff) { 
+		printk(KERN_WARNING "%s: Hotswap adapter removal.\n",dev->name) ; 
+		olympic_freemem(dev) ; 
+		free_irq(dev->irq, dev) ;
+		dev->stop = NULL ;  
+		spin_unlock(&olympic_priv->olympic_lock) ; 
+		return ;
+	} 
+		
 	if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK |  
-			SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) {  
+			SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF | SISR_ERR)) {  
 	
+		/* If we ever get this the adapter is seriously dead. Only a reset is going to 
+		 * bring it back to life. We're talking pci bus errors and such like :( */ 
+		if((sisr & SISR_ERR) && (readl(olympic_mmio+EISR) & EISR_MASK_OPTIONS)) {
+			printk(KERN_ERR "Olympic: EISR Error, EISR=%08x\n",readl(olympic_mmio+EISR)) ; 
+			printk(KERN_ERR "The adapter must be reset to clear this condition.\n") ; 
+			printk(KERN_ERR "Please report this error to the driver maintainer and/\n") ; 
+			printk(KERN_ERR "or the linux-tr mailing list.\n") ; 
+			olympic_freemem(dev) ; 
+			free_irq(dev->irq, dev) ;
+			dev->stop = NULL ;  
+			spin_unlock(&olympic_priv->olympic_lock) ; 
+			return ;
+		} /* SISR_ERR */
+
 		if(sisr & SISR_SRB_REPLY) {
 			if(olympic_priv->srb_queued==1) {
 				wake_up_interruptible(&olympic_priv->srb_wait);
@@ -878,34 +964,12 @@
 		} /* SISR_RX_STATUS */
 	
 		if (sisr & SISR_ADAPTER_CHECK) {
-			int i ; 
 			netif_stop_queue(dev);
 			printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
-			writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
-			adapter_check_area = (u8 *)(olympic_mmio+LAPWWO) ; 
+			writel(readl(olympic_mmio+LAPWWC),olympic_mmio+LAPA);
+			adapter_check_area = olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWC)) & (~0xf800)) ;
 			printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; 
-			/* The adapter is effectively dead, clean up and exit */
-			for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
-				dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
-				if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) {
-					pci_unmap_single(olympic_priv->pdev, 
-						le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer),
-						olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE);
-				}
-				olympic_priv->rx_status_last_received++;
-				olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
-			}
-			/* unmap rings */
-			pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, 
-				sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE);
-			pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr,
-				sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE);
-
-			pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, 
-				sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE);
-			pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, 
-				sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE);
-
+			olympic_freemem(dev) ;
 			free_irq(dev->irq, dev) ;
 			dev->stop = NULL ;  
 			spin_unlock(&olympic_priv->olympic_lock) ; 
@@ -980,7 +1044,8 @@
 	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
     	u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb;
 	unsigned long t,flags;
-	int i;
+
+	DECLARE_WAITQUEUE(wait,current) ; 
 
 	netif_stop_queue(dev);
 	
@@ -991,16 +1056,19 @@
 	writeb(0,srb+1);
 	writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
 
-	save_flags(flags);
-	cli();	
-
+	spin_lock_irqsave(&olympic_priv->olympic_lock,flags);
 	olympic_priv->srb_queued=1;
 
 	writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
+	spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
 	
 	t = jiffies ; 
+
+	add_wait_queue(&olympic_priv->srb_wait,&wait) ;
+	set_current_state(TASK_INTERRUPTIBLE) ; 
+
 	while(olympic_priv->srb_queued) {
-	        interruptible_sleep_on_timeout(&olympic_priv->srb_wait, jiffies+60*HZ);
+		schedule() ; 
         	if(signal_pending(current))	{            
 			printk(KERN_WARNING "%s: SRB timed out.\n",dev->name);
             		printk(KERN_WARNING "SISR=%x MISR=%x\n",readl(olympic_mmio+SISR),readl(olympic_mmio+LISR));
@@ -1012,32 +1080,15 @@
 			olympic_priv->srb_queued=0;
 			break ; 
 		} 
+		set_current_state(TASK_INTERRUPTIBLE) ; 
     	}
+	remove_wait_queue(&olympic_priv->srb_wait,&wait) ; 
+	set_current_state(TASK_RUNNING) ; 
 
-	restore_flags(flags) ; 
 	olympic_priv->rx_status_last_received++;
 	olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
-	
-	for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
-		dev_kfree_skb(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
-		if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) {
-			pci_unmap_single(olympic_priv->pdev, 
-				le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer),
-				olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE);
-		}
-		olympic_priv->rx_status_last_received++;
-		olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
-	}
-	/* unmap rings */
-	pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, 
-		sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE);
-	pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr,
-		sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE);
 
-	pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, 
-		sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE);
-	pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, 
-		sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE);
+	olympic_freemem(dev) ; 	
 
 	/* reset tx/rx fifo's and busmaster logic */
 

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