diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-11-23 02:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-11-23 02:00:47 +0000 |
commit | 06615f62b17d7de6e12d2f5ec6b88cf30af08413 (patch) | |
tree | 8766f208847d4876a6db619aebbf54d53b76eb44 /drivers/net/tlan.c | |
parent | fa9bdb574f4febb751848a685d9a9017e04e1d53 (diff) |
Merge with Linux 2.4.0-test10.
Diffstat (limited to 'drivers/net/tlan.c')
-rw-r--r-- | drivers/net/tlan.c | 863 |
1 files changed, 506 insertions, 357 deletions
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 63dce60eb..33e98c23e 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -98,14 +98,47 @@ * v1.8a May 28, 2000 - Minor updates. * * v1.9 July 25, 2000 - Fixed a few remaining Full-Duplex issues. - * - Updated with timer fixes from Andrew Morton. - * - Fixed module race in TLan_Open. - * - Added routine to monitor PHY status. - * - Added activity led support for Proliant devices. + * - Updated with timer fixes from Andrew Morton. + * - Fixed module race in TLan_Open. + * - Added routine to monitor PHY status. + * - Added activity led support for Proliant devices. + * + * v1.10 Aug 30, 2000 - Added support for EISA based tlan controllers + * like the Compaq NetFlex3/E. + * - Rewrote tlan_probe to better handle multiple + * bus probes. Probing and device setup is now + * done through TLan_Probe and TLan_init_one. Actual + * hardware probe is done with kernel API and + * TLan_EisaProbe. + * - Adjusted debug information for probing. + * - Fixed bug that would cause general debug information + * to be printed after driver removal. + * - Added transmit timeout handling. + * - Fixed OOM return values in tlan_probe. + * - Fixed possible mem leak in tlan_exit + * (now tlan_remove_one). + * - Fixed timer bug in TLan_phyMonitor. + * - This driver version is alpha quality, please + * send me any bug issues you may encounter. + * + * v1.11 Aug 31, 2000 - Do not try to register irq 0 if no irq line was + * set for EISA cards. + * - Added support for NetFlex3/E with nibble-rate + * 10Base-T PHY. This is untestet as I haven't got + * one of these cards. + * - Fixed timer being added twice. + * - Disabled PhyMonitoring by default as this is + * work in progress. Define MONITOR to enable it. + * - Now we don't display link info with PHYs that + * doesn't support it (level1). + * - Incresed tx_timeout beacuse of auto-neg. + * - Adjusted timers for forced speeds. + * + * v1.12 Oct 12, 2000 - Minor fixes (memleak, init, etc.) * *******************************************************************************/ - + #include <linux/module.h> #include "tlan.h" @@ -121,14 +154,15 @@ typedef u32 (TLanIntVectorFunc)( struct net_device *, u16 ); +/* For removing EISA devices */ +static struct net_device *TLan_Eisa_Devices; -static struct net_device *TLanDevices = NULL; -static int TLanDevicesInstalled = 0; +static int TLanDevicesInstalled; /* Force speed, duplex and aui settings */ -static int aui = 0; -static int duplex = 0; -static int speed = 0; +static int aui; +static int duplex; +static int speed; MODULE_AUTHOR("Maintainer: Torben Mathiasen <torben.mathiasen@compaq.com>"); MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters"); @@ -138,13 +172,18 @@ MODULE_PARM(speed, "i"); MODULE_PARM(debug, "i"); EXPORT_NO_SYMBOLS; +/* Define this to enable Link beat monitoring */ +#undef MONITOR + /* Turn on debugging. See linux/Documentation/networking/tlan.txt for details */ -static int debug = 0; +static int debug; -static int bbuf = 0; +static int bbuf; static u8 *TLanPadBuffer; static char TLanSignature[] = "TLAN"; -static const char *tlan_banner = "ThunderLAN driver v1.9\n"; +static const char *tlan_banner = "ThunderLAN driver v1.12\n"; +static int tlan_have_pci; +static int tlan_have_eisa; const char *media[] = { "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", @@ -153,103 +192,73 @@ const char *media[] = { int media_map[] = { 0x0020, 0x0040, 0x0080, 0x0100, 0x0200,}; -static TLanAdapterEntry TLanAdapterList[] __initdata = { - { PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_NETELLIGENT_10, - "Compaq Netelligent 10 T PCI UTP", - TLAN_ADAPTER_ACTIVITY_LED, - 0x83 - }, - { PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_NETELLIGENT_10_100, - "Compaq Netelligent 10/100 TX PCI UTP", - TLAN_ADAPTER_ACTIVITY_LED, - 0x83 - }, - { PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED, - "Compaq Integrated NetFlex-3/P", - TLAN_ADAPTER_NONE, - 0x83 - }, - { PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_NETFLEX_3P, - "Compaq NetFlex-3/P", - TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, - 0x83 - }, - { PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_NETFLEX_3P_BNC, - "Compaq NetFlex-3/P", - TLAN_ADAPTER_NONE, - 0x83 - }, - { PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT, - "Compaq Netelligent Integrated 10/100 TX UTP", - TLAN_ADAPTER_ACTIVITY_LED, - 0x83 - }, - { PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL, - "Compaq Netelligent Dual 10/100 TX PCI UTP", - TLAN_ADAPTER_NONE, - 0x83 - }, - { PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_DESKPRO_4000_5233MMX, - "Compaq Netelligent 10/100 TX Embedded UTP", - TLAN_ADAPTER_NONE, - 0x83 - }, - { PCI_VENDOR_ID_OLICOM, - PCI_DEVICE_ID_OLICOM_OC2183, - "Olicom OC-2183/2185", - TLAN_ADAPTER_USE_INTERN_10, - 0xF8 - }, - { PCI_VENDOR_ID_OLICOM, - PCI_DEVICE_ID_OLICOM_OC2325, - "Olicom OC-2325", - TLAN_ADAPTER_UNMANAGED_PHY, - 0xF8 - }, - { PCI_VENDOR_ID_OLICOM, - PCI_DEVICE_ID_OLICOM_OC2326, - "Olicom OC-2326", - TLAN_ADAPTER_USE_INTERN_10, - 0xF8 - }, - { PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100, - "Compaq Netelligent 10/100 TX UTP", - TLAN_ADAPTER_ACTIVITY_LED, - 0x83 - }, - { PCI_VENDOR_ID_COMPAQ, - PCI_DEVICE_ID_NETELLIGENT_10_T2, - "Compaq Netelligent 10 T/2 PCI UTP/Coax", - TLAN_ADAPTER_NONE, - 0x83 - }, - { 0, - 0, - NULL, - 0, - 0 - } /* End of List */ +static struct board { + const char *deviceLabel; + u32 flags; + u16 addrOfs; +} board_info[] __devinitdata = { + { "Compaq Netelligent 10 T PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Netelligent 10/100 TX PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Integrated NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq NetFlex-3/P", TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, + { "Compaq NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq Netelligent Integrated 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Netelligent Dual 10/100 TX PCI UTP", TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq Netelligent 10/100 TX Embedded UTP", TLAN_ADAPTER_NONE, 0x83 }, + { "Olicom OC-2183/2185", TLAN_ADAPTER_USE_INTERN_10, 0x83 }, + { "Olicom OC-2325", TLAN_ADAPTER_UNMANAGED_PHY, 0xF8 }, + { "Olicom OC-2326", TLAN_ADAPTER_USE_INTERN_10, 0xF8 }, + { "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Netelligent 10 T/2 PCI UTP/Coax", TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */ + TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, + { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */ }; +static struct pci_device_id tlan_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P_BNC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_DESKPRO_4000_5233MMX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, + { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2183, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, + { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2325, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, + { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2326, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_T2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, + { 0,} +}; +MODULE_DEVICE_TABLE(pci, tlan_pci_tbl); -static int TLan_PciProbe( u8 *, u8 *, u8 *, u32 *, u32 * ); +static void TLan_EisaProbe( void ); +static void TLan_Eisa_Cleanup( void ); static int TLan_Init( struct net_device * ); -static int TLan_Open(struct net_device *dev); -static int TLan_StartTx(struct sk_buff *, struct net_device *); -static void TLan_HandleInterrupt(int, void *, struct pt_regs *); -static int TLan_Close(struct net_device *); -static struct net_device_stats *TLan_GetStats( struct net_device * ); -static void TLan_SetMulticastList( struct net_device * ); -static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int TLan_Open( struct net_device *dev ); +static int TLan_StartTx( struct sk_buff *, struct net_device *); +static void TLan_HandleInterrupt( int, void *, struct pt_regs *); +static int TLan_Close( struct net_device *); +static struct net_device_stats *TLan_GetStats( struct net_device *); +static void TLan_SetMulticastList( struct net_device *); +static int TLan_ioctl( struct net_device *dev, struct ifreq *rq, int cmd); +static int TLan_probe1( struct pci_dev *pdev, long ioaddr, int irq, int rev, const struct pci_device_id *ent); +static void TLan_tx_timeout( struct net_device *dev); +static int tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent); static u32 TLan_HandleInvalid( struct net_device *, u16 ); static u32 TLan_HandleTxEOF( struct net_device *, u16 ); @@ -278,7 +287,10 @@ static void TLan_PhyPowerUp( struct net_device * ); static void TLan_PhyReset( struct net_device * ); static void TLan_PhyStartLink( struct net_device * ); static void TLan_PhyFinishAutoNeg( struct net_device * ); -static void TLan_PhyMonitor( struct net_device * ); +#ifdef MONITOR +static void TLan_PhyMonitor( struct net_device * ); +#endif + /* static int TLan_PhyNop( struct net_device * ); static int TLan_PhyInternalCheck( struct net_device * ); @@ -316,7 +328,7 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) spin_lock_irqsave(&priv->lock, flags); if ( priv->timer.function != NULL && - priv->timerType != TLAN_TIMER_ACTIVITY) { + priv->timerType != TLAN_TIMER_ACTIVITY ) { spin_unlock_irqrestore(&priv->lock, flags); return; } @@ -324,11 +336,10 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) spin_unlock_irqrestore(&priv->lock, flags); priv->timer.data = (unsigned long) dev; - priv->timer.expires = jiffies + ticks; priv->timerSetAt = jiffies; priv->timerType = type; - add_timer( &priv->timer ); - + mod_timer(&priv->timer, jiffies + ticks); + } /* TLan_SetTimer */ @@ -344,8 +355,10 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) + + /*************************************************************** - * tlan_exit + * tlan_remove_one * * Returns: * Nothing @@ -360,31 +373,77 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) **************************************************************/ -static void __exit tlan_exit(void) +static void __devexit tlan_remove_one( struct pci_dev *pdev) { - struct net_device *dev; - TLanPrivateInfo *priv; + struct net_device *dev = pdev->driver_data; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + + unregister_netdev( dev ); - while ( TLanDevicesInstalled ) { - dev = TLanDevices; - priv = (TLanPrivateInfo *) dev->priv; - if ( priv->dmaStorage ) { - kfree( priv->dmaStorage ); - } - release_region( dev->base_addr, 0x10 ); - unregister_netdev( dev ); - TLanDevices = priv->nextDevice; - kfree( dev ); - TLanDevicesInstalled--; + if ( priv->dmaStorage ) { + kfree( priv->dmaStorage ); } - kfree( TLanPadBuffer ); + release_region( dev->base_addr, 0x10 ); + + kfree( dev ); + } +static struct pci_driver tlan_driver = { + name: "tlan", + id_table: tlan_pci_tbl, + probe: tlan_init_one, + remove: tlan_remove_one, +}; + +static int __init tlan_probe(void) +{ + static int pad_allocated = 0; + + printk(KERN_INFO "%s", tlan_banner); + + TLanPadBuffer = (u8 *) kmalloc(TLAN_MIN_FRAME_SIZE, + (GFP_KERNEL | GFP_DMA)); + + if (TLanPadBuffer == NULL) { + printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n"); + return -ENOMEM; + } + + memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE); + pad_allocated = 1; + + TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n"); + + /* Use new style PCI probing. Now the kernel will + do most of this for us */ + pci_module_init(&tlan_driver); + + TLAN_DBG(TLAN_DEBUG_PROBE, "Starting EISA Probe....\n"); + TLan_EisaProbe(); + + printk(KERN_INFO "TLAN: %d device%s installed, PCI: %d EISA: %d\n", + TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s", + tlan_have_pci, tlan_have_eisa); + + return ((TLanDevicesInstalled > 0) ? 0 : -ENODEV); + +} + + +static int __devinit tlan_init_one( struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + return TLan_probe1( pdev, pci_resource_start(pdev, 0), pdev->irq, + 0, ent); + +} + /* *************************************************************** - * tlan_probe + * tlan_probe1 * * Returns: * 0 on success, error code on error @@ -401,197 +460,249 @@ static void __exit tlan_exit(void) * **************************************************************/ -static int __init tlan_probe(void) +static int __devinit TLan_probe1(struct pci_dev *pdev, + long ioaddr, int irq, int rev, const struct pci_device_id *ent ) { struct net_device *dev; TLanPrivateInfo *priv; - static int pad_allocated = 0; - u8 dfn, irq, rev; - u32 io_base, index; - int found; - - printk(KERN_INFO "%s", tlan_banner); + u8 pci_rev; + u16 device_id; - TLanPadBuffer = (u8 *) kmalloc(TLAN_MIN_FRAME_SIZE, - (GFP_KERNEL | GFP_DMA)); - - if (TLanPadBuffer == NULL) { - printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n"); + dev = init_etherdev(NULL, sizeof(TLanPrivateInfo)); + if (dev == NULL) { + printk(KERN_ERR "TLAN: Could not allocate memory for device.\n"); return -ENOMEM; } - - memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE); - - while((found = TLan_PciProbe( &dfn, &irq, &rev, &io_base, &index))) { - dev = init_etherdev(NULL, sizeof(TLanPrivateInfo)); - if (dev == NULL) { - printk(KERN_ERR "TLAN: Could not allocate memory for device.\n"); - return -ENOMEM; + + priv = dev->priv; + + dev->base_addr = ioaddr; + dev->irq = irq; + + + /* Is this a PCI device? */ + if (pdev) { + priv->adapter = &board_info[ent->driver_data]; + if (pci_enable_device(pdev)) { + unregister_netdev(dev); + kfree(dev); + return -1; } - priv = dev->priv; - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(TLanPrivateInfo), GFP_KERNEL); - priv = dev->priv; + pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev); + priv->adapterRev = pci_rev; + pci_set_master(pdev); + pdev->driver_data = dev; + + } else { /* EISA card */ + /* This is a hack. We need to know which board structure + * is suited for this adapter */ + device_id = inw(ioaddr + EISA_ID2); + priv->is_eisa = 1; + if (device_id == 0x20F1) { + priv->adapter = &board_info[13]; /* NetFlex-3/E */ + priv->adapterRev = 23; /* TLAN 2.3 */ + } else { + priv->adapter = &board_info[14]; + priv->adapterRev = 10; /* TLAN 1.0 */ } - memset(priv, 0, sizeof(TLanPrivateInfo)); - - pad_allocated = 1; - - dev->base_addr = io_base; - dev->irq = irq; - priv->adapter = &TLanAdapterList[index]; - priv->adapterRev = rev; + } + + /* Kernel parameters */ + if (dev->mem_start) { + priv->aui = dev->mem_start & 0x01; + priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 : (dev->mem_start & 0x06) >> 1; + priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3; + + if (priv->speed == 0x1) { + priv->speed = TLAN_SPEED_10; + } else if (priv->speed == 0x2) { + priv->speed = TLAN_SPEED_100; + } + debug = priv->debug = dev->mem_end; + } else { + + if ( ( duplex != 1 ) && ( duplex != 2 ) ) + duplex = 0; + priv->duplex = duplex; + + if ( ( speed != 10 ) && ( speed != 100 ) ) + speed = 0; - /* Kernel parameters */ - if (dev->mem_start) { - priv->aui = dev->mem_start & 0x01; - priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 : (dev->mem_start & 0x06) >> 1; - priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3; + priv->aui = aui; + priv->speed = speed; + priv->debug = debug; - if (priv->speed == 0x1) { - priv->speed = TLAN_SPEED_10; - } else if (priv->speed == 0x2) { - priv->speed = TLAN_SPEED_100; - } - debug = priv->debug = dev->mem_end; - } else { + } + + spin_lock_init(&priv->lock); + + if (TLan_Init(dev)) { + printk(KERN_ERR "TLAN: Could not register device.\n"); + unregister_netdev(dev); + kfree(dev); + return -EAGAIN; + } else { + + TLanDevicesInstalled++; + + /* pdev is NULL if this is an EISA device */ + if (pdev) + tlan_have_pci++; + else { + priv->nextDevice = TLan_Eisa_Devices; + TLan_Eisa_Devices = dev; + tlan_have_eisa++; + } + + printk(KERN_INFO "TLAN: %s irq=%2d, io=%04x, %s, Rev. %d\n", + dev->name, + (int) dev->irq, + (int) dev->base_addr, + priv->adapter->deviceLabel, + priv->adapterRev); + return 0; + } - if ( ( duplex != 1 ) && ( duplex != 2 ) ) - duplex = 0; - - priv->duplex = duplex; +} - if ( ( speed != 10 ) && ( speed != 100 ) ) - speed = 0; - - priv->aui = aui; - priv->speed = speed; - priv->debug = debug; - - } - - spin_lock_init(&priv->lock); - - if (TLan_Init(dev)) { - printk(KERN_ERR "TLAN: Could not register device.\n"); - unregister_netdev(dev); - kfree(dev); - } else { - - TLanDevicesInstalled++; - priv->nextDevice = TLanDevices; - TLanDevices = dev; - printk(KERN_INFO "TLAN: %s irq=%2d, io=%04x, %s, Rev. %d\n", - dev->name, - (int) dev->irq, - (int) dev->base_addr, - priv->adapter->deviceLabel, - priv->adapterRev); - } - } +static void TLan_Eisa_Cleanup(void) +{ + struct net_device *dev; + TLanPrivateInfo *priv; - printk(KERN_INFO "TLAN: %d device%s installed\n", - TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s"); + while( tlan_have_eisa ) { + dev = TLan_Eisa_Devices; + priv = (TLanPrivateInfo *) dev->priv; + if (priv->dmaStorage) { + kfree(priv->dmaStorage); + } + release_region( dev->base_addr, 0x10); + unregister_netdev( dev ); + TLan_Eisa_Devices = priv->nextDevice; + kfree( dev ); + tlan_have_eisa--; + } +} - return ((TLanDevicesInstalled > 0) ? 0 : -ENODEV); + +static void __exit tlan_exit(void) +{ + if (tlan_have_pci) + pci_unregister_driver(&tlan_driver); + + if (tlan_have_eisa) + TLan_Eisa_Cleanup(); + + kfree( TLanPadBuffer ); + } + /* Module loading/unloading */ module_init(tlan_probe); module_exit(tlan_exit); - /*************************************************************** - * TLan_PciProbe + /************************************************************** + * TLan_EisaProbe * - * Returns: - * 1 if another TLAN card was found, 0 if not. - * Parms: - * pci_dfn The PCI whatever the card was - * found at. - * pci_irq The IRQ of the found adapter. - * pci_rev The revision of the adapter. - * pci_io_base The first IO port used by the - * adapter. - * dl_ix The index in the device list - * of the adapter. - * - * This function searches for an adapter with PCI vendor - * and device IDs matching those in the TLanAdapterList. - * The function 'remembers' the last device it found, - * and so finds a new device (if anymore are to be found) - * each time the function is called. It then looks up - * pertinent PCI info and returns it to the caller. + * Returns: 0 on success, 1 otherwise * - **************************************************************/ + * Parms: None + * + * + * This functions probes for EISA devices and calls + * TLan_probe1 when one is found. + * + *************************************************************/ -static int __init TLan_PciProbe(u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix ) +static void __init TLan_EisaProbe (void) { - static int dl_index = 0; - static struct pci_dev * pdev = NULL; - u16 pci_command; - int reg; - - - for (; TLanAdapterList[dl_index].vendorId != 0; dl_index++) { - - pdev = pci_find_device( - TLanAdapterList[dl_index].vendorId, - TLanAdapterList[dl_index].deviceId, pdev); - - if ( pdev ) { - - TLAN_DBG( - TLAN_DEBUG_GNRL, - "found: Vendor Id = 0x%hx, Device Id = 0x%hx\n", - TLanAdapterList[dl_index].vendorId, - TLanAdapterList[dl_index].deviceId - ); + long ioaddr; + int rc = -ENODEV; + int irq; + u16 device_id; - if (pci_enable_device(pdev)) - continue; - - *pci_irq = pdev->irq; - *pci_io_base = pci_resource_start (pdev, 0); - *pci_dfn = pdev->devfn; - pci_read_config_byte ( pdev, PCI_REVISION_ID, pci_rev); - pci_read_config_word ( pdev, PCI_COMMAND, &pci_command); - - for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg +=4 ) { - pci_read_config_dword( pdev, reg, pci_io_base); - if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) { - *pci_io_base &= PCI_BASE_ADDRESS_IO_MASK; - TLAN_DBG( TLAN_DEBUG_GNRL, "IO mapping is available at %x.\n", *pci_io_base); - break; - } else { - *pci_io_base = 0; - } - } - - if ( *pci_io_base == 0 ) - printk(KERN_INFO "TLAN: IO mapping not available, ignoring device.\n"); + if (!EISA_bus) { + TLAN_DBG(TLAN_DEBUG_PROBE, "No EISA bus present\n"); + return; + } + + /* Loop through all slots of the EISA bus */ + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { + + TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID)); + TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2)); - pci_set_master(pdev); - if ( *pci_io_base ) { - *dl_ix = dl_index; - return 1; - } + TLAN_DBG(TLAN_DEBUG_PROBE, "Probing for EISA adapter at IO: 0x%4x : ", + (int) ioaddr); + if (request_region(ioaddr, 0x10, TLanSignature) == NULL) + goto out; - } else { - pdev = NULL; + if (inw(ioaddr + EISA_ID) != 0x110E) { + release_region(ioaddr, 0x10); + goto out; + } + + device_id = inw(ioaddr + EISA_ID2); + if (device_id != 0x20F1 && device_id != 0x40F1) { + release_region (ioaddr, 0x10); + goto out; } + + if (inb(ioaddr + EISA_CR) != 0x1) { /* Check if adapter is enabled */ + release_region (ioaddr, 0x10); + goto out2; + } + + if (debug == 0x10) + printk("Found one\n"); + + + /* Get irq from board */ + switch (inb(ioaddr + 0xCC0)) { + case(0x10): + irq=5; + break; + case(0x20): + irq=9; + break; + case(0x40): + irq=10; + break; + case(0x80): + irq=11; + break; + default: + goto out; + } + + + /* Setup the newly found eisa adapter */ + rc = TLan_probe1( NULL, ioaddr, irq, + 12, NULL); + continue; + + out: + if (debug == 0x10) + printk("None found\n"); + continue; + + out2: if (debug == 0x10) + printk("Card found but it is not enabled, skipping\n"); + continue; + } - return 0; - -} /* TLan_PciProbe */ +} /* TLan_EisaProbe */ + /*************************************************************** @@ -620,14 +731,14 @@ static int TLan_Init( struct net_device *dev ) priv = (TLanPrivateInfo *) dev->priv; - if (!request_region( dev->base_addr, 0x10, TLanSignature )) { - printk(KERN_ERR "TLAN: %s: Io port region 0x%lx size 0x%x in use.\n", - dev->name, - dev->base_addr, - 0x10 ); - return -EIO; - } - + if (!priv->is_eisa) /* EISA devices have already requested IO */ + if (!request_region( dev->base_addr, 0x10, TLanSignature )) { + printk(KERN_ERR "TLAN: %s: IO port region 0x%lx size 0x%x in use.\n", + dev->name, + dev->base_addr, + 0x10 ); + return -EIO; + } if ( bbuf ) { dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) @@ -658,7 +769,7 @@ static int TLan_Init( struct net_device *dev ) (u8) priv->adapter->addrOfs + i, (u8 *) &dev->dev_addr[i] ); if ( err ) { - printk(KERN_ERR "TLAN: %s: Error reading MAC from eeprom: %d\n", + printk(KERN_ERR "TLAN: %s: Error reading MAC from eeprom: %d\n", dev->name, err ); } @@ -671,6 +782,8 @@ static int TLan_Init( struct net_device *dev ) dev->get_stats = &TLan_GetStats; dev->set_multicast_list = &TLan_SetMulticastList; dev->do_ioctl = &TLan_ioctl; + dev->tx_timeout = &TLan_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; return 0; @@ -712,6 +825,7 @@ static int TLan_Open( struct net_device *dev ) return err; } + init_timer(&priv->timer); netif_start_queue(dev); /* NOTE: It might not be necessary to read the stats before a @@ -772,6 +886,32 @@ static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } /* tlan_ioctl */ + /*************************************************************** + * TLan_tx_timeout + * + * Returns: nothing + * + * Params: + * dev structure of device which timed out + * during transmit. + * + **************************************************************/ + +static void TLan_tx_timeout(struct net_device *dev) +{ + + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name); + + /* Ok so we timed out, lets see what we can do about it...*/ + TLan_ResetLists( dev ); + TLan_ReadAndClearStats( dev, TLAN_IGNORE ); + TLan_ResetAdapter( dev ); + dev->trans_start = jiffies; + netif_wake_queue( dev ); + +} + + /*************************************************************** * TLan_StartTx @@ -953,6 +1093,7 @@ static int TLan_Close(struct net_device *dev) del_timer_sync( &priv->timer ); priv->timer.function = NULL; } + free_irq( dev->irq, dev ); TLan_FreeLists( dev ); TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name ); @@ -993,7 +1134,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev ) TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount ); if ( debug & TLAN_DEBUG_GNRL ) { TLan_PrintDio( dev->base_addr ); - TLan_PhyPrint( dev ); + TLan_PhyPrint( dev ); } if ( debug & TLAN_DEBUG_LIST ) { for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) @@ -1495,7 +1636,7 @@ u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) } if (debug) { - TLan_PhyPrint( dev ); + TLan_PhyPrint( dev ); } } } @@ -1598,9 +1739,11 @@ void TLan_Timer( unsigned long data ) priv->timer.function = NULL; switch ( priv->timerType ) { +#ifdef MONITOR case TLAN_TIMER_LINK_BEAT: TLan_PhyMonitor( dev ); break; +#endif case TLAN_TIMER_PHY_PDOWN: TLan_PhyPowerDown( dev ); break; @@ -2007,6 +2150,7 @@ TLan_FinishReset( struct net_device *dev ) u16 partner; u16 tlphy_ctl; u16 tlphy_par; + u16 tlphy_id1, tlphy_id2; int i; phy = priv->phy[priv->phyNum]; @@ -2022,7 +2166,9 @@ TLan_FinishReset( struct net_device *dev ) } TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data ); TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, TLAN_MAX_FRAME_SIZE ); - + TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 ); + TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 ); + if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) { status = MII_GS_LINK; printk( "TLAN: %s: Link forced.\n", dev->name ); @@ -2030,7 +2176,9 @@ TLan_FinishReset( struct net_device *dev ) TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); udelay( 1000 ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); - if ( status & MII_GS_LINK ) { + if ( (status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */ + (tlphy_id1 == NAT_SEM_ID1) && + (tlphy_id2 == NAT_SEM_ID2) ) { TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner ); TLan_MiiReadReg( dev, phy, TLAN_TLPHY_PAR, &tlphy_par ); @@ -2043,7 +2191,6 @@ TLan_FinishReset( struct net_device *dev ) printk( "AutoNegotiation enabled, at 10%sMbps %s-Duplex\n", tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); - printk("TLAN: Partner capability: "); for (i = 5; i <= 10; i++) if (partner & (1<<i)) @@ -2052,12 +2199,15 @@ TLan_FinishReset( struct net_device *dev ) } TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); - +#ifdef MONITOR /* We have link beat..for now anyway */ - priv->link = 1; - /*Enabling link beat monitoring */ + priv->link = 1; + /*Enabling link beat monitoring */ TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_LINK_BEAT ); - +#endif + } else if (status & MII_GS_LINK) { + printk( "TLAN: %s: Link active\n", dev->name ); + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); } } @@ -2074,13 +2224,12 @@ TLan_FinishReset( struct net_device *dev ) TLan_SetMac( dev, 0, dev->dev_addr ); priv->phyOnline = 1; outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); - if ( debug >= 1 ) { + if ( debug >= 1 && debug != TLAN_DEBUG_PROBE ) { outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); } outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); - - } else { + } else { printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET ); return; @@ -2217,7 +2366,7 @@ void TLan_PhyDetect( struct net_device *dev ) } TLan_MiiReadReg( dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi ); - + if ( hi != 0xFFFF ) { priv->phy[0] = TLAN_PHY_MAX_ADDR; } else { @@ -2289,7 +2438,7 @@ void TLan_PhyPowerUp( struct net_device *dev ) * tranceiver. The TLAN docs say both 50 ms and * 500 ms, so do the longer, just in case. */ - TLan_SetTimer( dev, (HZ/2), TLAN_TIMER_PHY_RESET ); + TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_RESET ); } /* TLan_PhyPowerUp */ @@ -2338,24 +2487,24 @@ void TLan_PhyStartLink( struct net_device *dev ) TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Trying to activate link.\n", dev->name ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &ability ); + if ( ( status & MII_GS_AUTONEG ) && ( ! priv->aui ) ) { - ability = status >> 11; if ( priv->speed == TLAN_SPEED_10 && priv->duplex == TLAN_DUPLEX_HALF) { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000); } else if ( priv->speed == TLAN_SPEED_10 && priv->duplex == TLAN_DUPLEX_FULL) { - priv->tlanFullDuplex = TRUE; - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100); + priv->tlanFullDuplex = TRUE; + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_HALF) { - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000); + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_FULL) { - priv->tlanFullDuplex = TRUE; - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100); + priv->tlanFullDuplex = TRUE; + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100); } else { /* Set Auto-Neg advertisement */ @@ -2370,7 +2519,7 @@ void TLan_PhyStartLink( struct net_device *dev ) * .5 sec should be plenty extra. */ printk( "TLAN: %s: Starting autonegotiation.\n", dev->name ); - TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_PHY_FINISH_AN ); + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN ); return; } @@ -2404,7 +2553,7 @@ void TLan_PhyStartLink( struct net_device *dev ) /* Wait for 2 sec to give the tranceiver time * to establish link. */ - TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_FINISH_RESET ); + TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_FINISH_RESET ); } /* TLan_PhyStartLink */ @@ -2424,6 +2573,9 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev ) phy = priv->phy[priv->phyNum]; TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); + udelay( 1000 ); + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); + if ( ! ( status & MII_GS_AUTOCMPLT ) ) { /* Wait for 8 sec to give the process * more time. Perhaps we should fail after a while. @@ -2438,9 +2590,9 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev ) TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa ); mode = an_adv & an_lpa & 0x03E0; if ( mode & 0x0100 ) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = TRUE; } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = TRUE; } if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) { @@ -2467,62 +2619,60 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev ) } /* TLan_PhyFinishAutoNeg */ - - - - /********************************************************************* - * - * TLan_PhyMonitor - * - * Returns: - * None - * - * Params: - * dev The device structure of this device. - * - * - * This function monitors PHY condition by reading the status - * register via the MII bus. This can be used to give info - * about link changes (up/down), and possible switch to alternate - * media. - * - * ******************************************************************/ +#ifdef MONITOR + + /********************************************************************* + * + * TLan_phyMonitor + * + * Returns: + * None + * + * Params: + * dev The device structure of this device. + * + * + * This function monitors PHY condition by reading the status + * register via the MII bus. This can be used to give info + * about link changes (up/down), and possible switch to alternate + * media. + * + * ******************************************************************/ void TLan_PhyMonitor( struct net_device *dev ) { TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - u16 phy; - u16 phy_status; + u16 phy; + u16 phy_status; phy = priv->phy[priv->phyNum]; - /* Get PHY status register */ - TLan_MiiReadReg( dev, phy, MII_GEN_STS, &phy_status ); - - /* Check if link has been lost */ - if (!(phy_status & MII_GS_LINK)) { - if (priv->link) { - priv->link = 0; - printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name); - dev->flags &= ~IFF_RUNNING; - TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); - return; + /* Get PHY status register */ + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &phy_status ); + + /* Check if link has been lost */ + if (!(phy_status & MII_GS_LINK)) { + if (priv->link) { + priv->link = 0; + printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name); + dev->flags &= ~IFF_RUNNING; + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + return; } } - /* Link restablished? */ - if ((phy_status & MII_GS_LINK) && !priv->link) { - priv->link = 1; - printk(KERN_DEBUG "TLAN: %s has reestablished link\n", dev->name); - dev->flags |= IFF_RUNNING; - TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); - } + /* Link restablished? */ + if ((phy_status & MII_GS_LINK) && !priv->link) { + priv->link = 1; + printk(KERN_DEBUG "TLAN: %s has reestablished link\n", dev->name); + dev->flags |= IFF_RUNNING; + } /* Setup a new monitor */ TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); +} -} - +#endif /* MONITOR */ /***************************************************************************** @@ -2996,4 +3146,3 @@ fail: - |