Commit fca22a09 authored by Jeff Garzik's avatar Jeff Garzik

fealnx net driver updates:

* Support MII ethtool helper interface, and associated ioctls.
* Replace some MII-related magic numbers with constants from linux/mii.h.
* Remove deprecated SIOCDEVPRIVATE ioctls, SIOCxMIIxxx ioctl replacements
have been in place since 2.4.x.
parent 9bd037f7
...@@ -77,7 +77,7 @@ obj-$(CONFIG_VETH) += veth.o ...@@ -77,7 +77,7 @@ obj-$(CONFIG_VETH) += veth.o
obj-$(CONFIG_NATSEMI) += natsemi.o obj-$(CONFIG_NATSEMI) += natsemi.o
obj-$(CONFIG_NS83820) += ns83820.o obj-$(CONFIG_NS83820) += ns83820.o
obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_STNIC) += stnic.o 8390.o
obj-$(CONFIG_FEALNX) += fealnx.o obj-$(CONFIG_FEALNX) += fealnx.o mii.o
ifeq ($(CONFIG_SK98LIN),y) ifeq ($(CONFIG_SK98LIN),y)
obj-y += sk98lin/sk98lin.o obj-y += sk98lin/sk98lin.o
......
...@@ -15,8 +15,19 @@ ...@@ -15,8 +15,19 @@
Support information and updates available at Support information and updates available at
http://www.scyld.com/network/pci-skeleton.html 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 debug; /* 1-> print debug message */
static int max_interrupt_work = 20; static int max_interrupt_work = 20;
...@@ -72,14 +83,16 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; ...@@ -72,14 +83,16 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/uaccess.h>
/* These identify the driver base version and may not be removed. */ /* These identify the driver base version and may not be removed. */
static char version[] __devinitdata = 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 /* This driver was written to use PCI memory space, however some x86 systems
...@@ -380,6 +393,8 @@ struct netdev_private { ...@@ -380,6 +393,8 @@ struct netdev_private {
dma_addr_t rx_ring_dma; dma_addr_t rx_ring_dma;
dma_addr_t tx_ring_dma; dma_addr_t tx_ring_dma;
spinlock_t lock;
struct net_device_stats stats; struct net_device_stats stats;
/* Media monitoring timer. */ /* Media monitoring timer. */
...@@ -404,19 +419,17 @@ struct netdev_private { ...@@ -404,19 +419,17 @@ struct netdev_private {
unsigned int linkok; unsigned int linkok;
unsigned int line_speed; unsigned int line_speed;
unsigned int duplexmode; 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 default_port:4; /* Last dev->if_port value. */
unsigned int PHYType; unsigned int PHYType;
/* MII transceiver section. */ /* MII transceiver section. */
int mii_cnt; /* MII device addresses. */ int mii_cnt; /* MII device addresses. */
unsigned char phys[2]; /* 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 void mdio_write(struct net_device *dev, int phy_id, int location, int value);
static int netdev_open(struct net_device *dev); static int netdev_open(struct net_device *dev);
static void getlinktype(struct net_device *dev); static void getlinktype(struct net_device *dev);
...@@ -539,9 +552,13 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, ...@@ -539,9 +552,13 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
/* Make certain the descriptor lists are aligned. */ /* Make certain the descriptor lists are aligned. */
np = dev->priv; np = dev->priv;
spin_lock_init(&np->lock);
np->pci_dev = pdev; np->pci_dev = pdev;
np->flags = skel_netdrv_tbl[chip_id].flags; np->flags = skel_netdrv_tbl[chip_id].flags;
pci_set_drvdata(pdev, dev); 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); ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
if (!ring_space) { if (!ring_space) {
...@@ -606,6 +623,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, ...@@ -606,6 +623,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
else else
np->PHYType = OtherPHY; np->PHYType = OtherPHY;
} }
np->mii.phy_id = np->phys[0];
if (dev->mem_start) if (dev->mem_start)
option = dev->mem_start; option = dev->mem_start;
...@@ -613,17 +631,14 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, ...@@ -613,17 +631,14 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
/* The lower four bits are the media type. */ /* The lower four bits are the media type. */
if (option > 0) { if (option > 0) {
if (option & 0x200) if (option & 0x200)
np->full_duplex = 1; np->mii.full_duplex = 1;
np->default_port = option & 15; np->default_port = option & 15;
if (np->default_port)
np->medialock = 1;
} }
if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) 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); printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
/* 89/6/13 add, (begin) */ /* 89/6/13 add, (begin) */
// if (np->PHYType==MarvellPHY) // if (np->PHYType==MarvellPHY)
...@@ -636,10 +651,10 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, ...@@ -636,10 +651,10 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
} }
/* 89/6/13 add, (end) */ /* 89/6/13 add, (end) */
if (np->flags == HAS_MII_XCVR) 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 else
writel(0x141, dev->base_addr + ANARANLPAR); writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR);
np->duplex_lock = 1; np->mii.duplex_lock = 1;
} }
/* The chip-specific entries in the device structure. */ /* The chip-specific entries in the device structure. */
...@@ -787,7 +802,7 @@ static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad ...@@ -787,7 +802,7 @@ static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad
} }
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; long miiport = dev->base_addr + MANAGEMENT;
ulong miir; ulong miir;
...@@ -821,7 +836,7 @@ static unsigned int mdio_read(struct net_device *dev, int phyad, int regad) ...@@ -821,7 +836,7 @@ static unsigned int mdio_read(struct net_device *dev, int phyad, int regad)
miir &= ~MASK_MIIR_MII_MDC; miir &= ~MASK_MIIR_MII_MDC;
writel(miir, miiport); writel(miir, miiport);
return data; return data & 0xffff;
} }
...@@ -941,7 +956,7 @@ static int netdev_open(struct net_device *dev) ...@@ -941,7 +956,7 @@ static int netdev_open(struct net_device *dev)
// 89/9/1 modify, // 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->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); getlinkstatus(dev);
if (np->linkok) if (np->linkok)
getlinktype(dev); getlinktype(dev);
...@@ -990,7 +1005,7 @@ static void getlinkstatus(struct net_device *dev) ...@@ -990,7 +1005,7 @@ static void getlinkstatus(struct net_device *dev)
} }
} else { } else {
for (i = 0; i < DelayTime; ++i) { 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; np->linkok = 1;
return; return;
} }
...@@ -1475,7 +1490,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) ...@@ -1475,7 +1490,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
np->stats.tx_window_errors++; np->stats.tx_window_errors++;
if (tx_status & UDF) if (tx_status & UDF)
np->stats.tx_fifo_errors++; 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++; np->stats.tx_heartbeat_errors++;
#ifdef ETHER_STATS #ifdef ETHER_STATS
...@@ -1751,24 +1766,100 @@ static void set_rx_mode(struct net_device *dev) ...@@ -1751,24 +1766,100 @@ static void set_rx_mode(struct net_device *dev)
writel(np->crvalue, ioaddr + TCRRCR); 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 (&ethcmd, 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) 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; struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
switch (cmd) { switch (cmd) {
case SIOCETHTOOL:
return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
case SIOCGMIIPHY: /* Get address of MII PHY in use. */ 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; data->phy_id = ((struct netdev_private *) dev->priv)->phys[0] & 0x1f;
/* Fall Through */ /* Fall Through */
case SIOCGMIIREG: /* Read MII PHY register. */ case SIOCGMIIREG: /* Read MII PHY register. */
case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */
data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
return 0; return 0;
case SIOCSMIIREG: /* Write MII PHY register. */ case SIOCSMIIREG: /* Write MII PHY register. */
case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment