From fca22a09e2ba361be33c1f14e8c576d7e916109e Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 6 Feb 2002 18:58:37 -0500 Subject: [PATCH] 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. --- drivers/net/Makefile | 2 +- drivers/net/fealnx.c | 135 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 114 insertions(+), 23 deletions(-) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 02bb6976ff15..6df38e0466c6 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -77,7 +77,7 @@ obj-$(CONFIG_VETH) += veth.o obj-$(CONFIG_NATSEMI) += natsemi.o obj-$(CONFIG_NS83820) += ns83820.o obj-$(CONFIG_STNIC) += stnic.o 8390.o -obj-$(CONFIG_FEALNX) += fealnx.o +obj-$(CONFIG_FEALNX) += fealnx.o mii.o ifeq ($(CONFIG_SK98LIN),y) obj-y += sk98lin/sk98lin.o diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 66bde2a1c1ca..473e59d9bde5 100644 --- a/drivers/net/fealnx.c +++ b/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,14 +83,16 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; #include #include #include +#include #include #include /* Processor type for cache alignment. */ #include #include +#include /* 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 @@ -380,6 +393,8 @@ struct netdev_private { dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; + spinlock_t lock; + struct net_device_stats stats; /* Media monitoring timer. */ @@ -404,19 +419,17 @@ struct netdev_private { 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 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, /* 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 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, else np->PHYType = OtherPHY; } + np->mii.phy_id = np->phys[0]; if (dev->mem_start) option = dev->mem_start; @@ -613,17 +631,14 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, /* 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 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, } /* 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 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; ulong miir; @@ -821,7 +836,7 @@ static unsigned int mdio_read(struct net_device *dev, int phyad, int regad) miir &= ~MASK_MIIR_MII_MDC; writel(miir, miiport); - return data; + return data & 0xffff; } @@ -941,7 +956,7 @@ static int netdev_open(struct net_device *dev) // 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 @@ static void getlinkstatus(struct net_device *dev) } } 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 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) 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 @@ -1751,24 +1766,100 @@ static void set_rx_mode(struct net_device *dev) 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; /* Fall Through */ 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); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); -- 2.39.5