igb: Add DMA Coalescing feature to driver
authorCarolyn Wyborny <carolyn.wyborny@intel.com>
Sat, 12 Mar 2011 04:43:54 +0000 (20:43 -0800)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 12 Mar 2011 12:09:55 +0000 (04:09 -0800)
This patch add DMA Coalescing which is a power-saving feature that
coalesces DMA writes in order to stay in a low-power state as much
as possible.  Feature is disabled by default.

Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/igb/e1000_defines.h
drivers/net/igb/e1000_regs.h
drivers/net/igb/igb.h
drivers/net/igb/igb_ethtool.c
drivers/net/igb/igb_main.c

index 97969ad8afefebf4b6e23aacf008b0a8295a8727..9bb192825893868bf3ee9786190bc9f01c57b628 100644 (file)
 #define E1000_TCTL_COLD   0x003ff000    /* collision distance */
 #define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
 
-/* Transmit Arbitration Count */
+/* DMA Coalescing register fields */
+#define E1000_DMACR_DMACWT_MASK         0x00003FFF /* DMA Coalescing
+                                                       * Watchdog Timer */
+#define E1000_DMACR_DMACTHR_MASK        0x00FF0000 /* DMA Coalescing Receive
+                                                       * Threshold */
+#define E1000_DMACR_DMACTHR_SHIFT       16
+#define E1000_DMACR_DMAC_LX_MASK        0x30000000 /* Lx when no PCIe
+                                                       * transactions */
+#define E1000_DMACR_DMAC_LX_SHIFT       28
+#define E1000_DMACR_DMAC_EN             0x80000000 /* Enable DMA Coalescing */
+
+#define E1000_DMCTXTH_DMCTTHR_MASK      0x00000FFF /* DMA Coalescing Transmit
+                                                       * Threshold */
+
+#define E1000_DMCTLX_TTLX_MASK          0x00000FFF /* Time to LX request */
+
+#define E1000_DMCRTRH_UTRESH_MASK       0x0007FFFF /* Receive Traffic Rate
+                                                       * Threshold */
+#define E1000_DMCRTRH_LRPRCW            0x80000000 /* Rcv packet rate in
+                                                       * current window */
+
+#define E1000_DMCCNT_CCOUNT_MASK        0x01FFFFFF /* DMA Coal Rcv Traffic
+                                                       * Current Cnt */
+
+#define E1000_FCRTC_RTH_COAL_MASK       0x0003FFF0 /* Flow ctrl Rcv Threshold
+                                                       * High val */
+#define E1000_FCRTC_RTH_COAL_SHIFT      4
+#define E1000_PCIEMISC_LX_DECISION      0x00000080 /* Lx power decision */
 
 /* SerDes Control */
 #define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
index b2f8e593da876761bc1da8f3f2835409e81746e5..ad77ed510d7c132810291ae15508f15d1a917aef 100644 (file)
 
 #define E1000_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
 
+/* DMA Coalescing registers */
+#define E1000_DMACR             0x02508 /* Control Register */
+#define E1000_DMCTXTH           0x03550 /* Transmit Threshold */
+#define E1000_DMCTLX            0x02514 /* Time to Lx Request */
+#define E1000_DMCRTRH           0x05DD0 /* Receive Packet Rate Threshold */
+#define E1000_DMCCNT            0x05DD4 /* Current Rx Count */
+#define E1000_FCRTC             0x02170 /* Flow Control Rx high watermark */
+#define E1000_PCIEMISC          0x05BB8 /* PCIE misc config register */
+
 /* TX Rate Limit Registers */
 #define E1000_RTTDQSEL 0x3604  /* Tx Desc Plane Queue Select - WO */
 #define E1000_RTTBCNRC 0x36B0  /* Tx BCN Rate-Scheduler Config - WO */
index bbc5ebfe254a040ebe9fc251b3c03cf7260b1175..1c687e298d5ef197dbf115815d59eb6518667a6c 100644 (file)
@@ -333,6 +333,12 @@ struct igb_adapter {
 #define IGB_FLAG_DCA_ENABLED       (1 << 1)
 #define IGB_FLAG_QUAD_PORT_A       (1 << 2)
 #define IGB_FLAG_QUEUE_PAIRS       (1 << 3)
+#define IGB_FLAG_DMAC              (1 << 4)
+
+/* DMA Coalescing defines */
+#define IGB_MIN_TXPBSIZE           20408
+#define IGB_TX_BUF_4096            4096
+#define IGB_DMCTLX_DCFLUSH_DIS     0x80000000  /* Disable DMA Coal Flush */
 
 #define IGB_82576_TSYNC_SHIFT 19
 #define IGB_82580_TSYNC_SHIFT 24
index df15a915bbeaca39b092c6de31ab48c31bd49fbf..d976733bbcc2de9cbf527fe56c421c18f22172c6 100644 (file)
@@ -2009,6 +2009,12 @@ static int igb_set_coalesce(struct net_device *netdev,
        if ((adapter->flags & IGB_FLAG_QUEUE_PAIRS) && ec->tx_coalesce_usecs)
                return -EINVAL;
 
+       /* If ITR is disabled, disable DMAC */
+       if (ec->rx_coalesce_usecs == 0) {
+               if (adapter->flags & IGB_FLAG_DMAC)
+                       adapter->flags &= ~IGB_FLAG_DMAC;
+       }
+
        /* convert to rate of irq's per second */
        if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3)
                adapter->rx_itr_setting = ec->rx_coalesce_usecs;
index 8c6af11d93a639b17286fa7463713a02a3fb6dcc..49476f7738250841b63534be9a61ebb5a96fd340 100644 (file)
@@ -1674,7 +1674,58 @@ void igb_reset(struct igb_adapter *adapter)
 
        if (hw->mac.ops.init_hw(hw))
                dev_err(&pdev->dev, "Hardware Error\n");
+       if (hw->mac.type > e1000_82580) {
+               if (adapter->flags & IGB_FLAG_DMAC) {
+                       u32 reg;
 
+                       /*
+                        * DMA Coalescing high water mark needs to be higher
+                        * than * the * Rx threshold.  The Rx threshold is
+                        * currently * pba - 6, so we * should use a high water
+                        * mark of pba * - 4. */
+                       hwm = (pba - 4) << 10;
+
+                       reg = (((pba-6) << E1000_DMACR_DMACTHR_SHIFT)
+                              & E1000_DMACR_DMACTHR_MASK);
+
+                       /* transition to L0x or L1 if available..*/
+                       reg |= (E1000_DMACR_DMAC_EN | E1000_DMACR_DMAC_LX_MASK);
+
+                       /* watchdog timer= +-1000 usec in 32usec intervals */
+                       reg |= (1000 >> 5);
+                       wr32(E1000_DMACR, reg);
+
+                       /* no lower threshold to disable coalescing(smart fifb)
+                        * -UTRESH=0*/
+                       wr32(E1000_DMCRTRH, 0);
+
+                       /* set hwm to PBA -  2 * max frame size */
+                       wr32(E1000_FCRTC, hwm);
+
+                       /*
+                        * This sets the time to wait before requesting tran-
+                        * sition to * low power state to number of usecs needed
+                        * to receive 1 512 * byte frame at gigabit line rate
+                        */
+                       reg = rd32(E1000_DMCTLX);
+                       reg |= IGB_DMCTLX_DCFLUSH_DIS;
+
+                       /* Delay 255 usec before entering Lx state. */
+                       reg |= 0xFF;
+                       wr32(E1000_DMCTLX, reg);
+
+                       /* free space in Tx packet buffer to wake from DMAC */
+                       wr32(E1000_DMCTXTH,
+                            (IGB_MIN_TXPBSIZE -
+                            (IGB_TX_BUF_4096 + adapter->max_frame_size))
+                            >> 6);
+
+                       /* make low power state decision controlled by DMAC */
+                       reg = rd32(E1000_PCIEMISC);
+                       reg |= E1000_PCIEMISC_LX_DECISION;
+                       wr32(E1000_PCIEMISC, reg);
+               } /* end if IGB_FLAG_DMAC set */
+       }
        if (hw->mac.type == e1000_82580) {
                u32 reg = rd32(E1000_PCIEMISC);
                wr32(E1000_PCIEMISC,
@@ -2157,6 +2208,9 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter)
                        random_ether_addr(mac_addr);
                        igb_set_vf_mac(adapter, i, mac_addr);
                }
+               /* DMA Coalescing is not supported in IOV mode. */
+               if (adapter->flags & IGB_FLAG_DMAC)
+                       adapter->flags &= ~IGB_FLAG_DMAC;
        }
 #endif /* CONFIG_PCI_IOV */
 }
@@ -2331,6 +2385,9 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
        /* Explicitly disable IRQ since the NIC can be in any state. */
        igb_irq_disable(adapter);
 
+       if (hw->mac.type == e1000_i350)
+               adapter->flags &= ~IGB_FLAG_DMAC;
+
        set_bit(__IGB_DOWN, &adapter->state);
        return 0;
 }