net: wireless: bcmdhd: Enable wlan access on resume for all sdio functions
[linux-2.6.git] / drivers / net / enc28j60.c
index 0f1581c..2837ce2 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -110,7 +109,7 @@ spi_read_buf(struct enc28j60_net *priv, int len, u8 *data)
        }
        if (ret && netif_msg_drv(priv))
                printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
-                       __FUNCTION__, ret);
+                       __func__, ret);
 
        return ret;
 }
@@ -131,7 +130,7 @@ static int spi_write_buf(struct enc28j60_net *priv, int len,
                ret = spi_write(priv->spi, priv->spi_transfer_buf, len + 1);
                if (ret && netif_msg_drv(priv))
                        printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
-                               __FUNCTION__, ret);
+                               __func__, ret);
        }
        return ret;
 }
@@ -156,7 +155,7 @@ static u8 spi_read_op(struct enc28j60_net *priv, u8 op,
        ret = spi_write_then_read(priv->spi, tx_buf, 1, rx_buf, slen);
        if (ret)
                printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
-                       __FUNCTION__, ret);
+                       __func__, ret);
        else
                val = rx_buf[slen - 1];
 
@@ -176,14 +175,14 @@ static int spi_write_op(struct enc28j60_net *priv, u8 op,
        ret = spi_write(priv->spi, priv->spi_transfer_buf, 2);
        if (ret && netif_msg_drv(priv))
                printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
-                       __FUNCTION__, ret);
+                       __func__, ret);
        return ret;
 }
 
 static void enc28j60_soft_reset(struct enc28j60_net *priv)
 {
        if (netif_msg_hw(priv))
-               printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+               printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
 
        spi_write_op(priv, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
        /* Errata workaround #1, CLKRDY check is unreliable,
@@ -196,16 +195,32 @@ static void enc28j60_soft_reset(struct enc28j60_net *priv)
  */
 static void enc28j60_set_bank(struct enc28j60_net *priv, u8 addr)
 {
-       if ((addr & BANK_MASK) != priv->bank) {
-               u8 b = (addr & BANK_MASK) >> 5;
+       u8 b = (addr & BANK_MASK) >> 5;
 
-               if (b != (ECON1_BSEL1 | ECON1_BSEL0))
+       /* These registers (EIE, EIR, ESTAT, ECON2, ECON1)
+        * are present in all banks, no need to switch bank
+        */
+       if (addr >= EIE && addr <= ECON1)
+               return;
+
+       /* Clear or set each bank selection bit as needed */
+       if ((b & ECON1_BSEL0) != (priv->bank & ECON1_BSEL0)) {
+               if (b & ECON1_BSEL0)
+                       spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1,
+                                       ECON1_BSEL0);
+               else
+                       spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1,
+                                       ECON1_BSEL0);
+       }
+       if ((b & ECON1_BSEL1) != (priv->bank & ECON1_BSEL1)) {
+               if (b & ECON1_BSEL1)
+                       spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1,
+                                       ECON1_BSEL1);
+               else
                        spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1,
-                                    ECON1_BSEL1 | ECON1_BSEL0);
-               if (b != 0)
-                       spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, b);
-               priv->bank = (addr & BANK_MASK);
+                                       ECON1_BSEL1);
        }
+       priv->bank = b;
 }
 
 /*
@@ -357,7 +372,7 @@ static void enc28j60_mem_read(struct enc28j60_net *priv,
                reg = nolock_regw_read(priv, ERDPTL);
                if (reg != addr)
                        printk(KERN_DEBUG DRV_NAME ": %s() error writing ERDPT "
-                               "(0x%04x - 0x%04x)\n", __FUNCTION__, reg, addr);
+                               "(0x%04x - 0x%04x)\n", __func__, reg, addr);
        }
 #endif
        spi_read_buf(priv, len, data);
@@ -380,7 +395,7 @@ enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data)
                if (reg != TXSTART_INIT)
                        printk(KERN_DEBUG DRV_NAME
                                ": %s() ERWPT:0x%04x != 0x%04x\n",
-                               __FUNCTION__, reg, TXSTART_INIT);
+                               __func__, reg, TXSTART_INIT);
        }
 #endif
        /* Set the TXND pointer to correspond to the packet size given */
@@ -390,36 +405,41 @@ enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data)
        if (netif_msg_hw(priv))
                printk(KERN_DEBUG DRV_NAME
                        ": %s() after control byte ERWPT:0x%04x\n",
-                       __FUNCTION__, nolock_regw_read(priv, EWRPTL));
+                       __func__, nolock_regw_read(priv, EWRPTL));
        /* copy the packet into the transmit buffer */
        spi_write_buf(priv, len, data);
        if (netif_msg_hw(priv))
                printk(KERN_DEBUG DRV_NAME
                         ": %s() after write packet ERWPT:0x%04x, len=%d\n",
-                        __FUNCTION__, nolock_regw_read(priv, EWRPTL), len);
+                        __func__, nolock_regw_read(priv, EWRPTL), len);
        mutex_unlock(&priv->lock);
 }
 
-/*
- * Wait until the PHY operation is complete.
- */
-static int wait_phy_ready(struct enc28j60_net *priv)
+static unsigned long msec20_to_jiffies;
+
+static int poll_ready(struct enc28j60_net *priv, u8 reg, u8 mask, u8 val)
 {
-       unsigned long timeout = jiffies + 20 * HZ / 1000;
-       int ret = 1;
+       unsigned long timeout = jiffies + msec20_to_jiffies;
 
        /* 20 msec timeout read */
-       while (nolock_regb_read(priv, MISTAT) & MISTAT_BUSY) {
+       while ((nolock_regb_read(priv, reg) & mask) != val) {
                if (time_after(jiffies, timeout)) {
                        if (netif_msg_drv(priv))
-                               printk(KERN_DEBUG DRV_NAME
-                                       ": PHY ready timeout!\n");
-                       ret = 0;
-                       break;
+                               dev_dbg(&priv->spi->dev,
+                                       "reg %02x ready timeout!\n", reg);
+                       return -ETIMEDOUT;
                }
                cpu_relax();
        }
-       return ret;
+       return 0;
+}
+
+/*
+ * Wait until the PHY operation is complete.
+ */
+static int wait_phy_ready(struct enc28j60_net *priv)
+{
+       return poll_ready(priv, MISTAT, MISTAT_BUSY, 0) ? 0 : 1;
 }
 
 /*
@@ -472,12 +492,10 @@ static int enc28j60_set_hw_macaddr(struct net_device *ndev)
 
        mutex_lock(&priv->lock);
        if (!priv->hw_enable) {
-               if (netif_msg_drv(priv)) {
-                       DECLARE_MAC_BUF(mac);
+               if (netif_msg_drv(priv))
                        printk(KERN_INFO DRV_NAME
-                               ": %s: Setting MAC address to %s\n",
-                               ndev->name, print_mac(mac, ndev->dev_addr));
-               }
+                               ": %s: Setting MAC address to %pM\n",
+                               ndev->name, ndev->dev_addr);
                /* NOTE: MAC address in ENC28J60 is byte-backward */
                nolock_regb_write(priv, MAADR5, ndev->dev_addr[0]);
                nolock_regb_write(priv, MAADR4, ndev->dev_addr[1]);
@@ -490,7 +508,7 @@ static int enc28j60_set_hw_macaddr(struct net_device *ndev)
                if (netif_msg_drv(priv))
                        printk(KERN_DEBUG DRV_NAME
                                ": %s() Hardware must be disabled to set "
-                               "Mac address\n", __FUNCTION__);
+                               "Mac address\n", __func__);
                ret = -EBUSY;
        }
        mutex_unlock(&priv->lock);
@@ -563,6 +581,17 @@ static u16 erxrdpt_workaround(u16 next_packet_ptr, u16 start, u16 end)
        return erxrdpt;
 }
 
+/*
+ * Calculate wrap around when reading beyond the end of the RX buffer
+ */
+static u16 rx_packet_start(u16 ptr)
+{
+       if (ptr + RSV_SIZE > RXEND_INIT)
+               return (ptr + RSV_SIZE) - (RXEND_INIT - RXSTART_INIT + 1);
+       else
+               return ptr + RSV_SIZE;
+}
+
 static void nolock_rxfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
 {
        u16 erxrdpt;
@@ -570,7 +599,7 @@ static void nolock_rxfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
        if (start > 0x1FFF || end > 0x1FFF || start > end) {
                if (netif_msg_drv(priv))
                        printk(KERN_ERR DRV_NAME ": %s(%d, %d) RXFIFO "
-                               "bad parameters!\n", __FUNCTION__, start, end);
+                               "bad parameters!\n", __func__, start, end);
                return;
        }
        /* set receive buffer start + end */
@@ -586,7 +615,7 @@ static void nolock_txfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
        if (start > 0x1FFF || end > 0x1FFF || start > end) {
                if (netif_msg_drv(priv))
                        printk(KERN_ERR DRV_NAME ": %s(%d, %d) TXFIFO "
-                               "bad parameters!\n", __FUNCTION__, start, end);
+                               "bad parameters!\n", __func__, start, end);
                return;
        }
        /* set transmit buffer start + end */
@@ -594,12 +623,38 @@ static void nolock_txfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
        nolock_regw_write(priv, ETXNDL, end);
 }
 
+/*
+ * Low power mode shrinks power consumption about 100x, so we'd like
+ * the chip to be in that mode whenever it's inactive.  (However, we
+ * can't stay in lowpower mode during suspend with WOL active.)
+ */
+static void enc28j60_lowpower(struct enc28j60_net *priv, bool is_low)
+{
+       if (netif_msg_drv(priv))
+               dev_dbg(&priv->spi->dev, "%s power...\n",
+                               is_low ? "low" : "high");
+
+       mutex_lock(&priv->lock);
+       if (is_low) {
+               nolock_reg_bfclr(priv, ECON1, ECON1_RXEN);
+               poll_ready(priv, ESTAT, ESTAT_RXBUSY, 0);
+               poll_ready(priv, ECON1, ECON1_TXRTS, 0);
+               /* ECON2_VRPS was set during initialization */
+               nolock_reg_bfset(priv, ECON2, ECON2_PWRSV);
+       } else {
+               nolock_reg_bfclr(priv, ECON2, ECON2_PWRSV);
+               poll_ready(priv, ESTAT, ESTAT_CLKRDY, ESTAT_CLKRDY);
+               /* caller sets ECON1_RXEN */
+       }
+       mutex_unlock(&priv->lock);
+}
+
 static int enc28j60_hw_init(struct enc28j60_net *priv)
 {
        u8 reg;
 
        if (netif_msg_drv(priv))
-               printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __FUNCTION__,
+               printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __func__,
                        priv->full_duplex ? "FullDuplex" : "HalfDuplex");
 
        mutex_lock(&priv->lock);
@@ -612,8 +667,8 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
        priv->tx_retry_count = 0;
        priv->max_pk_counter = 0;
        priv->rxfilter = RXFILTER_NORMAL;
-       /* enable address auto increment */
-       nolock_regb_write(priv, ECON2, ECON2_AUTOINC);
+       /* enable address auto increment and voltage regulator powersave */
+       nolock_regb_write(priv, ECON2, ECON2_AUTOINC | ECON2_VRPS);
 
        nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT);
        nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT);
@@ -630,7 +685,7 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
        if (reg == 0x00 || reg == 0xff) {
                if (netif_msg_drv(priv))
                        printk(KERN_DEBUG DRV_NAME ": %s() Invalid RevId %d\n",
-                               __FUNCTION__, reg);
+                               __func__, reg);
                return 0;
        }
 
@@ -690,10 +745,10 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
 
 static void enc28j60_hw_enable(struct enc28j60_net *priv)
 {
-       /* enable interrutps */
+       /* enable interrupts */
        if (netif_msg_hw(priv))
                printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n",
-                       __FUNCTION__);
+                       __func__);
 
        enc28j60_phy_write(priv, PHIE, PHIE_PGEIE | PHIE_PLNKIE);
 
@@ -726,15 +781,12 @@ enc28j60_setlink(struct net_device *ndev, u8 autoneg, u16 speed, u8 duplex)
        int ret = 0;
 
        if (!priv->hw_enable) {
-               if (autoneg == AUTONEG_DISABLE && speed == SPEED_10) {
+               /* link is in low power mode now; duplex setting
+                * will take effect on next enc28j60_hw_init().
+                */
+               if (autoneg == AUTONEG_DISABLE && speed == SPEED_10)
                        priv->full_duplex = (duplex == DUPLEX_FULL);
-                       if (!enc28j60_hw_init(priv)) {
-                               if (netif_msg_drv(priv))
-                                       dev_err(&ndev->dev,
-                                               "hw_reset() failed\n");
-                               ret = -EINVAL;
-                       }
-               } else {
+               else {
                        if (netif_msg_link(priv))
                                dev_warn(&ndev->dev,
                                        "unsupported link setting\n");
@@ -760,7 +812,7 @@ static void enc28j60_read_tsv(struct enc28j60_net *priv, u8 tsv[TSV_SIZE])
        if (netif_msg_hw(priv))
                printk(KERN_DEBUG DRV_NAME ": reading TSV at addr:0x%04x\n",
                         endptr + 1);
-       enc28j60_mem_read(priv, endptr + 1, sizeof(tsv), tsv);
+       enc28j60_mem_read(priv, endptr + 1, TSV_SIZE, tsv);
 }
 
 static void enc28j60_dump_tsv(struct enc28j60_net *priv, const char *msg,
@@ -860,7 +912,7 @@ static void enc28j60_hw_rx(struct net_device *ndev)
                if (netif_msg_rx_err(priv))
                        dev_err(&ndev->dev,
                                "%s() Invalid packet address!! 0x%04x\n",
-                               __FUNCTION__, priv->next_pk_ptr);
+                               __func__, priv->next_pk_ptr);
                /* packet address corrupted: reset RX logic */
                mutex_lock(&priv->lock);
                nolock_reg_bfclr(priv, ECON1, ECON1_RXEN);
@@ -889,9 +941,9 @@ static void enc28j60_hw_rx(struct net_device *ndev)
        rxstat |= rsv[4];
 
        if (netif_msg_rx_status(priv))
-               enc28j60_dump_rsv(priv, __FUNCTION__, next_packet, len, rxstat);
+               enc28j60_dump_rsv(priv, __func__, next_packet, len, rxstat);
 
-       if (!RSV_GETBIT(rxstat, RSV_RXOK)) {
+       if (!RSV_GETBIT(rxstat, RSV_RXOK) || len > MAX_FRAMELEN) {
                if (netif_msg_rx_err(priv))
                        dev_err(&ndev->dev, "Rx Error (%04x)\n", rxstat);
                ndev->stats.rx_errors++;
@@ -899,6 +951,8 @@ static void enc28j60_hw_rx(struct net_device *ndev)
                        ndev->stats.rx_crc_errors++;
                if (RSV_GETBIT(rxstat, RSV_LENCHECKERR))
                        ndev->stats.rx_frame_errors++;
+               if (len > MAX_FRAMELEN)
+                       ndev->stats.rx_over_errors++;
        } else {
                skb = dev_alloc_skb(len + NET_IP_ALIGN);
                if (!skb) {
@@ -910,16 +964,16 @@ static void enc28j60_hw_rx(struct net_device *ndev)
                        skb->dev = ndev;
                        skb_reserve(skb, NET_IP_ALIGN);
                        /* copy the packet from the receive buffer */
-                       enc28j60_mem_read(priv, priv->next_pk_ptr + sizeof(rsv),
-                                       len, skb_put(skb, len));
+                       enc28j60_mem_read(priv,
+                               rx_packet_start(priv->next_pk_ptr),
+                               len, skb_put(skb, len));
                        if (netif_msg_pktdata(priv))
-                               dump_packet(__FUNCTION__, skb->len, skb->data);
+                               dump_packet(__func__, skb->len, skb->data);
                        skb->protocol = eth_type_trans(skb, ndev);
                        /* update statistics */
                        ndev->stats.rx_packets++;
                        ndev->stats.rx_bytes += len;
-                       ndev->last_rx = jiffies;
-                       netif_rx(skb);
+                       netif_rx_ni(skb);
                }
        }
        /*
@@ -930,7 +984,7 @@ static void enc28j60_hw_rx(struct net_device *ndev)
        erxrdpt = erxrdpt_workaround(next_packet, RXSTART_INIT, RXEND_INIT);
        if (netif_msg_hw(priv))
                printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT:0x%04x\n",
-                       __FUNCTION__, erxrdpt);
+                       __func__, erxrdpt);
 
        mutex_lock(&priv->lock);
        nolock_regw_write(priv, ERXRDPTL, erxrdpt);
@@ -940,7 +994,7 @@ static void enc28j60_hw_rx(struct net_device *ndev)
                reg = nolock_regw_read(priv, ERXRDPTL);
                if (reg != erxrdpt)
                        printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT verify "
-                               "error (0x%04x - 0x%04x)\n", __FUNCTION__,
+                               "error (0x%04x - 0x%04x)\n", __func__,
                                reg, erxrdpt);
        }
 #endif
@@ -978,7 +1032,7 @@ static int enc28j60_get_free_rxfifo(struct enc28j60_net *priv)
        mutex_unlock(&priv->lock);
        if (netif_msg_rx_status(priv))
                printk(KERN_DEBUG DRV_NAME ": %s() free_space = %d\n",
-                       __FUNCTION__, free_space);
+                       __func__, free_space);
        return free_space;
 }
 
@@ -994,7 +1048,7 @@ static void enc28j60_check_link_status(struct net_device *ndev)
        reg = enc28j60_phy_read(priv, PHSTAT2);
        if (netif_msg_hw(priv))
                printk(KERN_DEBUG DRV_NAME ": %s() PHSTAT1: %04x, "
-                       "PHSTAT2: %04x\n", __FUNCTION__,
+                       "PHSTAT2: %04x\n", __func__,
                        enc28j60_phy_read(priv, PHSTAT1), reg);
        duplex = reg & PHSTAT2_DPXSTAT;
 
@@ -1067,7 +1121,7 @@ static void enc28j60_irq_work_handler(struct work_struct *work)
        int intflags, loop;
 
        if (netif_msg_intr(priv))
-               printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+               printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
        /* disable further interrupts */
        locked_reg_bfclr(priv, EIE, EIE_INTIE);
 
@@ -1170,7 +1224,7 @@ static void enc28j60_irq_work_handler(struct work_struct *work)
        /* re-enable interrupts */
        locked_reg_bfset(priv, EIE, EIE_INTIE);
        if (netif_msg_intr(priv))
-               printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __FUNCTION__);
+               printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __func__);
 }
 
 /*
@@ -1185,7 +1239,7 @@ static void enc28j60_hw_tx(struct enc28j60_net *priv)
                        ": Tx Packet Len:%d\n", priv->tx_skb->len);
 
        if (netif_msg_pktdata(priv))
-               dump_packet(__FUNCTION__,
+               dump_packet(__func__,
                            priv->tx_skb->len, priv->tx_skb->data);
        enc28j60_packet_write(priv, priv->tx_skb->len, priv->tx_skb->data);
 
@@ -1221,12 +1275,13 @@ static void enc28j60_hw_tx(struct enc28j60_net *priv)
        locked_reg_bfset(priv, ECON1, ECON1_TXRTS);
 }
 
-static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t enc28j60_send_packet(struct sk_buff *skb,
+                                       struct net_device *dev)
 {
        struct enc28j60_net *priv = netdev_priv(dev);
 
        if (netif_msg_tx_queued(priv))
-               printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+               printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
 
        /* If some error occurs while trying to transmit this
         * packet, you should return '1' from this function.
@@ -1238,13 +1293,11 @@ static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev)
         */
        netif_stop_queue(dev);
 
-       /* save the timestamp */
-       priv->netdev->trans_start = jiffies;
        /* Remember the skb for deferred processing */
        priv->tx_skb = skb;
        schedule_work(&priv->tx_work);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void enc28j60_tx_work_handler(struct work_struct *work)
@@ -1297,17 +1350,16 @@ static int enc28j60_net_open(struct net_device *dev)
        struct enc28j60_net *priv = netdev_priv(dev);
 
        if (netif_msg_drv(priv))
-               printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+               printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
 
        if (!is_valid_ether_addr(dev->dev_addr)) {
-               if (netif_msg_ifup(priv)) {
-                       DECLARE_MAC_BUF(mac);
-                       dev_err(&dev->dev, "invalid MAC address %s\n",
-                               print_mac(mac, dev->dev_addr));
-               }
+               if (netif_msg_ifup(priv))
+                       dev_err(&dev->dev, "invalid MAC address %pM\n",
+                               dev->dev_addr);
                return -EADDRNOTAVAIL;
        }
-       /* Reset the hardware here */
+       /* Reset the hardware here (and take it out of low power mode) */
+       enc28j60_lowpower(priv, false);
        enc28j60_hw_disable(priv);
        if (!enc28j60_hw_init(priv)) {
                if (netif_msg_ifup(priv))
@@ -1334,9 +1386,10 @@ static int enc28j60_net_close(struct net_device *dev)
        struct enc28j60_net *priv = netdev_priv(dev);
 
        if (netif_msg_drv(priv))
-               printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+               printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
 
        enc28j60_hw_disable(priv);
+       enc28j60_lowpower(priv, true);
        netif_stop_queue(dev);
 
        return 0;
@@ -1357,7 +1410,7 @@ static void enc28j60_set_multicast_list(struct net_device *dev)
                if (netif_msg_link(priv))
                        dev_info(&dev->dev, "promiscuous mode\n");
                priv->rxfilter = RXFILTER_PROMISC;
-       } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count) {
+       } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
                if (netif_msg_link(priv))
                        dev_info(&dev->dev, "%smulticast mode\n",
                                (dev->flags & IFF_ALLMULTI) ? "all-" : "");
@@ -1423,7 +1476,7 @@ enc28j60_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
        strlcpy(info->version, DRV_VERSION, sizeof(info->version));
        strlcpy(info->bus_info,
-               dev->dev.parent->bus_id, sizeof(info->bus_info));
+               dev_name(dev->dev.parent), sizeof(info->bus_info));
 }
 
 static int
@@ -1435,7 +1488,7 @@ enc28j60_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        cmd->supported  = SUPPORTED_10baseT_Half
                        | SUPPORTED_10baseT_Full
                        | SUPPORTED_TP;
-       cmd->speed      = SPEED_10;
+       ethtool_cmd_speed_set(cmd,  SPEED_10);
        cmd->duplex     = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
        cmd->port       = PORT_TP;
        cmd->autoneg    = AUTONEG_DISABLE;
@@ -1446,7 +1499,8 @@ enc28j60_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static int
 enc28j60_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       return enc28j60_setlink(dev, cmd->autoneg, cmd->speed, cmd->duplex);
+       return enc28j60_setlink(dev, cmd->autoneg,
+                               ethtool_cmd_speed(cmd), cmd->duplex);
 }
 
 static u32 enc28j60_get_msglevel(struct net_device *dev)
@@ -1476,6 +1530,17 @@ static int enc28j60_chipset_init(struct net_device *dev)
        return enc28j60_hw_init(priv);
 }
 
+static const struct net_device_ops enc28j60_netdev_ops = {
+       .ndo_open               = enc28j60_net_open,
+       .ndo_stop               = enc28j60_net_close,
+       .ndo_start_xmit         = enc28j60_send_packet,
+       .ndo_set_multicast_list = enc28j60_set_multicast_list,
+       .ndo_set_mac_address    = enc28j60_set_mac_address,
+       .ndo_tx_timeout         = enc28j60_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static int __devinit enc28j60_probe(struct spi_device *spi)
 {
        struct net_device *dev;
@@ -1517,8 +1582,10 @@ static int __devinit enc28j60_probe(struct spi_device *spi)
        random_ether_addr(dev->dev_addr);
        enc28j60_set_hw_macaddr(dev);
 
-       ret = request_irq(spi->irq, enc28j60_irq, IRQF_TRIGGER_FALLING,
-                         DRV_NAME, priv);
+       /* Board setup must set the relevant edge trigger type;
+        * level triggers won't currently work.
+        */
+       ret = request_irq(spi->irq, enc28j60_irq, 0, DRV_NAME, priv);
        if (ret < 0) {
                if (netif_msg_probe(priv))
                        dev_err(&spi->dev, DRV_NAME ": request irq %d failed "
@@ -1528,15 +1595,12 @@ static int __devinit enc28j60_probe(struct spi_device *spi)
 
        dev->if_port = IF_PORT_10BASET;
        dev->irq = spi->irq;
-       dev->open = enc28j60_net_open;
-       dev->stop = enc28j60_net_close;
-       dev->hard_start_xmit = enc28j60_send_packet;
-       dev->set_multicast_list = &enc28j60_set_multicast_list;
-       dev->set_mac_address = enc28j60_set_mac_address;
-       dev->tx_timeout = &enc28j60_tx_timeout;
+       dev->netdev_ops = &enc28j60_netdev_ops;
        dev->watchdog_timeo = TX_TIMEOUT;
        SET_ETHTOOL_OPS(dev, &enc28j60_ethtool_ops);
 
+       enc28j60_lowpower(priv, true);
+
        ret = register_netdev(dev);
        if (ret) {
                if (netif_msg_probe(priv))
@@ -1581,6 +1645,8 @@ static struct spi_driver enc28j60_driver = {
 
 static int __init enc28j60_init(void)
 {
+       msec20_to_jiffies = msecs_to_jiffies(20);
+
        return spi_register_driver(&enc28j60_driver);
 }
 
@@ -1598,3 +1664,4 @@ MODULE_AUTHOR("Claudio Lanconelli <lanconelli.claudio@eptar.com>");
 MODULE_LICENSE("GPL");
 module_param_named(debug, debug.msg_enable, int, 0);
 MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., ffff=all)");
+MODULE_ALIAS("spi:" DRV_NAME);