From b5412329a0ddc00bb2cb368da0ddb112b3629224 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 11 Feb 2002 15:29:52 -0500 Subject: [PATCH] Merge ethtool support and PPC fix into pcnet32 net driver, from 2.4.x. Also, remove deprecated SIOCDEVPRIVATE ioctl calls. Via Dave Jones. --- drivers/net/Makefile | 2 +- drivers/net/pcnet32.c | 194 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 168 insertions(+), 28 deletions(-) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 8dea1e329564..0c0f48d75bcb 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -65,7 +65,7 @@ obj-$(CONFIG_DGRS) += dgrs.o obj-$(CONFIG_RCPCI) += rcpci.o obj-$(CONFIG_VORTEX) += 3c59x.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o -obj-$(CONFIG_PCNET32) += pcnet32.o +obj-$(CONFIG_PCNET32) += pcnet32.o mii.o obj-$(CONFIG_EEPRO100) += eepro100.o obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_EPIC100) += epic100.o mii.o diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 8dd2af654ba1..28ba296f2f4d 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -21,7 +21,12 @@ * *************************************************************************/ -static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n"; +#define DRV_NAME "pcnet32" +#define DRV_VERSION "1.25kf" +#define DRV_RELDATE "17.11.2001" + +static const char *version = +DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n"; #include @@ -36,10 +41,13 @@ static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken #include #include #include +#include +#include #include #include #include #include +#include #include #include @@ -283,11 +291,11 @@ struct pcnet32_private { int shared_irq:1, /* shared irq possible */ ltint:1, #ifdef DO_DXSUFLO - dxsuflo:1, /* disable transmit stop on uflo */ + dxsuflo:1, /* disable transmit stop on uflo */ #endif - full_duplex:1, /* full duplex possible */ mii:1; /* mii port available */ struct net_device *next; + struct mii_if_info mii_if; }; static int pcnet32_probe_vlbus(int cards_found); @@ -302,9 +310,9 @@ static void pcnet32_interrupt(int, void *, struct pt_regs *); static int pcnet32_close(struct net_device *); static struct net_device_stats *pcnet32_get_stats(struct net_device *); static void pcnet32_set_multicast_list(struct net_device *); -#ifdef HAVE_PRIVATE_IOCTL -static int pcnet32_mii_ioctl(struct net_device *, struct ifreq *, int); -#endif +static int pcnet32_ioctl(struct net_device *, struct ifreq *, int); +static int mdio_read(struct net_device *dev, int phy_id, int reg_num); +static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val); enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, @@ -647,6 +655,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car #if defined(__i386__) printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name); memcpy(dev->dev_addr, promaddr, 6); +#elif defined(__powerpc__) + if (!is_valid_ether_addr(dev->dev_addr) + && is_valid_ether_addr(promaddr)) { + printk("\n" KERN_WARNING "%s: using PROM address:", + dev->name); + memcpy(dev->dev_addr, promaddr, 6); + } #endif } } @@ -702,7 +717,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car dev->priv = lp; lp->name = chipname; lp->shared_irq = shared; - lp->full_duplex = fdx; + lp->mii_if.full_duplex = fdx; #ifdef DO_DXSUFLO lp->dxsuflo = dxsuflo; #endif @@ -712,6 +727,9 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car lp->options = PCNET32_PORT_ASEL; else lp->options = options_mapping[options[card_idx]]; + lp->mii_if.dev = dev; + lp->mii_if.mdio_read = mdio_read; + lp->mii_if.mdio_write = mdio_write; if (fdx && !(lp->options & PCNET32_PORT_ASEL) && full_duplex[card_idx]) lp->options |= PCNET32_PORT_FD; @@ -781,9 +799,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car dev->stop = &pcnet32_close; dev->get_stats = &pcnet32_get_stats; dev->set_multicast_list = &pcnet32_set_multicast_list; -#ifdef HAVE_PRIVATE_IOCTL - dev->do_ioctl = &pcnet32_mii_ioctl; -#endif + dev->do_ioctl = &pcnet32_ioctl; dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (HZ >> 1); @@ -834,7 +850,7 @@ pcnet32_open(struct net_device *dev) lp->a.write_bcr (ioaddr, 2, val); /* handle full duplex setting */ - if (lp->full_duplex) { + if (lp->mii_if.full_duplex) { val = lp->a.read_bcr (ioaddr, 9) & ~3; if (lp->options & PCNET32_PORT_FD) { val |= 1; @@ -1476,29 +1492,154 @@ static void pcnet32_set_multicast_list(struct net_device *dev) pcnet32_restart(dev, 0x0042); /* Resume normal operation */ } -#ifdef HAVE_PRIVATE_IOCTL -static int pcnet32_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int mdio_read(struct net_device *dev, int phy_id, int reg_num) +{ + struct pcnet32_private *lp = dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 val_out; + int phyaddr; + + if (!lp->mii) + return 0; + + phyaddr = lp->a.read_bcr(ioaddr, 33); + + lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); + val_out = lp->a.read_bcr(ioaddr, 34); + lp->a.write_bcr(ioaddr, 33, phyaddr); + + return val_out; +} + +static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) +{ + struct pcnet32_private *lp = dev->priv; + unsigned long ioaddr = dev->base_addr; + int phyaddr; + + if (!lp->mii) + return; + + phyaddr = lp->a.read_bcr(ioaddr, 33); + + lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); + lp->a.write_bcr(ioaddr, 34, val); + lp->a.write_bcr(ioaddr, 33, phyaddr); +} + +static int pcnet32_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + struct pcnet32_private *lp = dev->priv; + u32 ethcmd; + int phyaddr = 0; + int phy_id = 0; + unsigned long ioaddr = dev->base_addr; + + if (lp->mii) { + phyaddr = lp->a.read_bcr (ioaddr, 33); + phy_id = (phyaddr >> 5) & 0x1f; + lp->mii_if.phy_id = phy_id; + } + + 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); + if (lp->pci_dev) + strcpy (info.bus_info, lp->pci_dev->slot_name); + else + sprintf(info.bus_info, "VLB 0x%lx", dev->base_addr); + 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(&lp->lock); + mii_ethtool_gset(&lp->mii_if, &ecmd); + spin_unlock_irq(&lp->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(&lp->lock); + r = mii_ethtool_sset(&lp->mii_if, &ecmd); + spin_unlock_irq(&lp->lock); + return r; + } + /* restart autonegotiation */ + case ETHTOOL_NWAY_RST: { + return mii_nway_restart(&lp->mii_if); + } + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + edata.data = mii_link_ok(&lp->mii_if); + 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 = pcnet32_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; + pcnet32_debug = edata.data; + return 0; + } + default: + break; + } + + return -EOPNOTSUPP; +} + +static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { unsigned long ioaddr = dev->base_addr; struct pcnet32_private *lp = dev->priv; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phyaddr = lp->a.read_bcr (ioaddr, 33); + if (cmd == SIOCETHTOOL) + return pcnet32_ethtool_ioctl(dev, (void *) rq->ifr_data); + if (lp->mii) { switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = (phyaddr >> 5) & 0x1f; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + data->phy_id = (phyaddr >> 5) & 0x1f; /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f)); - data[3] = lp->a.read_bcr (ioaddr, 34); + case SIOCGMIIREG: /* Read MII PHY register. */ + lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f)); + data->val_out = lp->a.read_bcr (ioaddr, 34); lp->a.write_bcr (ioaddr, 33, phyaddr); return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + case SIOCSMIIREG: /* Write MII PHY register. */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f)); - lp->a.write_bcr (ioaddr, 34, data[2]); + lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f)); + lp->a.write_bcr (ioaddr, 34, data->val_in); lp->a.write_bcr (ioaddr, 33, phyaddr); return 0; default: @@ -1507,13 +1648,12 @@ static int pcnet32_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } return -EOPNOTSUPP; } -#endif /* HAVE_PRIVATE_IOCTL */ static struct pci_driver pcnet32_driver = { - name: "pcnet32", - probe: pcnet32_probe_pci, - remove: NULL, - id_table: pcnet32_pci_tbl, + name: DRV_NAME, + probe: pcnet32_probe_pci, + remove: NULL, + id_table: pcnet32_pci_tbl, }; MODULE_PARM(debug, "i"); -- 2.39.5