Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[deliverable/linux.git] / drivers / net / ethernet / realtek / 8139cp.c
index 609125a249d9484835f77fd445e6a8ba32e299db..cb6fc5a743cae91cde7484ef94d1e329928df88b 100644 (file)
@@ -648,6 +648,7 @@ static void cp_tx (struct cp_private *cp)
 {
        unsigned tx_head = cp->tx_head;
        unsigned tx_tail = cp->tx_tail;
+       unsigned bytes_compl = 0, pkts_compl = 0;
 
        while (tx_tail != tx_head) {
                struct cp_desc *txd = cp->tx_ring + tx_tail;
@@ -666,6 +667,9 @@ static void cp_tx (struct cp_private *cp)
                                 le32_to_cpu(txd->opts1) & 0xffff,
                                 PCI_DMA_TODEVICE);
 
+               bytes_compl += skb->len;
+               pkts_compl++;
+
                if (status & LastFrag) {
                        if (status & (TxError | TxFIFOUnder)) {
                                netif_dbg(cp, tx_err, cp->dev,
@@ -697,6 +701,7 @@ static void cp_tx (struct cp_private *cp)
 
        cp->tx_tail = tx_tail;
 
+       netdev_completed_queue(cp->dev, pkts_compl, bytes_compl);
        if (TX_BUFFS_AVAIL(cp) > (MAX_SKB_FRAGS + 1))
                netif_wake_queue(cp->dev);
 }
@@ -843,6 +848,8 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
                wmb();
        }
        cp->tx_head = entry;
+
+       netdev_sent_queue(dev, skb->len);
        netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
                  entry, skb->len);
        if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
@@ -937,6 +944,8 @@ static void cp_stop_hw (struct cp_private *cp)
 
        cp->rx_tail = 0;
        cp->tx_head = cp->tx_tail = 0;
+
+       netdev_reset_queue(cp->dev);
 }
 
 static void cp_reset_hw (struct cp_private *cp)
@@ -957,8 +966,38 @@ static void cp_reset_hw (struct cp_private *cp)
 
 static inline void cp_start_hw (struct cp_private *cp)
 {
+       dma_addr_t ring_dma;
+
        cpw16(CpCmd, cp->cpcmd);
+
+       /*
+        * These (at least TxRingAddr) need to be configured after the
+        * corresponding bits in CpCmd are enabled. Datasheet v1.6 ยง6.33
+        * (C+ Command Register) recommends that these and more be configured
+        * *after* the [RT]xEnable bits in CpCmd are set. And on some hardware
+        * it's been observed that the TxRingAddr is actually reset to garbage
+        * when C+ mode Tx is enabled in CpCmd.
+        */
+       cpw32_f(HiTxRingAddr, 0);
+       cpw32_f(HiTxRingAddr + 4, 0);
+
+       ring_dma = cp->ring_dma;
+       cpw32_f(RxRingAddr, ring_dma & 0xffffffff);
+       cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16);
+
+       ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE;
+       cpw32_f(TxRingAddr, ring_dma & 0xffffffff);
+       cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16);
+
+       /*
+        * Strictly speaking, the datasheet says this should be enabled
+        * *before* setting the descriptor addresses. But what, then, would
+        * prevent it from doing DMA to random unconfigured addresses?
+        * This variant appears to work fine.
+        */
        cpw8(Cmd, RxOn | TxOn);
+
+       netdev_reset_queue(cp->dev);
 }
 
 static void cp_enable_irq(struct cp_private *cp)
@@ -969,7 +1008,6 @@ static void cp_enable_irq(struct cp_private *cp)
 static void cp_init_hw (struct cp_private *cp)
 {
        struct net_device *dev = cp->dev;
-       dma_addr_t ring_dma;
 
        cp_reset_hw(cp);
 
@@ -992,17 +1030,6 @@ static void cp_init_hw (struct cp_private *cp)
 
        cpw8(Config5, cpr8(Config5) & PMEStatus);
 
-       cpw32_f(HiTxRingAddr, 0);
-       cpw32_f(HiTxRingAddr + 4, 0);
-
-       ring_dma = cp->ring_dma;
-       cpw32_f(RxRingAddr, ring_dma & 0xffffffff);
-       cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16);
-
-       ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE;
-       cpw32_f(TxRingAddr, ring_dma & 0xffffffff);
-       cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16);
-
        cpw16(MultiIntr, 0);
 
        cpw8_f(Cfg9346, Cfg9346_Lock);
@@ -1197,18 +1224,16 @@ static void cp_tx_timeout(struct net_device *dev)
        cp_clean_rings(cp);
        rc = cp_init_rings(cp);
        cp_start_hw(cp);
+       cp_enable_irq(cp);
 
        netif_wake_queue(dev);
 
        spin_unlock_irqrestore(&cp->lock, flags);
 }
 
-#ifdef BROKEN
 static int cp_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct cp_private *cp = netdev_priv(dev);
-       int rc;
-       unsigned long flags;
 
        /* check for invalid MTU, according to hardware limits */
        if (new_mtu < CP_MIN_MTU || new_mtu > CP_MAX_MTU)
@@ -1221,22 +1246,12 @@ static int cp_change_mtu(struct net_device *dev, int new_mtu)
                return 0;
        }
 
-       spin_lock_irqsave(&cp->lock, flags);
-
-       cp_stop_hw(cp);                 /* stop h/w and free rings */
-       cp_clean_rings(cp);
-
+       /* network IS up, close it, reset MTU, and come up again. */
+       cp_close(dev);
        dev->mtu = new_mtu;
-       cp_set_rxbufsize(cp);           /* set new rx buf size */
-
-       rc = cp_init_rings(cp);         /* realloc and restart h/w */
-       cp_start_hw(cp);
-
-       spin_unlock_irqrestore(&cp->lock, flags);
-
-       return rc;
+       cp_set_rxbufsize(cp);
+       return cp_open(dev);
 }
-#endif /* BROKEN */
 
 static const char mii_2_8139_map[8] = {
        BasicModeCtrl,
@@ -1812,9 +1827,7 @@ static const struct net_device_ops cp_netdev_ops = {
        .ndo_start_xmit         = cp_start_xmit,
        .ndo_tx_timeout         = cp_tx_timeout,
        .ndo_set_features       = cp_set_features,
-#ifdef BROKEN
        .ndo_change_mtu         = cp_change_mtu,
-#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = cp_poll_controller,
This page took 0.027243 seconds and 5 git commands to generate.