int                     options;
        unsigned int            shared_irq:1,   /* shared irq possible */
                                dxsuflo:1,   /* disable transmit stop on uflo */
-                               mii:1;          /* mii port available */
+                               mii:1,          /* mii port available */
+                               autoneg:1,      /* autoneg enabled */
+                               port_tp:1,      /* port set to TP */
+                               fdx:1;          /* full duplex enabled */
        struct net_device       *next;
        struct mii_if_info      mii_if;
        struct timer_list       watchdog_timer;
 }
 #endif
 
+/*
+ * lp->lock must be held.
+ */
+static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
+                          int can_sleep)
+{
+       int csr5;
+       struct pcnet32_private *lp = netdev_priv(dev);
+       const struct pcnet32_access *a = lp->a;
+       ulong ioaddr = dev->base_addr;
+       int ticks;
+
+       /* really old chips have to be stopped. */
+       if (lp->chip_version < PCNET32_79C970A)
+               return 0;
+
+       /* set SUSPEND (SPND) - CSR5 bit 0 */
+       csr5 = a->read_csr(ioaddr, CSR5);
+       a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);
+
+       /* poll waiting for bit to be set */
+       ticks = 0;
+       while (!(a->read_csr(ioaddr, CSR5) & CSR5_SUSPEND)) {
+               spin_unlock_irqrestore(&lp->lock, *flags);
+               if (can_sleep)
+                       msleep(1);
+               else
+                       mdelay(1);
+               spin_lock_irqsave(&lp->lock, *flags);
+               ticks++;
+               if (ticks > 200) {
+                       netif_printk(lp, hw, KERN_DEBUG, dev,
+                                    "Error getting into suspend!\n");
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+static void pcnet32_clr_suspend(struct pcnet32_private *lp, ulong ioaddr)
+{
+       int csr5 = lp->a->read_csr(ioaddr, CSR5);
+       /* clear SUSPEND (SPND) - CSR5 bit 0 */
+       lp->a->write_csr(ioaddr, CSR5, csr5 & ~CSR5_SUSPEND);
+}
+
 static int pcnet32_get_link_ksettings(struct net_device *dev,
                                      struct ethtool_link_ksettings *cmd)
 {
        unsigned long flags;
        int r = -EOPNOTSUPP;
 
+       spin_lock_irqsave(&lp->lock, flags);
        if (lp->mii) {
-               spin_lock_irqsave(&lp->lock, flags);
                mii_ethtool_get_link_ksettings(&lp->mii_if, cmd);
-               spin_unlock_irqrestore(&lp->lock, flags);
+               r = 0;
+       } else if (lp->chip_version == PCNET32_79C970A) {
+               if (lp->autoneg) {
+                       cmd->base.autoneg = AUTONEG_ENABLE;
+                       if (lp->a->read_bcr(dev->base_addr, 4) == 0xc0)
+                               cmd->base.port = PORT_AUI;
+                       else
+                               cmd->base.port = PORT_TP;
+               } else {
+                       cmd->base.autoneg = AUTONEG_DISABLE;
+                       cmd->base.port = lp->port_tp ? PORT_TP : PORT_AUI;
+               }
+               cmd->base.duplex = lp->fdx ? DUPLEX_FULL : DUPLEX_HALF;
+               cmd->base.speed = SPEED_10;
+               ethtool_convert_legacy_u32_to_link_mode(
+                                               cmd->link_modes.supported,
+                                               SUPPORTED_TP | SUPPORTED_AUI);
                r = 0;
        }
+       spin_unlock_irqrestore(&lp->lock, flags);
        return r;
 }
 
                                      const struct ethtool_link_ksettings *cmd)
 {
        struct pcnet32_private *lp = netdev_priv(dev);
+       ulong ioaddr = dev->base_addr;
        unsigned long flags;
        int r = -EOPNOTSUPP;
+       int suspended, bcr2, bcr9, csr15;
 
+       spin_lock_irqsave(&lp->lock, flags);
        if (lp->mii) {
-               spin_lock_irqsave(&lp->lock, flags);
                r = mii_ethtool_set_link_ksettings(&lp->mii_if, cmd);
-               spin_unlock_irqrestore(&lp->lock, flags);
+       } else if (lp->chip_version == PCNET32_79C970A) {
+               suspended = pcnet32_suspend(dev, &flags, 0);
+               if (!suspended)
+                       lp->a->write_csr(ioaddr, CSR0, CSR0_STOP);
+
+               lp->autoneg = cmd->base.autoneg == AUTONEG_ENABLE;
+               bcr2 = lp->a->read_bcr(ioaddr, 2);
+               if (cmd->base.autoneg == AUTONEG_ENABLE) {
+                       lp->a->write_bcr(ioaddr, 2, bcr2 | 0x0002);
+               } else {
+                       lp->a->write_bcr(ioaddr, 2, bcr2 & ~0x0002);
+
+                       lp->port_tp = cmd->base.port == PORT_TP;
+                       csr15 = lp->a->read_csr(ioaddr, CSR15) & ~0x0180;
+                       if (cmd->base.port == PORT_TP)
+                               csr15 |= 0x0080;
+                       lp->a->write_csr(ioaddr, CSR15, csr15);
+                       lp->init_block->mode = cpu_to_le16(csr15);
+
+                       lp->fdx = cmd->base.duplex == DUPLEX_FULL;
+                       bcr9 = lp->a->read_bcr(ioaddr, 9) & ~0x0003;
+                       if (cmd->base.duplex == DUPLEX_FULL)
+                               bcr9 |= 0x0003;
+                       lp->a->write_bcr(ioaddr, 9, bcr9);
+               }
+               if (suspended)
+                       pcnet32_clr_suspend(lp, ioaddr);
+               else if (netif_running(dev))
+                       pcnet32_restart(dev, CSR0_NORMAL);
+               r = 0;
        }
+       spin_unlock_irqrestore(&lp->lock, flags);
        return r;
 }
 
        spin_lock_irqsave(&lp->lock, flags);
        if (lp->mii) {
                r = mii_link_ok(&lp->mii_if);
-       } else if (lp->chip_version >= PCNET32_79C970A) {
+       } else if (lp->chip_version == PCNET32_79C970A) {
+               ulong ioaddr = dev->base_addr;  /* card base I/O address */
+               /* only read link if port is set to TP */
+               if (!lp->autoneg && lp->port_tp)
+                       r = (lp->a->read_bcr(ioaddr, 4) != 0xc0);
+               else /* link always up for AUI port or port auto select */
+                       r = 1;
+       } else if (lp->chip_version > PCNET32_79C970A) {
                ulong ioaddr = dev->base_addr;  /* card base I/O address */
                r = (lp->a->read_bcr(ioaddr, 4) != 0xc0);
        } else {        /* can not detect link on really old chips */
        return 0;
 }
 
-/*
- * lp->lock must be held.
- */
-static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
-               int can_sleep)
-{
-       int csr5;
-       struct pcnet32_private *lp = netdev_priv(dev);
-       const struct pcnet32_access *a = lp->a;
-       ulong ioaddr = dev->base_addr;
-       int ticks;
-
-       /* really old chips have to be stopped. */
-       if (lp->chip_version < PCNET32_79C970A)
-               return 0;
-
-       /* set SUSPEND (SPND) - CSR5 bit 0 */
-       csr5 = a->read_csr(ioaddr, CSR5);
-       a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);
-
-       /* poll waiting for bit to be set */
-       ticks = 0;
-       while (!(a->read_csr(ioaddr, CSR5) & CSR5_SUSPEND)) {
-               spin_unlock_irqrestore(&lp->lock, *flags);
-               if (can_sleep)
-                       msleep(1);
-               else
-                       mdelay(1);
-               spin_lock_irqsave(&lp->lock, *flags);
-               ticks++;
-               if (ticks > 200) {
-                       netif_printk(lp, hw, KERN_DEBUG, dev,
-                                    "Error getting into suspend!\n");
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-static void pcnet32_clr_suspend(struct pcnet32_private *lp, ulong ioaddr)
-{
-       int csr5 = lp->a->read_csr(ioaddr, CSR5);
-       /* clear SUSPEND (SPND) - CSR5 bit 0 */
-       lp->a->write_csr(ioaddr, CSR5, csr5 & ~CSR5_SUSPEND);
-}
-
 /*
  * process one receive descriptor entry
  */
                lp->options = PCNET32_PORT_ASEL;
        else
                lp->options = options_mapping[options[cards_found]];
+       /* force default port to TP on 79C970A so link detection can work */
+       if (lp->chip_version == PCNET32_79C970A)
+               lp->options = PCNET32_PORT_10BT;
        lp->mii_if.dev = dev;
        lp->mii_if.mdio_read = mdio_read;
        lp->mii_if.mdio_write = mdio_write;
                     (u32) (lp->rx_ring_dma_addr),
                     (u32) (lp->init_dma_addr));
 
+       lp->autoneg = !!(lp->options & PCNET32_PORT_ASEL);
+       lp->port_tp = !!(lp->options & PCNET32_PORT_10BT);
+       lp->fdx = !!(lp->options & PCNET32_PORT_FD);
+
        /* set/reset autoselect bit */
        val = lp->a->read_bcr(ioaddr, 2) & ~2;
        if (lp->options & PCNET32_PORT_ASEL)
 
        if (lp->mii) {
                curr_link = mii_link_ok(&lp->mii_if);
+       } else if (lp->chip_version == PCNET32_79C970A) {
+               ulong ioaddr = dev->base_addr;  /* card base I/O address */
+               /* only read link if port is set to TP */
+               if (!lp->autoneg && lp->port_tp)
+                       curr_link = (lp->a->read_bcr(ioaddr, 4) != 0xc0);
+               else /* link always up for AUI port or port auto select */
+                       curr_link = 1;
        } else {
                ulong ioaddr = dev->base_addr;  /* card base I/O address */
                curr_link = (lp->a->read_bcr(ioaddr, 4) != 0xc0);