[Intel-wired-lan] [next-queue 02/10] ixgbe: add ipsec register access routines

Alexander Duyck alexander.duyck at gmail.com
Thu Dec 7 16:02:39 UTC 2017


On Wed, Dec 6, 2017 at 9:43 PM, Shannon Nelson
<shannon.nelson at oracle.com> wrote:
> Thanks, Alex, for your detailed comments, I do appreciate the time and
> thought you put into them.
>
> Responses below...
>
> sln
>
> On 12/5/2017 8:56 AM, Alexander Duyck wrote:
>>
>> On Mon, Dec 4, 2017 at 9:35 PM, Shannon Nelson
>> <shannon.nelson at oracle.com> wrote:
>>>
>>> Add a few routines to make access to the ipsec registers just a little
>>> easier, and throw in the beginnings of an initialization.
>>>
>>> Signed-off-by: Shannon Nelson <shannon.nelson at oracle.com>
>>> ---
>>>   drivers/net/ethernet/intel/ixgbe/Makefile      |   1 +
>>>   drivers/net/ethernet/intel/ixgbe/ixgbe.h       |   6 +
>>>   drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c | 157
>>> +++++++++++++++++++++++++
>>>   drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h |  50 ++++++++
>>>   drivers/net/ethernet/intel/ixgbe/ixgbe_main.c  |   1 +
>>>   5 files changed, 215 insertions(+)
>>>   create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
>>>   create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h
>>>
>>> diff --git a/drivers/net/ethernet/intel/ixgbe/Makefile
>>> b/drivers/net/ethernet/intel/ixgbe/Makefile
>>> index 35e6fa6..8319465 100644
>>> --- a/drivers/net/ethernet/intel/ixgbe/Makefile
>>> +++ b/drivers/net/ethernet/intel/ixgbe/Makefile
>>> @@ -42,3 +42,4 @@ ixgbe-$(CONFIG_IXGBE_DCB) +=  ixgbe_dcb.o
>>> ixgbe_dcb_82598.o \
>>>   ixgbe-$(CONFIG_IXGBE_HWMON) += ixgbe_sysfs.o
>>>   ixgbe-$(CONFIG_DEBUG_FS) += ixgbe_debugfs.o
>>>   ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o
>>> +ixgbe-$(CONFIG_XFRM_OFFLOAD) += ixgbe_ipsec.o
>>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
>>> b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
>>> index dd55787..1e11462 100644
>>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
>>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
>>> @@ -52,6 +52,7 @@
>>>   #ifdef CONFIG_IXGBE_DCA
>>>   #include <linux/dca.h>
>>>   #endif
>>> +#include "ixgbe_ipsec.h"
>>>
>>>   #include <net/busy_poll.h>
>>>
>>> @@ -1001,4 +1002,9 @@ void ixgbe_store_key(struct ixgbe_adapter
>>> *adapter);
>>>   void ixgbe_store_reta(struct ixgbe_adapter *adapter);
>>>   s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg,
>>>                         u32 adv_sym, u32 adv_asm, u32 lp_sym, u32
>>> lp_asm);
>>> +#ifdef CONFIG_XFRM_OFFLOAD
>>> +void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter);
>>> +#else
>>> +static inline void ixgbe_init_ipsec_offload(struct ixgbe_adapter
>>> *adapter) { };
>>> +#endif /* CONFIG_XFRM_OFFLOAD */
>>>   #endif /* _IXGBE_H_ */
>>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
>>> b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
>>> new file mode 100644
>>> index 0000000..14dd011
>>> --- /dev/null
>>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
>>> @@ -0,0 +1,157 @@
>>>
>>> +/*******************************************************************************
>>> + *
>>> + * Intel 10 Gigabit PCI Express Linux driver
>>> + * Copyright(c) 2017 Oracle and/or its affiliates. All rights reserved.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> it
>>> + * under the terms and conditions of the GNU General Public License,
>>> + * version 2, as published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope it will be useful, but
>>> WITHOUT
>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>> for
>>> + * more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> along with
>>> + * this program.  If not, see <http://www.gnu.org/licenses/>.
>>> + *
>>> + * The full GNU General Public License is included in this distribution
>>> in
>>> + * the file called "COPYING".
>>> + *
>>> + * Contact Information:
>>> + * Linux NICS <linux.nics at intel.com>
>>> + * e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
>>> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR
>>> 97124-6497
>>> + *
>>> +
>>> ******************************************************************************/
>>> +
>>> +#include "ixgbe.h"
>>> +
>>> +/**
>>> + * ixgbe_ipsec_set_tx_sa - set the Tx SA registers
>>> + * @hw: hw specific details
>>> + * @idx: register index to write
>>> + * @key: key byte array
>>> + * @salt: salt bytes
>>> + **/
>>> +static void ixgbe_ipsec_set_tx_sa(struct ixgbe_hw *hw, u16 idx,
>>> +                                 u32 key[], u32 salt)
>>> +{
>>> +       u32 reg;
>>> +       int i;
>>> +
>>> +       for (i = 0; i < 4; i++)
>>> +               IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(i),
>>> cpu_to_be32(key[3-i]));
>>> +       IXGBE_WRITE_REG(hw, IXGBE_IPSTXSALT, cpu_to_be32(salt));
>>> +       IXGBE_WRITE_FLUSH(hw);
>>> +
>>> +       reg = IXGBE_READ_REG(hw, IXGBE_IPSTXIDX);
>>> +       reg &= IXGBE_RXTXIDX_IPS_EN;
>>> +       reg |= idx << 3 | IXGBE_RXTXIDX_IDX_WRITE;
>>> +       IXGBE_WRITE_REG(hw, IXGBE_IPSTXIDX, reg);
>>> +       IXGBE_WRITE_FLUSH(hw);
>>> +}
>>> +
>>
>>
>> So there are a few things here to unpack.
>>
>> The first is the carry-forward of the IPS bit. I'm not sure that is
>> the best way to go. Do we really expect to be updating SA values if
>> IPsec offload is not enabled?
>
>
> In order to save on energy, we don't enable the engine until we have the
> first SA successfully stored in the tables, so the enable bit will be off
> for that one.
>
> Also, the datasheet specifically says for the Rx table "Software should not
> make changes in the Rx SA tables while changing the IPSEC_EN bit." I figured
> I'd use the same method on both tables for consistency.
>
>> If so we may just want to carry a bit
>> flag somewhere in the ixgbe_hw struct indicating if Tx IPsec offload
>> is enabled and use that to determine the value for this bit.
>>
>> Also we should probably replace "3" with a value indicating that it is
>> the SA index shift.
>
>
> Sure, that would be good.
>
>>
>> Also technically the WRITE_FLUSH isn't needed if you are doing a PCIe
>> read anyway to get IPSTXIDX.
>
>
> That's from having to be very fastidious about these reads/writes/flushes
> before the engine actually worked for me.  I could spend time taking them
> out and testing each change again, but they aren't in a fast path, so I'm
> really not worried about it.
>
>
>>
>>> +/**
>>> + * ixgbe_ipsec_set_rx_item - set an Rx table item
>>> + * @hw: hw specific details
>>> + * @idx: register index to write
>>> + * @tbl: table selector
>>> + *
>>> + * Trigger the device to store into a particular Rx table the
>>> + * data that has already been loaded into the input register
>>> + **/
>>> +static void ixgbe_ipsec_set_rx_item(struct ixgbe_hw *hw, u16 idx, u32
>>> tbl)
>>> +{
>>> +       u32 reg;
>>> +
>>> +       reg = IXGBE_READ_REG(hw, IXGBE_IPSRXIDX);
>>> +       reg &= IXGBE_RXTXIDX_IPS_EN;
>>> +       reg |= tbl | idx << 3 | IXGBE_RXTXIDX_IDX_WRITE;
>>> +       IXGBE_WRITE_REG(hw, IXGBE_IPSRXIDX, reg);
>>> +       IXGBE_WRITE_FLUSH(hw);
>>> +}
>>> +
>>
>>
>> The Rx version of this gets a bit trickier since the datasheet
>> actually indicates there are a few different types of tables that can
>> be indexed via this. Also why is the tbl value not being shifted? It
>> seems like it should be shifted by 1 to avoid overwriting the IPS_EN
>> bit. Really I would like to see the tbl value converted to an enum and
>> shifted by 1 in order to generate the table reference.
>
>
> I would have done this, but we can't use an enum shifted bit because the
> field values are 01, 10, and 11.  I used the direct 2, 4, and 6 values
> rather than shifting by one, but I can reset them and shift by 1.

I didn't mean 1 << enum I was referring to enum << 1. Right now you
can be given a table value of 3 if somebody incorrectly used the
function and the side effect is that it overwrites the enable bit.

>>
>> Here the "3" is a table index. It might be nice to call that out with
>> a name instead of using the magic number.
>
>
> Yep
>
>
>>
>>> +/**
>>> + * ixgbe_ipsec_set_rx_sa - set up the register bits to save SA info
>>> + * @hw: hw specific details
>>> + * @idx: register index to write
>>> + * @spi: security parameter index
>>> + * @key: key byte array
>>> + * @salt: salt bytes
>>> + * @mode: rx decrypt control bits
>>> + * @ip_idx: index into IP table for related IP address
>>> + **/
>>> +static void ixgbe_ipsec_set_rx_sa(struct ixgbe_hw *hw, u16 idx, __be32
>>> spi,
>>> +                                 u32 key[], u32 salt, u32 mode, u32
>>> ip_idx)
>>> +{
>>> +       int i;
>>> +
>>> +       /* store the SPI (in bigendian) and IPidx */
>>> +       IXGBE_WRITE_REG(hw, IXGBE_IPSRXSPI, spi);
>>> +       IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPIDX, ip_idx);
>>> +       IXGBE_WRITE_FLUSH(hw);
>>> +
>>> +       ixgbe_ipsec_set_rx_item(hw, idx, IXGBE_RXIDX_TBL_SPI);
>>> +
>>> +       /* store the key, salt, and mode */
>>> +       for (i = 0; i < 4; i++)
>>> +               IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(i),
>>> cpu_to_be32(key[3-i]));
>>> +       IXGBE_WRITE_REG(hw, IXGBE_IPSRXSALT, cpu_to_be32(salt));
>>> +       IXGBE_WRITE_REG(hw, IXGBE_IPSRXMOD, mode);
>>> +       IXGBE_WRITE_FLUSH(hw);
>>> +
>>> +       ixgbe_ipsec_set_rx_item(hw, idx, IXGBE_RXIDX_TBL_KEY);
>>> +}
>>
>>
>> Is there any reason why you could write the SPI, key, salt, and mode,
>> then flush, and trigger the writes via the IPSRXIDX? Just wondering
>> since it would likely save you a few cycles avoiding PCIe bus stalls.
>
>
> See note above about religiously flushing everything to make a persnickety
> chip work.

I get the flushing. What I am saying is that as far as I can tell the
SPI, salt, and mode don't overlap so you could update all 3, flush,
and then call set_rx_item twice.

>>
>>
>>> +
>>> +/**
>>> + * ixgbe_ipsec_set_rx_ip - set up the register bits to save SA IP addr
>>> info
>>> + * @hw: hw specific details
>>> + * @idx: register index to write
>>> + * @addr: IP address byte array
>>> + **/
>>> +static void ixgbe_ipsec_set_rx_ip(struct ixgbe_hw *hw, u16 idx, u32
>>> addr[])
>>> +{
>>> +       int i;
>>> +
>>> +       /* store the ip address */
>>> +       for (i = 0; i < 4; i++)
>>> +               IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(i), addr[i]);
>>> +       IXGBE_WRITE_FLUSH(hw);
>>> +
>>> +       ixgbe_ipsec_set_rx_item(hw, idx, IXGBE_RXIDX_TBL_IP);
>>> +}
>>> +
>>
>>
>> This piece is kind of confusing. I would suggest storing the address
>> as a __be32 pointer instead of a u32 array. That way you start with
>> either an IPv6 or an IPv4 address at offset 0 instead of the way the
>> hardware is defined which has you writing it at either 0 or 3
>> depending on if the address is IPv6 or IPv4.
>
>
> Using a __be32 rather than u32 is fine here, it doesn't make much
> difference.
>
> If I understand your suggestion correctly, we would also need an additional
> function parameter to tell us if we were pointing to an ipv6 or ipv4
> address.  Since the driver's SW tables are modeling the HW, I think it is
> simpler to leave it in the array.

Actually I am not too concerned about needing a flag, but the __be32
usage addresses another problem. If I am not mistaken in order to
store an IPv6 value you will have to write addr[3] to IPADDR(0) and so
forth since the hardware is storing the IPv6 address as little endian.
So if you store the IPv4 address in addr[0] as a __be32 value and
leave the rest as zero you should get the correct ordering in either
setup when you store either IPv6 or IPv4 values.

>
>>
>>> +/**
>>> + * ixgbe_ipsec_clear_hw_tables - because some tables don't get cleared
>>> on reset
>>> + * @adapter: board private structure
>>> + **/
>>> +void ixgbe_ipsec_clear_hw_tables(struct ixgbe_adapter *adapter)
>>> +{
>>> +       struct ixgbe_hw *hw = &adapter->hw;
>>> +       u32 buf[4] = {0, 0, 0, 0};
>>> +       u16 idx;
>>> +
>>> +       /* disable Rx and Tx SA lookup */
>>> +       IXGBE_WRITE_REG(hw, IXGBE_IPSRXIDX, 0);
>>> +       IXGBE_WRITE_REG(hw, IXGBE_IPSTXIDX, 0);
>>> +
>>> +       /* scrub the tables */
>>> +       for (idx = 0; idx < IXGBE_IPSEC_MAX_SA_COUNT; idx++)
>>> +               ixgbe_ipsec_set_tx_sa(hw, idx, buf, 0);
>>> +
>>> +       for (idx = 0; idx < IXGBE_IPSEC_MAX_SA_COUNT; idx++)
>>> +               ixgbe_ipsec_set_rx_sa(hw, idx, 0, buf, 0, 0, 0);
>>> +
>>> +       for (idx = 0; idx < IXGBE_IPSEC_MAX_RX_IP_COUNT; idx++)
>>> +               ixgbe_ipsec_set_rx_ip(hw, idx, buf);
>>> +}
>>> +
>>> +/**
>>> + * ixgbe_init_ipsec_offload - initialize security registers for IPSec
>>> operation
>>> + * @adapter: board private structure
>>> + **/
>>> +void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter)
>>> +{
>>> +       ixgbe_ipsec_clear_hw_tables(adapter);
>>> +}
>>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h
>>> b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h
>>> new file mode 100644
>>> index 0000000..017b13f
>>> --- /dev/null
>>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h
>>> @@ -0,0 +1,50 @@
>>>
>>> +/*******************************************************************************
>>> +
>>> +  Intel 10 Gigabit PCI Express Linux driver
>>> +  Copyright(c) 2017 Oracle and/or its affiliates. All rights reserved.
>>> +
>>> +  This program is free software; you can redistribute it and/or modify
>>> it
>>> +  under the terms and conditions of the GNU General Public License,
>>> +  version 2, as published by the Free Software Foundation.
>>> +
>>> +  This program is distributed in the hope it will be useful, but WITHOUT
>>> +  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>> +  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>> for
>>> +  more details.
>>> +
>>> +  You should have received a copy of the GNU General Public License
>>> along with
>>> +  this program.  If not, see <http://www.gnu.org/licenses/>.
>>> +
>>> +  The full GNU General Public License is included in this distribution
>>> in
>>> +  the file called "COPYING".
>>> +
>>> +  Contact Information:
>>> +  Linux NICS <linux.nics at intel.com>
>>> +  e1000-devel Mailing List <e1000-devel at lists.sourceforge.net>
>>> +  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR
>>> 97124-6497
>>> +
>>>
>>> +*******************************************************************************/
>>> +
>>> +#ifndef _IXGBE_IPSEC_H_
>>> +#define _IXGBE_IPSEC_H_
>>> +
>>> +#define IXGBE_IPSEC_MAX_SA_COUNT       1024
>>> +#define IXGBE_IPSEC_MAX_RX_IP_COUNT    128
>>> +#define IXGBE_IPSEC_BASE_RX_INDEX      IXGBE_IPSEC_MAX_SA_COUNT
>>> +#define IXGBE_IPSEC_BASE_TX_INDEX      (IXGBE_IPSEC_MAX_SA_COUNT * 2)
>>> +
>>> +#define IXGBE_RXTXIDX_IPS_EN           0x00000001
>>> +#define IXGBE_RXIDX_TBL_MASK           0x00000006
>>> +#define IXGBE_RXIDX_TBL_IP             0x00000002
>>> +#define IXGBE_RXIDX_TBL_SPI            0x00000004
>>> +#define IXGBE_RXIDX_TBL_KEY            0x00000006
>>
>>
>> You might look at converting these table entries into an enum and add
>> a shift value. It will make things much easier to read.
>>
>>> +#define IXGBE_RXTXIDX_IDX_MASK         0x00001ff8
>>> +#define IXGBE_RXTXIDX_IDX_READ         0x40000000
>>> +#define IXGBE_RXTXIDX_IDX_WRITE                0x80000000
>>> +
>>> +#define IXGBE_RXMOD_VALID              0x00000001
>>> +#define IXGBE_RXMOD_PROTO_ESP          0x00000004
>>> +#define IXGBE_RXMOD_DECRYPT            0x00000008
>>> +#define IXGBE_RXMOD_IPV6               0x00000010
>>> +
>>> +#endif /* _IXGBE_IPSEC_H_ */
>>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>>> b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>>> index 6d5f31e..51fb3cf 100644
>>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>>> @@ -10327,6 +10327,7 @@ static int ixgbe_probe(struct pci_dev *pdev,
>>> const struct pci_device_id *ent)
>>>                                           NETIF_F_FCOE_MTU;
>>>          }
>>>   #endif /* IXGBE_FCOE */
>>> +       ixgbe_init_ipsec_offload(adapter);
>>>
>>>          if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)
>>>                  netdev->hw_features |= NETIF_F_LRO;
>>> --
>>> 2.7.4
>>>
>>> _______________________________________________
>>> Intel-wired-lan mailing list
>>> Intel-wired-lan at osuosl.org
>>> https://lists.osuosl.org/mailman/listinfo/intel-wired-lan


More information about the Intel-wired-lan mailing list