patch-2.4.18 linux/drivers/net/fealnx.c
Next file: linux/drivers/net/gmac.c
Previous file: linux/drivers/net/fc/Makefile
Back to the patch index
Back to the overall index
- Lines: 271
- Date:
Mon Jan 14 17:27:24 2002
- Orig file:
linux.orig/drivers/net/fealnx.c
- Orig date:
Mon Feb 18 20:18:39 2002
diff -Naur -X /home/marcelo/lib/dontdiff linux.orig/drivers/net/fealnx.c linux/drivers/net/fealnx.c
@@ -15,8 +15,19 @@
Support information and updates available at
http://www.scyld.com/network/pci-skeleton.html
+
+ Linux kernel updates:
+
+ Version 2.51, Nov 17, 2001 (jgarzik):
+ - Add ethtool support
+ - Replace some MII-related magic numbers with constants
+
*/
+#define DRV_NAME "fealnx"
+#define DRV_VERSION "2.51"
+#define DRV_RELDATE "Nov-17-2001"
+
static int debug; /* 1-> print debug message */
static int max_interrupt_work = 20;
@@ -72,13 +83,15 @@
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/mii.h>
+#include <linux/ethtool.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
+#include <asm/uaccess.h>
/* These identify the driver base version and may not be removed. */
static char version[] __devinitdata =
-KERN_INFO "fealnx.c:v2.50 1/17/2001\n";
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "\n";
/* This driver was written to use PCI memory space, however some x86 systems
@@ -379,6 +392,8 @@
dma_addr_t rx_ring_dma;
dma_addr_t tx_ring_dma;
+ spinlock_t lock;
+
struct net_device_stats stats;
/* Media monitoring timer. */
@@ -403,19 +418,17 @@
unsigned int linkok;
unsigned int line_speed;
unsigned int duplexmode;
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int duplex_lock:1;
- unsigned int medialock:1; /* Do not sense media. */
unsigned int default_port:4; /* Last dev->if_port value. */
unsigned int PHYType;
/* MII transceiver section. */
int mii_cnt; /* MII device addresses. */
unsigned char phys[2]; /* MII device addresses. */
+ struct mii_if_info mii;
};
-static unsigned int mdio_read(struct net_device *dev, int phy_id, int location);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
static int netdev_open(struct net_device *dev);
static void getlinktype(struct net_device *dev);
@@ -539,9 +552,13 @@
/* Make certain the descriptor lists are aligned. */
np = dev->priv;
+ spin_lock_init(&np->lock);
np->pci_dev = pdev;
np->flags = skel_netdrv_tbl[chip_id].flags;
pci_set_drvdata(pdev, dev);
+ np->mii.dev = dev;
+ np->mii.mdio_read = mdio_read;
+ np->mii.mdio_write = mdio_write;
ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
if (!ring_space) {
@@ -606,6 +623,7 @@
else
np->PHYType = OtherPHY;
}
+ np->mii.phy_id = np->phys[0];
if (dev->mem_start)
option = dev->mem_start;
@@ -613,17 +631,14 @@
/* The lower four bits are the media type. */
if (option > 0) {
if (option & 0x200)
- np->full_duplex = 1;
+ np->mii.full_duplex = 1;
np->default_port = option & 15;
-
- if (np->default_port)
- np->medialock = 1;
}
if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
- np->full_duplex = full_duplex[card_idx];
+ np->mii.full_duplex = full_duplex[card_idx];
- if (np->full_duplex) {
+ if (np->mii.full_duplex) {
printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
/* 89/6/13 add, (begin) */
// if (np->PHYType==MarvellPHY)
@@ -636,10 +651,10 @@
}
/* 89/6/13 add, (end) */
if (np->flags == HAS_MII_XCVR)
- mdio_write(dev, np->phys[0], 4, 0x141);
+ mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
else
- writel(0x141, dev->base_addr + ANARANLPAR);
- np->duplex_lock = 1;
+ writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR);
+ np->mii.duplex_lock = 1;
}
/* The chip-specific entries in the device structure. */
@@ -787,7 +802,7 @@
}
-static unsigned int mdio_read(struct net_device *dev, int phyad, int regad)
+static int mdio_read(struct net_device *dev, int phyad, int regad)
{
long miiport = dev->base_addr + MANAGEMENT;
ulong miir;
@@ -821,7 +836,7 @@
miir &= ~MASK_MIIR_MII_MDC;
writel(miir, miiport);
- return data;
+ return data & 0xffff;
}
@@ -941,7 +956,7 @@
// 89/9/1 modify,
// np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */
np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */
- np->full_duplex = np->duplex_lock;
+ np->mii.full_duplex = np->mii.duplex_lock;
getlinkstatus(dev);
if (np->linkok)
getlinktype(dev);
@@ -990,7 +1005,7 @@
}
} else {
for (i = 0; i < DelayTime; ++i) {
- if (mdio_read(dev, np->phys[0], 1) & 0x4) {
+ if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS) {
np->linkok = 1;
return;
}
@@ -1475,7 +1490,7 @@
np->stats.tx_window_errors++;
if (tx_status & UDF)
np->stats.tx_fifo_errors++;
- if ((tx_status & HF) && np->full_duplex == 0)
+ if ((tx_status & HF) && np->mii.full_duplex == 0)
np->stats.tx_heartbeat_errors++;
#ifdef ETHER_STATS
@@ -1771,12 +1786,91 @@
writel(np->crvalue, ioaddr + TCRRCR);
}
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+ struct netdev_private *np = dev->priv;
+ u32 ethcmd;
+
+ if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd)))
+ return -EFAULT;
+
+ switch (ethcmd) {
+ case ETHTOOL_GDRVINFO: {
+ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+ strcpy (info.driver, DRV_NAME);
+ strcpy (info.version, DRV_VERSION);
+ strcpy (info.bus_info, np->pci_dev->slot_name);
+ if (copy_to_user (useraddr, &info, sizeof (info)))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* get settings */
+ case ETHTOOL_GSET: {
+ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+ spin_lock_irq(&np->lock);
+ mii_ethtool_gset(&np->mii, &ecmd);
+ spin_unlock_irq(&np->lock);
+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ return 0;
+ }
+ /* set settings */
+ case ETHTOOL_SSET: {
+ int r;
+ struct ethtool_cmd ecmd;
+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+ return -EFAULT;
+ spin_lock_irq(&np->lock);
+ r = mii_ethtool_sset(&np->mii, &ecmd);
+ spin_unlock_irq(&np->lock);
+ return r;
+ }
+ /* restart autonegotiation */
+ case ETHTOOL_NWAY_RST: {
+ return mii_nway_restart(&np->mii);
+ }
+ /* get link status */
+ case ETHTOOL_GLINK: {
+ struct ethtool_value edata = {ETHTOOL_GLINK};
+ edata.data = mii_link_ok(&np->mii);
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* get message-level */
+ case ETHTOOL_GMSGLVL: {
+ struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+ edata.data = debug;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+ /* set message-level */
+ case ETHTOOL_SMSGLVL: {
+ struct ethtool_value edata;
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ debug = edata.data;
+ return 0;
+ }
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
switch (cmd) {
+ case SIOCETHTOOL:
+ return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */
data->phy_id = ((struct netdev_private *) dev->priv)->phys[0] & 0x1f;
@@ -1789,7 +1883,7 @@
case SIOCSMIIREG: /* Write MII PHY register. */
case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
return 0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)