patch-2.2.17 linux/drivers/net/tlan.c
Next file: linux/drivers/net/tlan.h
Previous file: linux/drivers/net/sunhme.c
Back to the patch index
Back to the overall index
- Lines: 529
- Date:
Mon Sep 4 18:39:20 2000
- Orig file:
v2.2.16/drivers/net/tlan.c
- Orig date:
Mon Sep 4 18:37:24 2000
diff -u --recursive --new-file v2.2.16/drivers/net/tlan.c linux/drivers/net/tlan.c
@@ -42,8 +42,21 @@
* to overwrite timers like TLAN_TIMER_ACTIVITY
* Patch from John Cagle <john.cagle@compaq.com>
* - Removed dependency of HZ being 100.
- * - Statistics is now fixed.
+ * - Statistics are now fixed.
* - Minor stuff.
+ *
+ * v1.3 June 9, 2000 - Updated for better SMP performance.
+ * - Fixed forced speed/duplex settings.
+ * - Added support for custom MII ioctls.
+ * - Code clean up.
+ * - Thanks to Herman Bos <hbos@mih.net> and
+ * Martin Lathoud <nytral@endirect.qc.ca>
+ * for providing me with extensive debug information.
+ *
+ * v1.3a June 21, 2000 - Minor fixes when driver build as module.
+ *
+ * v1.3b June 28, 2000 - Clean ups.
+ *
********************************************************************************/
@@ -55,29 +68,28 @@
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
-
+#include <asm/spinlock.h>
typedef u32 (TLanIntVectorFunc)( struct device *, u16 );
-
-#ifdef MODULE
+#ifdef MODULE
static struct device *TLanDevices = NULL;
static int TLanDevicesInstalled = 0;
static int aui = 0;
-static int sa_int = 0;
static int duplex = 0;
static int speed = 0;
+static const char *tlan_banner = "ThunderLAN driver v1.3b\n";
+MODULE_AUTHOR("Maintainer: Torben Mathiasen <torben.mathiasen@compaq.com>");
+MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet adapters");
MODULE_PARM(aui, "i");
-MODULE_PARM(sa_int, "i");
MODULE_PARM(duplex, "i");
MODULE_PARM(speed, "i");
MODULE_PARM(debug, "i");
EXPORT_NO_SYMBOLS;
-
#endif
@@ -85,8 +97,6 @@
static int bbuf = 0;
static u8 *TLanPadBuffer;
static char TLanSignature[] = "TLAN";
-static int TLanVersionMajor = 1;
-static int TLanVersionMinor = 2;
static TLanAdapterEntry TLanAdapterList[] = {
@@ -185,6 +195,7 @@
static int TLan_Close(struct device *);
static struct net_device_stats *TLan_GetStats( struct device * );
static void TLan_SetMulticastList( struct device * );
+static int TLan_ioctl(struct device *dev, struct ifreq *req, int cmd);
static u32 TLan_HandleInvalid( struct device *, u16 );
static u32 TLan_HandleTxEOF( struct device *, u16 );
@@ -246,14 +257,16 @@
TLan_SetTimer( struct device *dev, u32 ticks, u32 type )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+ unsigned long flags;
- cli();
+ spin_lock_irqsave(&priv->lock, flags);
if ( priv->timer.function != NULL &&
priv->timerType != TLAN_TIMER_ACTIVITY) {
+ spin_unlock_irqrestore(&priv->lock, flags);
return;
}
priv->timer.function = &TLan_Timer;
- sti();
+ spin_unlock_irqrestore(&priv->lock, flags);
priv->timer.data = (unsigned long) dev;
priv->timer.expires = jiffies + ticks;
@@ -305,10 +318,8 @@
u8 irq;
u8 rev;
- printk(KERN_INFO "TLAN driver, v%d.%d, (C) 1997-8 Caldera, Inc.\n",
- TLanVersionMajor,
- TLanVersionMinor
- );
+ printk(KERN_INFO "%s", tlan_banner);
+
TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE,
( GFP_KERNEL | GFP_DMA )
);
@@ -347,11 +358,12 @@
speed = 0;
}
priv->speed = speed;
- priv->sa_int = sa_int;
priv->debug = debug;
-
+
ether_setup( dev );
+ spin_lock_init(&priv->lock);
+
failed = register_netdev( dev );
if ( failed ) {
@@ -496,13 +508,9 @@
} else if ( priv->speed == 0x2 ) {
priv->speed = TLAN_SPEED_100;
}
- priv->sa_int = dev->mem_start & 0x02;
priv->debug = dev->mem_end;
-
- printk(KERN_INFO "TLAN %d.%d: %s irq=%2d io=%04x, %s, Rev. %d\n",
- TLanVersionMajor,
- TLanVersionMinor,
+ printk(KERN_INFO "TLAN 1.3b: %s irq=%2d io=%04x, %s, Rev. %d\n",
dev->name,
(int) irq,
io_base,
@@ -691,7 +699,7 @@
dev->stop = &TLan_Close;
dev->get_stats = &TLan_GetStats;
dev->set_multicast_list = &TLan_SetMulticastList;
-
+ dev->do_ioctl = &TLan_ioctl;
return 0;
@@ -726,12 +734,8 @@
MOD_INC_USE_COUNT;
- if ( priv->sa_int ) {
- TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Using SA_INTERRUPT\n" );
- err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ | SA_INTERRUPT, TLanSignature, dev );
- } else {
- err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
- }
+ err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
+
if ( err ) {
printk( "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
return -EAGAIN;
@@ -754,6 +758,33 @@
} /* TLan_Open */
+static int TLan_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+ u16 *data = (u16 *)&rq->ifr_data;
+ u32 phy = priv->phy[priv->phyNum];
+
+ if (!priv->phyOnline)
+ return -EAGAIN;
+
+ switch(cmd) {
+ case SIOCDEVPRIVATE:
+ data[0] = phy;
+
+ case SIOCDEVPRIVATE+1: /* Read MII register */
+ TLan_MiiReadReg(dev, data[0], data[1], &data[3]);
+ return 0;
+
+ case SIOCDEVPRIVATE+2: /* Write MII register */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ TLan_MiiWriteReg(dev, data[0], data[1], data[2]);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+} /* tlan_ioctl */
+
/***************************************************************
@@ -783,6 +814,7 @@
TLanList *tail_list;
u8 *tail_buffer;
int pad;
+ unsigned long flags;
if ( ! priv->phyOnline ) {
TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s PHY is not ready\n", dev->name );
@@ -823,7 +855,7 @@
tail_list->buffer[1].address = 0;
}
- cli();
+ spin_lock_irqsave(&priv->lock, flags);
tail_list->cStat = TLAN_CSTAT_READY;
if ( ! priv->txInProgress ) {
priv->txInProgress = 1;
@@ -839,7 +871,7 @@
( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list );
}
}
- sti();
+ spin_unlock_irqrestore(&priv->lock, flags);
CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
@@ -883,14 +915,11 @@
u32 host_cmd;
u16 host_int;
int type;
+ TLanPrivateInfo *priv;
dev = (struct device *) dev_id;
-
- cli();
- if ( dev->interrupt ) {
- printk( "TLAN: Re-entering interrupt handler for %s: %ld.\n" , dev->name, dev->interrupt );
- }
- dev->interrupt++;
+ priv = (TLanPrivateInfo *) dev->priv;
+ spin_lock(&priv->lock);
host_int = inw( dev->base_addr + TLAN_HOST_INT );
outw( host_int, dev->base_addr + TLAN_HOST_INT );
@@ -905,7 +934,7 @@
}
dev->interrupt--;
- sti();
+ spin_unlock(&priv->lock);
} /* TLan_HandleInterrupts */
@@ -1092,7 +1121,7 @@
u32 TLan_HandleInvalid( struct device *dev, u16 host_int )
{
host_int = 0;
- /* printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); */
+ printk( "TLAN: Invalid interrupt on %s.\n", dev->name );
return 0;
} /* TLan_HandleInvalid */
@@ -1163,7 +1192,12 @@
if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
if ( priv->timer.function == NULL ) {
- TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
+ priv->timer.function = &TLan_Timer;
+ priv->timer.data = (unsigned long) dev;
+ priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+ priv->timerSetAt = jiffies;
+ priv->timerType = TLAN_TIMER_ACTIVITY;
+ add_timer(&priv->timer);
} else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
priv->timerSetAt = jiffies;
}
@@ -1319,7 +1353,12 @@
if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
if ( priv->timer.function == NULL ) {
- TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
+ priv->timer.function = &TLan_Timer;
+ priv->timer.data = (unsigned long) dev;
+ priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+ priv->timerSetAt = jiffies;
+ priv->timerType = TLAN_TIMER_ACTIVITY;
+ add_timer(&priv->timer);
} else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
priv->timerSetAt = jiffies;
}
@@ -1567,6 +1606,7 @@
struct device *dev = (struct device *) data;
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
u32 elapsed;
+ unsigned long flags = 0;
priv->timer.function = NULL;
@@ -1590,7 +1630,7 @@
TLan_FinishReset( dev );
break;
case TLAN_TIMER_ACTIVITY:
- cli();
+ spin_lock_irqsave(&priv->lock, flags);
if ( priv->timer.function == NULL ) {
elapsed = jiffies - priv->timerSetAt;
if ( elapsed >= TLAN_TIMER_ACT_DELAY ) {
@@ -1598,11 +1638,11 @@
} else {
priv->timer.function = &TLan_Timer;
priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
- sti();
+ spin_unlock_irqrestore(&priv->lock, flags);
add_timer( &priv->timer );
}
}
- sti();
+ spin_unlock_irqrestore(&priv->lock, flags);
break;
default:
break;
@@ -2224,6 +2264,7 @@
TLan_MiiSync( dev->base_addr );
value = MII_GC_LOOPBK;
TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
+ TLan_MiiSync(dev->base_addr);
/* Wait for 500 ms and reset the
* tranceiver. The TLAN docs say both 50 ms and
@@ -2252,7 +2293,6 @@
while ( value & MII_GC_RESET ) {
TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value );
}
- TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0 );
/* Wait for 500 ms and initialize.
* I don't remember why I wait this long.
@@ -2275,39 +2315,46 @@
u16 tctl;
phy = priv->phy[priv->phyNum];
-
TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Trying to activate link.\n", dev->name );
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
- if ( ( status & MII_GS_AUTONEG ) &&
- ( priv->duplex == TLAN_DUPLEX_DEFAULT ) &&
- ( priv->speed == TLAN_SPEED_DEFAULT ) &&
- ( ! priv->aui ) ) {
+ 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);
+ } else if ( priv->speed == TLAN_SPEED_100 &&
+ priv->duplex == TLAN_DUPLEX_HALF ) {
+ 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);
+ } else {
- if ( priv->speed == TLAN_SPEED_10 ) {
- ability &= 0x0003;
- } else if ( priv->speed == TLAN_SPEED_100 ) {
- ability &= 0x001C;
- }
-
- if ( priv->duplex == TLAN_DUPLEX_FULL ) {
- ability &= 0x000A;
- } else if ( priv->duplex == TLAN_DUPLEX_HALF ) {
- ability &= 0x0005;
- }
-
- TLan_MiiWriteReg( dev, phy, MII_AN_ADV, ( ability << 5 ) | 1 );
- TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 );
- TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 );
-
- /* Wait for 4 sec for autonegotiation
- * to complete. The max spec time is less than this
- * but the card need additional time to start AN.
- * .5 sec should be plenty extra.
- */
- printk(KERN_INFO "TLAN: %s: Starting autonegotiation.\n", dev->name );
- TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_PHY_FINISH_AN );
- return;
+ /* Set Auto-Neg advertisement */
+ TLan_MiiWriteReg( dev, phy, MII_AN_ADV, ( ability << 5 ) | 1 );
+ /* Enable Auto-Neg */
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 );
+ /* Restart Auto-Neg */
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 );
+
+ /* Wait for 4 sec for autonegotiation
+ * to complete. The max spec time is less than this
+ * but the card need additional time to start AN.
+ * .5 sec should be plenty extra.
+ */
+ printk(KERN_INFO "TLAN: %s: Starting autonegotiation.\n", dev->name );
+ TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_PHY_FINISH_AN );
+ return;
+ }
}
if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) {
@@ -2338,7 +2385,7 @@
/* Wait for 1 sec to give the tranceiver time
* to establish link.
*/
- TLan_SetTimer( dev, HZ, TLAN_TIMER_FINISH_RESET );
+ TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_FINISH_RESET );
} /* TLan_PhyStartLink */
@@ -2447,14 +2494,15 @@
u32 i;
int err;
int minten;
+ TLanPrivateInfo *priv;
+ unsigned long flags = 0;
err = FALSE;
outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
-
- if ( dev->interrupt == 0 )
- cli();
- dev->interrupt++;
+
+ priv = (TLanPrivateInfo *) dev->priv;
+ spin_lock_irqsave(&priv->lock, flags);
TLan_MiiSync(dev->base_addr);
@@ -2501,9 +2549,7 @@
*val = tmp;
- dev->interrupt--;
- if ( dev->interrupt == 0 )
- sti();
+ spin_unlock_irqrestore(&priv->lock, flags);
return err;
@@ -2615,13 +2661,14 @@
{
u16 sio;
int minten;
+ unsigned long flags;
+ TLanPrivateInfo *priv;
outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
-
- if ( dev->interrupt == 0 )
- cli();
- dev->interrupt++;
+
+ priv = (TLanPrivateInfo *) dev->priv;
+ spin_lock_irqsave(&priv->lock, flags);
TLan_MiiSync( dev->base_addr );
@@ -2643,9 +2690,7 @@
if ( minten )
TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
- dev->interrupt--;
- if ( dev->interrupt == 0 )
- sti();
+ spin_unlock_irqrestore(&priv->lock, flags);
} /* TLan_MiiWriteReg */
@@ -2843,29 +2888,38 @@
int TLan_EeReadByte( struct device *dev, u8 ee_addr, u8 *data )
{
int err;
+ TLanPrivateInfo *priv;
+ unsigned long flags = 0;
+ int ret = 0;
- if ( dev->interrupt == 0 )
- cli();
- dev->interrupt++;
-
+ priv = (TLanPrivateInfo *) dev->priv;
+ spin_lock_irqsave(&priv->lock, flags);
+
TLan_EeSendStart( dev->base_addr );
err = TLan_EeSendByte( dev->base_addr, 0xA0, TLAN_EEPROM_ACK );
if (err)
- return 1;
+ {
+ ret=1;
+ goto fail;
+ }
err = TLan_EeSendByte( dev->base_addr, ee_addr, TLAN_EEPROM_ACK );
if (err)
- return 2;
+ {
+ ret=2;
+ goto fail;
+ }
TLan_EeSendStart( dev->base_addr );
err = TLan_EeSendByte( dev->base_addr, 0xA1, TLAN_EEPROM_ACK );
if (err)
- return 3;
+ {
+ ret=3;
+ goto fail;
+ }
TLan_EeReceiveByte( dev->base_addr, data, TLAN_EEPROM_STOP );
- dev->interrupt--;
- if ( dev->interrupt == 0 )
- sti();
-
- return 0;
+fail:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
} /* TLan_EeReadByte */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)