Re: IP1000 gigabit nic driver

From: David Vrabel
Date: Sun Apr 30 2006 - 19:40:41 EST


Pekka Enberg wrote:
On Sat, 2006-04-29 at 14:21 +0200, David Gómez wrote:
I already had it modified, just needed to create the patch... Anyway,
have you submitted it to netdev?

On Sat, 2006-04-29 at 23:35 +0300, Pekka Enberg wrote:
No, I haven't. I don't have the hardware, so I can't test the driver.
Furthermore, there's plenty of stuff to fix before it's in any shape for
submission. If someone wants to give this patch a spin, I would love to
hear the results.

Thanks for doing this Pekka. I've fixed up some stuff and given it some brief testing on a 100BaseT network and it seems to work now.

Subject: [PATCH] IP1000 Gigabit Ethernet device driver

This is a cleaned up fork of the IP1000A device driver:

<http://www.icplus.com.tw/driver-pp-IP1000A.html>

Open issues include but are not limited to:

- ipg_probe() looks really fishy and doesn't handle all errors
(e.g. ioremap failing).
- ipg_nic_do_ioctl() is playing games with user-space pointer.
We should use ethtool ioctl instead as suggested by Arjan.

Still pending. Also:

- something (PHY reset/auto negotiation?) takes 2-3 seconds and
appears to be done with interrupts disabled.

- For multiple devices, the driver uses a global root_dev and
ipg_remove() play some tricks which look fishy.

Killed this. It was broke and ugly as hell.

Attached is patch with some more changes:

- Remove changelogs
- Remove ether_crc_le() -- use crc32_le() instead.
- No more nonsense with root_dev -- ipg_remove() now works.
- Move PHY and MAC address initialization into the ipg_probe(). It was
previously filling in the MAC address on open which breaks some user
space.
- Folded ipg_nic_init into ipg_probe since it was broke otherwise.

Signed-off-by: David Vrabel <dvrabel@xxxxxxxxxx> Index: linux-source-2.6.16/drivers/net/ipg.c
===================================================================
--- linux-source-2.6.16.orig/drivers/net/ipg.c 2006-04-30 22:26:05.788013667 +0100
+++ linux-source-2.6.16/drivers/net/ipg.c 2006-05-01 00:23:28.358641581 +0100
@@ -13,149 +13,14 @@
* 408 873 4117
* www.sundanceti.com
* craig_rich@xxxxxxxxxxxxxx
- *
- * Rev Date Description
- * --------------------------------------------------------------
- * 0.1 11/8/99 Initial revision work begins.
- *
- * 0.2 11/12/99 Basic operation achieved, continuing work.
- *
- * 0.3 11/19/99 MAC Loop Back for sync problem testing.
- *
- * 0.4 12/22/99 ioctl for diagnotic program 'hunter' support.
- *
- * 0.5 4/13/00 Updates to
- *
- * 0.6 6/14/00 Slight correction to handling TFDDONE, and
- * preservation of PHYCTRL polarity bits.
- *
- * 0.7 7/27/00 Modifications to accomodate triple speed
- * autonegotiation. Also change to ioctl routine
- * to handle unknown PHY address.
- *
- * 0.8 8/11/00 Added change_mtu function.
- *
- * 0.9 8/15/00 Corrected autonegotiation resolution.
- *
- * 0.10 8/30/00 Changed constants to use IPG in place
- * of RIO. Also, removed most of debug
- * code in preparation for production release.
- *
- * 0.11 8/31/00 Utilize 64 bit data types where appropriate.
- *
- * 0.12 9/1/00 Move some constants to include file and utilize
- * RxDMAInt register.
- *
- * 0.13 10/31/00 Several minor modifications to improve stability.
- *
- * 0.14 11/28/00 Added call to nic_tx_free if TFD not available.
- *
- * 0.15 12/5/00 Corrected problem with receive errors, always set
- * receive buffer address to NULL. Release RX buffers
- * on errors.
- *
- * 0.16 12/20/00 Corrected autoneg resolution issue, must detect
- * speed via PHYCTRL register. Also, perform only 1
- * loop in the nic_txcleanup routine.
- *
- * 0.17 2/7/01 Changed all references of ST2021 to IPG.
- * When next TFD not available, return -ENOMEM instead
- * of 0. Removed references to RUBICON.
- *
- * 0.18 2/14/01 Corrected problem when unexpected jumbo frames are
- * received (now dropped properly.) Changed
- * "DROP_ON_ERRORS" breaking out Ethernet errors and
- * TCP/IP errors serparately. Corrected Gigabit
- * copper PAUSE autonegotiation.
- *
- * 0.19 2/22/01 Changed interrupt handling of RFD_LIST_END,
- * INT_REQUESTED, and RX_DMA_COMPLETE. Masked off
- * RMON statistics and unused MIB statistics.
- * Make sure *all* statistics are accounted for
- * (either masked or read in get_stats) to avoid
- * perpetual UpdateStats interrupt from causing
- * driver to crash.
- *
- * 0.20 3/2/01 Corrected error in nic_stop. Need to set
- * TxBuff[] = NULL after freeing TxBuff and
- * RxBuff[] = NULL after freeing RxBuff.
- *
- * 0.21 3/5/01 Correct 10/100Mbit PAUSE autonegotiation.
- *
- * 0.22 3/16/01 Used TxDMAIndicate for 100/1000Mbps modes. Add
- * "TFD unavailable" and "RFD list end" counters
- * to assist with performance measurement. Added
- * check for maxtfdcnt != 0 to while loop within
- * txcleanup.
- *
- * 0.23 3/22/01 Set the CurrentTxFrameID to 1 upon detecting
- * a TxDMAComplete to reduce the number of TxDMAComplete.
- * Also, indicate IP/TCP/UDP checksum is unneseccary
- * if IPG indicates checksum validates.
- *
- * 0.24 3/23/01 Changed the txfree routine, eliminating the margin
- * between the last freed TFD and the current TFD.
- *
- * 0.25 4/3/01 Corrected errors in config_autoneg to deal with
- * fiber flag properly.
- *
- * 0.26 5/1/01 Port for operation with Linux 2.2 or 2.4 kernel.
- *
- * 0.27 5/22/01 Cleaned up some extraneous comments.
- *
- * 0.28 6/20/01 Added auto IP, TCP, and UDP checksum addition
- * on transmit based on compilation option.
- *
- * 0.29 7/26/01 Comment out #include <asm/spinlock.h> from ipg.h
- * for compatibility with RedHat 7.1. Unkown reason.
- *
- * 0.30 8/10/01 Added debug message to each function, print function
- * name when entered. Added DEBUGCTRL register bit 5 for
- * Rx DMA Poll Now bug work around. Added ifdef IPG_DEBUG
- * flags to IPG_TFDlistunabvail and IPG_RFDlistend
- * counters. Removed clearing of sp->stat struct from
- * nic_open and added check in get_stats to make sure
- * NIC is initialized before reading statistic registers.
- * Corrected erroneous MACCTRL setting for Fiber based
- * 10/100 boards. Corrected storage of phyctrlpolarity
- * variable.
- *
- * 0.31 8/13/01 Incorporate STI or TMI fiber based NIC detection.
- * Corrected problem with _pciremove_linux2_4 routine.
- * Corrected setting of IP/TCP/UDP checksumming on receive
- * and transmit.
- *
- * 0.32 8/15/01 Changed the tmi_fiber_detect routine.
- *
- * 0.33 8/16/01 Changed PHY reset method in nic_open routine. Added
- * a chip reset in nic_stop to shut down the IPG.
- *
- * 0.34 9/5/01 Corrected some misuage of dev_kfree_skb.
- *
- * 0.35 10/30/01 Unmap register space (IO or memory) in the nic_stop
- * routine instead of in the cleanup or remove routines.
- * Corrects driver up/down/up problem when using IO
- * register mapping.
- *
- * 0.36 10/31/01 Modify the constant IPG_FRAMESBETWEENTXDMACOMPLETES
- * from 0x10 to 1.
- * 0.37 11/05/03 Modify the IPG_PHY_1000BASETCONTROL
- * in IP1000A this register is without 1000BPS Ability by default
- * so enable 1000BPS ability before PHY RESET/RESTART_AN
- * 0.38 11/05/03 update ipg_config_autoneg routine
- * 0.39 11/05/03 add Vendor_ID=13F0/Device_ID=1023 into support_cards
- * 2.05 10/16/04 Remove IPG_IE_RFD_LIST_END for pass SmartBit test.
- * (see 20041019Jesse_For_SmartBit.)
- * 2.06 10/27/04 Support for kernel 2.6.x
- * 2.06a 11/03/04 remove some compile warring message.
- * 2.09b 06/03/05 Support 4k jumbo (IC Plus, Jesse)
- * 2.09d 06/22/05 Support 10k jumbo, more than 4k will using copy mode (IC Plus, Jesse)
*/
#define JUMBO_FRAME_4k_ONLY
enum {
netdev_io_size = 128
};

+#include <linux/crc32.h>
+
#include "ipg.h"
#define DRV_NAME "ipg"

@@ -214,14 +79,12 @@
static int ipg_nic_hard_start_xmit(struct sk_buff *, struct net_device *);
static struct net_device_stats *ipg_nic_get_stats(struct net_device *);
static void ipg_nic_set_multicast_list(struct net_device *);
-static int ipg_nic_init(struct net_device *);
static int ipg_nic_rx(struct net_device *);
static int ipg_nic_rxrestore(struct net_device *);
static int init_rfdlist(struct net_device *);
static int init_tfdlist(struct net_device *);
static int ipg_get_rxbuff(struct net_device *, int);
static int ipg_config_autoneg(struct net_device *);
-static unsigned ether_crc_le(int, unsigned char *);
static int ipg_nic_do_ioctl(struct net_device *, struct ifreq *, int);
static int ipg_nic_change_mtu(struct net_device *, int);

@@ -1637,60 +1500,12 @@
* by ifconfig.
*/

- int phyaddr = 0;
int error = 0;
- int i;
void __iomem *ioaddr = ipg_ioaddr(dev);
- u8 revisionid = 0;
struct ipg_nic_private *sp = netdev_priv(dev);

IPG_DEBUG_MSG("_nic_open\n");

- /* Reset all functions within the IPG. Do not assert
- * RST_OUT as not compatible with some PHYs.
- */
- i = IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET |
- IPG_AC_TX_RESET | IPG_AC_DMA |
- IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | IPG_AC_AUTO_INIT;
- /* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */
- /* Read LED Mode Configuration from EEPROM */
- sp->LED_Mode = read_eeprom(dev, 6);
-
- error = ipg_reset(dev, i);
- if (error < 0) {
- return error;
- }
-
- /* Reset PHY. */
- phyaddr = ipg_find_phyaddr(dev);
-
- if (phyaddr != -1) {
- u16 mii_phyctrl, mii_1000cr;
- mii_1000cr = read_phy_register(dev,
- phyaddr,
- GMII_PHY_1000BASETCONTROL);
- write_phy_register(dev, phyaddr,
- GMII_PHY_1000BASETCONTROL,
- mii_1000cr |
- GMII_PHY_1000BASETCONTROL_FULL_DUPLEX |
- GMII_PHY_1000BASETCONTROL_HALF_DUPLEX |
- GMII_PHY_1000BASETCONTROL_PreferMaster);
-
- mii_phyctrl = read_phy_register(dev, phyaddr, GMII_PHY_CONTROL);
- /* Set default phyparam */
- pci_read_config_byte(sp->pdev, PCI_REVISION_ID, &revisionid);
- ipg_set_phy_default_param(revisionid, dev, phyaddr);
-
- /* reset Phy */
- write_phy_register(dev,
- phyaddr, GMII_PHY_CONTROL,
- (mii_phyctrl | GMII_PHY_CONTROL_RESET |
- MII_PHY_CONTROL_RESTARTAN));
-
- }
-
- spin_lock_init(&sp->lock);
-
/* Check for interrupt line conflicts, and request interrupt
* line for IPG.
*
@@ -1743,26 +1558,6 @@
return error;
}

- /* Read MAC Address from EERPOM Jesse20040128EEPROM_VALUE */
- sp->StationAddr0 = read_eeprom(dev, 16);
- sp->StationAddr1 = read_eeprom(dev, 17);
- sp->StationAddr2 = read_eeprom(dev, 18);
- /* Write MAC Address to Station Address */
- iowrite16(sp->StationAddr0, ioaddr + IPG_STATIONADDRESS0);
- iowrite16(sp->StationAddr1, ioaddr + IPG_STATIONADDRESS1);
- iowrite16(sp->StationAddr2, ioaddr + IPG_STATIONADDRESS2);
-
- /* Set station address in ethernet_device structure. */
- dev->dev_addr[0] = ioread16(ioaddr + IPG_STATIONADDRESS0) & 0x00FF;
- dev->dev_addr[1] =
- (ioread16(ioaddr + IPG_STATIONADDRESS0) & 0xFF00) >> 8;
- dev->dev_addr[2] = ioread16(ioaddr + IPG_STATIONADDRESS1) & 0x00FF;
- dev->dev_addr[3] =
- (ioread16(ioaddr + IPG_STATIONADDRESS1) & 0xFF00) >> 8;
- dev->dev_addr[4] = ioread16(ioaddr + IPG_STATIONADDRESS2) & 0x00FF;
- dev->dev_addr[5] =
- (ioread16(ioaddr + IPG_STATIONADDRESS2) & 0xFF00) >> 8;
-
/* Configure IPG I/O registers. */
error = ipg_io_config(dev);
if (error < 0) {
@@ -2860,7 +2655,8 @@
for (mc_list_ptr = dev->mc_list;
mc_list_ptr != NULL; mc_list_ptr = mc_list_ptr->next) {
/* Calculate CRC result for each multicast address. */
- hashindex = ether_crc_le(ETH_ALEN, mc_list_ptr->dmi_addr);
+ hashindex = crc32_le(0xffffffff, mc_list_ptr->dmi_addr,
+ ETH_ALEN);

/* Use only the least significant 6 bits. */
hashindex = hashindex & 0x3F;
@@ -2883,86 +2679,79 @@
ioread8(ioaddr + IPG_RECEIVEMODE));
}

-/*
- * The following code fragment was authored by Donald Becker.
- */
-
-/* The little-endian AUTODIN II ethernet CRC calculations.
- A big-endian version is also available.
- This is slow but compact code. Do not use this routine for bulk data,
- use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c.
- Chips may use the upper or lower CRC bits, and may reverse and/or invert
- them. Select the endian-ness that results in minimal calculations.
-*/
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static unsigned ether_crc_le(int length, unsigned char *data)
+static int ipg_hw_init(struct net_device *dev)
{
- unsigned int crc = 0xffffffff; /* Initial value. */
- while (--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
+ int phyaddr = 0;
+ int error = 0;
+ int i;
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ u8 revisionid = 0;
+ struct ipg_nic_private *sp = netdev_priv(dev);

-/*
- * End of code fragment authored by Donald Becker.
- */
+ /* Reset all functions within the IPG. Do not assert
+ * RST_OUT as not compatible with some PHYs.
+ */
+ i = IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET |
+ IPG_AC_TX_RESET | IPG_AC_DMA |
+ IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | IPG_AC_AUTO_INIT;
+ /* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */
+ /* Read LED Mode Configuration from EEPROM */
+ sp->LED_Mode = read_eeprom(dev, 6);

-static int ipg_nic_init(struct net_device *dev)
-{
- /* Initialize IPG NIC. */
+ error = ipg_reset(dev, i);
+ if (error < 0) {
+ return error;
+ }

- struct ipg_nic_private *sp = NULL;
+ ioaddr = ipg_ioaddr(dev);

- IPG_DEBUG_MSG("_nic_init\n");
+ /* Reset PHY. */
+ phyaddr = ipg_find_phyaddr(dev);

- /* Register the IPG NIC in the list of Ethernet devices. */
- dev = alloc_etherdev(sizeof(struct ipg_nic_private));
+ if (phyaddr != -1) {
+ u16 mii_phyctrl, mii_1000cr;
+ mii_1000cr = read_phy_register(dev,
+ phyaddr,
+ GMII_PHY_1000BASETCONTROL);
+ write_phy_register(dev, phyaddr,
+ GMII_PHY_1000BASETCONTROL,
+ mii_1000cr |
+ GMII_PHY_1000BASETCONTROL_FULL_DUPLEX |
+ GMII_PHY_1000BASETCONTROL_HALF_DUPLEX |
+ GMII_PHY_1000BASETCONTROL_PreferMaster);

- if (dev == NULL) {
- printk(KERN_INFO "Could not initialize IP1000 based NIC.\n");
- return -ENODEV;
- }
+ mii_phyctrl = read_phy_register(dev, phyaddr, GMII_PHY_CONTROL);
+ /* Set default phyparam */
+ pci_read_config_byte(sp->pdev, PCI_REVISION_ID, &revisionid);
+ ipg_set_phy_default_param(revisionid, dev, phyaddr);

- /* Reserve memory for ipg_nic_private structure. */
- sp = kmalloc(sizeof(struct ipg_nic_private), GFP_KERNEL);
+ /* reset Phy */
+ write_phy_register(dev,
+ phyaddr, GMII_PHY_CONTROL,
+ (mii_phyctrl | GMII_PHY_CONTROL_RESET |
+ MII_PHY_CONTROL_RESTARTAN));

- if (sp == NULL) {
- printk(KERN_INFO
- "%s: No memory available for IP1000 private strucutre.\n",
- dev->name);
- return -ENOMEM;
- } else {
- /* Fill the allocated memory space with 0s.
- * Essentially sets all ipg_nic_private
- * structure fields to 0.
- */
- memset(sp, 0, sizeof(*sp));
- dev->priv = sp;
}

- /* Assign the new device to the list of IPG Ethernet devices. */
- sp->next_dev = root_dev;
- root_dev = dev;
+ /* Read MAC Address from EERPOM Jesse20040128EEPROM_VALUE */
+ sp->StationAddr0 = read_eeprom(dev, 16);
+ sp->StationAddr1 = read_eeprom(dev, 17);
+ sp->StationAddr2 = read_eeprom(dev, 18);
+ /* Write MAC Address to Station Address */
+ iowrite16(sp->StationAddr0, ioaddr + IPG_STATIONADDRESS0);
+ iowrite16(sp->StationAddr1, ioaddr + IPG_STATIONADDRESS1);
+ iowrite16(sp->StationAddr2, ioaddr + IPG_STATIONADDRESS2);

- /* Declare IPG NIC functions for Ethernet device methods.
- */
- dev->open = &ipg_nic_open;
- dev->stop = &ipg_nic_stop;
- dev->hard_start_xmit = &ipg_nic_hard_start_xmit;
- dev->get_stats = &ipg_nic_get_stats;
- dev->set_multicast_list = &ipg_nic_set_multicast_list;
- dev->do_ioctl = &ipg_nic_do_ioctl;
- dev->change_mtu = &ipg_nic_change_mtu;
+ /* Set station address in ethernet_device structure. */
+ dev->dev_addr[0] = ioread16(ioaddr + IPG_STATIONADDRESS0) & 0x00FF;
+ dev->dev_addr[1] =
+ (ioread16(ioaddr + IPG_STATIONADDRESS0) & 0xFF00) >> 8;
+ dev->dev_addr[2] = ioread16(ioaddr + IPG_STATIONADDRESS1) & 0x00FF;
+ dev->dev_addr[3] =
+ (ioread16(ioaddr + IPG_STATIONADDRESS1) & 0xFF00) >> 8;
+ dev->dev_addr[4] = ioread16(ioaddr + IPG_STATIONADDRESS2) & 0x00FF;
+ dev->dev_addr[5] =
+ (ioread16(ioaddr + IPG_STATIONADDRESS2) & 0xFF00) >> 8;

return 0;
}
@@ -3144,99 +2933,23 @@

static void ipg_remove(struct pci_dev *pdev)
{
- /* Remove function called when a IPG device is
- * to be shut down.
- */
-
- struct net_device *prev_dev = NULL;
- struct net_device *dev = NULL;
- struct net_device *dev_to_remove = NULL;
- struct ipg_nic_private *prev_sp = NULL;
- struct ipg_nic_private *sp = NULL;
- struct ipg_nic_private *sp_to_remove = NULL;
-
- IPG_DEBUG_MSG("_pciremove_linux2_4\n");
-
- dev = root_dev;
-
- /* Move through list of Ethernet devices looking for
- * a match.
- */
- while (dev) {
- sp = netdev_priv(dev);
-
- if (sp->pdev == pdev) {
- /* Save the pointer to the previous Ethernet
- * device.
- */
- dev_to_remove = dev;
-
- sp_to_remove = sp;
-
- break;
- }
-
- /* Save the "previous" device in the list. */
- prev_dev = dev;
-
- /* Retrieve next Ethernet device to be
- * released.
- */
- dev = sp->next_dev;
- }
-
- /* Check if there is a device to remove. */
- if (dev_to_remove == NULL) {
- /* There are no Ethernet devices to remove. */
- printk(KERN_INFO
- "A device remove request does not match with any Ethernet devices.\n");
-
- return;
- }
-
- /* Check to see if we are removing the root device in the list. */
- if (root_dev == dev_to_remove) {
- /* Change the root Ethernet device to the next device to be
- * released.
- */
- root_dev = sp_to_remove->next_dev;
- } else if (sp_to_remove->next_dev != NULL)
- /* Check if we need to re-link the list of devices. */
- {
- /* If the "previous" Ethernet device is NULL,
- * the device is at the head of the list, and
- * no re-linking is needed.
- */
- prev_sp = netdev_priv(prev_dev);
-
- prev_sp->next_dev = sp_to_remove->next_dev;
- }
-
- /* Free memory associated with Ethernet device's
- * private data structure.
- */
- if (sp_to_remove) {
- kfree(sp_to_remove);
- }
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct ipg_nic_private *sp = netdev_priv(dev);

- printk(KERN_INFO "Un-registering Ethernet device %s\n",
- dev_to_remove->name);
+ IPG_DEBUG_MSG("_remove\n");

/* Un-register Ethernet device. */
- unregister_netdev(dev_to_remove);
+ unregister_netdev(dev);

#ifdef USE_IO_OPS
ioport_unmap(ioaddr);
#else
iounmap(sp->ioaddr);
#endif
-
pci_release_regions(pdev);

- /* Free memory associated with Ethernet device. */
- if (dev_to_remove) {
- kfree(dev_to_remove);
- }
+ free_netdev(dev);
+ pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}

@@ -3269,13 +2982,31 @@
goto out;
}

- err = ipg_nic_init(dev);
- if (err) {
- printk(KERN_INFO "Could not intialize IP1000 based NIC.\n");
+ /*
+ * Initialize net device.
+ */
+ dev = alloc_etherdev(sizeof(struct ipg_nic_private));
+ if (!dev) {
+ printk(KERN_ERR "ipg: alloc_etherdev failed\n");
+ err = -ENOMEM;
goto out;
}
- dev = root_dev;
+
+ sp = netdev_priv(dev);
+ spin_lock_init(&sp->lock);
+
+ /* Declare IPG NIC functions for Ethernet device methods.
+ */
+ dev->open = &ipg_nic_open;
+ dev->stop = &ipg_nic_stop;
+ dev->hard_start_xmit = &ipg_nic_hard_start_xmit;
+ dev->get_stats = &ipg_nic_get_stats;
+ dev->set_multicast_list = &ipg_nic_set_multicast_list;
+ dev->do_ioctl = &ipg_nic_do_ioctl;
+ dev->change_mtu = &ipg_nic_change_mtu;
+
SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);

err = pci_request_regions(pdev, DRV_NAME);
if (err)
@@ -3300,13 +3031,17 @@
goto out;
}
#endif
- sp = netdev_priv(root_dev);
+ sp = netdev_priv(dev);
/* Save the pointer to the PCI device information. */
sp->ioaddr = ioaddr;
sp->pdev = pdev;

pci_set_drvdata(pdev, dev);

+ err = ipg_hw_init(dev);
+ if (err)
+ goto out;
+
err = register_netdev(dev);
if (err)
goto out;
Index: linux-source-2.6.16/drivers/net/ipg.h
===================================================================
--- linux-source-2.6.16.orig/drivers/net/ipg.h 2006-04-30 23:02:09.861345105 +0100
+++ linux-source-2.6.16/drivers/net/ipg.h 2006-05-01 00:11:14.974349454 +0100
@@ -15,85 +15,6 @@
* 408 873 4117
* www.sundanceti.com
* craig_rich@xxxxxxxxxxxxxx
- *
- * Rev Date Description
- * --------------------------------------------------------------
- * 0.1 11/8/99 Initial revision work begins
- *
- * 0.2 12/1/99 Minor update to modversions.h inclusion.
- *
- * 0.3 12/30/99 Updates to fully comply with IPG spec.
- *
- * 0.4 4/24/00 Updates to allow for removal of FCS generation
- * and verification.
- * 0.5 8/15/00 Updates for MII PHY registers and fields.
- *
- * 0.6 8/31/00 Updates to change to using 64 bit data types
- *
- * 0.7 10/31/00 Added DDEBUG_MSG to allow for easy activation of
- * individual DEBUG_MSGs.
- *
- * 0.8 11/06/00 Changed LastFreedRxBuff to LastRestoredRxBuff for
- * clarity.
- *
- * 0.9 11/10/00 Changed Sundance DeviceID to 0x9020
- *
- * 0.10 2/14/01 Changed "DROP_ON_ERRORS", breaking out Ethernet from
- * TCP/IP errors.
- *
- * 0.11 3/16/01 Changed "IPG_FRAMESBETWEENTXCOMPLETES" to
- * "IPG_FRAMESBETWEENTXDMACOMPLETES" since will
- * be using TxDMAIndicate instead of TxIndicate to
- * improve performance. Added TFDunavailCount and
- * RFDlistendCount to aid in performance improvement.
- *
- * 0.12 3/22/01 Removed IPG_DROP_ON_RX_TCPIP_ERRORS.
- *
- * 0.13 3/23/01 Removed IPG_TXQUEUE_MARGIN.
- *
- * 0.14 3/30/01 Broke out sections into multiple files and added
- * OS version specific detection and settings.
- */
-
-/*
- * Linux header utilization:
- *
- * config.h For PCI support, namely CONFIG_PCI macro.
- *
- * version.h For Linux kernel version detection.
- *
- * module.h For modularized driver support.
- *
- * kernel.h For 'printk'.
- *
- * pci.h PCI support, including ID, VENDOR, and CLASS
- * standard definitions; PCI specific structures,
- * including pci_dev struct.
- *
- * ioport.h I/O ports, check_region, request_region,
- * release_region.
- *
- * errno.h Standard error numbers, e.g. ENODEV.
- *
- * asm/io.h For reading/writing I/O ports, and for virt_to_bus
- * function.
- *
- * delay.h For milisecond delays.
- *
- * types.h For specific typedefs (i.e. u32, u16, u8).
- *
- * netdevice.h For device structure needed for network support.
- *
- * etherdevice.h For ethernet device support.
- *
- * init.h For __initfunc.
- *
- * skbuff.h Socket buffer (skbuff) definition.
- *
- * asm/bitops.h For test_and_set_bit, clear_bit functions.
- *
- * asm/spinlock.h For spin_lock_irqsave, spin_lock_irqrestore functions.
- *
*/
#ifndef __LINUX_IPG_H
#define __LINUX_IPG_H
@@ -1000,9 +921,6 @@
* End miscellaneous macros.
*/

-/* IPG Ethernet device structure, used for removing module. */
-struct net_device *root_dev = NULL;
-
/* Transmit Frame Descriptor. The IPG supports 15 fragments,
* however Linux requires only a single fragment. Note, each
* TFD field is 64 bits wide.
@@ -1054,7 +972,6 @@
int RxBuffNotReady;
struct pci_dev *pdev;
struct net_device_stats stats;
- struct net_device *next_dev;
spinlock_t lock;
int tenmbpsmode;