memory_accessor: implement the new memory_accessor interface for I2C EEPROM
[safe/jmp/linux-2.6] / drivers / net / 3c515.c
index c4cf4fc..167bf23 100644 (file)
        Annapolis MD 21403
 
 
-       2000/2/2- Added support for kernel-level ISAPnP 
+       2000/2/2- Added support for kernel-level ISAPnP
                by Stephen Frost <sfrost@snowman.net> and Alessandro Zummo
        Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox.
-       
+
        2001/11/17 - Added ethtool support (jgarzik)
-       
-       2002/10/28 - Locking updates for 2.5 (alan@redhat.com)
+
+       2002/10/28 - Locking updates for 2.5 (alan@lxorguk.ukuu.org.uk)
 
 */
 
@@ -57,7 +57,6 @@ static int max_interrupt_work = 20;
 #define RX_RING_SIZE   16
 #define PKT_BUF_SZ             1536    /* Size of each temporary Rx buffer. */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/isapnp.h>
 #include <linux/kernel.h>
@@ -188,9 +187,9 @@ enum corkscrew_cmd {
        TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11,
        RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11,
        UpStall = 6 << 11, UpUnstall = (6 << 11) + 1, DownStall = (6 << 11) + 2,
-       DownUnstall = (6 << 11) + 3, RxDiscard = 8 << 11, TxEnable = 9 << 11, 
-       TxDisable = 10 << 11, TxReset = 11 << 11, FakeIntr = 12 << 11, 
-       AckIntr = 13 << 11, SetIntrEnb = 14 << 11, SetStatusEnb = 15 << 11, 
+       DownUnstall = (6 << 11) + 3, RxDiscard = 8 << 11, TxEnable = 9 << 11,
+       TxDisable = 10 << 11, TxReset = 11 << 11, FakeIntr = 12 << 11,
+       AckIntr = 13 << 11, SetIntrEnb = 14 << 11, SetStatusEnb = 15 << 11,
        SetRxFilter = 16 << 11, SetRxThreshold = 17 << 11,
        SetTxThreshold = 18 << 11, SetTxStart = 19 << 11, StartDMAUp = 20 << 11,
        StartDMADown = (20 << 11) + 1, StatsEnable = 21 << 11,
@@ -244,14 +243,16 @@ enum eeprom_offset {
 enum Window3 {                 /* Window 3: MAC/config bits. */
        Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8,
 };
-union wn3_config {
-       int i;
-       struct w3_config_fields {
-               unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
-               int pad8:8;
-               unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
-               int pad24:7;
-       } u;
+enum wn3_config {
+       Ram_size = 7,
+       Ram_width = 8,
+       Ram_speed = 0x30,
+       Rom_size = 0xc0,
+       Ram_split_shift = 16,
+       Ram_split = 3 << Ram_split_shift,
+       Xcvr_shift = 20,
+       Xcvr = 7 << Xcvr_shift,
+       Autoselect = 0x1000000,
 };
 
 enum Window4 {
@@ -309,7 +310,6 @@ struct corkscrew_private {
        struct sk_buff *tx_skbuff[TX_RING_SIZE];
        unsigned int cur_rx, cur_tx;    /* The next free ring entry */
        unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */
-       struct net_device_stats stats;
        struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl.  */
        struct timer_list timer;        /* Media selection timer. */
        int capabilities        ;       /* Adapter capabilities word. */
@@ -339,15 +339,15 @@ static struct media_table {
                mask:8,                 /* The transceiver-present bit in Wn3_Config. */
                next:8;                 /* The media type to try next. */
        short wait;                     /* Time before we check media status. */
-} media_tbl[] = {      
-       { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 }, 
-       { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10}, 
-       { "undefined", 0, 0x80, XCVR_10baseT, 10000}, 
-       { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10}, 
-       { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10}, 
-       { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10}, 
-       { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ}, 
-       { "undefined", 0, 0x01, XCVR_10baseT, 10000}, 
+} media_tbl[] = {
+       { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 },
+       { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10},
+       { "undefined", 0, 0x80, XCVR_10baseT, 10000},
+       { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10},
+       { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10},
+       { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10},
+       { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ},
+       { "undefined", 0, 0x01, XCVR_10baseT, 10000},
        { "Default", 0, 0xFF, XCVR_10baseT, 10000},
 };
 
@@ -365,7 +365,7 @@ static int nopnp;
 #endif /* __ISAPNP__ */
 
 static struct net_device *corkscrew_scan(int unit);
-static void corkscrew_setup(struct net_device *dev, int ioaddr,
+static int corkscrew_setup(struct net_device *dev, int ioaddr,
                            struct pnp_dev *idev, int card_number);
 static int corkscrew_open(struct net_device *dev);
 static void corkscrew_timer(unsigned long arg);
@@ -374,16 +374,15 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
 static int corkscrew_rx(struct net_device *dev);
 static void corkscrew_timeout(struct net_device *dev);
 static int boomerang_rx(struct net_device *dev);
-static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
-                                   struct pt_regs *regs);
+static irqreturn_t corkscrew_interrupt(int irq, void *dev_id);
 static int corkscrew_close(struct net_device *dev);
 static void update_stats(int addr, struct net_device *dev);
 static struct net_device_stats *corkscrew_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
-static struct ethtool_ops netdev_ethtool_ops;
-\f
+static const struct ethtool_ops netdev_ethtool_ops;
+
 
-/* 
+/*
    Unfortunately maximizing the shared code between the integrated and
    module version of the driver results in a complicated set of initialization
    procedures.
@@ -503,8 +502,6 @@ static struct net_device *corkscrew_scan(int unit)
                netdev_boot_setup_check(dev);
        }
 
-       SET_MODULE_OWNER(dev);
-
 #ifdef __ISAPNP__
        if(nopnp == 1)
                goto no_pnp;
@@ -539,10 +536,9 @@ static struct net_device *corkscrew_scan(int unit)
                        printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
                                inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
                        /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */
-                       corkscrew_setup(dev, ioaddr, idev, cards_found++);
                        SET_NETDEV_DEV(dev, &idev->dev);
                        pnp_cards++;
-                       err = register_netdev(dev);
+                       err = corkscrew_setup(dev, ioaddr, idev, cards_found++);
                        if (!err)
                                return dev;
                        cleanup_card(dev);
@@ -558,8 +554,7 @@ no_pnp:
 
                printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
                     inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
-               corkscrew_setup(dev, ioaddr, NULL, cards_found++);
-               err = register_netdev(dev);
+               err = corkscrew_setup(dev, ioaddr, NULL, cards_found++);
                if (!err)
                        return dev;
                cleanup_card(dev);
@@ -568,7 +563,21 @@ no_pnp:
        return NULL;
 }
 
-static void corkscrew_setup(struct net_device *dev, int ioaddr,
+
+static const struct net_device_ops netdev_ops = {
+       .ndo_open               = corkscrew_open,
+       .ndo_stop               = corkscrew_close,
+       .ndo_start_xmit         = corkscrew_start_xmit,
+       .ndo_tx_timeout         = corkscrew_timeout,
+       .ndo_get_stats          = corkscrew_get_stats,
+       .ndo_set_multicast_list = set_rx_mode,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+
+static int corkscrew_setup(struct net_device *dev, int ioaddr,
                            struct pnp_dev *idev, int card_number)
 {
        struct corkscrew_private *vp = netdev_priv(dev);
@@ -576,12 +585,16 @@ static void corkscrew_setup(struct net_device *dev, int ioaddr,
        int i;
        int irq;
 
+#ifdef __ISAPNP__
        if (idev) {
                irq = pnp_irq(idev, 0);
                vp->dev = &idev->dev;
        } else {
                irq = inw(ioaddr + 0x2002) & 15;
        }
+#else
+       irq = inw(ioaddr + 0x2002) & 15;
+#endif
 
        dev->base_addr = ioaddr;
        dev->irq = irq;
@@ -615,11 +628,11 @@ static void corkscrew_setup(struct net_device *dev, int ioaddr,
        printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr);
 
        spin_lock_init(&vp->lock);
-       
+
        /* Read the station address from the EEPROM. */
        EL3WINDOW(0);
        for (i = 0; i < 0x18; i++) {
-               short *phys_addr = (short *) dev->dev_addr;
+               __be16 *phys_addr = (__be16 *) dev->dev_addr;
                int timer;
                outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
                /* Pause for at least 162 us. for the read to take place. */
@@ -636,8 +649,7 @@ static void corkscrew_setup(struct net_device *dev, int ioaddr,
        checksum = (checksum ^ (checksum >> 8)) & 0xff;
        if (checksum != 0x00)
                printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-       for (i = 0; i < 6; i++)
-               printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
+       printk(" %pM", dev->dev_addr);
        if (eeprom[16] == 0x11c7) {     /* Corkscrew */
                if (request_dma(dev->dma, "3c515")) {
                        printk(", DMA %d allocation failed", dev->dma);
@@ -652,22 +664,22 @@ static void corkscrew_setup(struct net_device *dev, int ioaddr,
 
        {
                char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" };
-               union wn3_config config;
+               __u32 config;
                EL3WINDOW(3);
                vp->available_media = inw(ioaddr + Wn3_Options);
-               config.i = inl(ioaddr + Wn3_Config);
+               config = inl(ioaddr + Wn3_Config);
                if (corkscrew_debug > 1)
                        printk(KERN_INFO "  Internal config register is %4.4x, transceivers %#x.\n",
-                               config.i, inw(ioaddr + Wn3_Options));
+                               config, inw(ioaddr + Wn3_Options));
                printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
-                       8 << config.u.ram_size,
-                       config.u.ram_width ? "word" : "byte",
-                       ram_split[config.u.ram_split],
-                       config.u.autoselect ? "autoselect/" : "",
-                       media_tbl[config.u.xcvr].name);
-               dev->if_port = config.u.xcvr;
-               vp->default_media = config.u.xcvr;
-               vp->autoselect = config.u.autoselect;
+                       8 << config & Ram_size,
+                       config & Ram_width ? "word" : "byte",
+                       ram_split[(config & Ram_split) >> Ram_split_shift],
+                       config & Autoselect ? "autoselect/" : "",
+                       media_tbl[(config & Xcvr) >> Xcvr_shift].name);
+               vp->default_media = (config & Xcvr) >> Xcvr_shift;
+               vp->autoselect = config & Autoselect ? 1 : 0;
+               dev->if_port = vp->default_media;
        }
        if (vp->media_override != 7) {
                printk(KERN_INFO "  Media override to transceiver type %d (%s).\n",
@@ -683,29 +695,26 @@ static void corkscrew_setup(struct net_device *dev, int ioaddr,
        vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0;
 
        /* The 3c51x-specific entries in the device structure. */
-       dev->open = &corkscrew_open;
-       dev->hard_start_xmit = &corkscrew_start_xmit;
-       dev->tx_timeout = &corkscrew_timeout;
+       dev->netdev_ops = &netdev_ops;
        dev->watchdog_timeo = (400 * HZ) / 1000;
-       dev->stop = &corkscrew_close;
-       dev->get_stats = &corkscrew_get_stats;
-       dev->set_multicast_list = &set_rx_mode;
        dev->ethtool_ops = &netdev_ethtool_ops;
+
+       return register_netdev(dev);
 }
-\f
+
 
 static int corkscrew_open(struct net_device *dev)
 {
        int ioaddr = dev->base_addr;
        struct corkscrew_private *vp = netdev_priv(dev);
-       union wn3_config config;
+       __u32 config;
        int i;
 
        /* Before initializing select the active media port. */
        EL3WINDOW(3);
        if (vp->full_duplex)
                outb(0x20, ioaddr + Wn3_MAC_Ctrl);      /* Set the full-duplex bit. */
-       config.i = inl(ioaddr + Wn3_Config);
+       config = inl(ioaddr + Wn3_Config);
 
        if (vp->media_override != 7) {
                if (corkscrew_debug > 1)
@@ -716,7 +725,7 @@ static int corkscrew_open(struct net_device *dev)
        } else if (vp->autoselect) {
                /* Find first available media type, starting with 100baseTx. */
                dev->if_port = 4;
-               while (!(vp->available_media & media_tbl[dev->if_port].mask)) 
+               while (!(vp->available_media & media_tbl[dev->if_port].mask))
                        dev->if_port = media_tbl[dev->if_port].next;
 
                if (corkscrew_debug > 1)
@@ -731,12 +740,12 @@ static int corkscrew_open(struct net_device *dev)
        } else
                dev->if_port = vp->default_media;
 
-       config.u.xcvr = dev->if_port;
-       outl(config.i, ioaddr + Wn3_Config);
+       config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift);
+       outl(config, ioaddr + Wn3_Config);
 
        if (corkscrew_debug > 1) {
                printk("%s: corkscrew_open() InternalConfig %8.8x.\n",
-                      dev->name, config.i);
+                      dev->name, config);
        }
 
        outw(TxReset, ioaddr + EL3_CMD);
@@ -761,7 +770,7 @@ static int corkscrew_open(struct net_device *dev)
                                   vp->product_name, dev)) return -EAGAIN;
                enable_dma(dev->dma);
                set_dma_mode(dev->dma, DMA_MODE_CASCADE);
-       } else if (request_irq(dev->irq, &corkscrew_interrupt, SA_SHIRQ,
+       } else if (request_irq(dev->irq, &corkscrew_interrupt, IRQF_SHARED,
                               vp->product_name, dev)) {
                return -EAGAIN;
        }
@@ -822,7 +831,7 @@ static int corkscrew_open(struct net_device *dev)
                                break;  /* Bad news!  */
                        skb->dev = dev; /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
-                       vp->rx_ring[i].addr = isa_virt_to_bus(skb->tail);
+                       vp->rx_ring[i].addr = isa_virt_to_bus(skb->data);
                }
                vp->rx_ring[i - 1].next = isa_virt_to_bus(&vp->rx_ring[0]);     /* Wrap the ring. */
                outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
@@ -872,7 +881,7 @@ static void corkscrew_timer(unsigned long data)
                       dev->name, media_tbl[dev->if_port].name);
 
        spin_lock_irqsave(&vp->lock, flags);
-       
+
        {
                int old_window = inw(ioaddr + EL3_CMD) >> 13;
                int media_status;
@@ -905,14 +914,14 @@ static void corkscrew_timer(unsigned long data)
                        ok = 1;
                }
                if (!ok) {
-                       union wn3_config config;
+                       __u32 config;
 
                        do {
                                dev->if_port =
                                    media_tbl[dev->if_port].next;
                        }
                        while (!(vp->available_media & media_tbl[dev->if_port].mask));
-                       
+
                        if (dev->if_port == 8) {        /* Go back to default. */
                                dev->if_port = vp->default_media;
                                if (corkscrew_debug > 1)
@@ -932,16 +941,16 @@ static void corkscrew_timer(unsigned long data)
                             ioaddr + Wn4_Media);
 
                        EL3WINDOW(3);
-                       config.i = inl(ioaddr + Wn3_Config);
-                       config.u.xcvr = dev->if_port;
-                       outl(config.i, ioaddr + Wn3_Config);
+                       config = inl(ioaddr + Wn3_Config);
+                       config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift);
+                       outl(config, ioaddr + Wn3_Config);
 
                        outw(dev->if_port == 3 ? StartCoax : StopCoax,
                             ioaddr + EL3_CMD);
                }
                EL3WINDOW(old_window);
        }
-       
+
        spin_unlock_irqrestore(&vp->lock, flags);
        if (corkscrew_debug > 1)
                printk("%s: Media selection timer finished, %s.\n",
@@ -985,8 +994,8 @@ static void corkscrew_timeout(struct net_device *dev)
                        break;
        outw(TxEnable, ioaddr + EL3_CMD);
        dev->trans_start = jiffies;
-       vp->stats.tx_errors++;
-       vp->stats.tx_dropped++;
+       dev->stats.tx_errors++;
+       dev->stats.tx_dropped++;
        netif_wake_queue(dev);
 }
 
@@ -1004,7 +1013,8 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
                /* Calculate the next Tx descriptor entry. */
                int entry = vp->cur_tx % TX_RING_SIZE;
                struct boom_tx_desc *prev_entry;
-               unsigned long flags, i;
+               unsigned long flags;
+               int i;
 
                if (vp->tx_full)        /* No room to transmit with */
                        return 1;
@@ -1026,7 +1036,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
                outw(DownStall, ioaddr + EL3_CMD);
                /* Wait for the stall to complete. */
                for (i = 20; i >= 0; i--)
-                       if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) 
+                       if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
                                break;
                if (prev_entry)
                        prev_entry->next = isa_virt_to_bus(&vp->tx_ring[entry]);
@@ -1051,7 +1061,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
        }
        /* Put out the doubleword header... */
        outl(skb->len, ioaddr + TX_FIFO);
-       vp->stats.tx_bytes += skb->len;
+       dev->stats.tx_bytes += skb->len;
 #ifdef VORTEX_BUS_MASTER
        if (vp->bus_master) {
                /* Set the bus-master controller to transfer the packet. */
@@ -1095,14 +1105,14 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
                                        printk("%s: Tx error, status %2.2x.\n",
                                                dev->name, tx_status);
                                if (tx_status & 0x04)
-                                       vp->stats.tx_fifo_errors++;
+                                       dev->stats.tx_fifo_errors++;
                                if (tx_status & 0x38)
-                                       vp->stats.tx_aborted_errors++;
+                                       dev->stats.tx_aborted_errors++;
                                if (tx_status & 0x30) {
                                        int j;
                                        outw(TxReset, ioaddr + EL3_CMD);
                                        for (j = 20; j >= 0; j--)
-                                               if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) 
+                                               if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
                                                        break;
                                }
                                outw(TxEnable, ioaddr + EL3_CMD);
@@ -1116,8 +1126,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 
-static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
-                                   struct pt_regs *regs)
+static irqreturn_t corkscrew_interrupt(int irq, void *dev_id)
 {
        /* Use the now-standard shared IRQ implementation. */
        struct net_device *dev = dev_id;
@@ -1130,7 +1139,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
        latency = inb(ioaddr + Timer);
 
        spin_lock(&lp->lock);
-       
+
        status = inw(ioaddr + EL3_STATUS);
 
        if (corkscrew_debug > 4)
@@ -1249,7 +1258,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
                outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
 
        } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
-       
+
        spin_unlock(&lp->lock);
 
        if (corkscrew_debug > 4)
@@ -1259,7 +1268,6 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
 
 static int corkscrew_rx(struct net_device *dev)
 {
-       struct corkscrew_private *vp = netdev_priv(dev);
        int ioaddr = dev->base_addr;
        int i;
        short rx_status;
@@ -1273,17 +1281,17 @@ static int corkscrew_rx(struct net_device *dev)
                        if (corkscrew_debug > 2)
                                printk(" Rx error: status %2.2x.\n",
                                       rx_error);
-                       vp->stats.rx_errors++;
+                       dev->stats.rx_errors++;
                        if (rx_error & 0x01)
-                               vp->stats.rx_over_errors++;
+                               dev->stats.rx_over_errors++;
                        if (rx_error & 0x02)
-                               vp->stats.rx_length_errors++;
+                               dev->stats.rx_length_errors++;
                        if (rx_error & 0x04)
-                               vp->stats.rx_frame_errors++;
+                               dev->stats.rx_frame_errors++;
                        if (rx_error & 0x08)
-                               vp->stats.rx_crc_errors++;
+                               dev->stats.rx_crc_errors++;
                        if (rx_error & 0x10)
-                               vp->stats.rx_length_errors++;
+                               dev->stats.rx_length_errors++;
                } else {
                        /* The packet length: up to 4.5K!. */
                        short pkt_len = rx_status & 0x1fff;
@@ -1294,7 +1302,6 @@ static int corkscrew_rx(struct net_device *dev)
                                printk("Receiving packet size %d status %4.4x.\n",
                                     pkt_len, rx_status);
                        if (skb != NULL) {
-                               skb->dev = dev;
                                skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
                                /* 'skb_put()' points to the start of sk_buff data area. */
                                insl(ioaddr + RX_FIFO,
@@ -1303,19 +1310,18 @@ static int corkscrew_rx(struct net_device *dev)
                                outw(RxDiscard, ioaddr + EL3_CMD);      /* Pop top Rx packet. */
                                skb->protocol = eth_type_trans(skb, dev);
                                netif_rx(skb);
-                               dev->last_rx = jiffies;
-                               vp->stats.rx_packets++;
-                               vp->stats.rx_bytes += pkt_len;
+                               dev->stats.rx_packets++;
+                               dev->stats.rx_bytes += pkt_len;
                                /* Wait a limited time to go to next packet. */
                                for (i = 200; i >= 0; i--)
-                                       if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) 
+                                       if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
                                                break;
                                continue;
                        } else if (corkscrew_debug)
                                printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
                }
                outw(RxDiscard, ioaddr + EL3_CMD);
-               vp->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
                /* Wait a limited time to skip this packet. */
                for (i = 200; i >= 0; i--)
                        if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
@@ -1340,23 +1346,23 @@ static int boomerang_rx(struct net_device *dev)
                        if (corkscrew_debug > 2)
                                printk(" Rx error: status %2.2x.\n",
                                       rx_error);
-                       vp->stats.rx_errors++;
+                       dev->stats.rx_errors++;
                        if (rx_error & 0x01)
-                               vp->stats.rx_over_errors++;
+                               dev->stats.rx_over_errors++;
                        if (rx_error & 0x02)
-                               vp->stats.rx_length_errors++;
+                               dev->stats.rx_length_errors++;
                        if (rx_error & 0x04)
-                               vp->stats.rx_frame_errors++;
+                               dev->stats.rx_frame_errors++;
                        if (rx_error & 0x08)
-                               vp->stats.rx_crc_errors++;
+                               dev->stats.rx_crc_errors++;
                        if (rx_error & 0x10)
-                               vp->stats.rx_length_errors++;
+                               dev->stats.rx_length_errors++;
                } else {
                        /* The packet length: up to 4.5K!. */
                        short pkt_len = rx_status & 0x1fff;
                        struct sk_buff *skb;
 
-                       vp->stats.rx_bytes += pkt_len;
+                       dev->stats.rx_bytes += pkt_len;
                        if (corkscrew_debug > 4)
                                printk("Receiving packet size %d status %4.4x.\n",
                                     pkt_len, rx_status);
@@ -1364,8 +1370,7 @@ static int boomerang_rx(struct net_device *dev)
                        /* Check if the packet is long enough to just accept without
                           copying to a properly sized skbuff. */
                        if (pkt_len < rx_copybreak
-                           && (skb = dev_alloc_skb(pkt_len + 4)) != 0) {
-                               skb->dev = dev;
+                           && (skb = dev_alloc_skb(pkt_len + 4)) != NULL) {
                                skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
                                /* 'skb_put()' points to the start of sk_buff data area. */
                                memcpy(skb_put(skb, pkt_len),
@@ -1391,8 +1396,7 @@ static int boomerang_rx(struct net_device *dev)
                        }
                        skb->protocol = eth_type_trans(skb, dev);
                        netif_rx(skb);
-                       dev->last_rx = jiffies;
-                       vp->stats.rx_packets++;
+                       dev->stats.rx_packets++;
                }
                entry = (++vp->cur_rx) % RX_RING_SIZE;
        }
@@ -1406,7 +1410,7 @@ static int boomerang_rx(struct net_device *dev)
                                break;  /* Bad news!  */
                        skb->dev = dev; /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
-                       vp->rx_ring[entry].addr = isa_virt_to_bus(skb->tail);
+                       vp->rx_ring[entry].addr = isa_virt_to_bus(skb->data);
                        vp->rx_skbuff[entry] = skb;
                }
                vp->rx_ring[entry].status = 0;  /* Clear complete bit. */
@@ -1479,7 +1483,7 @@ static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
                update_stats(dev->base_addr, dev);
                spin_unlock_irqrestore(&vp->lock, flags);
        }
-       return &vp->stats;
+       return &dev->stats;
 }
 
 /*  Update statistics.
@@ -1491,19 +1495,17 @@ static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
        */
 static void update_stats(int ioaddr, struct net_device *dev)
 {
-       struct corkscrew_private *vp = netdev_priv(dev);
-
        /* Unlike the 3c5x9 we need not turn off stats updates while reading. */
        /* Switch to the stats window, and read everything. */
        EL3WINDOW(6);
-       vp->stats.tx_carrier_errors += inb(ioaddr + 0);
-       vp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
+       dev->stats.tx_carrier_errors += inb(ioaddr + 0);
+       dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
        /* Multiple collisions. */ inb(ioaddr + 2);
-       vp->stats.collisions += inb(ioaddr + 3);
-       vp->stats.tx_window_errors += inb(ioaddr + 4);
-       vp->stats.rx_fifo_errors += inb(ioaddr + 5);
-       vp->stats.tx_packets += inb(ioaddr + 6);
-       vp->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
+       dev->stats.collisions += inb(ioaddr + 3);
+       dev->stats.tx_window_errors += inb(ioaddr + 4);
+       dev->stats.rx_fifo_errors += inb(ioaddr + 5);
+       dev->stats.tx_packets += inb(ioaddr + 6);
+       dev->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
                                                /* Rx packets   */ inb(ioaddr + 7);
                                                /* Must read to clear */
        /* Tx deferrals */ inb(ioaddr + 8);
@@ -1561,13 +1563,13 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
        corkscrew_debug = level;
 }
 
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
        .get_drvinfo            = netdev_get_drvinfo,
        .get_msglevel           = netdev_get_msglevel,
        .set_msglevel           = netdev_set_msglevel,
 };
 
-\f
+
 #ifdef MODULE
 void cleanup_module(void)
 {
@@ -1584,11 +1586,3 @@ void cleanup_module(void)
        }
 }
 #endif                         /* MODULE */
-\f
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c515.c"
- *  c-indent-level: 4
- *  tab-width: 4
- * End:
- */