]> git.hungrycats.org Git - linux/commitdiff
Merge ns83820 GigE net driver changes from 2.4.x kernel:
authorJeff Garzik <jgarzik@rum.normnet.org>
Mon, 11 Feb 2002 20:26:18 +0000 (15:26 -0500)
committerJeff Garzik <jgarzik@rum.normnet.org>
Mon, 11 Feb 2002 20:26:18 +0000 (15:26 -0500)
0.13a - optical transceiver support added
by Michael Clark <michael@metaparadigm.com>
0.13b - call register_netdev earlier in initialization
suppress duplicate link status messages
0.15 get ppc (big endian) working

Via Dave Jones.

drivers/net/ns83820.c

index 1016a21105212065f05b36d0997be5c6b01abf04..5e72b5c6b2edac9f1c2ee666100b4a2ec46005da 100644 (file)
@@ -1,7 +1,7 @@
-#define VERSION "0.14"
-/* ns83820.c by Benjamin LaHaise <bcrl@redhat.com>
+#define _VERSION "0.15"
+/* ns83820.c by Benjamin LaHaise <bcrl@redhat.com> with contributions.
  *
- * $Revision: 1.34.2.8 $
+ * $Revision: 1.34.2.12 $
  *
  * Copyright 2001 Benjamin LaHaise.
  * Copyright 2001 Red Hat.
  *                     0.12 - add statistics counters
  *                          - add allmulti/promisc support
  *     20011009        0.13 - hotplug support, other smaller pci api cleanups
- *     20011117        0.14 - ethtool GDRVINFO, GLINK support
+ *     20011204        0.13a - optical transceiver support added
+ *                             by Michael Clark <michael@metaparadigm.com>
+ *     20011205        0.13b - call register_netdev earlier in initialization
+ *                             suppress duplicate link status messages
+ *     20011117        0.14 - ethtool GDRVINFO, GLINK support
+ *     20011204        0.15    get ppc (big endian) working
  *
  * Driver Overview
  * ===============
@@ -66,6 +71,7 @@
  *     D-Link          DGE-500T
  *     PureData        PDP8023Z-TG
  *     SMC             SMC9452TX       SMC9462TX
+ *     Netgear         GA621
  *
  * Special thanks to SMC for providing hardware to test this driver on.
  *
 #define        Dprintk                 dprintk
 
 #ifdef CONFIG_HIGHMEM64G
-#define USE_64BIT_ADDR
+#define USE_64BIT_ADDR "+"
 #elif defined(__ia64__)
-#define USE_64BIT_ADDR
+#define USE_64BIT_ADDR "+"
 #endif
 
 /* Tell davem to fix the pci dma api.  Grrr. */
 /* stolen from acenic.c */
-#ifdef CONFIG_HIGHMEM
+#if 0 //def CONFIG_HIGHMEM
 #if defined(CONFIG_X86)
 #define DMAADDR_OFFSET  0
 #if defined(CONFIG_HIGHMEM64G)
@@ -141,6 +147,12 @@ pci_map_single_high(struct pci_dev *hwdev, struct page *page,
 }
 #endif
 
+#if defined(USE_64BIT_ADDR)
+#define        VERSION _VERSION USE_64BIT_ADDR
+#else
+#define        VERSION _VERSION
+#endif
+
 /* tunables */
 #define RX_BUF_SIZE    6144    /* 8192 */
 #define NR_RX_DESC     256
@@ -216,6 +228,7 @@ pci_map_single_high(struct pci_dev *hwdev, struct page *page,
 #define CFG_DUPSTS     0x10000000
 #define CFG_TBI_EN     0x01000000
 #define CFG_MODE_1000  0x00400000
+#define CFG_AUTO_1000  0x00200000
 #define CFG_PINT_CTL   0x001c0000
 #define CFG_PINT_DUPSTS        0x00100000
 #define CFG_PINT_LNKSTS        0x00080000
@@ -319,6 +332,36 @@ pci_map_single_high(struct pci_dev *hwdev, struct page *page,
 #define VDR            0xc4
 #define CCSR           0xcc
 
+#define TBICR          0xe0
+#define TBISR          0xe4
+#define TANAR          0xe8
+#define TANLPAR                0xec
+#define TANER          0xf0
+#define TESR           0xf4
+
+#define TBICR_MR_AN_ENABLE     0x00001000
+#define TBICR_MR_RESTART_AN    0x00000200
+
+#define TBISR_MR_LINK_STATUS   0x00000020
+#define TBISR_MR_AN_COMPLETE   0x00000004
+
+#define TANAR_PS2              0x00000100
+#define TANAR_PS1              0x00000080
+#define TANAR_HALF_DUP                 0x00000040
+#define TANAR_FULL_DUP                 0x00000020
+
+#define GPIOR_GP5_OE           0x00000200
+#define GPIOR_GP4_OE           0x00000100
+#define GPIOR_GP3_OE           0x00000080
+#define GPIOR_GP2_OE           0x00000040
+#define GPIOR_GP1_OE           0x00000020
+#define GPIOR_GP3_OUT          0x00000004
+#define GPIOR_GP1_OUT          0x00000001
+
+#define LINK_AUTONEGOTIATE     0x01
+#define LINK_DOWN              0x02
+#define LINK_UP                        0x04
+
 #define __kick_rx(dev) writel(CR_RXE, dev->base + CR)
 
 #define kick_rx(dev) do { \
@@ -393,6 +436,7 @@ struct ns83820 {
        u32                     IMR_cache;
        struct eeprom           ee;
 
+       unsigned                linkstate;
 
        spinlock_t      tx_lock;
 
@@ -444,11 +488,11 @@ static inline void build_rx_desc64(struct ns83820 *dev, u32 *desc, u64 link, u64
 
 static inline void build_rx_desc32(struct ns83820 *dev, u32 *desc, u32 link, u32 buf, u32 cmdsts, u32 extsts)
 {
-       desc[0] = link;
-       desc[1] = buf;
-       desc[3] = extsts;
+       desc[0] = cpu_to_le32(link);
+       desc[1] = cpu_to_le32(buf);
+       desc[3] = cpu_to_le32(extsts);
        mb();
-       desc[2] = cmdsts;
+       desc[2] = cpu_to_le32(cmdsts);
 }
 
 #define build_rx_desc  build_rx_desc32
@@ -489,7 +533,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
        build_rx_desc(dev, sg, 0, buf, cmdsts, 0);
        /* update link of previous rx */
        if (next_empty != dev->rx_info.next_rx)
-               dev->rx_info.descs[((NR_RX_DESC + next_empty - 1) % NR_RX_DESC) * DESC_SIZE] = dev->rx_info.phy_descs + (next_empty * DESC_SIZE * 4);
+               dev->rx_info.descs[((NR_RX_DESC + next_empty - 1) % NR_RX_DESC) * DESC_SIZE] = cpu_to_le32(dev->rx_info.phy_descs + (next_empty * DESC_SIZE * 4));
 
        return 0;
 }
@@ -548,39 +592,93 @@ static inline void clear_rx_desc(struct ns83820 *dev, unsigned i)
 
 static void phy_intr(struct ns83820 *dev)
 {
-       static char *speeds[] = { "10", "100", "1000", "1000(?)" };
+       static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" };
        u32 cfg, new_cfg;
+       u32 tbisr, tanar, tanlpar;
+       int speed, fullduplex, newlinkstate;
 
-       new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
        cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
 
-       if (cfg & CFG_SPDSTS1)
-               new_cfg |= CFG_MODE_1000 | CFG_SB;
-       else
-               new_cfg &= ~CFG_MODE_1000 | CFG_SB;
+       if (dev->CFG_cache & CFG_TBI_EN) {
+
+               /* we have an optical transceiver */
+               tbisr = readl(dev->base + TBISR);
+               tanar = readl(dev->base + TANAR);
+               tanlpar = readl(dev->base + TANLPAR);
+               dprintk("phy_intr: tbisr=%08x, tanar=%08x, tanlpar=%08x\n",
+                       tbisr, tanar, tanlpar);
+
+               if ( (fullduplex = (tanlpar & TANAR_FULL_DUP)
+                     && (tanar & TANAR_FULL_DUP)) ) {
+
+                       /* both of us are full duplex */
+                       writel(readl(dev->base + TXCFG)
+                              | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
+                              dev->base + TXCFG);
+                       writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
+                              dev->base + RXCFG);
+                       /* Light up full duplex LED */
+                       writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT,
+                              dev->base + GPIOR);
+
+               } else if(((tanlpar & TANAR_HALF_DUP)
+                          && (tanar & TANAR_HALF_DUP))
+                       || ((tanlpar & TANAR_FULL_DUP)
+                           && (tanar & TANAR_HALF_DUP))
+                       || ((tanlpar & TANAR_HALF_DUP)
+                           && (tanar & TANAR_FULL_DUP))) {
+
+                       /* one or both of us are half duplex */
+                       writel((readl(dev->base + TXCFG)
+                               & ~(TXCFG_CSI | TXCFG_HBI)) | TXCFG_ATP,
+                              dev->base + TXCFG);
+                       writel(readl(dev->base + RXCFG) & ~RXCFG_RX_FD,
+                              dev->base + RXCFG);
+                       /* Turn off full duplex LED */
+                       writel(readl(dev->base + GPIOR) & ~GPIOR_GP1_OUT,
+                              dev->base + GPIOR);
+               }
+
+               speed = 4; /* 1000F */
+
+       } else {
+               /* we have a copper transceiver */
+               new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
+
+               if (cfg & CFG_SPDSTS1)
+                       new_cfg |= CFG_MODE_1000 | CFG_SB;
+               else
+                       new_cfg &= ~CFG_MODE_1000 | CFG_SB;
 
-       if ((cfg & CFG_LNKSTS) && ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) {
-               writel(new_cfg, dev->base + CFG);
-               dev->CFG_cache = new_cfg;
+               if ((cfg & CFG_LNKSTS) && ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) {
+                       writel(new_cfg, dev->base + CFG);
+                       dev->CFG_cache = new_cfg;
+               }
+
+               dev->CFG_cache &= ~CFG_SPDSTS;
+               dev->CFG_cache |= cfg & CFG_SPDSTS;
+
+               speed = ((cfg / CFG_SPDSTS0) & 3);
+               fullduplex = (cfg & CFG_DUPSTS);
        }
 
-       dev->CFG_cache &= ~CFG_SPDSTS;
-       dev->CFG_cache |= cfg & CFG_SPDSTS;
+       newlinkstate = (cfg & CFG_LNKSTS) ? LINK_UP : LINK_DOWN;
 
-       if (cfg & CFG_LNKSTS) {
+       if (newlinkstate & LINK_UP
+           && dev->linkstate != newlinkstate) {
                netif_start_queue(&dev->net_dev);
                netif_wake_queue(&dev->net_dev);
-       } else {
-               netif_stop_queue(&dev->net_dev);
-       }
-
-       if (cfg & CFG_LNKSTS)
                printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n",
                        dev->net_dev.name,
-                       speeds[((cfg / CFG_SPDSTS0) & 3)],
-                       (cfg & CFG_DUPSTS) ? "full" : "half");
-       else
+                       speeds[speed],
+                       fullduplex ? "full" : "half");
+       } else if (newlinkstate & LINK_DOWN
+                  && dev->linkstate != newlinkstate) {
+               netif_stop_queue(&dev->net_dev);
                printk(KERN_INFO "%s: link now down.\n", dev->net_dev.name);
+       }
+
+       dev->linkstate = newlinkstate;
 }
 
 static int ns83820_setup_rx(struct ns83820 *dev)
@@ -701,15 +799,15 @@ static void rx_irq(struct ns83820 *dev)
        dprintk("walking descs\n");
        next_rx = info->next_rx;
        desc = info->descs + (DESC_SIZE * next_rx);
-       while ((CMDSTS_OWN & (cmdsts = desc[CMDSTS])) &&
+       while ((CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) &&
               (cmdsts != CMDSTS_OWN)) {
                struct sk_buff *skb;
-               u32 extsts = desc[EXTSTS];
-               dmaaddr_high_t bufptr = *(hw_addr_t *)(desc + BUFPTR);
+               u32 extsts = le32_to_cpu(desc[EXTSTS]);
+               dmaaddr_high_t bufptr = le32_to_cpu(desc[BUFPTR]);
 
                dprintk("cmdsts: %08x\n", cmdsts);
-               dprintk("link: %08x\n", desc[LINK]);
-               dprintk("extsts: %08x\n", desc[EXTSTS]);
+               dprintk("link: %08x\n", cpu_to_le32(desc[LINK]));
+               dprintk("extsts: %08x\n", extsts);
 
                skb = info->skbs[next_rx];
                info->skbs[next_rx] = NULL;
@@ -721,14 +819,14 @@ static void rx_irq(struct ns83820 *dev)
                pci_unmap_single(dev->pci_dev, bufptr,
                                 RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
                if (CMDSTS_OK & cmdsts) {
-#ifndef __i386__
+#if 0 //ndef __i386__
                        struct sk_buff *tmp;
 #endif
                        int len = cmdsts & 0xffff;
                        if (!skb)
                                BUG();
                        skb_put(skb, len);
-#ifndef __i386__       /* I hate the network stack sometimes */
+#if 0 //ndef __i386__  /* I hate the network stack sometimes */
                        tmp = __dev_alloc_skb(RX_BUF_SIZE+16, GFP_ATOMIC);
                        if (!tmp)
                                goto done;
@@ -750,7 +848,7 @@ static void rx_irq(struct ns83820 *dev)
                        skb->protocol = eth_type_trans(skb, &dev->net_dev);
                        if (NET_RX_DROP == netif_rx(skb))
                                dev->stats.rx_dropped ++;
-#ifndef __i386__
+#if 0 //ndef __i386__
                done:;
 #endif
                } else {
@@ -791,9 +889,9 @@ static void do_tx_done(struct ns83820 *dev)
        desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
 
        dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
-               tx_done_idx, dev->tx_free_idx, desc[CMDSTS]);
+               tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[CMDSTS]));
        while ((tx_done_idx != dev->tx_free_idx) &&
-              !(CMDSTS_OWN & (cmdsts = desc[CMDSTS])) ) {
+              !(CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) ) {
                struct sk_buff *skb;
 
                if (cmdsts & CMDSTS_ERR)
@@ -804,13 +902,13 @@ static void do_tx_done(struct ns83820 *dev)
                        dev->stats.tx_bytes += cmdsts & 0xffff;
 
                dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
-                       tx_done_idx, dev->tx_free_idx, desc[CMDSTS]);
+                       tx_done_idx, dev->tx_free_idx, cmdsts);
                skb = dev->tx_skbs[tx_done_idx];
                dev->tx_skbs[tx_done_idx] = NULL;
                dprintk("done(%p)\n", skb);
                if (skb) {
                        pci_unmap_single(dev->pci_dev,
-                                       *(hw_addr_t *)(desc + BUFPTR),
+                                       le32_to_cpu(desc[BUFPTR]),
                                        skb->len,
                                        PCI_DMA_TODEVICE);
                        dev_kfree_skb_irq(skb);
@@ -818,7 +916,7 @@ static void do_tx_done(struct ns83820 *dev)
 
                tx_done_idx = (tx_done_idx + 1) % NR_TX_DESC;
                dev->tx_done_idx = tx_done_idx;
-               desc[CMDSTS] = 0;
+               desc[CMDSTS] = cpu_to_le32(0);
                barrier();
                desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
        }
@@ -939,17 +1037,17 @@ again:
                }
 #endif
 
-               dprintk("frag[%3u]: %4u @ 0x%x%08Lx\n", free_idx, len,
+               dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len,
                        (unsigned long long)buf);
                free_idx = (free_idx + 1) % NR_TX_DESC;
-               desc[LINK] = dev->tx_phy_descs + (free_idx * DESC_SIZE * 4);
-               *(hw_addr_t *)(desc + BUFPTR) = buf;
-               desc[EXTSTS] = extsts;
+               desc[LINK] = cpu_to_le32(dev->tx_phy_descs + (free_idx * DESC_SIZE * 4));
+               desc[BUFPTR] = cpu_to_le32(buf);
+               desc[EXTSTS] = cpu_to_le32(extsts);
 
                cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
                cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN;
                cmdsts |= len;
-               desc[CMDSTS] = cmdsts;
+               desc[CMDSTS] = cpu_to_le32(cmdsts);
 
                if (residue) {
                        buf += len;
@@ -960,7 +1058,8 @@ again:
                if (!nr_frags)
                        break;
 
-               buf = pci_map_single_high(dev->pci_dev, frag->page, 0,
+               buf = pci_map_single_high(dev->pci_dev, frag->page,
+                                         frag->page_offset,
                                          frag->size, PCI_DMA_TODEVICE);
                dprintk("frag: buf=%08Lx  page=%08lx\n",
                        (long long)buf, (long)(frag->page - mem_map));
@@ -970,7 +1069,7 @@ again:
        }
        dprintk("done pkt\n");
        dev->tx_skbs[free_idx] = skb;
-       first_desc[CMDSTS] |= CMDSTS_OWN;
+       first_desc[CMDSTS] |= cpu_to_le32(CMDSTS_OWN);
        dev->tx_free_idx = free_idx;
        kick_tx(dev);
 
@@ -1014,24 +1113,24 @@ static int ns83820_ethtool_ioctl (struct ns83820 *dev, void *useraddr)
 {
        u32 ethcmd;
 
-       if (copy_from_user (&ethcmd, useraddr, sizeof (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, "ns83820");
-                       strcpy (info.version, VERSION);
-                       strcpy (info.bus_info, dev->pci_dev->slot_name);
-                       if (copy_to_user (useraddr, &info, sizeof (info)))
+                       strcpy(info.driver, "ns83820");
+                       strcpy(info.version, VERSION);
+                       strcpy(info.bus_info, dev->pci_dev->slot_name);
+                       if (copy_to_user(useraddr, &info, sizeof (info)))
                                return -EFAULT;
                        return 0;
                }
 
        /* get link status */
        case ETHTOOL_GLINK: {
-               struct ethtool_value edata = {ETHTOOL_GLINK};
+               struct ethtool_value edata = { ETHTOOL_GLINK };
                u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
 
                if (cfg & CFG_LNKSTS)
@@ -1104,10 +1203,14 @@ static void ns83820_irq(int foo, void *data, struct pt_regs *regs)
                        Dprintk("BAD\n");
        }
 
-       if (ISR_RXSOVR & isr)
-               Dprintk("overrun\n");
-       if (ISR_RXORN & isr)
-               Dprintk("overrun\n");
+       if (unlikely(ISR_RXSOVR & isr)) {
+               Dprintk("overrun: rxsovr\n");
+               dev->stats.rx_over_errors ++;
+       }
+       if (unlikely(ISR_RXORN & isr)) {
+               Dprintk("overrun: rxorn\n");
+               dev->stats.rx_over_errors ++;
+       }
 
        if ((ISR_RXRCMP & isr) && dev->rx_info.up)
                writel(CR_RXE, dev->base + CR);
@@ -1206,9 +1309,10 @@ static int ns83820_open(struct net_device *_dev)
 
        memset(dev->tx_descs, 0, 4 * NR_TX_DESC * DESC_SIZE);
        for (i=0; i<NR_TX_DESC; i++) {
-               *(hw_addr_t *)(dev->tx_descs + (i * DESC_SIZE) + LINK)
-                               = dev->tx_phy_descs
-                                 + ((i+1) % NR_TX_DESC) * DESC_SIZE * 4;
+               dev->tx_descs[(i * DESC_SIZE) + LINK]
+                               = cpu_to_le32(
+                                 dev->tx_phy_descs
+                                 + ((i+1) % NR_TX_DESC) * DESC_SIZE * 4);
        }
 
        dev->tx_idx = 0;
@@ -1246,6 +1350,9 @@ static void ns83820_getmac(struct ns83820 *dev, u8 *mac)
 #if 0  /* I've left this in as an example of how to use eeprom.h */
                data = eeprom_readw(&dev->ee, 0xa + 2 - i);
 #else
+               /* Read from the perfect match memory: this is loaded by
+                * the chip from the EEPROM via the EELOAD self test.
+                */
                writel(i*2, dev->base + RFCR);
                data = readl(dev->base + RFDR);
 #endif
@@ -1343,6 +1450,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
                goto out_unmap;
        }
 
+       if(register_netdev(&dev->net_dev)) goto out_unmap;
+
        dev->net_dev.open = ns83820_open;
        dev->net_dev.stop = ns83820_stop;
        dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit;
@@ -1375,12 +1484,15 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
        dev->CFG_cache = readl(dev->base + CFG);
 
        if ((dev->CFG_cache & CFG_PCI64_DET)) {
-               printk("%s: enabling 64 bit PCI.\n", dev->net_dev.name);
+               printk("%s: enabling 64 bit PCI addressing.\n",
+                       dev->net_dev.name);
                dev->CFG_cache |= CFG_T64ADDR | CFG_DATA64_EN;
-       } else {
-               printk("%s: disabling 64 bit PCI.\n", dev->net_dev.name);
+#if defined(USE_64BIT_ADDR)
+               dev->net_dev.features |= NETIF_F_HIGHDMA;
+#endif
+       } else
                dev->CFG_cache &= ~(CFG_T64ADDR | CFG_DATA64_EN);
-       }
+
        dev->CFG_cache &= (CFG_TBI_EN  | CFG_MRM_DIS   | CFG_MWI_DIS |
                           CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 |
                           CFG_M64ADDR);
@@ -1390,15 +1502,28 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
        dev->CFG_cache |= CFG_POW;
 #ifdef USE_64BIT_ADDR
        dev->CFG_cache |= CFG_M64ADDR;
-       printk("using 64 bit addressing\n");
 #endif
-#ifdef __LITTLE_ENDIAN
+       /* Big endian mode does not seem to do what the docs suggest */
        dev->CFG_cache &= ~CFG_BEM;
-#elif defined(__BIG_ENDIAN)
-       dev->CFG_cache |= CFG_BEM;
-#else
-#error This driver only works for big or little endian!!!
-#endif
+
+       /* setup optical transceiver if we have one */
+       if (dev->CFG_cache & CFG_TBI_EN) {
+               printk("%s: enabling optical transceiver\n", dev->net_dev.name);
+               writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR);
+
+               /* setup auto negotiation feature advertisement */
+               writel(readl(dev->base + TANAR)
+                      | TANAR_HALF_DUP | TANAR_FULL_DUP,
+                      dev->base + TANAR);
+
+               /* start auto negotiation */
+               writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
+                      dev->base + TBICR);
+               writel(TBICR_MR_AN_ENABLE, dev->base + TBICR);
+               dev->linkstate = LINK_AUTONEGOTIATE;
+
+               dev->CFG_cache |= CFG_MODE_1000;
+       }
 
        writel(dev->CFG_cache, dev->base + CFG);
        dprintk("CFG: %08x\n", dev->CFG_cache);
@@ -1454,15 +1579,15 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
        dev->net_dev.features |= NETIF_F_HIGHDMA;
 #endif
 
-       register_netdev(&dev->net_dev);
-
-       printk(KERN_INFO "%s: ns83820.c v" VERSION ": DP83820 %02x:%02x:%02x:%02x:%02x:%02x pciaddr=0x%08lx irq=%d rev 0x%x\n",
+       printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n",
                dev->net_dev.name,
+               (unsigned)readl(dev->base + SRR) >> 8,
+               (unsigned)readl(dev->base + SRR) & 0xff,
                dev->net_dev.dev_addr[0], dev->net_dev.dev_addr[1],
                dev->net_dev.dev_addr[2], dev->net_dev.dev_addr[3],
                dev->net_dev.dev_addr[4], dev->net_dev.dev_addr[5],
                addr, pci_dev->irq,
-               (unsigned)readl(dev->base + SRR)
+               (dev->net_dev.features & NETIF_F_HIGHDMA) ? "sg" : "h,sg"
                );
 
        return 0;