patch-2.4.3 linux/drivers/net/defxx.c

Next file: linux/drivers/net/depca.c
Previous file: linux/drivers/net/declance.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.2/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
@@ -195,6 +195,8 @@
  *		Jun 2000	jgarzik		PCI and resource alloc cleanups
  *		Jul 2000	tjeerd		Much cleanup and some bug fixes
  *		Sep 2000	tjeerd		Fix leak on unload, cosmetic code cleanup
+ *		Feb 2001			Skb allocation fixes
+ *		Feb 2001	davej		PCI enable cleanups.
  */
 
 /* Include files */
@@ -225,7 +227,7 @@
 /* Version information string - should be updated prior to each new release!!! */
 
 static char version[] __devinitdata =
-	"defxx.c:v1.05d 2000/09/05  Lawrence V. Stefani and others\n";
+	"defxx.c:v1.05e 2001/02/03  Lawrence V. Stefani and others\n";
 
 #define DYNAMIC_BUFFERS 1
 
@@ -242,7 +244,7 @@
 static void		dfx_bus_config_check(DFX_board_t *bp);
 
 static int		dfx_driver_init(struct net_device *dev);
-static int		dfx_adap_init(DFX_board_t *bp);
+static int		dfx_adap_init(DFX_board_t *bp, int get_buffers);
 
 static int		dfx_open(struct net_device *dev);
 static int		dfx_close(struct net_device *dev);
@@ -264,8 +266,9 @@
 static int		dfx_hw_adap_state_rd(DFX_board_t *bp);
 static int		dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type);
 
-static void		dfx_rcv_init(DFX_board_t *bp);
+static int		dfx_rcv_init(DFX_board_t *bp, int get_buffers);
 static void		dfx_rcv_queue_process(DFX_board_t *bp);
+static void		dfx_rcv_flush(DFX_board_t *bp);
 
 static int		dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev);
 static int		dfx_xmt_done(DFX_board_t *bp);
@@ -339,7 +342,6 @@
 	u16 port = bp->base_addr + offset;
 
 	outb(data, port);
-	return;
 	}
 
 static inline void dfx_port_read_byte(
@@ -352,7 +354,6 @@
 	u16 port = bp->base_addr + offset;
 
 	*data = inb(port);
-	return;
 	}
 
 static inline void dfx_port_write_long(
@@ -365,7 +366,6 @@
 	u16 port = bp->base_addr + offset;
 
 	outl(data, port);
-	return;
 	}
 
 static inline void dfx_port_read_long(
@@ -378,7 +378,6 @@
 	u16 port = bp->base_addr + offset;
 
 	*data = inl(port);
-	return;
 	}
 
 
@@ -395,6 +394,7 @@
  *       
  * Arguments:
  *   pdev - pointer to pci device information (NULL for EISA)
+ *   ioaddr - pointer to port (NULL for PCI)
  *
  * Functional Description:
  *
@@ -415,6 +415,7 @@
 	struct net_device *dev;
 	DFX_board_t	  *bp;			/* board pointer */
 	static int version_disp;
+	int err;
 
 	if (!version_disp)					/* display version info if adapter is found */
 	{
@@ -426,18 +427,27 @@
 	 * init_fddidev() allocates a device structure with private data, clears the device structure and private data,
 	 * and  calls fddi_setup() and register_netdev(). Not much left to do for us here.
 	 */
-	dev = init_fddidev( NULL, sizeof(*bp));
-
+	dev = init_fddidev(NULL, sizeof(*bp));
 	if (!dev) {
 		printk (KERN_ERR "defxx: unable to allocate fddidev, aborting\n");
 		return -ENOMEM;
 	}
 
-	bp = (DFX_board_t*)dev->priv;
+	/* Enable PCI device. */
+	if (pdev != NULL) {
+		err = pci_enable_device (pdev);
+		if (err) goto err_out;
+		ioaddr = pci_resource_start (pdev, 1);
+	}
+
+	SET_MODULE_OWNER(dev);
+
+	bp = dev->priv;
 
 	if (!request_region (ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, dev->name)) {
 		printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
 			dev->name, PFI_K_CSR_IO_LEN, ioaddr);
+		err = -EBUSY;
 		goto err_out;
 	}
 
@@ -461,14 +471,14 @@
 		/* PCI board */
 		bp->bus_type = DFX_BUS_TYPE_PCI;
 		bp->pci_dev = pdev;
-		pdev->driver_data = dev;
-		if (pci_enable_device (pdev))
-			goto err_out_region;
+		pci_set_drvdata (pdev, dev);
 		pci_set_master (pdev);
 	}
 
-	if (dfx_driver_init(dev) != DFX_K_SUCCESS)
+	if (dfx_driver_init(dev) != DFX_K_SUCCESS) {
+		err = -ENODEV;
 		goto err_out_region;
+	}
 
 	return 0;
 
@@ -477,12 +487,12 @@
 err_out:
 	unregister_netdev(dev);
 	kfree(dev);
-	return -ENODEV;
+	return err;
 }
 
 static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	return  dfx_init_one_pci_or_eisa(pdev, pci_resource_start (pdev, 1));
+	return dfx_init_one_pci_or_eisa(pdev, 0);
 }
 
 static int __init dfx_eisa_init(void)
@@ -543,7 +553,7 @@
 
 static void __devinit dfx_bus_init(struct net_device *dev)
 {
-	DFX_board_t *bp = (DFX_board_t *)dev->priv;
+	DFX_board_t *bp = dev->priv;
 	u8			val;	/* used for I/O read/writes */
 
 	DBG_printk("In dfx_bus_init...\n");
@@ -642,7 +652,6 @@
 
 		dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB));
 		}
-	return;
 	}
 
 
@@ -737,7 +746,6 @@
 				}
 			}
 		}
-	return;
 	}
 
 
@@ -779,7 +787,7 @@
 
 static int __devinit dfx_driver_init(struct net_device *dev)
 {
-	DFX_board_t *bp = (DFX_board_t *)dev->priv;
+	DFX_board_t *bp = dev->priv;
 	int			alloc_size;			/* total buffer size needed */
 	char		*top_v, *curr_v;	/* virtual addrs into memory block */
 	u32			top_p, curr_p;		/* physical addrs into memory block */
@@ -977,6 +985,7 @@
  *       
  * Arguments:
  *   bp - pointer to board information
+ *   get_buffers - non-zero if buffers to be allocated
  *
  * Functional Description:
  *   Issues the low-level firmware/hardware calls necessary to bring
@@ -996,7 +1005,7 @@
  *   upon a successful return of this routine.
  */
 
-static int dfx_adap_init(DFX_board_t *bp)
+static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
 	{
 	DBG_printk("In dfx_adap_init...\n");
 
@@ -1131,9 +1140,23 @@
 		return(DFX_K_FAILURE);
 		}
 
+	/*
+	 * Remove any existing dynamic buffers (i.e. if the adapter is being
+	 * reinitialized)
+	 */
+
+	if (get_buffers)
+		dfx_rcv_flush(bp);
+
 	/* Initialize receive descriptor block and produce buffers */
 
-	dfx_rcv_init(bp);
+	if (dfx_rcv_init(bp, get_buffers))
+	        {
+		printk("%s: Receive buffer allocation failed\n", bp->dev->name);
+		if (get_buffers)
+			dfx_rcv_flush(bp);
+		return(DFX_K_FAILURE);
+		}
 
 	/* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */
 
@@ -1141,6 +1164,8 @@
 	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
 		{
 		printk("%s: Start command failed\n", bp->dev->name);
+		if (get_buffers)
+			dfx_rcv_flush(bp);
 		return(DFX_K_FAILURE);
 		}
 
@@ -1183,19 +1208,17 @@
 
 static int dfx_open(struct net_device *dev)
 {
-	DFX_board_t	*bp = (DFX_board_t *)dev->priv;
+	int ret;
+	DFX_board_t	*bp = dev->priv;
 
 	DBG_printk("In dfx_open...\n");
 	
-	MOD_INC_USE_COUNT;
-
 	/* Register IRQ - support shared interrupts by passing device ptr */
 
-	if (request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev))
-	{
+	ret = request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev);
+	if (ret) {
 		printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
-		MOD_DEC_USE_COUNT;
-		return -EAGAIN;
+		return ret;
 	}
 
 	/*
@@ -1228,11 +1251,10 @@
 	/* Reset and initialize adapter */
 
 	bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST;	/* skip self-test */
-	if (dfx_adap_init(bp) != DFX_K_SUCCESS)
+	if (dfx_adap_init(bp, 1) != DFX_K_SUCCESS)
 	{
 		printk(KERN_ERR "%s: Adapter open failed!\n", dev->name);
 		free_irq(dev->irq, dev);
-		MOD_DEC_USE_COUNT;
 		return -EAGAIN;
 	}
 
@@ -1276,7 +1298,7 @@
 
 static int dfx_close(struct net_device *dev)
 {
-	DFX_board_t	*bp = (DFX_board_t *)dev->priv;
+	DFX_board_t	*bp = dev->priv;
 
 	DBG_printk("In dfx_close...\n");
 
@@ -1318,6 +1340,10 @@
 
 	memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK));
 
+	/* Release all dynamically allocate skb in the receive ring. */
+
+	dfx_rcv_flush(bp);
+
 	/* Clear device structure flags */
 
 	netif_stop_queue(dev);
@@ -1326,7 +1352,6 @@
 
 	free_irq(dev->irq, dev);
 	
-	MOD_DEC_USE_COUNT;
 	return(0);
 }
 
@@ -1412,7 +1437,6 @@
 			printk("%s: Halt ID: Unknown (code = %X)\n", bp->dev->name, halt_id);
 			break;
 		}
-	return;
 	}
 
 
@@ -1504,7 +1528,7 @@
 		bp->link_available = PI_K_FALSE;	/* link is no longer available */
 		bp->reset_type = 0;					/* rerun on-board diagnostics */
 		printk("%s: Resetting adapter...\n", bp->dev->name);
-		if (dfx_adap_init(bp) != DFX_K_SUCCESS)
+		if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS)
 			{
 			printk("%s: Adapter reset failed!  Disabling adapter interrupts.\n", bp->dev->name);
 			dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS);
@@ -1552,7 +1576,7 @@
 			bp->link_available = PI_K_FALSE;	/* link is no longer available */
 			bp->reset_type = 0;					/* rerun on-board diagnostics */
 			printk("%s: Resetting adapter...\n", bp->dev->name);
-			if (dfx_adap_init(bp) != DFX_K_SUCCESS)
+			if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS)
 				{
 				printk("%s: Adapter reset failed!  Disabling adapter interrupts.\n", bp->dev->name);
 				dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS);
@@ -1565,7 +1589,6 @@
 			bp->link_available = PI_K_TRUE;		/* set link available flag */
 			}
 		}
-	return;
 	}
 
 
@@ -1611,7 +1634,7 @@
 
 static void dfx_int_common(struct net_device *dev)
 {
-	DFX_board_t 	*bp = (DFX_board_t *) dev->priv;
+	DFX_board_t 	*bp = dev->priv;
 	PI_UINT32	port_status;		/* Port Status register */
 
 	/* Process xmt interrupts - frequent case, so always call this routine */
@@ -1640,7 +1663,6 @@
 
 	if (port_status & PI_PSTATUS_M_TYPE_0_PENDING)
 		dfx_int_type_0_process(bp);	/* process Type 0 interrupts */
-	return;
 	}
 
 
@@ -1682,13 +1704,13 @@
 
 static void dfx_interrupt(int irq, void *dev_id, struct pt_regs	*regs)
 	{
-	struct net_device	*dev = (struct net_device *) dev_id;
+	struct net_device	*dev = dev_id;
 	DFX_board_t		*bp;	/* private board structure pointer */
 	u8				tmp;	/* used for disabling/enabling ints */
 
 	/* Get board pointer only if device structure is valid */
 
-	bp = (DFX_board_t *) dev->priv;
+	bp = dev->priv;
 
 	spin_lock(&bp->lock);
 	
@@ -1732,7 +1754,6 @@
 		}
 
 	spin_unlock(&bp->lock);
-	return;
 	}
 
 
@@ -1781,7 +1802,7 @@
 
 static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
 	{
-	DFX_board_t	*bp = (DFX_board_t *)dev->priv;
+	DFX_board_t	*bp = dev->priv;
 
 	/* Fill the bp->stats structure with driver-maintained counters */
 
@@ -1966,7 +1987,7 @@
 
 static void dfx_ctl_set_multicast_list(struct net_device *dev)
 	{
-	DFX_board_t			*bp = (DFX_board_t *)dev->priv;
+	DFX_board_t			*bp = dev->priv;
 	int					i;			/* used as index in for loop */
 	struct dev_mc_list	*dmi;		/* ptr to multicast addr entry */
 
@@ -2039,7 +2060,6 @@
 		{
 		DBG_printk("%s: Adapter filters updated!\n", dev->name);
 		}
-	return;
 	}
 
 
@@ -2081,7 +2101,7 @@
 
 static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr)
 	{
-	DFX_board_t		*bp = (DFX_board_t *)dev->priv;
+	DFX_board_t		*bp = dev->priv;
 	struct sockaddr	*p_sockaddr = (struct sockaddr *)addr;
 
 	/* Copy unicast address to driver-maintained structs and update count */
@@ -2540,7 +2560,6 @@
 	/* Deassert reset */
 
 	dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0);
-	return;
 	}
 
 
@@ -2631,8 +2650,7 @@
 		return(DFX_K_HW_TIMEOUT);
 	return(DFX_K_SUCCESS);
 	}
-
-
+
 /*
  *	Align an sk_buff to a boundary power of 2
  *
@@ -2662,6 +2680,7 @@
  *       
  * Arguments:
  *   bp - pointer to board information
+ *   get_buffers - non-zero if buffers to be allocated
  *
  * Functional Description:
  *   This routine can be called during dfx_adap_init() or during an adapter
@@ -2669,7 +2688,10 @@
  *   LLC Host queue receive buffers.
  *
  * Return Codes:
- *   None
+ *   Return 0 on success or -ENOMEM if buffer allocation failed (when using
+ *   dynamic buffer allocation). If the buffer allocation failed, the
+ *   already allocated buffers will not be released and the caller should do
+ *   this.
  *
  * Assumptions:
  *   The PDQ has been reset and the adapter and driver maintained Type 2
@@ -2680,7 +2702,7 @@
  *   is notified.
  */
 
-static void dfx_rcv_init(DFX_board_t *bp)
+static int dfx_rcv_init(DFX_board_t *bp, int get_buffers)
 	{
 	int	i, j;					/* used in for loop */
 
@@ -2702,20 +2724,22 @@
 	 *		driver initialization when we allocated memory for the receive buffers.
 	 */
 
+	if (get_buffers) {
 #ifdef DYNAMIC_BUFFERS
 	for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++)
 		for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
 		{
-			struct sk_buff *newskb;
+			struct sk_buff *newskb = __dev_alloc_skb(NEW_SKB_SIZE, GFP_BUFFER);
+			if (!newskb)
+				return -ENOMEM;
 			bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
 				((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
-			newskb = dev_alloc_skb(NEW_SKB_SIZE);
 			/*
 			 * align to 128 bytes for compatibility with
 			 * the old EISA boards.
 			 */
 			 
-			my_skb_align(newskb,128);
+			my_skb_align(newskb, 128);
 			bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data);
 			/*
 			 * p_rcv_buff_va is only used inside the
@@ -2733,12 +2757,13 @@
 			bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX));
 			}
 #endif
+	}
 
 	/* Update receive producer and Type 2 register */
 
 	bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post;
 	dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
-	return;
+	return 0;
 	}
 
 
@@ -2833,7 +2858,7 @@
 						bp->p_rcv_buff_va[entry] = (char *)newskb;
 						bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data);
 					} else
-						skb = 0;
+						skb = NULL;
 				} else
 #endif
 					skb = dev_alloc_skb(pkt_len+3);	/* alloc new buffer to pass up, add room for PRH */
@@ -2858,6 +2883,7 @@
 					skb->dev = bp->dev;		/* pass up device pointer */
 
 					skb->protocol = fddi_type_trans(skb, bp->dev);
+					bp->rcv_total_bytes += skb->len;
 					netif_rx(skb);
 
 					/* Update the rcv counters */
@@ -2865,8 +2891,6 @@
 					bp->rcv_total_frames++;
 					if (*(p_buff + RCV_BUFF_K_DA) & 0x01)
 						bp->rcv_multicast_frames++;
-				 
-					bp->rcv_total_bytes += skb->len;
 				}
 			}
 			}
@@ -2882,7 +2906,6 @@
 		bp->rcv_xmt_reg.index.rcv_prod += 1;
 		bp->rcv_xmt_reg.index.rcv_comp += 1;
 		}
-	return;
 	}
 
 
@@ -2953,7 +2976,7 @@
 	)
 
 	{
-	DFX_board_t		*bp = (DFX_board_t *) dev->priv;
+	DFX_board_t		*bp = dev->priv;
 	u8			prod;				/* local transmit producer index */
 	PI_XMT_DESCR		*p_xmt_descr;		/* ptr to transmit descriptor block entry */
 	XMT_DRIVER_DESCR	*p_xmt_drv_descr;	/* ptr to transmit driver descriptor */
@@ -3183,6 +3206,54 @@
 
 /*
  * =================
+ * = dfx_rcv_flush =
+ * =================
+ *   
+ * Overview:
+ *   Remove all skb's in the receive ring.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   Free's all the dynamically allocated skb's that are
+ *   currently attached to the device receive ring. This
+ *   function is typically only used when the device is
+ *   initialized or reinitialized.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Side Effects:
+ *   None
+ */
+#ifdef DYNAMIC_BUFFERS
+static void dfx_rcv_flush( DFX_board_t *bp )
+	{
+	int i, j;
+
+	for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++)
+		for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
+		{
+			struct sk_buff *skb;
+			skb = (struct sk_buff *)bp->p_rcv_buff_va[i+j];
+			if (skb)
+				dev_kfree_skb(skb);
+			bp->p_rcv_buff_va[i+j] = NULL;
+		}
+
+	}
+#else
+static inline void dfx_rcv_flush( DFX_board_t *bp )
+{
+}
+#endif /* DYNAMIC_BUFFERS */
+
+/*
+ * =================
  * = dfx_xmt_flush =
  * =================
  *   
@@ -3257,12 +3328,11 @@
 	prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX);
 	prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX);
 	bp->cons_block_virt->xmt_rcv_data = prod_cons;
-	return;
 	}
 
 static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev)
 {
-	DFX_board_t	  *bp = (DFX_board_t*)dev->priv;
+	DFX_board_t	  *bp = dev->priv;
 
 	unregister_netdev(dev);
 	release_region(dev->base_addr,  pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN );
@@ -3272,9 +3342,10 @@
 
 static void __devexit dfx_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 
 	dfx_remove_one_pci_or_eisa(pdev, dev);
+	pci_set_drvdata(pdev, NULL);
 }
 
 static struct pci_device_id dfx_pci_tbl[] __devinitdata = {

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