ixgbe: add ipsec engine start and stop routines
authorShannon Nelson <shannon.nelson@oracle.com>
Tue, 19 Dec 2017 23:59:55 +0000 (15:59 -0800)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Tue, 23 Jan 2018 17:08:57 +0000 (09:08 -0800)
Add in the code for running and stopping the hardware ipsec
encryption/decryption engine.  It is good to keep the engine
off when not in use in order to save on the power draw.

Signed-off-by: Shannon Nelson <shannon.nelson@oracle.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c

index c1228cf..d478730 100644 (file)
@@ -151,6 +151,147 @@ static void ixgbe_ipsec_clear_hw_tables(struct ixgbe_adapter *adapter)
        }
 }
 
+/**
+ * ixgbe_ipsec_stop_data
+ * @adapter: board private structure
+ **/
+static void ixgbe_ipsec_stop_data(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       bool link = adapter->link_up;
+       u32 t_rdy, r_rdy;
+       u32 limit;
+       u32 reg;
+
+       /* halt data paths */
+       reg = IXGBE_READ_REG(hw, IXGBE_SECTXCTRL);
+       reg |= IXGBE_SECTXCTRL_TX_DIS;
+       IXGBE_WRITE_REG(hw, IXGBE_SECTXCTRL, reg);
+
+       reg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
+       reg |= IXGBE_SECRXCTRL_RX_DIS;
+       IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, reg);
+
+       IXGBE_WRITE_FLUSH(hw);
+
+       /* If the tx fifo doesn't have link, but still has data,
+        * we can't clear the tx sec block.  Set the MAC loopback
+        * before block clear
+        */
+       if (!link) {
+               reg = IXGBE_READ_REG(hw, IXGBE_MACC);
+               reg |= IXGBE_MACC_FLU;
+               IXGBE_WRITE_REG(hw, IXGBE_MACC, reg);
+
+               reg = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+               reg |= IXGBE_HLREG0_LPBK;
+               IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg);
+
+               IXGBE_WRITE_FLUSH(hw);
+               mdelay(3);
+       }
+
+       /* wait for the paths to empty */
+       limit = 20;
+       do {
+               mdelay(10);
+               t_rdy = IXGBE_READ_REG(hw, IXGBE_SECTXSTAT) &
+                       IXGBE_SECTXSTAT_SECTX_RDY;
+               r_rdy = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT) &
+                       IXGBE_SECRXSTAT_SECRX_RDY;
+       } while (!t_rdy && !r_rdy && limit--);
+
+       /* undo loopback if we played with it earlier */
+       if (!link) {
+               reg = IXGBE_READ_REG(hw, IXGBE_MACC);
+               reg &= ~IXGBE_MACC_FLU;
+               IXGBE_WRITE_REG(hw, IXGBE_MACC, reg);
+
+               reg = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+               reg &= ~IXGBE_HLREG0_LPBK;
+               IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg);
+
+               IXGBE_WRITE_FLUSH(hw);
+       }
+}
+
+/**
+ * ixgbe_ipsec_stop_engine
+ * @adapter: board private structure
+ **/
+static void ixgbe_ipsec_stop_engine(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 reg;
+
+       ixgbe_ipsec_stop_data(adapter);
+
+       /* disable Rx and Tx SA lookup */
+       IXGBE_WRITE_REG(hw, IXGBE_IPSTXIDX, 0);
+       IXGBE_WRITE_REG(hw, IXGBE_IPSRXIDX, 0);
+
+       /* disable the Rx and Tx engines and full packet store-n-forward */
+       reg = IXGBE_READ_REG(hw, IXGBE_SECTXCTRL);
+       reg |= IXGBE_SECTXCTRL_SECTX_DIS;
+       reg &= ~IXGBE_SECTXCTRL_STORE_FORWARD;
+       IXGBE_WRITE_REG(hw, IXGBE_SECTXCTRL, reg);
+
+       reg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
+       reg |= IXGBE_SECRXCTRL_SECRX_DIS;
+       IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, reg);
+
+       /* restore the "tx security buffer almost full threshold" to 0x250 */
+       IXGBE_WRITE_REG(hw, IXGBE_SECTXBUFFAF, 0x250);
+
+       /* Set minimum IFG between packets back to the default 0x1 */
+       reg = IXGBE_READ_REG(hw, IXGBE_SECTXMINIFG);
+       reg = (reg & 0xfffffff0) | 0x1;
+       IXGBE_WRITE_REG(hw, IXGBE_SECTXMINIFG, reg);
+
+       /* final set for normal (no ipsec offload) processing */
+       IXGBE_WRITE_REG(hw, IXGBE_SECTXCTRL, IXGBE_SECTXCTRL_SECTX_DIS);
+       IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, IXGBE_SECRXCTRL_SECRX_DIS);
+
+       IXGBE_WRITE_FLUSH(hw);
+}
+
+/**
+ * ixgbe_ipsec_start_engine
+ * @adapter: board private structure
+ *
+ * NOTE: this increases power consumption whether being used or not
+ **/
+static void ixgbe_ipsec_start_engine(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 reg;
+
+       ixgbe_ipsec_stop_data(adapter);
+
+       /* Set minimum IFG between packets to 3 */
+       reg = IXGBE_READ_REG(hw, IXGBE_SECTXMINIFG);
+       reg = (reg & 0xfffffff0) | 0x3;
+       IXGBE_WRITE_REG(hw, IXGBE_SECTXMINIFG, reg);
+
+       /* Set "tx security buffer almost full threshold" to 0x15 so that the
+        * almost full indication is generated only after buffer contains at
+        * least an entire jumbo packet.
+        */
+       reg = IXGBE_READ_REG(hw, IXGBE_SECTXBUFFAF);
+       reg = (reg & 0xfffffc00) | 0x15;
+       IXGBE_WRITE_REG(hw, IXGBE_SECTXBUFFAF, reg);
+
+       /* restart the data paths by clearing the DISABLE bits */
+       IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, 0);
+       IXGBE_WRITE_REG(hw, IXGBE_SECTXCTRL, IXGBE_SECTXCTRL_STORE_FORWARD);
+
+       /* enable Rx and Tx SA lookup */
+       IXGBE_WRITE_REG(hw, IXGBE_IPSTXIDX, IXGBE_RXTXIDX_IPS_EN);
+       IXGBE_WRITE_REG(hw, IXGBE_IPSRXIDX, IXGBE_RXTXIDX_IPS_EN);
+
+       IXGBE_WRITE_FLUSH(hw);
+}
+
 /**
  * ixgbe_init_ipsec_offload - initialize security registers for IPSec operation
  * @adapter: board private structure
@@ -158,4 +299,5 @@ static void ixgbe_ipsec_clear_hw_tables(struct ixgbe_adapter *adapter)
 void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter)
 {
        ixgbe_ipsec_clear_hw_tables(adapter);
+       ixgbe_ipsec_stop_engine(adapter);
 }