patch-2.4.0-test2 linux/drivers/net/tlan.c
Next file: linux/drivers/net/tlan.h
Previous file: linux/drivers/net/sunqe.c
Back to the patch index
Back to the overall index
- Lines: 415
- Date:
Mon Jun 19 13:42:39 2000
- Orig file:
v2.4.0-test1/linux/drivers/net/tlan.c
- Orig date:
Mon Mar 27 08:08:26 2000
diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
@@ -72,6 +72,31 @@
* - TODO: Port completely to new PCI/DMA API
* Auto-Neg fallback.
*
+ * v1.6 April 04, 2000 - Fixed driver support for kernel-parameters. Haven't
+ * tested it though, as the kernel support is currently
+ * broken (2.3.99p4p3).
+ * - Updated tlan.txt accordingly.
+ * - Adjusted minimum/maximum frame length.
+ * - There is now a TLAN website up at
+ * http://tlan.kernel.dk
+ *
+ * v1.7 April 07, 2000 - Started to implement custom ioctls. Driver now
+ * reports PHY information when used with Donald
+ * Beckers userspace MII diagnostics utility.
+ *
+ * v1.8 April 23, 2000 - Fixed support for forced speed/duplex settings.
+ * - Added link information to Auto-Neg and forced
+ * modes. When NIC operates with auto-neg the driver
+ * will report Link speed & duplex modes as well as
+ * link partner abilities. When forced link is used,
+ * the driver will report status of the established
+ * link.
+ * Please read tlan.txt for additional information.
+ * - Removed call to check_region(), and used
+ * return value of request_region() instead.
+ *
+ * v1.8a May 28, 2000 - Minor updates.
+ *
*******************************************************************************/
@@ -99,6 +124,8 @@
static int duplex = 0;
static int speed = 0;
+MODULE_AUTHOR("Maintainer: Torben Mathiasen <torben.mathiasen@compaq.com>");
+MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters");
MODULE_PARM(aui, "i");
MODULE_PARM(duplex, "i");
MODULE_PARM(speed, "i");
@@ -111,9 +138,14 @@
static int bbuf = 0;
static u8 *TLanPadBuffer;
static char TLanSignature[] = "TLAN";
-static int TLanVersionMajor = 1;
-static int TLanVersionMinor = 5;
+static const char *tlan_banner = "ThunderLAN driver v1.8a\n";
+const char *media[] = {
+ "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ",
+ "100baseTx-FD", "100baseT4", 0
+};
+
+int media_map[] = { 0x0020, 0x0040, 0x0080, 0x0100, 0x0200,};
static TLanAdapterEntry TLanAdapterList[] __initdata = {
{ PCI_VENDOR_ID_COMPAQ,
@@ -211,6 +243,7 @@
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 u32 TLan_HandleInvalid( struct net_device *, u16 );
static u32 TLan_HandleTxEOF( struct net_device *, u16 );
@@ -371,9 +404,7 @@
u32 io_base, index;
int found;
- printk(KERN_INFO "ThunderLAN driver v%d.%d\n",
- TLanVersionMajor,
- TLanVersionMinor);
+ printk(KERN_INFO "%s", tlan_banner);
TLanPadBuffer = (u8 *) kmalloc(TLAN_MIN_FRAME_SIZE,
(GFP_KERNEL | GFP_DMA));
@@ -404,17 +435,36 @@
dev->irq = irq;
priv->adapter = &TLanAdapterList[index];
priv->adapterRev = rev;
- priv->aui = aui;
- if ( ( duplex != 1 ) && ( duplex != 2 ) )
- duplex = 0;
- priv->duplex = duplex;
+
+ /* 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 ( ( speed != 10 ) && ( speed != 100 ) )
- speed = 0;
+ if ( ( duplex != 1 ) && ( duplex != 2 ) )
+ duplex = 0;
+
+ priv->duplex = duplex;
- priv->speed = speed;
- priv->debug = debug;
+ 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)) {
@@ -495,8 +545,11 @@
TLanAdapterList[dl_index].deviceId
);
+ if (pci_enable_device(pdev))
+ continue;
+
*pci_irq = pdev->irq;
- *pci_io_base = pdev->resource[0].start;
+ *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);
@@ -554,13 +607,13 @@
static int TLan_Init( struct net_device *dev )
{
int dma_size;
- int err;
+ int err;
int i;
TLanPrivateInfo *priv;
priv = (TLanPrivateInfo *) dev->priv;
- err = check_region( dev->base_addr, 0x10 );
- if ( err ) {
+
+ 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,
@@ -568,7 +621,6 @@
return -EIO;
}
- request_region( dev->base_addr, 0x10, TLanSignature );
if ( bbuf ) {
dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
@@ -611,7 +663,7 @@
dev->stop = &TLan_Close;
dev->get_stats = &TLan_GetStats;
dev->set_multicast_list = &TLan_SetMulticastList;
-
+ dev->do_ioctl = &TLan_ioctl;
return 0;
@@ -669,6 +721,49 @@
+ /**************************************************************
+ * TLan_ioctl
+ *
+ * Returns:
+ * 0 on success, error code otherwise
+ * Params:
+ * dev structure of device to receive ioctl.
+ *
+ * rq ifreq structure to hold userspace data.
+ *
+ * cmd ioctl command.
+ *
+ *
+ *************************************************************/
+
+static int TLan_ioctl(struct net_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 */
+
+
/***************************************************************
* TLan_StartTx
@@ -1898,7 +1993,10 @@
u32 phy;
u8 sio;
u16 status;
+ u16 partner;
u16 tlphy_ctl;
+ u16 tlphy_par;
+ int i;
phy = priv->phy[priv->phyNum];
@@ -1922,7 +2020,26 @@
udelay( 1000 );
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
if ( status & MII_GS_LINK ) {
- printk( "TLAN: %s: Link active.\n", dev->name );
+ TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner );
+ TLan_MiiReadReg( dev, phy, TLAN_TLPHY_PAR, &tlphy_par );
+
+ printk( "TLAN: %s: Link active with ", dev->name );
+ if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) {
+ printk( "forced 10%sMbps %s-Duplex\n",
+ tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
+ tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
+ } else {
+ 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))
+ printk("%s", media[i-5]);
+ printk("\n");
+ }
+
TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
}
}
@@ -1946,7 +2063,7 @@
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 {
- printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name );
+ printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name );
TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET );
return;
}
@@ -2149,10 +2266,10 @@
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
- * 500 ms, so do the longer, just in case
+ * 500 ms, so do the longer, just in case.
*/
TLan_SetTimer( dev, (HZ/2), TLAN_TIMER_PHY_RESET );
@@ -2177,12 +2294,12 @@
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.
+ * I've changed this to 50ms, as it seems long enough.
*/
- TLan_SetTimer( dev, (HZ/2), TLAN_TIMER_PHY_START_LINK );
+ TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_START_LINK );
} /* TLan_PhyReset */
@@ -2200,52 +2317,56 @@
u16 tctl;
phy = priv->phy[priv->phyNum];
-
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->duplex == TLAN_DUPLEX_DEFAULT ) &&
- ( priv->speed == TLAN_SPEED_DEFAULT ) &&
( ! priv->aui ) ) {
- ability = status >> 11;
-
- 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( "TLAN: %s: Starting autonegotiation.\n", dev->name );
- TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_PHY_FINISH_AN );
- return;
- }
+ 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) {
+ 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) {
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100);
+ } else {
+
+ /* Set Auto-Neg advertisement */
+ TLan_MiiWriteReg( dev, phy, MII_AN_ADV, (ability << 5) | 1);
+ /* Enablee 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( "TLAN: %s: Starting autonegotiation.\n", dev->name );
+ TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_PHY_FINISH_AN );
+ return;
+ }
+
+ }
+
if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) {
priv->phyNum = 0;
data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data );
- TLan_SetTimer( dev, (4*(HZ/1000)), TLAN_TIMER_PHY_PDOWN );
+ TLan_SetTimer( dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN );
return;
- } else if ( priv->phyNum == 0 ) {
+ } else if ( priv->phyNum == 0 ) {
TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl );
if ( priv->aui ) {
tctl |= TLAN_TC_AUISEL;
- } else {
+ } else {
tctl &= ~TLAN_TC_AUISEL;
control = 0;
if ( priv->duplex == TLAN_DUPLEX_FULL ) {
@@ -2260,10 +2381,10 @@
TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl );
}
- /* Wait for 1 sec to give the tranceiver time
+ /* Wait for 2 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 */
@@ -2306,14 +2427,14 @@
priv->phyNum = 0;
data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data );
- TLan_SetTimer( dev, (400*(HZ/1000)), TLAN_TIMER_PHY_PDOWN );
+ TLan_SetTimer( dev, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN );
return;
}
if ( priv->phyNum == 0 ) {
if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) {
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX );
- printk( "TLAN: Starting internal PHY with DUPLEX\n" );
+ printk( "TLAN: Starting internal PHY with FULL-DUPLEX\n" );
} else {
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB );
printk( "TLAN: Starting internal PHY with HALF-DUPLEX\n" );
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)