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
- Lines: 624
- Date:
Sun Mar 25 18:24:31 2001
- Orig file:
v2.4.2/linux/drivers/net/defxx.c
- Orig date:
Wed Feb 21 18:20:26 2001
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)