]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/net/starfire.c
arm: tegra: comms: Enable autopm for RAW-IP network driver.
[linux-2.6.git] / drivers / net / starfire.c
index 0358809f409c8d8522d983fd54966b54be78b5ef..7ae1f990a98e1034ee8e851189537a6674c8b50f 100644 (file)
@@ -30,6 +30,7 @@
 #define DRV_VERSION    "2.1"
 #define DRV_RELDATE    "July  6, 2008"
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/mii.h>
 #include <linux/if_vlan.h>
 #include <linux/mm.h>
+#include <linux/firmware.h>
 #include <asm/processor.h>             /* Processor type for cache alignment. */
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#include "starfire_firmware.h"
 /*
  * The current frame processor firmware fails to checksum a fragment
  * of length 1. If and when this is fixed, the #define below can be removed.
@@ -144,11 +145,7 @@ static int full_duplex[MAX_UNITS] = {0, };
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT     (2 * HZ)
 
-/*
- * This SUCKS.
- * We need a much better method to determine if dma_addr_t is 64-bit.
- */
-#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
 /* 64-bit dma_addr_t */
 #define ADDR_64BITS    /* This chip uses 64 bit addresses. */
 #define netdrv_addr_t __le64
@@ -173,15 +170,21 @@ static int full_duplex[MAX_UNITS] = {0, };
 #define skb_first_frag_len(skb)        skb_headlen(skb)
 #define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1)
 
+/* Firmware names */
+#define FIRMWARE_RX    "adaptec/starfire_rx.bin"
+#define FIRMWARE_TX    "adaptec/starfire_tx.bin"
+
 /* These identify the driver base version and may not be removed. */
-static char version[] =
+static const char version[] __devinitconst =
 KERN_INFO "starfire.c:v1.03 7/26/2000  Written by Donald Becker <becker@scyld.com>\n"
-KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
+" (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
+MODULE_FIRMWARE(FIRMWARE_RX);
+MODULE_FIRMWARE(FIRMWARE_TX);
 
 module_param(max_interrupt_work, int, 0);
 module_param(mtu, int, 0);
@@ -295,8 +298,8 @@ enum chipset {
        CH_6915 = 0,
 };
 
-static struct pci_device_id starfire_pci_tbl[] = {
-       { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 },
+static DEFINE_PCI_DEVICE_TABLE(starfire_pci_tbl) = {
+       { PCI_VDEVICE(ADAPTEC, 0x6915), CH_6915 },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, starfire_pci_tbl);
@@ -556,10 +559,9 @@ struct netdev_private {
        unsigned int tx_done;
        struct napi_struct napi;
        struct net_device *dev;
-       struct net_device_stats stats;
        struct pci_dev *pci_dev;
 #ifdef VLAN_SUPPORT
-       struct vlan_group *vlgrp;
+       unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
 #endif
        void *queue_mem;
        dma_addr_t queue_mem_dma;
@@ -589,7 +591,7 @@ static int  netdev_open(struct net_device *dev);
 static void    check_duplex(struct net_device *dev);
 static void    tx_timeout(struct net_device *dev);
 static void    init_ring(struct net_device *dev);
-static int     start_tx(struct sk_buff *skb, struct net_device *dev);
+static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t intr_handler(int irq, void *dev_instance);
 static void    netdev_error(struct net_device *dev, int intr_status);
 static int     __netdev_rx(struct net_device *dev, int *quota);
@@ -605,18 +607,6 @@ static const struct ethtool_ops ethtool_ops;
 
 
 #ifdef VLAN_SUPPORT
-static void netdev_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
-{
-        struct netdev_private *np = netdev_priv(dev);
-
-        spin_lock(&np->lock);
-       if (debug > 2)
-               printk("%s: Setting vlgrp to %p\n", dev->name, grp);
-        np->vlgrp = grp;
-       set_rx_mode(dev);
-        spin_unlock(&np->lock);
-}
-
 static void netdev_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
 {
        struct netdev_private *np = netdev_priv(dev);
@@ -624,6 +614,7 @@ static void netdev_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
        spin_lock(&np->lock);
        if (debug > 1)
                printk("%s: Adding vlanid %d to vlan filter\n", dev->name, vid);
+       set_bit(vid, np->active_vlans);
        set_rx_mode(dev);
        spin_unlock(&np->lock);
 }
@@ -635,13 +626,30 @@ static void netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
        spin_lock(&np->lock);
        if (debug > 1)
                printk("%s: removing vlanid %d from vlan filter\n", dev->name, vid);
-       vlan_group_set_device(np->vlgrp, vid, NULL);
+       clear_bit(vid, np->active_vlans);
        set_rx_mode(dev);
        spin_unlock(&np->lock);
 }
 #endif /* VLAN_SUPPORT */
 
 
+static const struct net_device_ops netdev_ops = {
+       .ndo_open               = netdev_open,
+       .ndo_stop               = netdev_close,
+       .ndo_start_xmit         = start_tx,
+       .ndo_tx_timeout         = tx_timeout,
+       .ndo_get_stats          = get_stats,
+       .ndo_set_multicast_list = &set_rx_mode,
+       .ndo_do_ioctl           = netdev_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+#ifdef VLAN_SUPPORT
+       .ndo_vlan_rx_add_vid    = netdev_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = netdev_vlan_rx_kill_vid,
+#endif
+};
+
 static int __devinit starfire_init_one(struct pci_dev *pdev,
                                       const struct pci_device_id *ent)
 {
@@ -704,11 +712,9 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
        if (enable_hw_cksum)
                dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
 #endif /* ZEROCOPY */
+
 #ifdef VLAN_SUPPORT
        dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
-       dev->vlan_rx_register = netdev_vlan_rx_register;
-       dev->vlan_rx_add_vid = netdev_vlan_rx_add_vid;
-       dev->vlan_rx_kill_vid = netdev_vlan_rx_kill_vid;
 #endif /* VLAN_RX_KILL_VID */
 #ifdef ADDR_64BITS
        dev->features |= NETIF_F_HIGHDMA;
@@ -804,18 +810,12 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
                }
        }
 
-       /* The chip-specific entries in the device structure. */
-       dev->open = &netdev_open;
-       dev->hard_start_xmit = &start_tx;
-       dev->tx_timeout = tx_timeout;
+       dev->netdev_ops = &netdev_ops;
        dev->watchdog_timeo = TX_TIMEOUT;
-       netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work);
-       dev->stop = &netdev_close;
-       dev->get_stats = &get_stats;
-       dev->set_multicast_list = &set_rx_mode;
-       dev->do_ioctl = &netdev_ioctl;
        SET_ETHTOOL_OPS(dev, &ethtool_ops);
 
+       netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work);
+
        if (mtu)
                dev->mtu = mtu;
 
@@ -880,9 +880,9 @@ static int mdio_read(struct net_device *dev, int phy_id, int location)
        void __iomem *mdio_addr = np->base + MIICtrl + (phy_id<<7) + (location<<2);
        int result, boguscnt=1000;
        /* ??? Should we add a busy-wait here? */
-       do
+       do {
                result = readl(mdio_addr);
-       while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0);
+       while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0);
        if (boguscnt == 0)
                return 0;
        if ((result & 0xffff) == 0xffff)
@@ -902,14 +902,17 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
 
 static int netdev_open(struct net_device *dev)
 {
+       const struct firmware *fw_rx, *fw_tx;
+       const __be32 *fw_rx_data, *fw_tx_data;
        struct netdev_private *np = netdev_priv(dev);
        void __iomem *ioaddr = np->base;
        int i, retval;
+       size_t tx_size, rx_size;
        size_t tx_done_q_size, rx_done_q_size, tx_ring_size, rx_ring_size;
 
        /* Do we ever need to reset the chip??? */
 
-       retval = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev);
+       retval = request_irq(dev->irq, intr_handler, IRQF_SHARED, dev->name, dev);
        if (retval)
                return retval;
 
@@ -1040,11 +1043,40 @@ static int netdev_open(struct net_device *dev)
        writel(ETH_P_8021Q, ioaddr + VlanType);
 #endif /* VLAN_SUPPORT */
 
+       retval = request_firmware(&fw_rx, FIRMWARE_RX, &np->pci_dev->dev);
+       if (retval) {
+               printk(KERN_ERR "starfire: Failed to load firmware \"%s\"\n",
+                      FIRMWARE_RX);
+               goto out_init;
+       }
+       if (fw_rx->size % 4) {
+               printk(KERN_ERR "starfire: bogus length %zu in \"%s\"\n",
+                      fw_rx->size, FIRMWARE_RX);
+               retval = -EINVAL;
+               goto out_rx;
+       }
+       retval = request_firmware(&fw_tx, FIRMWARE_TX, &np->pci_dev->dev);
+       if (retval) {
+               printk(KERN_ERR "starfire: Failed to load firmware \"%s\"\n",
+                      FIRMWARE_TX);
+               goto out_rx;
+       }
+       if (fw_tx->size % 4) {
+               printk(KERN_ERR "starfire: bogus length %zu in \"%s\"\n",
+                      fw_tx->size, FIRMWARE_TX);
+               retval = -EINVAL;
+               goto out_tx;
+       }
+       fw_rx_data = (const __be32 *)&fw_rx->data[0];
+       fw_tx_data = (const __be32 *)&fw_tx->data[0];
+       rx_size = fw_rx->size / 4;
+       tx_size = fw_tx->size / 4;
+
        /* Load Rx/Tx firmware into the frame processors */
-       for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++)
-               writel(firmware_rx[i], ioaddr + RxGfpMem + i * 4);
-       for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++)
-               writel(firmware_tx[i], ioaddr + TxGfpMem + i * 4);
+       for (i = 0; i < rx_size; i++)
+               writel(be32_to_cpup(&fw_rx_data[i]), ioaddr + RxGfpMem + i * 4);
+       for (i = 0; i < tx_size; i++)
+               writel(be32_to_cpup(&fw_tx_data[i]), ioaddr + TxGfpMem + i * 4);
        if (enable_hw_cksum)
                /* Enable the Rx and Tx units, and the Rx/Tx frame processors. */
                writel(TxEnable|TxGFPEnable|RxEnable|RxGFPEnable, ioaddr + GenCtrl);
@@ -1056,7 +1088,14 @@ static int netdev_open(struct net_device *dev)
                printk(KERN_DEBUG "%s: Done netdev_open().\n",
                       dev->name);
 
-       return 0;
+out_tx:
+       release_firmware(fw_tx);
+out_rx:
+       release_firmware(fw_rx);
+out_init:
+       if (retval)
+               netdev_close(dev);
+       return retval;
 }
 
 
@@ -1118,8 +1157,8 @@ static void tx_timeout(struct net_device *dev)
 
        /* Trigger an immediate transmit demand. */
 
-       dev->trans_start = jiffies;
-       np->stats.tx_errors++;
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       dev->stats.tx_errors++;
        netif_wake_queue(dev);
 }
 
@@ -1166,12 +1205,10 @@ static void init_ring(struct net_device *dev)
 
        for (i = 0; i < TX_RING_SIZE; i++)
                memset(&np->tx_info[i], 0, sizeof(np->tx_info[i]));
-
-       return;
 }
 
 
-static int start_tx(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
 {
        struct netdev_private *np = netdev_priv(dev);
        unsigned int entry;
@@ -1184,7 +1221,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
         */
        if ((np->cur_tx - np->dirty_tx) + skb_num_frags(skb) * 2 > TX_RING_SIZE) {
                netif_stop_queue(dev);
-               return 1;
+               return NETDEV_TX_BUSY;
        }
 
 #if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE)
@@ -1212,7 +1249,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
                        }
                        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                                status |= TxCalTCP;
-                               np->stats.tx_compressed++;
+                               dev->stats.tx_compressed++;
                        }
                        status |= skb_first_frag_len(skb) | (skb_num_frags(skb) << 16);
 
@@ -1257,9 +1294,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
        if ((np->cur_tx - np->dirty_tx) + 4 > TX_RING_SIZE)
                netif_stop_queue(dev);
 
-       dev->trans_start = jiffies;
-
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
@@ -1290,8 +1325,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
                if (intr_status & (IntrRxDone | IntrRxEmpty)) {
                        u32 enable;
 
-                       if (likely(netif_rx_schedule_prep(dev, &np->napi))) {
-                               __netif_rx_schedule(dev, &np->napi);
+                       if (likely(napi_schedule_prep(&np->napi))) {
+                               __napi_schedule(&np->napi);
                                enable = readl(ioaddr + IntrEnable);
                                enable &= ~(IntrRxDone | IntrRxEmpty);
                                writel(enable, ioaddr + IntrEnable);
@@ -1323,7 +1358,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
                                printk(KERN_DEBUG "%s: Tx completion #%d entry %d is %#8.8x.\n",
                                       dev->name, np->dirty_tx, np->tx_done, tx_status);
                        if ((tx_status & 0xe0000000) == 0xa0000000) {
-                               np->stats.tx_packets++;
+                               dev->stats.tx_packets++;
                        } else if ((tx_status & 0xe0000000) == 0x80000000) {
                                u16 entry = (tx_status & 0x7fff) / sizeof(starfire_tx_desc);
                                struct sk_buff *skb = np->tx_info[entry].skb;
@@ -1411,9 +1446,9 @@ static int __netdev_rx(struct net_device *dev, int *quota)
                        /* There was an error. */
                        if (debug > 2)
                                printk(KERN_DEBUG "  netdev_rx() Rx error was %#8.8x.\n", desc_status);
-                       np->stats.rx_errors++;
+                       dev->stats.rx_errors++;
                        if (desc_status & RxFIFOErr)
-                               np->stats.rx_fifo_errors++;
+                               dev->stats.rx_fifo_errors++;
                        goto next_rx;
                }
 
@@ -1430,8 +1465,8 @@ static int __netdev_rx(struct net_device *dev, int *quota)
                        printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d, quota %d.\n", pkt_len, *quota);
                /* Check if the packet is long enough to accept without copying
                   to a minimally-sized skbuff. */
-               if (pkt_len < rx_copybreak
-                   && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+               if (pkt_len < rx_copybreak &&
+                   (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
                        skb_reserve(skb, 2);    /* 16 byte align the IP header */
                        pci_dma_sync_single_for_cpu(np->pci_dev,
                                                    np->rx_info[entry].mapping,
@@ -1464,7 +1499,7 @@ static int __netdev_rx(struct net_device *dev, int *quota)
 #endif
                if (le16_to_cpu(desc->status2) & 0x0100) {
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       np->stats.rx_compressed++;
+                       dev->stats.rx_compressed++;
                }
                /*
                 * This feature doesn't seem to be working, at least
@@ -1481,28 +1516,29 @@ static int __netdev_rx(struct net_device *dev, int *quota)
                        printk(KERN_DEBUG "%s: checksum_hw, status2 = %#x\n", dev->name, le16_to_cpu(desc->status2));
                }
 #ifdef VLAN_SUPPORT
-               if (np->vlgrp && le16_to_cpu(desc->status2) & 0x0200) {
+               if (le16_to_cpu(desc->status2) & 0x0200) {
                        u16 vlid = le16_to_cpu(desc->vlanid);
 
                        if (debug > 4) {
                                printk(KERN_DEBUG "  netdev_rx() vlanid = %d\n",
                                       vlid);
                        }
-                       /*
-                        * vlan_hwaccel_rx expects a packet with the VLAN tag
-                        * stripped out.
-                        */
-                       vlan_hwaccel_rx(skb, np->vlgrp, vlid);
-               } else
+                       __vlan_hwaccel_put_tag(skb, vlid);
+               }
 #endif /* VLAN_SUPPORT */
-                       netif_receive_skb(skb);
-               np->stats.rx_packets++;
+               netif_receive_skb(skb);
+               dev->stats.rx_packets++;
 
        next_rx:
                np->cur_rx++;
                desc->status = 0;
                np->rx_done = (np->rx_done + 1) % DONE_Q_SIZE;
        }
+
+       if (*quota == 0) {      /* out of rx quota */
+               retcode = 1;
+               goto out;
+       }
        writew(np->rx_done, np->base + CompletionQConsumerIdx);
 
  out:
@@ -1530,7 +1566,7 @@ static int netdev_poll(struct napi_struct *napi, int budget)
                intr_status = readl(ioaddr + IntrStatus);
        } while (intr_status & (IntrRxDone | IntrRxEmpty));
 
-       netif_rx_complete(dev, napi);
+       napi_complete(napi);
        intr_status = readl(ioaddr + IntrEnable);
        intr_status |= IntrRxDone | IntrRxEmpty;
        writel(intr_status, ioaddr + IntrEnable);
@@ -1661,12 +1697,12 @@ static void netdev_error(struct net_device *dev, int intr_status)
                        printk(KERN_WARNING "%s: PCI Tx underflow -- adapter is probably malfunctioning\n", dev->name);
        }
        if (intr_status & IntrRxGFPDead) {
-               np->stats.rx_fifo_errors++;
-               np->stats.rx_errors++;
+               dev->stats.rx_fifo_errors++;
+               dev->stats.rx_errors++;
        }
        if (intr_status & (IntrNoTxCsum | IntrDMAErr)) {
-               np->stats.tx_fifo_errors++;
-               np->stats.tx_errors++;
+               dev->stats.tx_fifo_errors++;
+               dev->stats.tx_errors++;
        }
        if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrRxGFPDead | IntrNoTxCsum | IntrPCIPad)) && debug)
                printk(KERN_ERR "%s: Something Wicked happened! %#8.8x.\n",
@@ -1680,78 +1716,83 @@ static struct net_device_stats *get_stats(struct net_device *dev)
        void __iomem *ioaddr = np->base;
 
        /* This adapter architecture needs no SMP locks. */
-       np->stats.tx_bytes = readl(ioaddr + 0x57010);
-       np->stats.rx_bytes = readl(ioaddr + 0x57044);
-       np->stats.tx_packets = readl(ioaddr + 0x57000);
-       np->stats.tx_aborted_errors =
+       dev->stats.tx_bytes = readl(ioaddr + 0x57010);
+       dev->stats.rx_bytes = readl(ioaddr + 0x57044);
+       dev->stats.tx_packets = readl(ioaddr + 0x57000);
+       dev->stats.tx_aborted_errors =
                readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028);
-       np->stats.tx_window_errors = readl(ioaddr + 0x57018);
-       np->stats.collisions =
+       dev->stats.tx_window_errors = readl(ioaddr + 0x57018);
+       dev->stats.collisions =
                readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008);
 
        /* The chip only need report frame silently dropped. */
-       np->stats.rx_dropped += readw(ioaddr + RxDMAStatus);
+       dev->stats.rx_dropped += readw(ioaddr + RxDMAStatus);
        writew(0, ioaddr + RxDMAStatus);
-       np->stats.rx_crc_errors = readl(ioaddr + 0x5703C);
-       np->stats.rx_frame_errors = readl(ioaddr + 0x57040);
-       np->stats.rx_length_errors = readl(ioaddr + 0x57058);
-       np->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
+       dev->stats.rx_crc_errors = readl(ioaddr + 0x5703C);
+       dev->stats.rx_frame_errors = readl(ioaddr + 0x57040);
+       dev->stats.rx_length_errors = readl(ioaddr + 0x57058);
+       dev->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
 
-       return &np->stats;
+       return &dev->stats;
 }
 
+#ifdef VLAN_SUPPORT
+static u32 set_vlan_mode(struct netdev_private *np)
+{
+       u32 ret = VlanMode;
+       u16 vid;
+       void __iomem *filter_addr = np->base + HashTable + 8;
+       int vlan_count = 0;
+
+       for_each_set_bit(vid, np->active_vlans, VLAN_N_VID) {
+               if (vlan_count == 32)
+                       break;
+               writew(vid, filter_addr);
+               filter_addr += 16;
+               vlan_count++;
+       }
+       if (vlan_count == 32) {
+               ret |= PerfectFilterVlan;
+               while (vlan_count < 32) {
+                       writew(0, filter_addr);
+                       filter_addr += 16;
+                       vlan_count++;
+               }
+       }
+       return ret;
+}
+#endif /* VLAN_SUPPORT */
 
 static void set_rx_mode(struct net_device *dev)
 {
        struct netdev_private *np = netdev_priv(dev);
        void __iomem *ioaddr = np->base;
        u32 rx_mode = MinVLANPrio;
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        int i;
-#ifdef VLAN_SUPPORT
 
-       rx_mode |= VlanMode;
-       if (np->vlgrp) {
-               int vlan_count = 0;
-               void __iomem *filter_addr = ioaddr + HashTable + 8;
-               for (i = 0; i < VLAN_VID_MASK; i++) {
-                       if (vlan_group_get_device(np->vlgrp, i)) {
-                               if (vlan_count >= 32)
-                                       break;
-                               writew(i, filter_addr);
-                               filter_addr += 16;
-                               vlan_count++;
-                       }
-               }
-               if (i == VLAN_VID_MASK) {
-                       rx_mode |= PerfectFilterVlan;
-                       while (vlan_count < 32) {
-                               writew(0, filter_addr);
-                               filter_addr += 16;
-                               vlan_count++;
-                       }
-               }
-       }
+#ifdef VLAN_SUPPORT
+       rx_mode |= set_vlan_mode(np);
 #endif /* VLAN_SUPPORT */
 
        if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
                rx_mode |= AcceptAll;
-       } else if ((dev->mc_count > multicast_filter_limit)
-                  || (dev->flags & IFF_ALLMULTI)) {
+       } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
+                  (dev->flags & IFF_ALLMULTI)) {
                /* Too many to match, or accept all multicasts. */
                rx_mode |= AcceptBroadcast|AcceptAllMulticast|PerfectFilter;
-       } else if (dev->mc_count <= 14) {
+       } else if (netdev_mc_count(dev) <= 14) {
                /* Use the 16 element perfect filter, skip first two entries. */
                void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16;
                __be16 *eaddrs;
-               for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2;
-                    i++, mclist = mclist->next) {
-                       eaddrs = (__be16 *)mclist->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       eaddrs = (__be16 *) ha->addr;
                        writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4;
                        writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
                        writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 8;
                }
                eaddrs = (__be16 *)dev->dev_addr;
+               i = netdev_mc_count(dev) + 2;
                while (i++ < 16) {
                        writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4;
                        writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
@@ -1765,11 +1806,10 @@ static void set_rx_mode(struct net_device *dev)
                __le16 mc_filter[32] __attribute__ ((aligned(sizeof(long))));   /* Multicast hash filter */
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-                    i++, mclist = mclist->next) {
+               netdev_for_each_mc_addr(ha, dev) {
                        /* The chip uses the upper 9 CRC bits
                           as index into the hash table */
-                       int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
+                       int bit_nr = ether_crc_le(ETH_ALEN, ha->addr) >> 23;
                        __le32 *fptr = (__le32 *) &mc_filter[(bit_nr >> 4) & ~1];
 
                        *fptr |= cpu_to_le32(1 << (bit_nr & 31));
@@ -2024,11 +2064,7 @@ static int __init starfire_init (void)
        printk(KERN_INFO DRV_NAME ": polling (NAPI) enabled\n");
 #endif
 
-       /* we can do this test only at run-time... sigh */
-       if (sizeof(dma_addr_t) != sizeof(netdrv_addr_t)) {
-               printk("This driver has dma_addr_t issues, please send email to maintainer\n");
-               return -ENODEV;
-       }
+       BUILD_BUG_ON(sizeof(dma_addr_t) != sizeof(netdrv_addr_t));
 
        return pci_register_driver(&starfire_driver);
 }