patch-2.4.22 linux-2.4.22/drivers/net/mace.c

Next file: linux-2.4.22/drivers/net/macmace.c
Previous file: linux-2.4.22/drivers/net/mac8390.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/drivers/net/mace.c linux-2.4.22/drivers/net/mace.c
@@ -1,8 +1,12 @@
 /*
  * Network device driver for the MACE ethernet controller on
  * Apple Powermacs.  Assumes it's under a DBDMA controller.
+ * 
+ * MACE is beleived to be an AMD 79C940
  *
  * Copyright (C) 1996 Paul Mackerras.
+ * 
+ * TODO: Use a spinlock for smp safety (backport 2.5 version ?)
  */
 
 #include <linux/config.h>
@@ -16,6 +20,8 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
@@ -82,7 +88,10 @@
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
 static struct net_device_stats *mace_stats(struct net_device *dev);
 static void mace_set_multicast(struct net_device *dev);
+static int mace_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int mace_ethtool_ioctl(struct net_device *dev, void *useraddr);
 static void mace_reset(struct net_device *dev);
+static void mace_restart(struct net_device *dev);
 static int mace_set_address(struct net_device *dev, void *addr);
 static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
@@ -226,6 +235,7 @@
 	dev->get_stats = mace_stats;
 	dev->set_multicast_list = mace_set_multicast;
 	dev->set_mac_address = mace_set_address;
+	dev->do_ioctl = mace_do_ioctl;
 
 	ether_setup(dev);
 
@@ -362,6 +372,90 @@
     return 0;
 }
 
+static int mace_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+        switch(cmd) {
+        case SIOCETHTOOL:
+                return mace_ethtool_ioctl(dev, (void *) ifr->ifr_data);
+
+        case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
+        case SIOCDEVPRIVATE:            /* for binary compat, remove in 2.5 */
+        case SIOCGMIIREG:               /* Read MII PHY register. */
+        case SIOCDEVPRIVATE+1:          /* for binary compat, remove in 2.5 */
+        case SIOCSMIIREG:               /* Write MII PHY register. */
+        case SIOCDEVPRIVATE+2:          /* for binary compat, remove in 2.5 */
+        default:
+                return -EOPNOTSUPP;
+        }
+}
+
+static int mace_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct mace_data *mp = (struct mace_data *) dev->priv;
+	u32 ethcmd;
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { .cmd = ETHTOOL_GDRVINFO };
+		struct mace_data *mp = dev->priv;
+		strcpy (info.driver, "mace");
+		info.version[0] = '\0';
+		snprintf(info.fw_version, 31, "chip revision %d.%d", mp->chipid >> 8, mp->chipid & 0xff);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
+
+		cmd.supported = SUPPORTED_10baseT_Half |
+				SUPPORTED_AUI |
+				SUPPORTED_MII;
+		cmd.advertising = SUPPORTED_10baseT_Half;
+		cmd.port = mp->port_aaui ? PORT_AUI : PORT_MII;
+		cmd.speed = SPEED_10;
+		if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SSET: {
+		struct ethtool_cmd cmd;
+
+		if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+			return -EFAULT;
+
+		if (cmd.autoneg != AUTONEG_DISABLE)
+			return -EINVAL;
+		if (cmd.speed != SPEED_10)
+			return -EINVAL;
+		if ((cmd.port == PORT_AUI) != mp->port_aaui) {
+			int aaui = (cmd.port == PORT_AUI);
+			unsigned long flags;
+
+			printk("%s: switching port to: %s\n",
+				dev->name, aaui ? "AAUI" : "MII");
+			mp->port_aaui = aaui;
+    			save_flags(flags);
+			cli();
+			mace_restart(dev);
+			restore_flags(flags);
+		}
+		return 0;
+	}
+	case ETHTOOL_NWAY_RST:
+	case ETHTOOL_GLINK:
+	case ETHTOOL_GMSGLVL:
+	case ETHTOOL_SMSGLVL:
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
 static int mace_open(struct net_device *dev)
 {
     struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -473,10 +567,7 @@
 static inline void mace_set_timeout(struct net_device *dev)
 {
     struct mace_data *mp = (struct mace_data *) dev->priv;
-    unsigned long flags;
 
-    save_flags(flags);
-    cli();
     if (mp->timeout_active)
 	del_timer(&mp->tx_timeout);
     mp->tx_timeout.expires = jiffies + TX_TIMEOUT;
@@ -484,7 +575,6 @@
     mp->tx_timeout.data = (unsigned long) dev;
     add_timer(&mp->tx_timeout);
     mp->timeout_active = 1;
-    restore_flags(flags);
 }
 
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
@@ -763,31 +853,17 @@
     }
 }
 
-static void mace_tx_timeout(unsigned long data)
+static void mace_restart(struct net_device *dev)
 {
-    struct net_device *dev = (struct net_device *) data;
     struct mace_data *mp = (struct mace_data *) dev->priv;
     volatile struct mace *mb = mp->mace;
     volatile struct dbdma_regs *td = mp->tx_dma;
     volatile struct dbdma_regs *rd = mp->rx_dma;
     volatile struct dbdma_cmd *cp;
-    unsigned long flags;
     int i;
 
-    save_flags(flags);
-    cli();
-    mp->timeout_active = 0;
-    if (mp->tx_active == 0 && !mp->tx_bad_runt)
-	goto out;
-
-    /* update various counters */
-    mace_handle_misc_intrs(mp, in_8(&mb->ir));
-
-    cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
-
     /* turn off both tx and rx and reset the chip */
     out_8(&mb->maccc, 0);
-    printk(KERN_ERR "mace: transmit timeout - resetting\n");
     dbdma_reset(td);
     mace_reset(dev);
 
@@ -825,7 +901,29 @@
     /* turn it back on */
     out_8(&mb->imr, RCVINT);
     out_8(&mb->maccc, mp->maccc);
+}
+
+static void mace_tx_timeout(unsigned long data)
+{
+    struct net_device *dev = (struct net_device *) data;
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+    mp->timeout_active = 0;
+    if (mp->tx_active == 0 && !mp->tx_bad_runt)
+	goto out;
+
+    /* update various counters */
+    mace_handle_misc_intrs(mp, in_8(&mb->ir));
+
+    printk(KERN_ERR "mace: transmit timeout - resetting\n");
 
+    /* Kick chip */
+    mace_restart(dev);
+    
 out:
     restore_flags(flags);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)