]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/net/spider_net.c
sfc: 10Xpress: Report support for pause frames
[linux-2.6.git] / drivers / net / spider_net.c
index e429abc1e947c1663194fa368f73313cd2fb755d..90e663f4515c1ad4a89338f9922497a4daa76ed0 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * Network device driver for Cell Processor-Based Blade
+ * Network device driver for Cell Processor-Based Blade and Celleb platform
  *
  * (C) Copyright IBM Corp. 2005
+ * (C) Copyright 2006 TOSHIBA CORPORATION
  *
  * Authors : Utz Bacher <utz.bacher@de.ibm.com>
  *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
@@ -45,7 +46,7 @@
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/pci-bridge.h>
 #include <net/checksum.h>
 
@@ -88,12 +89,11 @@ MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);
 static inline u32
 spider_net_read_reg(struct spider_net_card *card, u32 reg)
 {
-       u32 value;
-
-       value = readl(card->regs + reg);
-       value = le32_to_cpu(value);
-
-       return value;
+       /* We use the powerpc specific variants instead of readl_be() because
+        * we know spidernet is not a real PCI device and we can thus avoid the
+        * performance hit caused by the PCI workarounds.
+        */
+       return in_be32(card->regs + reg);
 }
 
 /**
@@ -105,8 +105,11 @@ spider_net_read_reg(struct spider_net_card *card, u32 reg)
 static inline void
 spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
 {
-       value = cpu_to_le32(value);
-       writel(value, card->regs + reg);
+       /* We use the powerpc specific variants instead of writel_be() because
+        * we know spidernet is not a real PCI device and we can thus avoid the
+        * performance hit caused by the PCI workarounds.
+        */
+       out_be32(card->regs + reg, value);
 }
 
 /** spider_net_write_phy - write to phy register
@@ -163,6 +166,39 @@ spider_net_read_phy(struct net_device *netdev, int mii_id, int reg)
        return readvalue;
 }
 
+/**
+ * spider_net_setup_aneg - initial auto-negotiation setup
+ * @card: device structure
+ **/
+static void
+spider_net_setup_aneg(struct spider_net_card *card)
+{
+       struct mii_phy *phy = &card->phy;
+       u32 advertise = 0;
+       u16 bmsr, estat;
+
+       bmsr  = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
+       estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS);
+
+       if (bmsr & BMSR_10HALF)
+               advertise |= ADVERTISED_10baseT_Half;
+       if (bmsr & BMSR_10FULL)
+               advertise |= ADVERTISED_10baseT_Full;
+       if (bmsr & BMSR_100HALF)
+               advertise |= ADVERTISED_100baseT_Half;
+       if (bmsr & BMSR_100FULL)
+               advertise |= ADVERTISED_100baseT_Full;
+
+       if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL))
+               advertise |= SUPPORTED_1000baseT_Full;
+       if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF))
+               advertise |= SUPPORTED_1000baseT_Half;
+
+       mii_phy_probe(phy, phy->mii_id);
+       phy->def->ops->setup_aneg(phy, advertise);
+
+}
+
 /**
  * spider_net_rx_irq_off - switch off rx irq on this spider card
  * @card: device structure
@@ -261,9 +297,9 @@ spider_net_get_mac_address(struct net_device *netdev)
  * returns the status as in the dmac_cmd_status field of the descriptor
  */
 static inline int
-spider_net_get_descr_status(struct spider_net_descr *descr)
+spider_net_get_descr_status(struct spider_net_hw_descr *hwdescr)
 {
-       return descr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
+       return hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
 }
 
 /**
@@ -278,77 +314,70 @@ spider_net_free_chain(struct spider_net_card *card,
 {
        struct spider_net_descr *descr;
 
-       for (descr = chain->tail; !descr->bus_addr; descr = descr->next) {
-               pci_unmap_single(card->pdev, descr->bus_addr,
-                                SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
+       descr = chain->ring;
+       do {
                descr->bus_addr = 0;
-       }
+               descr->hwdescr->next_descr_addr = 0;
+               descr = descr->next;
+       } while (descr != chain->ring);
+
+       dma_free_coherent(&card->pdev->dev, chain->num_desc,
+           chain->hwring, chain->dma_addr);
 }
 
 /**
- * spider_net_init_chain - links descriptor chain
+ * spider_net_init_chain - alloc and link descriptor chain
  * @card: card structure
  * @chain: address of chain
- * @start_descr: address of descriptor array
- * @no: number of descriptors
  *
- * we manage a circular list that mirrors the hardware structure,
+ * We manage a circular list that mirrors the hardware structure,
  * except that the hardware uses bus addresses.
  *
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure
  */
 static int
 spider_net_init_chain(struct spider_net_card *card,
-                      struct spider_net_descr_chain *chain,
-                      struct spider_net_descr *start_descr,
-                      int direction, int no)
+                      struct spider_net_descr_chain *chain)
 {
        int i;
        struct spider_net_descr *descr;
+       struct spider_net_hw_descr *hwdescr;
        dma_addr_t buf;
+       size_t alloc_size;
 
-       descr = start_descr;
-       memset(descr, 0, sizeof(*descr) * no);
+       alloc_size = chain->num_desc * sizeof(struct spider_net_hw_descr);
 
-       /* set up the hardware pointers in each descriptor */
-       for (i=0; i<no; i++, descr++) {
-               descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+       chain->hwring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
+               &chain->dma_addr, GFP_KERNEL);
 
-               buf = pci_map_single(card->pdev, descr,
-                                    SPIDER_NET_DESCR_SIZE,
-                                    direction);
+       if (!chain->hwring)
+               return -ENOMEM;
 
-               if (pci_dma_mapping_error(buf))
-                       goto iommu_error;
+       memset(chain->ring, 0, chain->num_desc * sizeof(struct spider_net_descr));
 
+       /* Set up the hardware pointers in each descriptor */
+       descr = chain->ring;
+       hwdescr = chain->hwring;
+       buf = chain->dma_addr;
+       for (i=0; i < chain->num_desc; i++, descr++, hwdescr++) {
+               hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+               hwdescr->next_descr_addr = 0;
+
+               descr->hwdescr = hwdescr;
                descr->bus_addr = buf;
                descr->next = descr + 1;
                descr->prev = descr - 1;
 
+               buf += sizeof(struct spider_net_hw_descr);
        }
        /* do actual circular list */
-       (descr-1)->next = start_descr;
-       start_descr->prev = descr-1;
-
-       descr = start_descr;
-       if (direction == PCI_DMA_FROMDEVICE)
-               for (i=0; i < no; i++, descr++)
-                       descr->next_descr_addr = descr->next->bus_addr;
+       (descr-1)->next = chain->ring;
+       chain->ring->prev = descr-1;
 
        spin_lock_init(&chain->lock);
-       chain->head = start_descr;
-       chain->tail = start_descr;
-
+       chain->head = chain->ring;
+       chain->tail = chain->ring;
        return 0;
-
-iommu_error:
-       descr = start_descr;
-       for (i=0; i < no; i++, descr++)
-               if (descr->bus_addr)
-                       pci_unmap_single(card->pdev, descr->bus_addr,
-                                        SPIDER_NET_DESCR_SIZE,
-                                        direction);
-       return -ENOMEM;
 }
 
 /**
@@ -363,33 +392,34 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card)
        struct spider_net_descr *descr;
 
        descr = card->rx_chain.head;
-       while (descr->next != card->rx_chain.head) {
+       do {
                if (descr->skb) {
-                       dev_kfree_skb(descr->skb);
-                       pci_unmap_single(card->pdev, descr->buf_addr,
+                       pci_unmap_single(card->pdev, descr->hwdescr->buf_addr,
                                         SPIDER_NET_MAX_FRAME,
-                                        PCI_DMA_FROMDEVICE);
+                                        PCI_DMA_BIDIRECTIONAL);
+                       dev_kfree_skb(descr->skb);
+                       descr->skb = NULL;
                }
                descr = descr->next;
-       }
+       } while (descr != card->rx_chain.head);
 }
 
 /**
- * spider_net_prepare_rx_descr - reinitializes a rx descriptor
+ * spider_net_prepare_rx_descr - Reinitialize RX descriptor
  * @card: card structure
  * @descr: descriptor to re-init
  *
- * return 0 on succes, <0 on failure
+ * Return 0 on succes, <0 on failure.
  *
- * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
- * Activate the descriptor state-wise
+ * Allocates a new rx skb, iommu-maps it and attaches it to the
+ * descriptor. Mark the descriptor as activated, ready-to-use.
  */
 static int
 spider_net_prepare_rx_descr(struct spider_net_card *card,
                            struct spider_net_descr *descr)
 {
+       struct spider_net_hw_descr *hwdescr = descr->hwdescr;
        dma_addr_t buf;
-       int error = 0;
        int offset;
        int bufsize;
 
@@ -400,39 +430,43 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
        /* and we need to have it 128 byte aligned, therefore we allocate a
         * bit more */
        /* allocate an skb */
-       descr->skb = dev_alloc_skb(bufsize + SPIDER_NET_RXBUF_ALIGN - 1);
+       descr->skb = netdev_alloc_skb(card->netdev,
+                                     bufsize + SPIDER_NET_RXBUF_ALIGN - 1);
        if (!descr->skb) {
                if (netif_msg_rx_err(card) && net_ratelimit())
-                       pr_err("Not enough memory to allocate rx buffer\n");
+                       dev_err(&card->netdev->dev,
+                               "Not enough memory to allocate rx buffer\n");
                card->spider_stats.alloc_rx_skb_error++;
                return -ENOMEM;
        }
-       descr->buf_size = bufsize;
-       descr->result_size = 0;
-       descr->valid_size = 0;
-       descr->data_status = 0;
-       descr->data_error = 0;
+       hwdescr->buf_size = bufsize;
+       hwdescr->result_size = 0;
+       hwdescr->valid_size = 0;
+       hwdescr->data_status = 0;
+       hwdescr->data_error = 0;
 
        offset = ((unsigned long)descr->skb->data) &
                (SPIDER_NET_RXBUF_ALIGN - 1);
        if (offset)
                skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
-       /* io-mmu-map the skb */
+       /* iommu-map the skb */
        buf = pci_map_single(card->pdev, descr->skb->data,
                        SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
-       descr->buf_addr = buf;
-       if (pci_dma_mapping_error(buf)) {
+       if (pci_dma_mapping_error(card->pdev, buf)) {
                dev_kfree_skb_any(descr->skb);
+               descr->skb = NULL;
                if (netif_msg_rx_err(card) && net_ratelimit())
-                       pr_err("Could not iommu-map rx buffer\n");
+                       dev_err(&card->netdev->dev, "Could not iommu-map rx buffer\n");
                card->spider_stats.rx_iommu_map_error++;
-               descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+               hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
        } else {
-               descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
+               hwdescr->buf_addr = buf;
+               wmb();
+               hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
                                         SPIDER_NET_DMAC_NOINTR_COMPLETE;
        }
 
-       return error;
+       return 0;
 }
 
 /**
@@ -466,6 +500,20 @@ spider_net_enable_rxdmac(struct spider_net_card *card)
                             SPIDER_NET_DMA_RX_VALUE);
 }
 
+/**
+ * spider_net_disable_rxdmac - disables the receive DMA controller
+ * @card: card structure
+ *
+ * spider_net_disable_rxdmac terminates processing on the DMA controller
+ * by turing off the DMA controller, with the force-end flag set.
+ */
+static inline void
+spider_net_disable_rxdmac(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
+                            SPIDER_NET_DMA_RX_FEND_VALUE);
+}
+
 /**
  * spider_net_refill_rx_chain - refills descriptors/skbs in the rx chains
  * @card: card structure
@@ -485,7 +533,7 @@ spider_net_refill_rx_chain(struct spider_net_card *card)
        if (!spin_trylock_irqsave(&chain->lock, flags))
                return;
 
-       while (spider_net_get_descr_status(chain->head) ==
+       while (spider_net_get_descr_status(chain->head->hwdescr) ==
                        SPIDER_NET_DESCR_NOT_IN_USE) {
                if (spider_net_prepare_rx_descr(card, chain->head))
                        break;
@@ -496,37 +544,41 @@ spider_net_refill_rx_chain(struct spider_net_card *card)
 }
 
 /**
- * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
+ * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains
  * @card: card structure
  *
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure.
  */
 static int
 spider_net_alloc_rx_skbs(struct spider_net_card *card)
 {
-       int result;
-       struct spider_net_descr_chain *chain;
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       struct spider_net_descr *start = chain->tail;
+       struct spider_net_descr *descr = start;
 
-       result = -ENOMEM;
+       /* Link up the hardware chain pointers */
+       do {
+               descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
+               descr = descr->next;
+       } while (descr != start);
 
-       chain = &card->rx_chain;
-       /* put at least one buffer into the chain. if this fails,
-        * we've got a problem. if not, spider_net_refill_rx_chain
-        * will do the rest at the end of this function */
+       /* Put at least one buffer into the chain. if this fails,
+        * we've got a problem. If not, spider_net_refill_rx_chain
+        * will do the rest at the end of this function. */
        if (spider_net_prepare_rx_descr(card, chain->head))
                goto error;
        else
                chain->head = chain->head->next;
 
-       /* this will allocate the rest of the rx buffers; if not, it's
-        * business as usual later on */
+       /* This will allocate the rest of the rx buffers;
+        * if not, it's business as usual later on. */
        spider_net_refill_rx_chain(card);
        spider_net_enable_rxdmac(card);
        return 0;
 
 error:
        spider_net_free_rx_chain_contents(card);
-       return result;
+       return -ENOMEM;
 }
 
 /**
@@ -617,24 +669,9 @@ write_hash:
        }
 }
 
-/**
- * spider_net_disable_rxdmac - disables the receive DMA controller
- * @card: card structure
- *
- * spider_net_disable_rxdmac terminates processing on the DMA controller by
- * turing off DMA and issueing a force end
- */
-static void
-spider_net_disable_rxdmac(struct spider_net_card *card)
-{
-       spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
-                            SPIDER_NET_DMA_RX_FEND_VALUE);
-}
-
 /**
  * spider_net_prepare_tx_descr - fill tx descriptor with skb data
  * @card: card structure
- * @descr: descriptor structure to fill out
  * @skb: packet to use
  *
  * returns 0 on success, <0 on failure.
@@ -646,89 +683,73 @@ static int
 spider_net_prepare_tx_descr(struct spider_net_card *card,
                            struct sk_buff *skb)
 {
-       struct spider_net_descr *descr = card->tx_chain.head;
+       struct spider_net_descr_chain *chain = &card->tx_chain;
+       struct spider_net_descr *descr;
+       struct spider_net_hw_descr *hwdescr;
        dma_addr_t buf;
-       int length;
-
-       length = skb->len;
-       if (length < ETH_ZLEN) {
-               if (skb_pad(skb, ETH_ZLEN-length))
-                       return 0;
-               length = ETH_ZLEN;
-       }
+       unsigned long flags;
 
-       buf = pci_map_single(card->pdev, skb->data, length, PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(buf)) {
+       buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(card->pdev, buf)) {
                if (netif_msg_tx_err(card) && net_ratelimit())
-                       pr_err("could not iommu-map packet (%p, %i). "
-                                 "Dropping packet\n", skb->data, length);
+                       dev_err(&card->netdev->dev, "could not iommu-map packet (%p, %i). "
+                                 "Dropping packet\n", skb->data, skb->len);
                card->spider_stats.tx_iommu_map_error++;
                return -ENOMEM;
        }
 
-       descr->buf_addr = buf;
-       descr->buf_size = length;
-       descr->next_descr_addr = 0;
+       spin_lock_irqsave(&chain->lock, flags);
+       descr = card->tx_chain.head;
+       if (descr->next == chain->tail->prev) {
+               spin_unlock_irqrestore(&chain->lock, flags);
+               pci_unmap_single(card->pdev, buf, skb->len, PCI_DMA_TODEVICE);
+               return -ENOMEM;
+       }
+       hwdescr = descr->hwdescr;
+       chain->head = descr->next;
+
        descr->skb = skb;
-       descr->data_status = 0;
+       hwdescr->buf_addr = buf;
+       hwdescr->buf_size = skb->len;
+       hwdescr->next_descr_addr = 0;
+       hwdescr->data_status = 0;
+
+       hwdescr->dmac_cmd_status =
+                       SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_TXFRMTL;
+       spin_unlock_irqrestore(&chain->lock, flags);
 
-       descr->dmac_cmd_status =
-                       SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
-       if (skb->protocol == htons(ETH_P_IP))
-               switch (skb->nh.iph->protocol) {
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               switch (ip_hdr(skb)->protocol) {
                case IPPROTO_TCP:
-                       descr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
+                       hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
                        break;
                case IPPROTO_UDP:
-                       descr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
+                       hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
                        break;
                }
 
        /* Chain the bus address, so that the DMA engine finds this descr. */
-       descr->prev->next_descr_addr = descr->bus_addr;
+       wmb();
+       descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
 
        card->netdev->trans_start = jiffies; /* set netdev watchdog timer */
        return 0;
 }
 
-/**
- * spider_net_release_tx_descr - processes a used tx descriptor
- * @card: card structure
- * @descr: descriptor to release
- *
- * releases a used tx descriptor (unmapping, freeing of skb)
- */
-static inline void
-spider_net_release_tx_descr(struct spider_net_card *card)
-{
-       struct spider_net_descr *descr = card->tx_chain.tail;
-       struct sk_buff *skb;
-       unsigned int len;
-
-       card->tx_chain.tail = card->tx_chain.tail->next;
-       descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
-
-       /* unmap the skb */
-       skb = descr->skb;
-       if (!skb)
-               return;
-       len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
-       pci_unmap_single(card->pdev, descr->buf_addr, len,
-                       PCI_DMA_TODEVICE);
-       dev_kfree_skb(skb);
-}
-
-static void
+static int
 spider_net_set_low_watermark(struct spider_net_card *card)
 {
+       struct spider_net_descr *descr = card->tx_chain.tail;
+       struct spider_net_hw_descr *hwdescr;
+       unsigned long flags;
        int status;
        int cnt=0;
        int i;
-       struct spider_net_descr *descr = card->tx_chain.tail;
 
-       /* Measure the length of the queue. */
+       /* Measure the length of the queue. Measurement does not
+        * need to be precise -- does not need a lock. */
        while (descr != card->tx_chain.head) {
-               status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
+               status = descr->hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
                if (status == SPIDER_NET_DESCR_NOT_IN_USE)
                        break;
                descr = descr->next;
@@ -736,8 +757,8 @@ spider_net_set_low_watermark(struct spider_net_card *card)
        }
 
        /* If TX queue is short, don't even bother with interrupts */
-       if (cnt < card->tx_desc/4)
-               return;
+       if (cnt < card->tx_chain.num_desc/4)
+               return cnt;
 
        /* Set low-watermark 3/4th's of the way into the queue. */
        descr = card->tx_chain.tail;
@@ -746,11 +767,16 @@ spider_net_set_low_watermark(struct spider_net_card *card)
                descr = descr->next;
 
        /* Set the new watermark, clear the old watermark */
-       descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
-       if (card->low_watermark && card->low_watermark != descr)
-               card->low_watermark->dmac_cmd_status =
-                    card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
+       spin_lock_irqsave(&card->tx_chain.lock, flags);
+       descr->hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
+       if (card->low_watermark && card->low_watermark != descr) {
+               hwdescr = card->low_watermark->hwdescr;
+               hwdescr->dmac_cmd_status =
+                    hwdescr->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
+       }
        card->low_watermark = descr;
+       spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+       return cnt;
 }
 
 /**
@@ -763,27 +789,42 @@ spider_net_set_low_watermark(struct spider_net_card *card)
  * spider_net_release_tx_chain releases the tx descriptors that spider has
  * finished with (if non-brutal) or simply release tx descriptors (if brutal).
  * If some other context is calling this function, we return 1 so that we're
- * scheduled again (if we were scheduled) and will not loose initiative.
+ * scheduled again (if we were scheduled) and will not lose initiative.
  */
 static int
 spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
 {
+       struct net_device *dev = card->netdev;
        struct spider_net_descr_chain *chain = &card->tx_chain;
+       struct spider_net_descr *descr;
+       struct spider_net_hw_descr *hwdescr;
+       struct sk_buff *skb;
+       u32 buf_addr;
+       unsigned long flags;
        int status;
 
-       spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR);
+       while (1) {
+               spin_lock_irqsave(&chain->lock, flags);
+               if (chain->tail == chain->head) {
+                       spin_unlock_irqrestore(&chain->lock, flags);
+                       return 0;
+               }
+               descr = chain->tail;
+               hwdescr = descr->hwdescr;
 
-       while (chain->tail != chain->head) {
-               status = spider_net_get_descr_status(chain->tail);
+               status = spider_net_get_descr_status(hwdescr);
                switch (status) {
                case SPIDER_NET_DESCR_COMPLETE:
-                       card->netdev_stats.tx_packets++;
-                       card->netdev_stats.tx_bytes += chain->tail->skb->len;
+                       dev->stats.tx_packets++;
+                       dev->stats.tx_bytes += descr->skb->len;
                        break;
 
                case SPIDER_NET_DESCR_CARDOWNED:
-                       if (!brutal)
+                       if (!brutal) {
+                               spin_unlock_irqrestore(&chain->lock, flags);
                                return 1;
+                       }
+
                        /* fallthrough, if we release the descriptors
                         * brutally (then we don't care about
                         * SPIDER_NET_DESCR_CARDOWNED) */
@@ -792,30 +833,46 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
                case SPIDER_NET_DESCR_PROTECTION_ERROR:
                case SPIDER_NET_DESCR_FORCE_END:
                        if (netif_msg_tx_err(card))
-                               pr_err("%s: forcing end of tx descriptor "
-                                      "with status x%02x\n",
-                                      card->netdev->name, status);
-                       card->netdev_stats.tx_errors++;
+                               dev_err(&card->netdev->dev, "forcing end of tx descriptor "
+                                      "with status x%02x\n", status);
+                       dev->stats.tx_errors++;
                        break;
 
                default:
-                       card->netdev_stats.tx_dropped++;
-                       if (!brutal)
+                       dev->stats.tx_dropped++;
+                       if (!brutal) {
+                               spin_unlock_irqrestore(&chain->lock, flags);
                                return 1;
+                       }
                }
-               spider_net_release_tx_descr(card);
-       }
 
+               chain->tail = descr->next;
+               hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
+               skb = descr->skb;
+               descr->skb = NULL;
+               buf_addr = hwdescr->buf_addr;
+               spin_unlock_irqrestore(&chain->lock, flags);
+
+               /* unmap the skb */
+               if (skb) {
+                       pci_unmap_single(card->pdev, buf_addr, skb->len,
+                                       PCI_DMA_TODEVICE);
+                       dev_kfree_skb(skb);
+               }
+       }
        return 0;
 }
 
 /**
  * spider_net_kick_tx_dma - enables TX DMA processing
  * @card: card structure
- * @descr: descriptor address to enable TX processing at
  *
- * spider_net_kick_tx_dma writes the current tx chain head as start address
- * of the tx descriptor chain and enables the transmission DMA engine
+ * This routine will start the transmit DMA running if
+ * it is not already running. This routine ned only be
+ * called when queueing a new packet to an empty tx queue.
+ * Writes the current tx chain head as start address
+ * of the tx descriptor chain and enables the transmission
+ * DMA engine.
  */
 static inline void
 spider_net_kick_tx_dma(struct spider_net_card *card)
@@ -828,7 +885,7 @@ spider_net_kick_tx_dma(struct spider_net_card *card)
 
        descr = card->tx_chain.tail;
        for (;;) {
-               if (spider_net_get_descr_status(descr) ==
+               if (spider_net_get_descr_status(descr->hwdescr) ==
                                SPIDER_NET_DESCR_CARDOWNED) {
                        spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
                                        descr->bus_addr);
@@ -855,29 +912,20 @@ out:
 static int
 spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
+       int cnt;
        struct spider_net_card *card = netdev_priv(netdev);
-       struct spider_net_descr_chain *chain = &card->tx_chain;
-       struct spider_net_descr *descr = chain->head;
-       unsigned long flags;
-
-       spin_lock_irqsave(&chain->lock, flags);
 
        spider_net_release_tx_chain(card, 0);
 
-       if ((chain->head->next == chain->tail->prev) ||
-          (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) ||
-          (spider_net_prepare_tx_descr(card, skb) != 0)) {
-
-               card->netdev_stats.tx_dropped++;
-               spin_unlock_irqrestore(&chain->lock, flags);
+       if (spider_net_prepare_tx_descr(card, skb) != 0) {
+               netdev->stats.tx_dropped++;
                netif_stop_queue(netdev);
                return NETDEV_TX_BUSY;
        }
 
-       spider_net_set_low_watermark(card);
-       spider_net_kick_tx_dma(card);
-       card->tx_chain.head = card->tx_chain.head->next;
-       spin_unlock_irqrestore(&chain->lock, flags);
+       cnt = spider_net_set_low_watermark(card);
+       if (cnt < 5)
+               spider_net_kick_tx_dma(card);
        return NETDEV_TX_OK;
 }
 
@@ -893,16 +941,11 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
 static void
 spider_net_cleanup_tx_ring(struct spider_net_card *card)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->tx_chain.lock, flags);
-
        if ((spider_net_release_tx_chain(card, 0) != 0) &&
            (card->netdev->flags & IFF_UP)) {
                spider_net_kick_tx_dma(card);
                netif_wake_queue(card->netdev);
        }
-       spin_unlock_irqrestore(&card->tx_chain.lock, flags);
 }
 
 /**
@@ -927,43 +970,21 @@ spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
  * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
  * @descr: descriptor to process
  * @card: card structure
- * @napi: whether caller is in NAPI context
- *
- * returns 1 on success, 0 if no packet was passed to the stack
  *
- * iommu-unmaps the skb, fills out skb structure and passes the data to the
- * stack. The descriptor state is not changed.
+ * Fills out skb structure and passes the data to the stack.
+ * The descriptor state is not changed.
  */
-static int
+static void
 spider_net_pass_skb_up(struct spider_net_descr *descr,
-                      struct spider_net_card *card, int napi)
+                      struct spider_net_card *card)
 {
-       struct sk_buff *skb;
-       struct net_device *netdev;
-       u32 data_status, data_error;
-
-       data_status = descr->data_status;
-       data_error = descr->data_error;
-
-       netdev = card->netdev;
-
-       /* unmap descriptor */
-       pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME,
-                       PCI_DMA_FROMDEVICE);
-
-       /* the cases we'll throw away the packet immediately */
-       if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
-               if (netif_msg_rx_err(card))
-                       pr_err("error in received descriptor found, "
-                              "data_status=x%08x, data_error=x%08x\n",
-                              data_status, data_error);
-               card->spider_stats.rx_desc_error++;
-               return 0;
-       }
+       struct spider_net_hw_descr *hwdescr = descr->hwdescr;
+       struct sk_buff *skb = descr->skb;
+       struct net_device *netdev = card->netdev;
+       u32 data_status = hwdescr->data_status;
+       u32 data_error = hwdescr->data_error;
 
-       skb = descr->skb;
-       skb->dev = netdev;
-       skb_put(skb, descr->valid_size);
+       skb_put(skb, hwdescr->valid_size);
 
        /* the card seems to add 2 bytes of junk in front
         * of the ethernet frame */
@@ -988,90 +1009,257 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
                 */
        }
 
+       /* update netdevice statistics */
+       netdev->stats.rx_packets++;
+       netdev->stats.rx_bytes += skb->len;
+
        /* pass skb up to stack */
-       if (napi)
-               netif_receive_skb(skb);
-       else
-               netif_rx_ni(skb);
+       netif_receive_skb(skb);
+}
 
-       /* update netdevice statistics */
-       card->netdev_stats.rx_packets++;
-       card->netdev_stats.rx_bytes += skb->len;
+static void show_rx_chain(struct spider_net_card *card)
+{
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       struct spider_net_descr *start= chain->tail;
+       struct spider_net_descr *descr= start;
+       struct spider_net_hw_descr *hwd = start->hwdescr;
+       struct device *dev = &card->netdev->dev;
+       u32 curr_desc, next_desc;
+       int status;
+
+       int tot = 0;
+       int cnt = 0;
+       int off = start - chain->ring;
+       int cstat = hwd->dmac_cmd_status;
+
+       dev_info(dev, "Total number of descrs=%d\n",
+               chain->num_desc);
+       dev_info(dev, "Chain tail located at descr=%d, status=0x%x\n",
+               off, cstat);
+
+       curr_desc = spider_net_read_reg(card, SPIDER_NET_GDACTDPA);
+       next_desc = spider_net_read_reg(card, SPIDER_NET_GDACNEXTDA);
+
+       status = cstat;
+       do
+       {
+               hwd = descr->hwdescr;
+               off = descr - chain->ring;
+               status = hwd->dmac_cmd_status;
+
+               if (descr == chain->head)
+                       dev_info(dev, "Chain head is at %d, head status=0x%x\n",
+                                off, status);
+
+               if (curr_desc == descr->bus_addr)
+                       dev_info(dev, "HW curr desc (GDACTDPA) is at %d, status=0x%x\n",
+                                off, status);
+
+               if (next_desc == descr->bus_addr)
+                       dev_info(dev, "HW next desc (GDACNEXTDA) is at %d, status=0x%x\n",
+                                off, status);
+
+               if (hwd->next_descr_addr == 0)
+                       dev_info(dev, "chain is cut at %d\n", off);
+
+               if (cstat != status) {
+                       int from = (chain->num_desc + off - cnt) % chain->num_desc;
+                       int to = (chain->num_desc + off - 1) % chain->num_desc;
+                       dev_info(dev, "Have %d (from %d to %d) descrs "
+                                "with stat=0x%08x\n", cnt, from, to, cstat);
+                       cstat = status;
+                       cnt = 0;
+               }
+
+               cnt ++;
+               tot ++;
+               descr = descr->next;
+       } while (descr != start);
+
+       dev_info(dev, "Last %d descrs with stat=0x%08x "
+                "for a total of %d descrs\n", cnt, cstat, tot);
+
+#ifdef DEBUG
+       /* Now dump the whole ring */
+       descr = start;
+       do
+       {
+               struct spider_net_hw_descr *hwd = descr->hwdescr;
+               status = spider_net_get_descr_status(hwd);
+               cnt = descr - chain->ring;
+               dev_info(dev, "Descr %d stat=0x%08x skb=%p\n",
+                        cnt, status, descr->skb);
+               dev_info(dev, "bus addr=%08x buf addr=%08x sz=%d\n",
+                        descr->bus_addr, hwd->buf_addr, hwd->buf_size);
+               dev_info(dev, "next=%08x result sz=%d valid sz=%d\n",
+                        hwd->next_descr_addr, hwd->result_size,
+                        hwd->valid_size);
+               dev_info(dev, "dmac=%08x data stat=%08x data err=%08x\n",
+                        hwd->dmac_cmd_status, hwd->data_status,
+                        hwd->data_error);
+               dev_info(dev, "\n");
+
+               descr = descr->next;
+       } while (descr != start);
+#endif
 
-       return 1;
 }
 
 /**
- * spider_net_decode_one_descr - processes an rx descriptor
+ * spider_net_resync_head_ptr - Advance head ptr past empty descrs
+ *
+ * If the driver fails to keep up and empty the queue, then the
+ * hardware wil run out of room to put incoming packets. This
+ * will cause the hardware to skip descrs that are full (instead
+ * of halting/retrying). Thus, once the driver runs, it wil need
+ * to "catch up" to where the hardware chain pointer is at.
+ */
+static void spider_net_resync_head_ptr(struct spider_net_card *card)
+{
+       unsigned long flags;
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       struct spider_net_descr *descr;
+       int i, status;
+
+       /* Advance head pointer past any empty descrs */
+       descr = chain->head;
+       status = spider_net_get_descr_status(descr->hwdescr);
+
+       if (status == SPIDER_NET_DESCR_NOT_IN_USE)
+               return;
+
+       spin_lock_irqsave(&chain->lock, flags);
+
+       descr = chain->head;
+       status = spider_net_get_descr_status(descr->hwdescr);
+       for (i=0; i<chain->num_desc; i++) {
+               if (status != SPIDER_NET_DESCR_CARDOWNED) break;
+               descr = descr->next;
+               status = spider_net_get_descr_status(descr->hwdescr);
+       }
+       chain->head = descr;
+
+       spin_unlock_irqrestore(&chain->lock, flags);
+}
+
+static int spider_net_resync_tail_ptr(struct spider_net_card *card)
+{
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       struct spider_net_descr *descr;
+       int i, status;
+
+       /* Advance tail pointer past any empty and reaped descrs */
+       descr = chain->tail;
+       status = spider_net_get_descr_status(descr->hwdescr);
+
+       for (i=0; i<chain->num_desc; i++) {
+               if ((status != SPIDER_NET_DESCR_CARDOWNED) &&
+                   (status != SPIDER_NET_DESCR_NOT_IN_USE)) break;
+               descr = descr->next;
+               status = spider_net_get_descr_status(descr->hwdescr);
+       }
+       chain->tail = descr;
+
+       if ((i == chain->num_desc) || (i == 0))
+               return 1;
+       return 0;
+}
+
+/**
+ * spider_net_decode_one_descr - processes an RX descriptor
  * @card: card structure
- * @napi: whether caller is in NAPI context
  *
- * returns 1 if a packet has been sent to the stack, otherwise 0
+ * Returns 1 if a packet has been sent to the stack, otherwise 0.
  *
- * processes an rx descriptor by iommu-unmapping the data buffer and passing
- * the packet up to the stack. This function is called in softirq
- * context, e.g. either bottom half from interrupt or NAPI polling context
+ * Processes an RX descriptor by iommu-unmapping the data buffer
+ * and passing the packet up to the stack. This function is called
+ * in softirq context, e.g. either bottom half from interrupt or
+ * NAPI polling context.
  */
 static int
-spider_net_decode_one_descr(struct spider_net_card *card, int napi)
+spider_net_decode_one_descr(struct spider_net_card *card)
 {
+       struct net_device *dev = card->netdev;
        struct spider_net_descr_chain *chain = &card->rx_chain;
        struct spider_net_descr *descr = chain->tail;
+       struct spider_net_hw_descr *hwdescr = descr->hwdescr;
+       u32 hw_buf_addr;
        int status;
-       int result;
 
-       status = spider_net_get_descr_status(descr);
+       status = spider_net_get_descr_status(hwdescr);
 
-       if (status == SPIDER_NET_DESCR_CARDOWNED) {
-               /* nothing in the descriptor yet */
-               result=0;
-               goto out;
-       }
-
-       if (status == SPIDER_NET_DESCR_NOT_IN_USE) {
-               /* not initialized yet, the ring must be empty */
-               spider_net_refill_rx_chain(card);
-               spider_net_enable_rxdmac(card);
-               result=0;
-               goto out;
-       }
+       /* Nothing in the descriptor, or ring must be empty */
+       if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
+           (status == SPIDER_NET_DESCR_NOT_IN_USE))
+               return 0;
 
        /* descriptor definitively used -- move on tail */
        chain->tail = descr->next;
 
-       result = 0;
+       /* unmap descriptor */
+       hw_buf_addr = hwdescr->buf_addr;
+       hwdescr->buf_addr = 0xffffffff;
+       pci_unmap_single(card->pdev, hw_buf_addr,
+                       SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
+
        if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
             (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
             (status == SPIDER_NET_DESCR_FORCE_END) ) {
                if (netif_msg_rx_err(card))
-                       pr_err("%s: dropping RX descriptor with state %d\n",
-                              card->netdev->name, status);
-               card->netdev_stats.rx_dropped++;
-               pci_unmap_single(card->pdev, descr->buf_addr,
-                               SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
-               dev_kfree_skb_irq(descr->skb);
-               goto refill;
+                       dev_err(&dev->dev,
+                              "dropping RX descriptor with state %d\n", status);
+               dev->stats.rx_dropped++;
+               goto bad_desc;
        }
 
        if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
             (status != SPIDER_NET_DESCR_FRAME_END) ) {
-               if (netif_msg_rx_err(card)) {
-                       pr_err("%s: RX descriptor with state %d\n",
-                              card->netdev->name, status);
-                       card->spider_stats.rx_desc_unk_state++;
-               }
-               goto refill;
+               if (netif_msg_rx_err(card))
+                       dev_err(&card->netdev->dev,
+                              "RX descriptor with unknown state %d\n", status);
+               card->spider_stats.rx_desc_unk_state++;
+               goto bad_desc;
        }
 
-       /* ok, we've got a packet in descr */
-       result = spider_net_pass_skb_up(descr, card, napi);
-refill:
-       descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
-       /* change the descriptor state: */
-       if (!napi)
-               spider_net_refill_rx_chain(card);
-out:
-       return result;
+       /* The cases we'll throw away the packet immediately */
+       if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
+               if (netif_msg_rx_err(card))
+                       dev_err(&card->netdev->dev,
+                              "error in received descriptor found, "
+                              "data_status=x%08x, data_error=x%08x\n",
+                              hwdescr->data_status, hwdescr->data_error);
+               goto bad_desc;
+       }
+
+       if (hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_BAD_STATUS) {
+               dev_err(&card->netdev->dev, "bad status, cmd_status=x%08x\n",
+                              hwdescr->dmac_cmd_status);
+               pr_err("buf_addr=x%08x\n", hw_buf_addr);
+               pr_err("buf_size=x%08x\n", hwdescr->buf_size);
+               pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr);
+               pr_err("result_size=x%08x\n", hwdescr->result_size);
+               pr_err("valid_size=x%08x\n", hwdescr->valid_size);
+               pr_err("data_status=x%08x\n", hwdescr->data_status);
+               pr_err("data_error=x%08x\n", hwdescr->data_error);
+               pr_err("which=%ld\n", descr - card->rx_chain.ring);
+
+               card->spider_stats.rx_desc_error++;
+               goto bad_desc;
+       }
+
+       /* Ok, we've got a packet in descr */
+       spider_net_pass_skb_up(descr, card);
+       descr->skb = NULL;
+       hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+       return 1;
+
+bad_desc:
+       if (netif_msg_rx_err(card))
+               show_rx_chain(card);
+       dev_kfree_skb_irq(descr->skb);
+       descr->skb = NULL;
+       hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+       return 0;
 }
 
 /**
@@ -1086,91 +1274,39 @@ out:
  * (using netif_receive_skb). If all/enough packets are up, the driver
  * reenables interrupts and returns 0. If not, 1 is returned.
  */
-static int
-spider_net_poll(struct net_device *netdev, int *budget)
+static int spider_net_poll(struct napi_struct *napi, int budget)
 {
-       struct spider_net_card *card = netdev_priv(netdev);
-       int packets_to_do, packets_done = 0;
-       int no_more_packets = 0;
+       struct spider_net_card *card = container_of(napi, struct spider_net_card, napi);
+       int packets_done = 0;
 
-       spider_net_cleanup_tx_ring(card);
-       packets_to_do = min(*budget, netdev->quota);
-
-       while (packets_to_do) {
-               if (spider_net_decode_one_descr(card, 1)) {
-                       packets_done++;
-                       packets_to_do--;
-               } else {
-                       /* no more packets for the stack */
-                       no_more_packets = 1;
+       while (packets_done < budget) {
+               if (!spider_net_decode_one_descr(card))
                        break;
-               }
+
+               packets_done++;
+       }
+
+       if ((packets_done == 0) && (card->num_rx_ints != 0)) {
+               if (!spider_net_resync_tail_ptr(card))
+                       packets_done = budget;
+               spider_net_resync_head_ptr(card);
        }
+       card->num_rx_ints = 0;
 
-       netdev->quota -= packets_done;
-       *budget -= packets_done;
        spider_net_refill_rx_chain(card);
+       spider_net_enable_rxdmac(card);
+
+       spider_net_cleanup_tx_ring(card);
 
        /* if all packets are in the stack, enable interrupts and return 0 */
        /* if not, return 1 */
-       if (no_more_packets) {
-               netif_rx_complete(netdev);
+       if (packets_done < budget) {
+               napi_complete(napi);
                spider_net_rx_irq_on(card);
-               return 0;
+               card->ignore_rx_ramfull = 0;
        }
 
-       return 1;
-}
-
-/**
- * spider_net_vlan_rx_reg - initializes VLAN structures in the driver and card
- * @netdev: interface device structure
- * @grp: vlan_group structure that is registered (NULL on destroying interface)
- */
-static void
-spider_net_vlan_rx_reg(struct net_device *netdev, struct vlan_group *grp)
-{
-       /* further enhancement... yet to do */
-       return;
-}
-
-/**
- * spider_net_vlan_rx_add - adds VLAN id to the card filter
- * @netdev: interface device structure
- * @vid: VLAN id to add
- */
-static void
-spider_net_vlan_rx_add(struct net_device *netdev, uint16_t vid)
-{
-       /* further enhancement... yet to do */
-       /* add vid to card's VLAN filter table */
-       return;
-}
-
-/**
- * spider_net_vlan_rx_kill - removes VLAN id to the card filter
- * @netdev: interface device structure
- * @vid: VLAN id to remove
- */
-static void
-spider_net_vlan_rx_kill(struct net_device *netdev, uint16_t vid)
-{
-       /* further enhancement... yet to do */
-       /* remove vid from card's VLAN filter table */
-}
-
-/**
- * spider_net_get_stats - get interface statistics
- * @netdev: interface device structure
- *
- * returns the interface statistics residing in the spider_net_card struct
- */
-static struct net_device_stats *
-spider_net_get_stats(struct net_device *netdev)
-{
-       struct spider_net_card *card = netdev_priv(netdev);
-       struct net_device_stats *stats = &card->netdev_stats;
-       return stats;
+       return packets_done;
 }
 
 /**
@@ -1239,21 +1375,32 @@ spider_net_set_mac(struct net_device *netdev, void *p)
 }
 
 /**
- * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt
- * @card: card structure
+ * spider_net_link_reset
+ * @netdev: net device structure
+ *
+ * This is called when the PHY_LINK signal is asserted. For the blade this is
+ * not connected so we should never get here.
  *
- * spider_net_handle_rxram_full empties the RX ring so that spider can put
- * more packets in it and empty its RX RAM. This is called in bottom half
- * context
  */
 static void
-spider_net_handle_rxram_full(struct spider_net_card *card)
+spider_net_link_reset(struct net_device *netdev)
 {
-       while (spider_net_decode_one_descr(card, 0))
-               ;
-       spider_net_enable_rxchtails(card);
-       spider_net_enable_rxdmac(card);
-       netif_rx_schedule(card->netdev);
+
+       struct spider_net_card *card = netdev_priv(netdev);
+
+       del_timer_sync(&card->aneg_timer);
+
+       /* clear interrupt, block further interrupts */
+       spider_net_write_reg(card, SPIDER_NET_GMACST,
+                            spider_net_read_reg(card, SPIDER_NET_GMACST));
+       spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
+
+       /* reset phy and setup aneg */
+       card->aneg_count = 0;
+       card->medium = BCM54XX_COPPER;
+       spider_net_setup_aneg(card);
+       mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+
 }
 
 /**
@@ -1265,14 +1412,11 @@ spider_net_handle_rxram_full(struct spider_net_card *card)
  * found when an interrupt is presented
  */
 static void
-spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
+spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg,
+                           u32 error_reg1, u32 error_reg2)
 {
-       u32 error_reg1, error_reg2;
-       u32 i;
-       int show_error = 1;
-
-       error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS);
-       error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS);
+       u32 i;
+       int show_error = 1;
 
        /* check GHIINT0STS ************************************/
        if (status_reg)
@@ -1307,7 +1451,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
        case SPIDER_NET_GPWFFINT:
                /* PHY command queue full */
                if (netif_msg_intr(card))
-                       pr_err("PHY write queue full\n");
+                       dev_err(&card->netdev->dev, "PHY write queue full\n");
                show_error = 0;
                break;
 
@@ -1368,8 +1512,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
                                switch (i)
        {
        case SPIDER_NET_GTMFLLINT:
-               if (netif_msg_intr(card) && net_ratelimit())
-                       pr_err("Spider TX RAM full\n");
+               /* TX RAM full may happen on a usual case.
+                * Logging is not needed. */
                show_error = 0;
                break;
        case SPIDER_NET_GRFDFLLINT: /* fallthrough */
@@ -1377,11 +1521,15 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
        case SPIDER_NET_GRFBFLLINT: /* fallthrough */
        case SPIDER_NET_GRFAFLLINT: /* fallthrough */
        case SPIDER_NET_GRMFLLINT:
-               if (netif_msg_intr(card) && net_ratelimit())
-                       pr_debug("Spider RX RAM full, incoming packets "
-                              "might be discarded!\n");
-               spider_net_rx_irq_off(card);
-               tasklet_schedule(&card->rxram_full_tl);
+               /* Could happen when rx chain is full */
+               if (card->ignore_rx_ramfull == 0) {
+                       card->ignore_rx_ramfull = 1;
+                       spider_net_resync_head_ptr(card);
+                       spider_net_refill_rx_chain(card);
+                       spider_net_enable_rxdmac(card);
+                       card->num_rx_ints ++;
+                       napi_schedule(&card->napi);
+               }
                show_error = 0;
                break;
 
@@ -1396,12 +1544,11 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
        case SPIDER_NET_GDCDCEINT: /* fallthrough */
        case SPIDER_NET_GDBDCEINT: /* fallthrough */
        case SPIDER_NET_GDADCEINT:
-               if (netif_msg_intr(card))
-                       pr_err("got descriptor chain end interrupt, "
-                              "restarting DMAC %c.\n",
-                              'D'-(i-SPIDER_NET_GDDDCEINT)/3);
+               spider_net_resync_head_ptr(card);
                spider_net_refill_rx_chain(card);
                spider_net_enable_rxdmac(card);
+               card->num_rx_ints ++;
+               napi_schedule(&card->napi);
                show_error = 0;
                break;
 
@@ -1410,9 +1557,12 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
        case SPIDER_NET_GDCINVDINT: /* fallthrough */
        case SPIDER_NET_GDBINVDINT: /* fallthrough */
        case SPIDER_NET_GDAINVDINT:
-               /* could happen when rx chain is full */
+               /* Could happen when rx chain is full */
+               spider_net_resync_head_ptr(card);
                spider_net_refill_rx_chain(card);
                spider_net_enable_rxdmac(card);
+               card->num_rx_ints ++;
+               napi_schedule(&card->napi);
                show_error = 0;
                break;
 
@@ -1467,10 +1617,9 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
                        break;
        }
 
-       if ((show_error) && (netif_msg_intr(card)))
-               pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, "
+       if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
+               dev_err(&card->netdev->dev, "Error interrupt, GHIINT0STS = 0x%08x, "
                       "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
-                      card->netdev->name,
                       status_reg, error_reg1, error_reg2);
 
        /* clear interrupt sources */
@@ -1480,9 +1629,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
 
 /**
  * spider_net_interrupt - interrupt handler for spider_net
- * @irq: interupt number
+ * @irq: interrupt number
  * @ptr: pointer to net_device
- * @regs: PU registers
  *
  * returns IRQ_HANDLED, if interrupt was for driver, or IRQ_NONE, if no
  * interrupt found raised by card.
@@ -1495,22 +1643,31 @@ spider_net_interrupt(int irq, void *ptr)
 {
        struct net_device *netdev = ptr;
        struct spider_net_card *card = netdev_priv(netdev);
-       u32 status_reg;
+       u32 status_reg, error_reg1, error_reg2;
 
        status_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0STS);
+       error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS);
+       error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS);
 
-       if (!status_reg)
+       if (!(status_reg & SPIDER_NET_INT0_MASK_VALUE) &&
+           !(error_reg1 & SPIDER_NET_INT1_MASK_VALUE) &&
+           !(error_reg2 & SPIDER_NET_INT2_MASK_VALUE))
                return IRQ_NONE;
 
        if (status_reg & SPIDER_NET_RXINT ) {
                spider_net_rx_irq_off(card);
-               netif_rx_schedule(netdev);
+               napi_schedule(&card->napi);
+               card->num_rx_ints ++;
        }
        if (status_reg & SPIDER_NET_TXINT)
-               netif_rx_schedule(netdev);
+               napi_schedule(&card->napi);
+
+       if (status_reg & SPIDER_NET_LINKINT)
+               spider_net_link_reset(netdev);
 
        if (status_reg & SPIDER_NET_ERRINT )
-               spider_net_handle_error_irq(card, status_reg);
+               spider_net_handle_error_irq(card, status_reg,
+                                           error_reg1, error_reg2);
 
        /* clear interrupt sources */
        spider_net_write_reg(card, SPIDER_NET_GHIINT0STS, status_reg);
@@ -1534,6 +1691,38 @@ spider_net_poll_controller(struct net_device *netdev)
 }
 #endif /* CONFIG_NET_POLL_CONTROLLER */
 
+/**
+ * spider_net_enable_interrupts - enable interrupts
+ * @card: card structure
+ *
+ * spider_net_enable_interrupt enables several interrupts
+ */
+static void
+spider_net_enable_interrupts(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK,
+                            SPIDER_NET_INT0_MASK_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK,
+                            SPIDER_NET_INT1_MASK_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK,
+                            SPIDER_NET_INT2_MASK_VALUE);
+}
+
+/**
+ * spider_net_disable_interrupts - disable interrupts
+ * @card: card structure
+ *
+ * spider_net_disable_interrupts disables all the interrupts
+ */
+static void
+spider_net_disable_interrupts(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
+       spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
+}
+
 /**
  * spider_net_init_card - initializes the card
  * @card: card structure
@@ -1549,6 +1738,12 @@ spider_net_init_card(struct spider_net_card *card)
 
        spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
                             SPIDER_NET_CKRCTRL_RUN_VALUE);
+
+       /* trigger ETOMOD signal */
+       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
+               spider_net_read_reg(card, SPIDER_NET_GMACOPEMD) | 0x4);
+
+       spider_net_disable_interrupts(card);
 }
 
 /**
@@ -1633,117 +1828,11 @@ spider_net_enable_card(struct spider_net_card *card)
 
        spider_net_write_reg(card, SPIDER_NET_GMACLENLMT,
                             SPIDER_NET_LENLMT_VALUE);
-       spider_net_write_reg(card, SPIDER_NET_GMACMODE,
-                            SPIDER_NET_MACMODE_VALUE);
        spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
                             SPIDER_NET_OPMODE_VALUE);
 
-       /* set interrupt mask registers */
-       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK,
-                            SPIDER_NET_INT0_MASK_VALUE);
-       spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK,
-                            SPIDER_NET_INT1_MASK_VALUE);
-       spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK,
-                            SPIDER_NET_INT2_MASK_VALUE);
-
        spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
-                            SPIDER_NET_GDTBSTA | SPIDER_NET_GDTDCEIDIS);
-}
-
-/**
- * spider_net_open - called upon ifonfig up
- * @netdev: interface device structure
- *
- * returns 0 on success, <0 on failure
- *
- * spider_net_open allocates all the descriptors and memory needed for
- * operation, sets up multicast list and enables interrupts
- */
-int
-spider_net_open(struct net_device *netdev)
-{
-       struct spider_net_card *card = netdev_priv(netdev);
-       int result;
-
-       result = -ENOMEM;
-       if (spider_net_init_chain(card, &card->tx_chain, card->descr,
-                       PCI_DMA_TODEVICE, card->tx_desc))
-               goto alloc_tx_failed;
-
-       card->low_watermark = NULL;
-
-       /* rx_chain is after tx_chain, so offset is descr + tx_count */
-       if (spider_net_init_chain(card, &card->rx_chain,
-                       card->descr + card->tx_desc,
-                       PCI_DMA_FROMDEVICE, card->rx_desc))
-               goto alloc_rx_failed;
-
-       /* allocate rx skbs */
-       if (spider_net_alloc_rx_skbs(card))
-               goto alloc_skbs_failed;
-
-       spider_net_set_multi(netdev);
-
-       /* further enhancement: setup hw vlan, if needed */
-
-       result = -EBUSY;
-       if (request_irq(netdev->irq, spider_net_interrupt,
-                            IRQF_SHARED, netdev->name, netdev))
-               goto register_int_failed;
-
-       spider_net_enable_card(card);
-
-       netif_start_queue(netdev);
-       netif_carrier_on(netdev);
-       netif_poll_enable(netdev);
-
-       return 0;
-
-register_int_failed:
-       spider_net_free_rx_chain_contents(card);
-alloc_skbs_failed:
-       spider_net_free_chain(card, &card->rx_chain);
-alloc_rx_failed:
-       spider_net_free_chain(card, &card->tx_chain);
-alloc_tx_failed:
-       return result;
-}
-
-/**
- * spider_net_setup_phy - setup PHY
- * @card: card structure
- *
- * returns 0 on success, <0 on failure
- *
- * spider_net_setup_phy is used as part of spider_net_probe. Sets
- * the PHY to 1000 Mbps
- **/
-static int
-spider_net_setup_phy(struct spider_net_card *card)
-{
-       struct mii_phy *phy = &card->phy;
-
-       spider_net_write_reg(card, SPIDER_NET_GDTDMASEL,
-                            SPIDER_NET_DMASEL_VALUE);
-       spider_net_write_reg(card, SPIDER_NET_GPCCTRL,
-                            SPIDER_NET_PHY_CTRL_VALUE);
-       phy->mii_id = 1;
-       phy->dev = card->netdev;
-       phy->mdio_read = spider_net_read_phy;
-       phy->mdio_write = spider_net_write_phy;
-
-       mii_phy_probe(phy, phy->mii_id);
-
-       if (phy->def->ops->setup_forced)
-               phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL);
-
-       phy->def->ops->enable_fiber(phy);
-
-       phy->def->ops->read_link(phy);
-       pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name,
-               phy->speed, phy->duplex==1 ? "Full" : "Half");
-
-       return 0;
+                            SPIDER_NET_GDTBSTA);
 }
 
 /**
@@ -1824,7 +1913,8 @@ spider_net_init_firmware(struct spider_net_card *card)
                             SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) == 0) {
                if ( (firmware->size != SPIDER_NET_FIRMWARE_LEN) &&
                     netif_msg_probe(card) ) {
-                       pr_err("Incorrect size of spidernet firmware in " \
+                       dev_err(&card->netdev->dev,
+                              "Incorrect size of spidernet firmware in " \
                               "filesystem. Looking in host firmware...\n");
                        goto try_host_fw;
                }
@@ -1842,14 +1932,14 @@ try_host_fw:
        if (!dn)
                goto out_err;
 
-       fw_prop = get_property(dn, "firmware", &fw_size);
+       fw_prop = of_get_property(dn, "firmware", &fw_size);
        if (!fw_prop)
                goto out_err;
 
        if ( (fw_size != SPIDER_NET_FIRMWARE_LEN) &&
             netif_msg_probe(card) ) {
-               pr_err("Incorrect size of spidernet firmware in " \
-                      "host firmware\n");
+               dev_err(&card->netdev->dev,
+                      "Incorrect size of spidernet firmware in host firmware\n");
                goto done;
        }
 
@@ -1859,11 +1949,191 @@ done:
        return err;
 out_err:
        if (netif_msg_probe(card))
-               pr_err("Couldn't find spidernet firmware in filesystem " \
+               dev_err(&card->netdev->dev,
+                      "Couldn't find spidernet firmware in filesystem " \
                       "or host firmware\n");
        return err;
 }
 
+/**
+ * spider_net_open - called upon ifonfig up
+ * @netdev: interface device structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * spider_net_open allocates all the descriptors and memory needed for
+ * operation, sets up multicast list and enables interrupts
+ */
+int
+spider_net_open(struct net_device *netdev)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       int result;
+
+       result = spider_net_init_firmware(card);
+       if (result)
+               goto init_firmware_failed;
+
+       /* start probing with copper */
+       card->aneg_count = 0;
+       card->medium = BCM54XX_COPPER;
+       spider_net_setup_aneg(card);
+       if (card->phy.def->phy_id)
+               mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+
+       result = spider_net_init_chain(card, &card->tx_chain);
+       if (result)
+               goto alloc_tx_failed;
+       card->low_watermark = NULL;
+
+       result = spider_net_init_chain(card, &card->rx_chain);
+       if (result)
+               goto alloc_rx_failed;
+
+       /* Allocate rx skbs */
+       if (spider_net_alloc_rx_skbs(card))
+               goto alloc_skbs_failed;
+
+       spider_net_set_multi(netdev);
+
+       /* further enhancement: setup hw vlan, if needed */
+
+       result = -EBUSY;
+       if (request_irq(netdev->irq, spider_net_interrupt,
+                            IRQF_SHARED, netdev->name, netdev))
+               goto register_int_failed;
+
+       spider_net_enable_card(card);
+
+       netif_start_queue(netdev);
+       netif_carrier_on(netdev);
+       napi_enable(&card->napi);
+
+       spider_net_enable_interrupts(card);
+
+       return 0;
+
+register_int_failed:
+       spider_net_free_rx_chain_contents(card);
+alloc_skbs_failed:
+       spider_net_free_chain(card, &card->rx_chain);
+alloc_rx_failed:
+       spider_net_free_chain(card, &card->tx_chain);
+alloc_tx_failed:
+       del_timer_sync(&card->aneg_timer);
+init_firmware_failed:
+       return result;
+}
+
+/**
+ * spider_net_link_phy
+ * @data: used for pointer to card structure
+ *
+ */
+static void spider_net_link_phy(unsigned long data)
+{
+       struct spider_net_card *card = (struct spider_net_card *)data;
+       struct mii_phy *phy = &card->phy;
+
+       /* if link didn't come up after SPIDER_NET_ANEG_TIMEOUT tries, setup phy again */
+       if (card->aneg_count > SPIDER_NET_ANEG_TIMEOUT) {
+
+               pr_debug("%s: link is down trying to bring it up\n",
+                        card->netdev->name);
+
+               switch (card->medium) {
+               case BCM54XX_COPPER:
+                       /* enable fiber with autonegotiation first */
+                       if (phy->def->ops->enable_fiber)
+                               phy->def->ops->enable_fiber(phy, 1);
+                       card->medium = BCM54XX_FIBER;
+                       break;
+
+               case BCM54XX_FIBER:
+                       /* fiber didn't come up, try to disable fiber autoneg */
+                       if (phy->def->ops->enable_fiber)
+                               phy->def->ops->enable_fiber(phy, 0);
+                       card->medium = BCM54XX_UNKNOWN;
+                       break;
+
+               case BCM54XX_UNKNOWN:
+                       /* copper, fiber with and without failed,
+                        * retry from beginning */
+                       spider_net_setup_aneg(card);
+                       card->medium = BCM54XX_COPPER;
+                       break;
+               }
+
+               card->aneg_count = 0;
+               mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+               return;
+       }
+
+       /* link still not up, try again later */
+       if (!(phy->def->ops->poll_link(phy))) {
+               card->aneg_count++;
+               mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+               return;
+       }
+
+       /* link came up, get abilities */
+       phy->def->ops->read_link(phy);
+
+       spider_net_write_reg(card, SPIDER_NET_GMACST,
+                            spider_net_read_reg(card, SPIDER_NET_GMACST));
+       spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4);
+
+       if (phy->speed == 1000)
+               spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001);
+       else
+               spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0);
+
+       card->aneg_count = 0;
+
+       pr_info("%s: link up, %i Mbps, %s-duplex %sautoneg.\n",
+               card->netdev->name, phy->speed,
+               phy->duplex == 1 ? "Full" : "Half",
+               phy->autoneg == 1 ? "" : "no ");
+
+       return;
+}
+
+/**
+ * spider_net_setup_phy - setup PHY
+ * @card: card structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * spider_net_setup_phy is used as part of spider_net_probe.
+ **/
+static int
+spider_net_setup_phy(struct spider_net_card *card)
+{
+       struct mii_phy *phy = &card->phy;
+
+       spider_net_write_reg(card, SPIDER_NET_GDTDMASEL,
+                            SPIDER_NET_DMASEL_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GPCCTRL,
+                            SPIDER_NET_PHY_CTRL_VALUE);
+
+       phy->dev = card->netdev;
+       phy->mdio_read = spider_net_read_phy;
+       phy->mdio_write = spider_net_write_phy;
+
+       for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) {
+               unsigned short id;
+               id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
+               if (id != 0x0000 && id != 0xffff) {
+                       if (!mii_phy_probe(phy, phy->mii_id)) {
+                               pr_info("Found %s.\n", phy->def->name);
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 /**
  * spider_net_workaround_rxramfull - work around firmware bug
  * @card: card structure
@@ -1909,19 +2179,15 @@ spider_net_stop(struct net_device *netdev)
 {
        struct spider_net_card *card = netdev_priv(netdev);
 
-       tasklet_kill(&card->rxram_full_tl);
-       netif_poll_disable(netdev);
+       napi_disable(&card->napi);
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
        del_timer_sync(&card->tx_timer);
+       del_timer_sync(&card->aneg_timer);
 
-       /* disable/mask all interrupts */
-       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
-       spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
-       spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
+       spider_net_disable_interrupts(card);
 
-       /* free_irq(netdev->irq, netdev);*/
-       free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev);
+       free_irq(netdev->irq, netdev);
 
        spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
                             SPIDER_NET_DMA_TX_FEND_VALUE);
@@ -1930,10 +2196,8 @@ spider_net_stop(struct net_device *netdev)
        spider_net_disable_rxdmac(card);
 
        /* release chains */
-       if (spin_trylock(&card->tx_chain.lock)) {
-               spider_net_release_tx_chain(card, 1);
-               spin_unlock(&card->tx_chain.lock);
-       }
+       spider_net_release_tx_chain(card, 1);
+       spider_net_free_rx_chain_contents(card);
 
        spider_net_free_chain(card, &card->tx_chain);
        spider_net_free_chain(card, &card->rx_chain);
@@ -1949,10 +2213,11 @@ spider_net_stop(struct net_device *netdev)
  * called as task when tx hangs, resets interface (if interface is up)
  */
 static void
-spider_net_tx_timeout_task(void *data)
+spider_net_tx_timeout_task(struct work_struct *work)
 {
-       struct net_device *netdev = data;
-       struct spider_net_card *card = netdev_priv(netdev);
+       struct spider_net_card *card =
+               container_of(work, struct spider_net_card, tx_timeout_task);
+       struct net_device *netdev = card->netdev;
 
        if (!(netdev->flags & IFF_UP))
                goto out;
@@ -1965,8 +2230,6 @@ spider_net_tx_timeout_task(void *data)
 
        if (spider_net_setup_phy(card))
                goto out;
-       if (spider_net_init_firmware(card))
-               goto out;
 
        spider_net_open(netdev);
        spider_net_kick_tx_dma(card);
@@ -1996,6 +2259,23 @@ spider_net_tx_timeout(struct net_device *netdev)
        card->spider_stats.tx_timeouts++;
 }
 
+static const struct net_device_ops spider_net_ops = {
+       .ndo_open               = spider_net_open,
+       .ndo_stop               = spider_net_stop,
+       .ndo_start_xmit         = spider_net_xmit,
+       .ndo_set_multicast_list = spider_net_set_multi,
+       .ndo_set_mac_address    = spider_net_set_mac,
+       .ndo_change_mtu         = spider_net_change_mtu,
+       .ndo_do_ioctl           = spider_net_do_ioctl,
+       .ndo_tx_timeout         = spider_net_tx_timeout,
+       .ndo_validate_addr      = eth_validate_addr,
+       /* HW VLAN */
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       /* poll controller */
+       .ndo_poll_controller    = spider_net_poll_controller,
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+};
+
 /**
  * spider_net_setup_netdev_ops - initialization of net_device operations
  * @netdev: net_device structure
@@ -2005,28 +2285,8 @@ spider_net_tx_timeout(struct net_device *netdev)
 static void
 spider_net_setup_netdev_ops(struct net_device *netdev)
 {
-       netdev->open = &spider_net_open;
-       netdev->stop = &spider_net_stop;
-       netdev->hard_start_xmit = &spider_net_xmit;
-       netdev->get_stats = &spider_net_get_stats;
-       netdev->set_multicast_list = &spider_net_set_multi;
-       netdev->set_mac_address = &spider_net_set_mac;
-       netdev->change_mtu = &spider_net_change_mtu;
-       netdev->do_ioctl = &spider_net_do_ioctl;
-       /* tx watchdog */
-       netdev->tx_timeout = &spider_net_tx_timeout;
+       netdev->netdev_ops = &spider_net_ops;
        netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
-       /* NAPI */
-       netdev->poll = &spider_net_poll;
-       netdev->weight = SPIDER_NET_NAPI_WEIGHT;
-       /* HW VLAN */
-       netdev->vlan_rx_register = &spider_net_vlan_rx_reg;
-       netdev->vlan_rx_add_vid = &spider_net_vlan_rx_add;
-       netdev->vlan_rx_kill_vid = &spider_net_vlan_rx_kill;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       /* poll controller */
-       netdev->poll_controller = &spider_net_poll_controller;
-#endif /* CONFIG_NET_POLL_CONTROLLER */
        /* ethtool ops */
        netdev->ethtool_ops = &spider_net_ethtool_ops;
 }
@@ -2048,51 +2308,55 @@ spider_net_setup_netdev(struct spider_net_card *card)
        struct sockaddr addr;
        const u8 *mac;
 
-       SET_MODULE_OWNER(netdev);
        SET_NETDEV_DEV(netdev, &card->pdev->dev);
 
        pci_set_drvdata(card->pdev, netdev);
 
-       card->rxram_full_tl.data = (unsigned long) card;
-       card->rxram_full_tl.func =
-               (void (*)(unsigned long)) spider_net_handle_rxram_full;
        init_timer(&card->tx_timer);
        card->tx_timer.function =
                (void (*)(unsigned long)) spider_net_cleanup_tx_ring;
        card->tx_timer.data = (unsigned long) card;
        netdev->irq = card->pdev->irq;
 
+       card->aneg_count = 0;
+       init_timer(&card->aneg_timer);
+       card->aneg_timer.function = spider_net_link_phy;
+       card->aneg_timer.data = (unsigned long) card;
+
        card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
 
-       card->tx_desc = tx_descriptors;
-       card->rx_desc = rx_descriptors;
+       netif_napi_add(netdev, &card->napi,
+                      spider_net_poll, SPIDER_NET_NAPI_WEIGHT);
 
        spider_net_setup_netdev_ops(netdev);
 
-       netdev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX;
+       netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX;
        /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
         *              NETIF_F_HW_VLAN_FILTER */
 
        netdev->irq = card->pdev->irq;
+       card->num_rx_ints = 0;
+       card->ignore_rx_ramfull = 0;
 
        dn = pci_device_to_OF_node(card->pdev);
        if (!dn)
                return -EIO;
 
-       mac = get_property(dn, "local-mac-address", NULL);
+       mac = of_get_property(dn, "local-mac-address", NULL);
        if (!mac)
                return -EIO;
        memcpy(addr.sa_data, mac, ETH_ALEN);
 
        result = spider_net_set_mac(netdev, &addr);
        if ((result) && (netif_msg_probe(card)))
-               pr_err("Failed to set MAC address: %i\n", result);
+               dev_err(&card->netdev->dev,
+                       "Failed to set MAC address: %i\n", result);
 
        result = register_netdev(netdev);
        if (result) {
                if (netif_msg_probe(card))
-                       pr_err("Couldn't register net_device: %i\n",
-                                 result);
+                       dev_err(&card->netdev->dev,
+                               "Couldn't register net_device: %i\n", result);
                return result;
        }
 
@@ -2116,9 +2380,8 @@ spider_net_alloc_card(void)
        struct spider_net_card *card;
        size_t alloc_size;
 
-       alloc_size = sizeof (*card) +
-               sizeof (struct spider_net_descr) * rx_descriptors +
-               sizeof (struct spider_net_descr) * tx_descriptors;
+       alloc_size = sizeof(struct spider_net_card) +
+          (tx_descriptors + rx_descriptors) * sizeof(struct spider_net_descr);
        netdev = alloc_etherdev(alloc_size);
        if (!netdev)
                return NULL;
@@ -2126,10 +2389,15 @@ spider_net_alloc_card(void)
        card = netdev_priv(netdev);
        card->netdev = netdev;
        card->msg_enable = SPIDER_NET_DEFAULT_MSG;
-       INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task, netdev);
+       INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task);
        init_waitqueue_head(&card->waitq);
        atomic_set(&card->tx_timeout_task_counter, 0);
 
+       card->rx_chain.num_desc = rx_descriptors;
+       card->rx_chain.ring = card->darray;
+       card->tx_chain.num_desc = tx_descriptors;
+       card->tx_chain.ring = card->darray + rx_descriptors;
+
        return card;
 }
 
@@ -2148,7 +2416,6 @@ spider_net_undo_pci_setup(struct spider_net_card *card)
 
 /**
  * spider_net_setup_pci_dev - sets up the device in terms of PCI operations
- * @card: card structure
  * @pdev: PCI device
  *
  * Returns the card structure or NULL if any errors occur
@@ -2166,17 +2433,19 @@ spider_net_setup_pci_dev(struct pci_dev *pdev)
        unsigned long mmio_start, mmio_len;
 
        if (pci_enable_device(pdev)) {
-               pr_err("Couldn't enable PCI device\n");
+               dev_err(&pdev->dev, "Couldn't enable PCI device\n");
                return NULL;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               pr_err("Couldn't find proper PCI device base address.\n");
+               dev_err(&pdev->dev,
+                       "Couldn't find proper PCI device base address.\n");
                goto out_disable_dev;
        }
 
        if (pci_request_regions(pdev, spider_net_driver_name)) {
-               pr_err("Couldn't obtain PCI resources, aborting.\n");
+               dev_err(&pdev->dev,
+                       "Couldn't obtain PCI resources, aborting.\n");
                goto out_disable_dev;
        }
 
@@ -2184,8 +2453,8 @@ spider_net_setup_pci_dev(struct pci_dev *pdev)
 
        card = spider_net_alloc_card();
        if (!card) {
-               pr_err("Couldn't allocate net_device structure, "
-                         "aborting.\n");
+               dev_err(&pdev->dev,
+                       "Couldn't allocate net_device structure, aborting.\n");
                goto out_release_regions;
        }
        card->pdev = pdev;
@@ -2199,7 +2468,8 @@ spider_net_setup_pci_dev(struct pci_dev *pdev)
        card->regs = ioremap(mmio_start, mmio_len);
 
        if (!card->regs) {
-               pr_err("Couldn't obtain PCI resources, aborting.\n");
+               dev_err(&pdev->dev,
+                       "Couldn't obtain PCI resources, aborting.\n");
                goto out_release_regions;
        }
 
@@ -2240,10 +2510,6 @@ spider_net_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (err)
                goto out_undo_pci;
 
-       err = spider_net_init_firmware(card);
-       if (err)
-               goto out_undo_pci;
-
        err = spider_net_setup_netdev(card);
        if (err)
                goto out_undo_pci;